その理由は、アプリケーション メニューやメッセージ ボックスのようなものが表示されたときに 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()
)。