在我看来,我遇到了WinAPI的奇怪行为。在我的程序中,我正在为窗口设置一个计时器
::SetTimer(window_handle, timer_id, 10, NULL);
并在我的窗口中处理WM_TIMER消息。为了减少所需的 CPU 时间,我还在消息泵中使用了 ::WaitMessage
函数。现在事实证明,只要我在那里有::WaitMessage
功能,WM_TIMER消息就会在一段时间后停止出现。如果我从我的消息泵中删除它,一切按预期工作正常。
现在我想知道我是否设置了错误的计时器,或者这是否是::WaitMessage
的标准行为。搜索MSDN和网络并没有让我知道为什么会这样。
这是我使用的消息泵:
while(true) {
if(GetMessage(&msg, _window_handle, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
return 0;
}
WaitMessage();
}
希望有人能为我澄清这一点。
是的,这将随机无法处理更多的计时器消息。 对于 WaitMessage() 来说,一个非常硬的规则是,在调用消息队列之前,它应该是空的。 如果它不为空,则队列中剩余的任何消息都将标记为"已见",WaitMessage() 会忽略它们。
因此,失败的情况是队列中有两条消息,例如鼠标消息和计时器消息。 您收到鼠标消息,但留下计时器消息。 不会生成其他计时器消息,因为您尚未处理挂起的计时器消息。 GetMessage + WaitMessage 的组合非常麻烦,您必须使用 PeekMessage 代替。
只需删除 WaitMessage(),它在这里没有任何用处。
除了Hans Passant所说的之外,你还应该改写代码。 WaitMessage
不能很好地与GetMessage
配合使用,请改用PeekMessage
,并仅在备用代码路径(else
)中保留WaitMessage
,如下所示:
while( true )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
WaitMessage();
}
}
WaitMessage
允许线程休眠,直到消息进入队列。