4

32ビットフックDLLファイルをインストールし、親プログラム(64ビットプログラム)が終了するまで待つことだけを目的としたウィンドウレスアプリケーションがあります。64ビットプログラムはC#で記述されており、ウィンドウレスアプリケーションはC++で記述されています。私はもともと、プログラムを開いたままにするこのGetMessageループを持っていました:

while(GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

C#でProcess.Killメソッドを使用してC ++アプリケーションを閉じていましたが、それではC++アプリケーションを完全に閉じることができないことがわかりました。また、C#アプリケーションがクラッシュした場合、C++アプリケーションは永久に開いたままになります。次のループを使用して、C ++アプリケーションでC#アプリケーションがまだ実行されているかどうかを確認しました。

while(true)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;

    Sleep(1000);
}

何らかの理由で、睡眠は問題を引き起こします。DLLファイルによってインストールされるフックはWH_CBTとWH_KEYBOARDです。このループでC++アプリケーションを実行しているときにキーを押すと、キーが使い果たされてしまいます。スリープを削除すると正常に動作しますが、予想どおり、100%CPUを使用します。これは望ましくありません。メッセージループを完全に削除し、代わりにisMainProgramRunningがfalseを返したときに終了するスレッドで無限のタイムアウトを持つWaitForSingleObjectを使用してみました。これは基本的にコンピュータ全体をロックします。

GetMessageは、私が見た限りでは戻ってこなかったが、メインスレッドを無期限に中断したためにこれらの問題が発生しなかった理由はよくわかりませんが、WaitForSingleObjectをクリックすると、すべてのアプリケーションがフリーズします。C#アプリケーションが閉じるまでC ++アプリケーションを開いたままにするにはどうすればよいですか?

編集:

メッセージポンプでのスリープが悪いことが指摘されたので、これを聞いてみましょう:メッセージ待機のタイムアウトを指定する方法はありますか?プログラムはメッセージを無期限に待機するのではなく、約250ミリ秒待って、タイムアウトし、isMainProgramRunningメソッドを実行してから、もう少し待ちますか?

Edit2:

私はMsgWaitForMultipleObjectsを使用してみましたが、Leoが提案した方法とは多少異なります。これは私が使用したループです:

while(MsgWaitForMultipleObjects (0, NULL, true, 250, QS_ALLPOSTMESSAGE) != WAIT_FAILED)
{
    if(PeekMessage(&msg, NULL, 0, 0, true))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(!isMainProgramRunning())
        break;
}

繰り返しますが、私は睡眠に関して同じ問題を抱えていました。また、メインスレッドを一時停止して、他のスレッドに再開させてみました。同じ問題。これらの問題を引き起こさずに待機できるようにするGetMessageの機能は何ですか?これは別の投稿の対象になるかもしれませんが、フックをインストールしているC ++アプリケーションがスリープまたは一時停止すると、フック内のすべての処理も一時停止しているように見えるのはなぜですか?

Edit3:

フックをインストールするためにC++アプリケーションが呼び出すDLLメソッドは次のとおりです。

extern "C" __declspec(dllexport) void install()
{
    cbtHook = SetWindowsHookEx(WH_CBT, hookWindowEvents, hinst, NULL);

    if(cbtHook == NULL)
        MessageBox(NULL, "Unable to install CBT hook", "Error!", MB_OK);

    keyHook = SetWindowsHookEx(WH_KEYBOARD, LowLevelKeyboardProc, hinst, NULL);

    if(keyHook == NULL)
        MessageBox(NULL, "Unable to install key hook", "Error!", MB_OK);
}
4

4 に答える 4

4

2つの別々の問題があります:

  1. C#プログラムが終了した場合(クラッシュなど)にウィンドウレスC++プログラムを自動的に終了させる方法。

    C ++プログラムで、C#プログラムへのハンドルを開きます。C#プログラムはC ++プログラムを実行するため、C#プログラムに独自のPIDを引数として渡してもらいます。C ++プログラムは、OpenProcessを使用してそのプロセスへのハンドルを開くことができます。

    次に、メッセージループでMsgWaitForMultipleObjectsを使用します。C#プログラムがハンドルを終了すると、ハンドルが通知され、ウェイクアップします。(プロセスが通知されているかどうかを確認するために使用することもできますWaitForSingleObject(hProcess,0)==WAIT_OBJECT_0。たとえば、ウェイクアップした理由を確認するために使用できますが、MsgWaitForMultipleObjectsの結果でもそのことがわかります。)

    終了するときにプロセスハンドルを閉じる必要があります(終了時にOSが自動的に処理しますが、このコードを別のコンテキストで再利用する場合に備えて、これをお勧めします)。ハンドルはそれが表すプロセスよりも長持ちすることに注意してください。そのため、ハンドルを待つことができます。

  2. C#プログラムを作成する方法は、C++プログラムに終了するように指示します。

    #1が機能する場合はこれは必要ないかもしれませんが、必要に応じてC#プログラムにC++プログラムにメッセージを送信させることができます。

    PostQuitMessageを使用したり、スレッドまたはプロセス間でWM_QUITを投稿または送信したりしないでください。

    代わりに、 PostThreadMessageを使用して、2つのアプリが同意する他のメッセージ(WM_APP + 1など)を投稿してください。

于 2010-12-20T08:23:51.610 に答える
1

名前付きイベントを作成して、次を使用できます。

MsgWaitForMultipleObjects

メッセージループ内。

C#アプリケーションは、このイベントを開いて発生させるだけで、アプリケーションに終了を指示できます。

これは一種の最小限のプロセス間通信です。

于 2010-12-20T08:18:12.983 に答える
0

レイモンド・チェンによるこの記事(モダリティ)で指定されているように、WM_QUITメッセージを送信して正しく処理することにより、プロセスを終了する必要があります。メッセージを処理せずにループ内でスリープしないでください-それは間違っています。アプリはメッセージを処理しているか、新しいメッセージを待っている必要があります。

于 2010-12-20T05:12:19.787 に答える
-1

GetMessageが返されないのは、ウィンドウが作成されていないためです。

メッセージキューを使用するには、GUIが必要です。たとえば、非表示のウィンドウを作成できます。

于 2010-12-20T15:17:38.470 に答える