3

現在、win32 GUI アプリ内から CreateProcess/WaitForSingleObject を使用して、ソフトウェア ライセンスの問題を処理する小さな GUI アプリを起動しています。これはすべて正常に機能しますが、ライセンス アプリが作業を完了するのを待つ間、基本的に「親」アプリがハングします。この間、親アプリの更新は行われず、ユーティリティ アプリのウィンドウを移動すると、醜い白い四角が表示されます。

また、何らかの奇妙な理由で、ユーティリティ アプリの実行中に、そのアプリ内から何かをクリップボードにコピーすると、ハングします。理由はまだわかりませんが、親アプリ内からアプリが終了するのを待っている場合にのみ発生します。

したがって、他のアプリが終了するのを待っている間に親アプリにイベントを処理させることができれば、両方の問題を解決できるのではないかと考えています。

では、UI の更新も処理する CreateProcess/WaitForSingleObject に代わるものはありますか?

4

5 に答える 5

5

WaitForSingleObject() 呼び出しは、呼び出しに渡すハンドルが通知されるまでスレッドをブロックするため、親プロセスがハングしているように見えます。

子プロセスは、クリップボードへのコピー操作中にハングする可能性があります。これは、その操作の一部として、親プロセスのウィンドウまたはすべての最上位ウィンドウにメッセージを送信するためです。親プロセスのスレッドのメッセージ ループは実行されていません。これは、子プロセスが終了するまでブロックされ、メッセージが処理されず、子プロセスがブロックされたままになるためです。

WaitForSingleObject() を呼び出す代わりに、MsgWaitForMultipleObjects()を呼び出すことができます。dwWaitMask パラメータに QS_ALLINPUT を指定すると、MsgWaitForMultipleObjects は、イベントが通知されたとき、またはスレッドのメッセージ キューに入力があるときに返されます。メッセージが利用可能であるために MsgWaitForMultipleObjects() が返された場合は、それを処理して待機を再開できます。

MSG msg;
DWORD reason = WAIT_TIMEOUT;
while (WAIT_OBJECT_0 != reason) {
    reason = MsgWaitForMultipleObjects(1, &hChildProcess, FALSE, INFINITE, QS_ALLINPUT);
    switch (reason) {
    case WAIT_OBJECT_0:
        // Your child process is finished.
        break;
    case (WAIT_OBJECT_0 + 1):
        // A message is available in the message queue.
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            // Note that if your main message loop does additional processing
            // (such as calling IsDialogMessage() for modeless dialogs)
            // you will want to do those things here, too.
        }
        break;
    }
}
于 2009-02-17T14:55:08.400 に答える
3

WaitForSingleObject 呼び出しをループに入れて、dwMilliseconds パラメーターに比較的小さい値を使用できます。

ループを終了する条件は、WaitForSingleObject 呼び出しが WAIT_OBJECT_0 を返す場合です。

ループでは、メッセージ キューを調べて、処理する必要があるものがあるかどうかを確認する必要があります。これをどのように処理するかは、実際にはあなた次第であり、通常のニーズによって異なります。

// Assuming hYourWaitHandle is the handle that you're waiting on
//   and hwnd is your window's handle, msg is a MSG variable and
//   result is a DWORD variable
//

// Give the process 33 ms (you can use a different value here depending on 
//  how responsive you wish your app to be)
while((result = WaitForSingleObject(hYourWaitHAndle, 33)) == WAIT_TIMEOUT)
{ 
   // if after 33 ms the object's handle is not signaled..       

   // we examine the message queue and if ther eare any waiting..
   //  Note:  see PeekMessage documentation for details on how to limit
   //         the types of messages to look for
   while(PeekMessage(&msg, hwnd,  0, 0, PM_NOREMOVE))
   {
     // we process them..
     if(GetMessage(&msg, NULL, 0, 0) > 0)
     {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
     }
   }
} 
// if you're here it means WaitForSingleObject returned WAIT_OBJECT_0, so you're done
//  (but you should always check and make sure it really is WAIT_OBJECT_0)
if(result != WAIT_OBJECT_0)
{
    // This should not be.. so react!
}

于 2009-02-13T17:07:53.413 に答える
1

これは次のように処理できることをお勧めします。

  • 親アプリケーションはCreateProcessを実行し、応答やユーティリティアプリの終了を待つのではなく、すぐに戻ります
  • 親アプリケーションが戻ってきたため、他のウィンドウメッセージ(WM_PAINTなど)を処理できます。
  • ユーティリティアプリが終了すると、親アプリケーションに通知します(たとえば、PostMessageおよびRegisterWindowMessage APIを使用)
  • 親アプリケーションは、PostMessageを介して受信した肯定的な通知を処理します
  • 親アプリケーションでは、Windowsタイマー(WM_TIMER)が実行されている場合もあるため、通知を送信する前に、ユーティリティアプリが強制終了されたかどうかがわかります。
于 2009-02-13T16:10:36.640 に答える
0

スポーンしているアプリが明示的または暗黙的にsendmessageブロードキャストを引き起こす場合、ハングの問題が発生する可能性があります。これは私のウェブサイトから切り抜かれています:

この問題は、アプリケーションにウィンドウがありますが、メッセージをポンピングしていないために発生します。生成されたアプリケーションがブロードキャストターゲット(HWND_BROADCASTまたはHWND_TOPMOST)の1つでSendMessageを呼び出す場合、すべてのアプリケーションがメッセージを処理するまで、SendMessageは新しいアプリケーションに戻りませんが、アプリはメッセージを処理できないため、 tメッセージをポンピングする....新しいアプリがロックされるため、待機が成功することはありません....デッドロック。

私はクリップボードコードを実行しませんが、それが上記の状況(信じられる)を引き起こす場合、あなたはデッドロックになります。あなたはできる:

  • セカンダリアプリケーションの起動を小さなスレッドに入れます
  • タイムアウトを使用して、PeekMessageループをスピンします(yuck)
  • MsgWaitForMultipleObjectsAPIを使用します。

その順序によって優先順位が暗示されることはありません...生成されたアプリケーションを自分で作成しないことを前提としています。その場合、ChrisWが提案したように、IPCを使用してこの問題を回避できます。

于 2009-02-13T16:14:13.090 に答える
0

次のことのみを行うスレッドを作成する必要があります。

  • CreateProcess() を呼び出して他のアプリを実行する

  • WaitForSingleObject() を呼び出してプロセスが終了するのを待ちます - これはバックグラウンド スレッドであるため、アプリはブロックしません

  • プロセス ハンドルで CloseHandle() を呼び出す

  • メインスレッドの通知メッセージで PostMessage() を呼び出します

ここで必要なのは、再入の問題を防ぐためにメイン アプリケーションの GUI が無効になっていることを確認することだけです。モーダル ダイアログを表示して、他のアプリが実行中であり、最初に対処する必要があることをユーザーに通知します。ダイアログを手動で閉じることができないこと、およびバックグラウンド スレッドから投稿された通知メッセージを受け取るとダイアログが自動的に閉じることを確認してください。スレッド作成全体をこのダイアログに入れることもでき、ダイアログを作成、表示、および破棄し、外部アプリケーションが生成する結果を返す単一の関数にすべてをラップできます。

于 2009-02-13T16:48:44.413 に答える