HANDLE g_event = CreateEvent(NULL, TRUE, FALSE, L"tasdfasdfsadfasdfasdfas");
BOOL bIsok = TRUE;
while(bIsok)
{
DWORD dwTime = MsgWaitForMultipleObjects(1, &g_event, FALSE, 5000, QS_ALLINPUT);
MSG msg;
switch(dwTime)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
switch(msg.message)
{
case WM_DESTROY:
case WM_CLOSE:
case WM_QUIT:
break;
default:
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
break;
case WAIT_TIMEOUT:
break;
}
}
运行此代码,然后单击关闭按钮。该窗口将隐藏,但程序不会退出。
为什么以及如何解决这个问题?
答案 0 :(得分:0)
该过程永远不会终止,因为while(bIsok)
循环的谓词永远不会求值为false
。要解决此问题,代码需要在关闭时更新bIsok
。最简单的解决方法是在WM_QUIT
消息处理程序中这样做:
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
switch(msg.message)
{
case WM_DESTROY:
case WM_CLOSE:
break;
case WM_QUIT:
bIsok = false;
break;
default:
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
尽管解决了紧迫的问题,但仍有更多应解决的代码问题,尤其是当消息到达时,无法完全耗尽消息队列。 MsgWaitForMultipleObjects的文档包含以下说明:
WAIT_OBJECT_0
+ nCount :在线程的输入队列中可以使用dwWakeMask
参数中指定类型的新输入。 PeekMessage,GetMessage和WaitMessage等功能将队列中的消息标记为旧消息。因此,在调用这些函数之一之后,对MsgWaitForMultipleObjects的后续调用将不会返回,直到指定类型的新输入到达为止。。
每当收到一条消息时,代码仅处理第一条消息,然后继续等待新消息。相反,代码应在继续之前处理所有消息。
并非严格要求,但我还将应用以下更改:
MsgWaitForMultipleObjects
中删除超时。不需要它,只是使线程反复唤醒,即使什么也没发生。DestroyWindow
调用WM_CLOSE
,响应PostQuitMessage
调用WM_DESTROY
。这是顶级窗口的window procedure:
LRESULT CALLBACK MyWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_CLOSE:
::DestroyWindow( hwnd );
return 0;
case WM_DESTROY:
::PostQuitMessage( 0 );
return 0;
default:
return ::DefWindowProc( hwnd, uMsg, wParam, lParam );
}
}
更新后的主循环:
HANDLE g_event = CreateEvent(NULL, TRUE, FALSE, L"tasdfasdfsadfasdfasdfas");
BOOL bIsok = TRUE;
while(bIsok)
{
DWORD dwTime = MsgWaitForMultipleObjects(1, &g_event, FALSE, INFINITE, QS_ALLINPUT);
switch(dwTime)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
{
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT)
{
bIsok = false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
break;
case WAIT_TIMEOUT:
break;
}
}