3

私は主に次のようなアプリケーションを開発しています。

while (true)
{
    while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
    {
       TranslateMessage(&Msg);
       DispatchMessage(&Msg);
    }
    DoSomething();
    Sleep(1);
}

私が気付いたのは、メニューバー(メニューオプションを表示)をクリックしてもDoSomething()が呼び出されないことです。メニューバーから出るまで、DispatchMessage呼び出しがメッセージループをブロックすることを確認しました。

どうすればこの動作を回避できますか?

ありがとう!

4

2 に答える 2

3

その理由は、アプリケーション メニューやメッセージ ボックスのようなものが表示されたときに Windows がメッセージの処理を引き継ぎ、Windows が使用するメッセージ ループがDoSomething()メソッドを呼び出さないためです。これは視覚化するのが難しいかもしれないので、何が起こっているのかを順を追って説明します。

  • 誰かがメニューを開くと、ウィンドウを描画するように指示するメッセージがウィンドウに送信されます。は、他のすべてのメッセージと同様DispatchMessage()に、メッセージを に送信します。WndProc
  • このメッセージを処理しないため、Windows に渡されます (WndProc呼び出しの可能性が高いためDefWindowProc) 。
  • デフォルトの操作として、Windows はメニューを描画し、呼び出しを行わない別のデフォルト メッセージ ループを開始します。DoSomething()
  • このループは、アプリケーション宛てのメッセージをフェッチし、 を呼び出してアプリケーションにディスパッチするWndProcため、アプリケーションはフリーズせず、動作を続けます (DoSomething()呼び出しを除く)。
  • メニューが閉じられると、制御がメッセージ ループに戻ります (この時点でのみ、DispatchMessage()最初の呼び出しからの呼び出しが返されます) 。

つまり、メニューが表示されると、メッセージ ループは次のようなデフォルトのメッセージ ループに置き換えられます (たとえば)。

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

ご覧のとおり、DoSomething()メソッドは呼び出されません。

これをテストするには、メニューが表示されていないときとメニューが表示されているときに、デバッガーでコードを一時停止してみてください。コールスタックを見ると、メニューが表示されたときに、メッセージが自分のメッセージ ループではなく、Windows メッセージ ループによって処理されていることがわかります。

私が考えることができる唯一の回避策(マルチスレッドなし)は、タイマーを開始し、WM_TIMERを呼び出してメッセージを処理する場合ですが、それは完全な解決策ではありません(処理するメッセージが残っていない場合にのみDoSomething()呼び出すことを意図していると思われるため)DoSomething())。

于 2009-09-19T21:27:07.897 に答える
-1

メッセージの翻訳とディスパッチを別のスレッドにスピンオフします。

DoSomething がメッセージのディスパッチに依存しない限り。

Dispatch がブロックされている理由を理解したいと思うかもしれませんが。これは正常な動作ですか?

于 2009-09-19T20:37:31.820 に答える