调整窗口大小时不断发送窗口消息WM_SIZING

Window message WM_SIZING sending incessantly when window resizing

本文关键字:窗口 消息 WM SIZING 小时 调整      更新时间:2023-10-16

我做了一个小游戏,但有一些低优先级窗口消息的问题,这些消息不断从系统发送,并阻止运行游戏逻辑的代码。

我创建了这样的消息循环:

bool Window::SystemRoutineAndCheckQuit() {
    ::MSG msg;
    while( ::PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) ) {
        if( msg.message == WM_QUIT ) {
            ::UnregisterClass( registeredClassName, ::GetModuleHandle( nullptr ) );
            DLOG( lg ) << "Exit from system loop" << DLOG_END;
            return false;
        }
        ::TranslateMessage( &msg );
        ::DispatchMessage( &msg );
    }
    return true;
}
//....
    while( window.SystemRoutineAndCheckQuit() ) {
        // do all render and logic
    }

也就是说,在每帧之前,我想处理来自窗口的所有消息,然后,当队列为空时,执行所有逻辑。我注意到,当调整窗口大小时,我一次又一次地收到相同的消息WM_SIZING,当鼠标按钮仍然按下时,队列永远不会变空(即使窗口的大小与上次调用不同,我也会收到具有相同窗口坐标的消息)。所以它阻止执行我的代码。

是否有其他消息可以保持windows消息队列不为空,在没有低优先级的情况下处理所有消息的最佳方式是什么,如WM_SIZING?

我在Windows8上测试它。

附言:我需要调整窗口大小,所以我不想通过改变样式来禁止它。

编辑:很抱歉出现不正确的描述问题,但发现了真实的情况(以及为什么我之前试图通过限制已处理消息的数量或在连续两次获得同一消息时中断消息处理来解决问题,但都不会成功)。从PeekMessage中,我得到消息WM_NCLBUTTONDOWN,在这个消息之后,程序不会从:DispatchMessage返回,并阻止继续执行线程,直到释放鼠标。当在DispatchMessage中编程时,我的处理程序会重复获得WM_SIZING或WM_MOVING(独立于消息处理程序函数的返回值(DefWindowProc的结果,TRUE(消息已处理)或0)。

您可以在每帧之前处理N条消息。。其中N是您在1-10之间设置的极限。这样你就可以处理合理数量的事件,然后进入你的实际游戏逻辑。

可以想象,当队列为空时,Windows可能只是不断生成"窗口大小调整"消息,以确保应用程序知道窗口正在调整大小。

(也许MS认为应用程序可能不知道,也许用户没有其他办法……所以MS想敲定这条消息。)

DefWindowProc在wParam中使用SC_MOVE或SC_SIZE处理WM_SYSCOMMAND时,它会进入一个循环,直到用户通过释放鼠标按钮或按enter或escape来停止它。它这样做是因为它允许程序通过处理WM_PAINT和WM_NCPAINT消息来渲染客户端区域(绘制小部件或游戏或其他内容的地方)以及边界和标题区域(您仍然应该在窗口过程中接收这些事件)。

它适用于普通的Windows应用程序,这些应用程序在接收消息时会在窗口过程中进行大部分处理。它只影响在窗口程序之外进行处理的程序,例如游戏(通常是全屏的,无论如何都不受影响)。

然而,有一种方法可以绕过它:自己处理WM_SYSCOMMAND,调整大小或移动自己。这需要付出大量的努力,但可能证明是值得的。或者,当发送WM_SIZING时,您可以使用setjmp/longjmp来退出窗口过程,或者使用相同的Windows光纤;不过,这些都是一些棘手的解决方案。

我在上周末解决了这个问题(使用第一种方法),如果你感兴趣的话,我已经在sourceforge上将代码发布到了公共领域。请务必阅读自述文件,尤其是注意事项部分。它在这里:https://sourceforge.net/projects/win32loopl/