Mike32ab
Mike32ab

Reputation: 466

Why is the window painted strangely (without visual styles) after sending WM_NCDESTROY?

I get strange window painting after I send WM_NCDESTROY manually. This only happens when visual styles are on. When 'Classic style' is on it does not seem to affect the window. I do not pass WM_NCDESTROY to DefWindowProc() when I send it manually, but the window still gets painted strangely. It seems like SendMessage() is processing WM_NCDESTROY. Why is WM_NCDESTROY getting processed even though I do not pass it to DefWindowProc()?

#include <windows.h>

HINSTANCE g_hInst;

LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static BOOL bProcessMsg = FALSE;

    switch(msg)
    {
    case WM_RBUTTONUP:
        SendMessage(hwnd, WM_NCDESTROY, 0, 0);
        //Size window manually after this message is processed to see the effects
        break;

    case WM_DESTROY:
        bProcessMsg = TRUE;
        break;

    case WM_NCDESTROY: 
        if(!bProcessMsg) return 0;
        MessageBox(0, L"Message processed", 0, MB_OK);
        return DefWindowProc(hwnd, msg, wParam, lParam);
        break;

    default: 
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

LRESULT CALLBACK WndProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_MBUTTONUP:
        {
            WNDCLASSEX wc = { 0 };
            wc.cbSize        = sizeof(WNDCLASSEX);
            wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
            wc.hCursor       = LoadCursor(0, IDC_ARROW);
            wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
            wc.hInstance     = g_hInst;
            wc.lpfnWndProc   = WndProc2;
            wc.lpszClassName = L"Testclass2";
            if(!RegisterClassEx(&wc)) return 0;
            CreateWindowEx(0, L"Testclass2", L"Test2", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 40, 40, 200, 200, hwnd, 0, g_hInst, 0);
        }
        break;

    case WM_DESTROY: 
        PostQuitMessage(0);
        break;

    default: 
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = { 0 };
    HWND hwnd;
    MSG msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.hCursor       = LoadCursor(0, IDC_ARROW);
    wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
    wc.hInstance     = hInstance;
    wc.lpfnWndProc   = WndProc1;
    wc.lpszClassName = L"Testclass";
    if(!RegisterClassEx(&wc)) return 0;

    g_hInst = hInstance;
    hwnd = CreateWindowEx(0, L"Testclass", L"Test1", WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, 0, 0, hInstance, 0);
    if(!hwnd) return 0;

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

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

    return (int)msg.wParam;
}

Before right clicking on Test2

enter image description here

After right clicking on Test2

enter image description here

Upvotes: 0

Views: 120

Answers (1)

Hans Passant
Hans Passant

Reputation: 942119

The WM_NCDESTROY message is rather special, it is guaranteed to be the last message that a window ever receives before it is destroyed. It is generated by the DestroyWindow() function.

Being last gives it a rather exalted status. It signals "stop doing what you've been doing". For example, you always use it when you subclass a window; this message tells you to stop subclassing it. And you'd always use it in a C++ wrapper class for a window, where it tells you when the C++ object needs to be destroyed. And it is pretty likely to be the notification that the Visual Styles renderer uses to stop making a window look different because it isn't around anymore.

Oops.

Messages like that are notifications that something interesting happened. As opposed to the kind of messages that are intended to make something interesting happen, like WM_LBUTTONDOWN, WM_KEYDOWN, WM_COMMAND. Most obvious in the WM_CLOSE vs WM_DESTROY message. WM_CLOSE is "please close the window". You can monkey with that and refuse to close the window, traditionally with the "Data not saved, are you sure" message. WM_DESTROY is "it is closed". That's a rock, it really did get destroyed, no point in ever monkeying with that one.

If you generate a fake notification, then you should be prepared to get a fake outcome. Don't mess with the important ones.

Upvotes: 5

Related Questions