1

在我看来,我遇到了 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();
}

希望有人可以为我解决这个问题。

4

2 回答 2

7

是的,这将随机无法处理更多计时器消息。WaitMessage() 的一个非常严格的规则是消息队列在调用之前应该是空的。如果它不为空,那么任何留在队列中的消息都被标记为“已看到”并且 WaitMessage() 会忽略它们。

所以失败的场景是队列中有两条消息,比如鼠标消息和计时器消息。您会收到鼠标消息,但会留下计时器消息。由于您尚未处理待处理的消息,因此不会生成额外的计时器消息。GetMessage + WaitMessage 的组合很麻烦,你必须使用 PeekMessage 来代替。

只需删除 WaitMessage(),它在这里没有用处。

于 2012-04-13T13:10:49.373 回答
0

除了 Hans Passant 所说的之外,您还应该重新编写代码。WaitMessage不能很好地与 一起GetMessage使用,PeekMessage而是使用并WaitMessage仅保留在替代代码路径 ( else) 中,如下所示:

while( true )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    else
    {
        WaitMessage();
    }
}

WaitMessage允许线程休眠,直到消息在队列中。

于 2021-01-05T16:34:32.353 回答