Win32 Windowlessアプリケーション - プログラムの出口を待ちます
-
11-10-2019 - |
質問
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を使用しました。これは基本的にコンピューター全体をロックします。
なぜ私が見た限り、戻ってこなかったが、メインスレッドを無期限に一時停止する理由は本当にわかりませんが、これらの問題を引き起こしませんでしたが、クリックするとすべてのアプリケーションがフリーズします。 C#アプリケーションが閉じるまで、C ++アプリケーションを開いたままにするにはどうすればよいですか?
編集:
メッセージポンプで寝るのは悪いことだと私に指摘されているので、これを聞いてみましょう:メッセージのタイムアウトを指定する方法はありますか?約250ミリ秒待って、タイムアウト、ismainprogramonningメソッドを実行させて、もう少し待ちますか?
編集2:
Leoが提案したものとは多少異なる方法で、MSGWAITFORMULTIPLEOBJECTSを使用してみました。これは私が使用したループです:
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 ++アプリケーションがスリープまたは吊り下げられているとき、フック内のすべての処理も同様に懸濁しているように見えるのですか?
編集3:
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);
}
解決
GetMessage Never Returnsは、窓が作成されていないためです!
メッセージキューを使用するには、GUIが必要です。たとえば、隠されたウィンドウを作成できます。
他のヒント
2つの別々の問題があります。
C#プログラムが終了した場合(クラッシュ)、Windowless C ++プログラムを自動的に終了する方法。
C ++プログラムでは、C#プログラムのハンドルを開きます。 C#プログラムはC ++プログラムを実行するため、C#プログラムに独自のPIDを引数として渡します。 C ++プログラムは、そのプロセスを使用してハンドルを開くことができます OpenProcess.
次に、使用します msgwaitformultipleObjects メッセージループで。 C#プログラムがハンドルを終了した場合、必要なハンドルが合図され、目覚めます。 (使用することもできます
WaitForSingleObject(hProcess,0)==WAIT_OBJECT_0
MSGWaitFormUltPipleObjectsの結果もそれを教えてくれるが、プロセスが合図されているかどうかを確認するには、たとえば、あなたが目覚めた理由を確認するために。終了しているときにプロセスハンドルを閉じる必要があります(OSは、終了するときにそれを行いますが、別のコンテキストでこのコードを再利用する場合は良い練習です)。ハンドルは、それが表すプロセスの概要を示していることに注意してください。それが、あなたがそれを待つことができる理由であることに注意してください。
C#プログラムにC ++プログラムに終了するよう指示する方法。
#1が機能する場合はこれを必要としないかもしれませんが、必要に応じてC#プログラムにメッセージをC ++に投稿させることができます。
追放後の使用を使用しないでください。スレッドまたはプロセスにWM_QUITを投稿または送信しないでください。
代わりに、2つのアプリが使用して2つのアプリが同意するという他のメッセージを投稿してください ThreadMessage後.
名前付きイベントを作成して使用できます。
msgwaitformultipleObjects
メッセージループで。
C#アプリケーションは、このイベントを開いて提起するだけで、アプリケーションに終了するように指示する必要があります。
それは一種の最小限のプロセス通信です。
wm_quitメッセージを投稿して正しく処理することにより、プロセスを終了する必要があります。 この記事(モダリティ), 、レイモンド・チェン。メッセージを処理せずにループ内で眠らないでください - それは間違っています。アプリはメッセージを処理するか、新しいメッセージを待っている必要があります。