Daros911
Daros911

Reputation: 435

Closing an app not sending WM_QUIT message?

Having such a simple Win32 app:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR pCmdLine, int nCmdShow) {
    ...
    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Learn to Program Windows", WS_POPUP | WS_BORDER, 0, 0, 190, 110, nHwnd, NULL, hInstance, NULL);

    if (hwnd != NULL) {
        ShowWindow(hwnd, nCmdShow);
            
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0) > 0) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if (msg.message == WM_QUIT)                 {
                swprintf_s(msgbuf, _T("WM_QUIT (main)\n"));
                OutputDebugString(msgbuf);
            }
        }
    }
    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {

        case WM_DESTROY:
            swprintf_s(msgbuf, _T("WM_DESTROY\n"));
            OutputDebugString(msgbuf);
            PostQuitMessage(0);
            return 0;

        case WM_CLOSE:
            swprintf_s(msgbuf, _T("WM_CLOSE\n"));
            OutputDebugString(msgbuf);
            DestroyWindow(hwnd);
            return 0;

        case WM_QUIT:
            swprintf_s(msgbuf, _T("WM_QUIT\n"));
            OutputDebugString(msgbuf);
            return 0;

        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
            Example_DrawImage9(hdc);
            EndPaint(hwnd, &ps);
            return 0;
        }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

When i do Alt+F4 to close it i get WM_CLOSE, WM_DESTROY but NOT WM_QUIT? Why don't I get the WM_QUIT message?

Upvotes: 1

Views: 1193

Answers (1)

Joseph Willcoxson
Joseph Willcoxson

Reputation: 6050

Reading documentation at https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-quit:

The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.

Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage.

=== Portion after this was added after answer accepted for further clarification ===

As others have noted, there are sort of two things going on in the original code submitted. In the message map, there is a switch case entry for WM_QUIT. The documentation I quoted shows that the message is not for windows and so the case statement will never get processed.

However, there is another issue going on. Look at the message pumping:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);

    if (msg.message == WM_QUIT)                 {
        swprintf_s(msgbuf, _T("WM_QUIT (main)\n"));
        OutputDebugString(msgbuf);
    }
}

When GetMessage() is called and the WM_QUIT message is the message retrieved in the queue, then the return value from GetMessage() will be zero and so it will immediately exit the while loop.

This is documented at https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage

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.

Upvotes: 4

Related Questions