Reputation: 127
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;
}
}
Run this code and then click the close-button. The window hides but the program doesn’t exit.
Why, and how can I resolve this?
Upvotes: 1
Views: 200
Reputation: 51355
The process never terminates, because the while(bIsok)
loop's predicate never evaluates to false
. To fix this, the code needs to update the bIsok
when it's time to shut down. The easiest fix would be to do so in the WM_QUIT
message handler:
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);
}
While that addresses the immediate issue, there are still more issues with the code, that should be fixed, most notably failure to fully deplete the message queue, when messages arrive. The documentation for MsgWaitForMultipleObjects contains the following remark:
WAIT_OBJECT_0
+ nCount: New input of the type specified in thedwWakeMask
parameter is available in the thread's input queue. Functions such as PeekMessage, GetMessage, and WaitMessage mark messages in the queue as old messages. Therefore, after you call one of these functions, a subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives.
Whenever a message arrives, the code handles only the first message, and then moves on to wait for new messages. Instead, the code should process all messages before moving on.
Not strictly required, but I would also apply the following changes:
MsgWaitForMultipleObjects
. It is not needed and merely causes the thread to wake up repeatedly, even if nothing happened.DestroyWindow
in response to WM_CLOSE
, and PostQuitMessage
in response to WM_DESTROY
.This is the window procedure of the toplevel window:
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 );
}
}
Updated main loop:
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;
}
}
Upvotes: 1