0

I came across weird problem. I have C++ (WinAPI) application and if I close it via [X] window button, everything works correctly - window is closed, application is ended.

But when I close the application from the taskbar button context menu, the window closes but application/process is still running. Stuck on GetMessage.

The application contains only one window.

My WndProc simply contains WM_DESTROY handler which is processed correctly in any case:

switch (message) {
...
case WM_DESTROY:
    PostQuitMessage(0);
    break;

default:
    return DefWindowProc(hWnd, message, wParam, lParam);
}

The application's main loop is:

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

When I close the application from taskbar menu, the window closes but the process remains stuck on GetMessage. Just like it does not receive WM_QUIT correctly. But if I replace GetMessage with PeekMessage, it reads WM_QUIT from queue correctly.

Also just adding the additional PeekMessage before GetMessage makes it work:

while (true) {
    if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
        int res = GetMessage(&msg, NULL, 0, 0);
        if (res) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        } else {
            break;
        }
    }
}

Is there any reason why simple GetMessage would not receive WM_QUIT correctly when application is closed from the taskbar menu?

Minimal application code to reproduce the problem:

#include "windows.h"

#pragma comment (lib,"user32.lib")

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;   
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // register Win32 class for this app
    WNDCLASSEX wndClass = { 0 };
    wndClass.cbSize = sizeof(wndClass);
    wndClass.lpszClassName = L"Minimal Window";
    wndClass.hInstance = hInstance;
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);

    if (RegisterClassEx(&wndClass)) {
        HWND hWnd = CreateWindowEx(0, wndClass.lpszClassName, L"Minimal", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 0, 0, 1024, 480, NULL, NULL, hInstance, NULL);
        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);

        // process window messages
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }               
    }
    return 0;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
bigmuscle
  • 419
  • 1
  • 6
  • 16
  • *when application is closed from the taskbar menu* this is unrelated at all – RbMm Oct 02 '18 at 09:55
  • 1
    Could you post a [mcve]? – Jabberwocky Oct 02 '18 at 09:55
  • Yes, I added snippet with the minimal code in my question. It still reproduces the problem when I close from taskbar context menu. – bigmuscle Oct 02 '18 at 10:27
  • @bigmuscle cannot reproduce with your minimal application. Which Windows do you have? What happens if you close the window with Alt-F4? – Jabberwocky Oct 02 '18 at 10:29
  • Compiled with MSVS 2015. OS is Win10 x64. But I just discovered that the problem appears only when my touch screen is connected. When I use regular display, problem does not appear. – bigmuscle Oct 02 '18 at 10:38
  • Alt-F4 closes the application correctly. – bigmuscle Oct 02 '18 at 10:56
  • Which touchscreen is this? Does the driver install any 'productivity enhancements'? – IInspectable Oct 02 '18 at 12:00
  • It is ELO 1002L - https://www.elotouch.com/touchscreen-monitors/1002l.html and it does not have need any custom drivers on Win10. It uses default Win10 interface (probably some Microsoft driver). – bigmuscle Oct 02 '18 at 12:10
  • Did you try catching `WM_CLOSE`? – Paul Sanders Oct 02 '18 at 17:02
  • 1
    @PaulSanders by default, if `WM_CLOSE` is passed to `DefWindowProc()`, it calls `DestroyWindow()`, thus generating `WM_DESTROY`. – Remy Lebeau Oct 02 '18 at 18:51
  • @Remy But the OP says his window is closing... – Paul Sanders Oct 02 '18 at 20:56
  • @PaulSanders Then something in the OP's app, such as an ill-coded modal message loop, or a message hook, or something, is likely receiving `WM_QUIT` first and not forwarding it on to the main message loop (https://blogs.msdn.microsoft.com/oldnewthing/20050222-00/?p=36393). That is the only explanation I can think of. But the code the OP showed as-is does not cause that issue. I tried the code shown and it works fine, both `WM_CLOSE` and `WM_QUIT` are generated and handled as expected, whether clicking on the window itself, or on the Taskbar. So I'm guessing the OP didn't show his *real* code. – Remy Lebeau Oct 02 '18 at 22:25
  • @Remy Yes, I agree, something doesn't add up. – Paul Sanders Oct 02 '18 at 22:29
  • 1
    Re. the touch screen issue, have you tried handling WM_NCDESTROY instead of WM_DESTROY? Not an explanation but worth checking. – SoronelHaetir Oct 03 '18 at 05:53
  • @SoronelHaetir Interesting idea and it really works! If I call PostQuitMessage(0) in WM_NCDESTROY instead of WM_DESTROY, then WM_QUIT is processed by GetMessage correctly. – bigmuscle Oct 03 '18 at 07:59

0 Answers0