我制作小游戏并且在低优先级窗口消息方面存在一些问题,即不断从系统发送并阻止运行游戏逻辑代码。
我创建了这样的消息循环:
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
}
即。在每一帧之前,我想处理来自windows的所有消息,然后,当队列将为空时,执行所有逻辑。我注意到当窗口调整大小时我一次又一次得到相同的消息WM_SIZING并且当鼠标按钮仍然按下时队列永远不会为空(即使窗口的大小没有从普通话调用改变我接收到具有相同窗口坐标的消息)。所以它会阻止执行我的代码。
是否有其他消息,保持Windows消息队列不为空,什么是处理所有消息的最佳方式,没有一些低优先级,如WM_SIZING?
我在Windows 8上测试它。
PS:我需要调整大小窗口,所以我不想通过改变风格来禁止它。
编辑:对不起错误的描述问题,但发现了真正发生的事情(以及为什么我以前尝试通过限制已处理邮件的数量来修复它,或者在获取相同邮件两次时通过中断邮件进程按顺序不会成功)。从PeekMessage我得到消息WM_NCLBUTTONDOWN并且在此消息程序之后不从:: DispatchMessage返回并阻止继续执行线程直到鼠标将被释放。当DispatchMessage中的程序时,我的处理程序重复WM_SIZING或WM_MOVING(独立于消息处理函数返回的内容(DefWindowProc的结果,TRUE(消息被处理)或0)。
答案 0 :(得分:1)
您可以在每个帧之前处理N个消息..其中N是您在1-10之间设置的限制。这样你就可以处理合理数量的事件,然后进入你的实际游戏逻辑。
可以想象,当队列为空时,Windows可能会不断生成“窗口大小调整”消息,以确保应用程序知道窗口正在调整大小。
(也许MS认为应用程序可能不知道,也许用户无法做任何事情......所以MS想要敲定那条消息。)
答案 1 :(得分:1)
当DefWindowProc在wParam中使用SC_MOVE或SC_SIZE处理WM_SYSCOMMAND时,它会进入一个循环,直到用户通过释放鼠标按钮或按Enter或escape来停止它。这样做是因为它允许程序通过处理WM_PAINT和WM_NCPAINT消息来呈现客户区(您的小部件或游戏或其他任何内容)以及边框和标题区域(您仍应在Window Procedure中接收这些事件)。
它适用于普通的Windows应用程序,这些应用程序由于接收消息而在其Window Procedure中进行大部分处理。它只影响在窗口过程之外进行处理的程序,例如游戏(通常是全屏但不受影响)。
然而,有一种解决方法:自己处理WM_SYSCOMMAND,调整大小或移动自己。这需要付出很多努力,但可能证明是值得的。或者,您可以使用setjmp / longjmp在发送WM_SIZING时从Window Procedure中逃脱,或者沿着相同的行使用Windows Fibers;这些都是黑客的解决方案。
我在上周末解决了它(使用第一种方法),如果您感兴趣我已经将代码发布到sourceforge上的公共域。只需确保阅读README,特别是警告部分。这是:https://sourceforge.net/projects/win32loopl/