0

我制作了小游戏,并且在低优先级窗口消息方面存在一些问题,这些消息不断地从系统发送并阻止运行游戏逻辑的代码。

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

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 并且当仍然按下鼠标按钮时队列永远不会为空(即使窗口的大小没有从 previos 调用中改变,我也会收到具有相同窗口坐标的消息)。所以它阻止执行我的代码。

是否有任何其他消息保持 Windows 消息队列不为空,以及处理所有没有低优先级(如 WM_SIZING)的消息的最佳方法是什么?

我在 Windows 8 上测试它。

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

编辑:对于不正确的描述问题感到抱歉,但发现了实际发生的事情(以及为什么我之前尝试通过限制处理的消息数量来修复它,或者在连续两次获得相同消息时通过中断消息处理将不会成功)。从 PeekMessage 我收到消息 WM_NCLBUTTONDOWN 并且在此消息之后程序不会从 ::DispatchMessage 返回并阻止线程继续执行,直到鼠标被释放。当在 DispatchMessage 中编程时,我的处理程序会重复 WM_SIZING 或 WM_MOVING(独立于从消息处理程序函数返回的内容(DefWindowProc 的结果,TRUE(消息已处理)或 0)。

4

2 回答 2

1

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

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

(也许 MS 认为应用程序可能不知道,也许用户无能为力.. 所以 MS 想敲定那条消息。)

于 2013-09-01T01:40:52.540 回答
1

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

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

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

我在上周末解决了它(使用第一种方法),如果您有兴趣,我已将代码发布到 sourceforge 上的公共领域。请务必阅读自述文件,尤其是警告部分。这是:https ://sourceforge.net/projects/win32loopl/

于 2014-01-18T08:25:57.523 回答