Reputation: 678
I have a window that cannot be closed immediately after being created despite my window procedure function being able to detect the WM_CLOSE
message, and calling PostQuitMessage
and letting Windows continue to handle the window messages with DefWindowProc
.
But, after moving the window by dragging the title bar, it seems to be able to close normally.
The code for the my window procedure function is the following:
LRESULT CALLBACK OnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_QUIT:
{
printf("WM_QUIT\n");
break;
}
case WM_CLOSE:
{
printf("WM_CLOSE\n");
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(handle, message, wParam, lParam);
}
So besides sending the WM_MOVE
message to my window or using exit(0)
in the WM_CLOSE
case block, how can I ensure that my window can be closed immediately after being created?
After passing NULL
to the hWnd
parameter of GetMessageW
, instead of my window handle, the window now closes properly hence answering my previous question.
Therefore, why did the GetMessageW
function previously not retrieve the WM_QUIT
message with the provided handle of the only window, instead of using NULL
as the hWnd
parameter?
Upvotes: 1
Views: 3112
Reputation: 1
Another issue that I had found was that when you had set your window classes (WNDCLASSEX) windows procedure (lpfnWndProc) I had set it to the default window procedure and had not used a custom built window procedure. So when you had closed it nothing would occur.
Upvotes: 0
Reputation: 23
I had this exact problem when I called GetMessage()
in my loop with the handle of the main window as the second argument:
GetMessage(&msg, hMainWindow, 0, 0)
instead of NULL to specify that I want to handle messages for the whole thread / application instance:
GetMessage(&msg, NULL, 0, 0)
The WM_CLOSE messages would lead to WM_QUIT messages, but GetMessage() will ignore these when it's only looking for messages for a particular window. From the documentation:
If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.
What exactly causes moving of the window to have subsequent closing attempts succeed is however still beyond me.
Upvotes: 0
Reputation: 597961
A properly written message loop will never dispatch a WM_QUIT
message to a window procedure, it will simply break the loop when GetMessage()
returns 0 when it receives a WM_QUIT
message:
If the function retrieves a message other than WM_QUIT, the return value is nonzero.
If the function retrieves the WM_QUIT message, the return value is zero.
If there is an error, the return value is -1. For example, the function fails if hWnd is an invalid window handle or lpMsg is an invalid pointer. To get extended error information, call GetLastError.
In response to WM_CLOSE
, you should be calling DestroyWindow()
instead of PostQuitMessage()
directly (the default behavior of DefWindowProc(WM_CLOSE)
is to call DestroyWindow()
for you). You need a WM_DESTROY
handler that should then call PostQuitMessage()
:
LRESULT CALLBACK OnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
{
printf("WM_CLOSE\n");
DestroyWindow(handle);
return 0;
}
case WM_DESTROY:
{
printf("WM_DESTROY\n");
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(handle, message, wParam, lParam);
}
This is documented on MSDN:
Here is the flow chart from that page:
As for the GetMessage()
issue, if you read the documentation for GetMessage()
and PostQuitMessage()
more carefully, you will see that the WM_QUIT
message posted by PostQuitMessage()
is not a window message. Passing a non-NULL HWND
to GetMessage()
only retrieves messages from PostMessage()
and SendMessage()
that are intended for that specific HWND
1. GetMessage()
will ignore any messages that are not intended for that HWND
, which includes thread messages from PostThreadMessage()
and PostQuitMessage()
. Passing a NULL HWND
to GetMessage()
allows it to return any pending message, including WM_QUIT
.
1 which is dangerous to do, BTW: The dangers of filtering window messages
Upvotes: 9