Windows 消息循环

Posted

技术标签:

【中文标题】Windows 消息循环【英文标题】:Windows message loop 【发布时间】:2009-07-16 07:14:07 【问题描述】:

这段代码没有到达第一个 else 有什么原因吗? 我从各种来源得到的完全一样。比我自己的封装。一切顺利。创建窗口,处理消息,为客户区的键盘输入生成事件,gl 画布工作正常(当我强制它绘制时)。

唯一的问题是消息循环永远不会离开第一个 if。 :/ 我真的被困住了。

while (!done)                                       

    if (::PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
    
        if (msg.message == WM_QUIT)                 
        
            done = TRUE;                            
        
        else                                        
        
            ::TranslateMessage (&msg);              
            ::DispatchMessage (&msg);               
        
    
    else                                        
    
        // Code is never reaching this!
        draw ();
        ::SwapBuffers(hDC);
        idle ();
    

return msg.wParam;

【问题讨论】:

显然它在翻译/调度完成时将新消息发布到队列中。您应该只列出所有检索到的消息并推断它是什么消息以及它出现的原因。 使用 spy 我得到了带有 hdc 0 的 WM_PAINT 的硬流。不知道这是如何生成的。 【参考方案1】:

在您的情况下,消息队列绝不能为空 - 为什么?好吧,这取决于程序的其余部分在做什么。一些可能性:

    您的代码将新消息发布到队列中,以使队列不会变空。我建议在处理消息 ID 时注销它们。

    您没有处理绘画消息 - 来自 msdn: “PeekMessage 函数通常不会从队列中删除 WM_PAINT 消息。WM_PAINT 消息在处理之前一直保留在队列中。但是,如果 WM_PAINT 消息具有 NULL 更新区域,则 PeekMessage 会将其从队列中删除。”

希望这会有所帮助。

[编辑] 要处理 WM_PAINT,请调用 BeginPaint 和 EndPaint 或转发到 DefWindowProc

【讨论】:

看起来就是问题所在。但是,我的 MainWndProc 从 WM_PAINT 返回 0。我所知道的是,您处理的每条消息都会返回 0。因此,理论上,不应留下任何消息。 他正在处理 WM_PAINT,因为他看到了正在出现的东西。 添加了此代码,它开始按预期工作。但如果可能的话,希望有一些解释。案例 WM_PAINT: BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps);返回 0; WM_PAINT 不是真正的消息 - 它只是窗口上的一个标志,表明它具有无效的区域(WM_PAINT 从未处理过。)只要该标志存在,就会生成 WM_PAINT。跨度> 看起来你也可以通过将 wm_paint 转发到 DefWindowProc 来做到这一点,但它可能做同样的事情【参考方案2】:

确保您正在正确处理 WM_PAINT

我的意思是确保你从 WM_PAINT 消息中调用 BeginPaintEndPaint,否则你会混淆 Windows 认为你的应用程序仍然需要绘制。

【讨论】:

【参考方案3】:

可能总是有消息在等待?

【讨论】:

【参考方案4】:

仅当消息队列中没有消息时,PeekMessage 才会返回 0。由于消息队列中有要分派的消息,因此它返回一个非零值,并且永远不会执行您的 else 条件。

【讨论】:

我猜他是在问这个问题——为什么从来没有消息没有留下。

以上是关于Windows 消息循环的主要内容,如果未能解决你的问题,请参考以下文章

Windows 线程何时需要消息循环,为啥?

理解Windows消息循环机制

qt卡在消息循环

Windows 消息循环

QT事件循环

Windows核心编程06-Windows的消息循环