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 不依赖于 Dispatching the Msg.

尽管我可能想了解 Dispatch 阻塞的原因;这是预期的正常行为吗?

于 2009-09-19T20:37:31.820 回答