Mike32ab
Mike32ab

Reputation: 466

DestroyWindow() is not destroying child window

WndProc is the window procedure of the main window. ChildProc is the window procedure of the child window. ChildProc is not receiving WM_DESTROY. What am I doing wrong?

EDIT: If I remove the WS_CHILD window style from hChild = CreateWindowExW(...); so it's hChild = CreateWindowExW(..., WS_VISIBLE, ...); I do get WM_DESTROY in ChildProc.

Also, I'm using Windows 10 and Visual Studio 2008

#include <windows.h>


HINSTANCE g_hInst;


LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint(hwnd, &ps);
            if(hdc)
            {
                RECT rc;
                GetClientRect(hwnd, &rc);
                SetBkMode(hdc, TRANSPARENT);
                FillRect(hdc, &rc, GetSysColorBrush(COLOR_GRAYTEXT));
                TextOut(hdc, 0, 0, TEXT("Child"), 5);
                EndPaint(hwnd, &ps);
            }
        }
        break;

    case WM_DESTROY:
        MessageBoxW(0, L"Child WM_DESTROY", 0, MB_OK);
        break;

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


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hChild;


    switch(msg)
    {
    case WM_CREATE:
        {
            WNDCLASSEXW wc;
            SecureZeroMemory(&wc, sizeof(WNDCLASSEXW));
            wc.cbSize        = sizeof(WNDCLASSEXW);
            wc.hCursor       = LoadCursorW(0, IDC_ARROW);
            wc.hInstance     = g_hInst;
            wc.lpfnWndProc   = ChildProc;
            wc.lpszClassName = L"Childclass////";
            if(!RegisterClassExW(&wc)) return -1;

            hChild = CreateWindowExW(0, L"Childclass////", 0, WS_VISIBLE | WS_CHILD, 
                0, 0, 200, 100, hwnd, 0, g_hInst, 0);
            if(!hChild) return -1;
        }
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

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


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEXW wc;
    HWND hwnd;
    MSG msg;

    SecureZeroMemory(&wc, sizeof(WNDCLASSEXW));
    wc.cbSize        = sizeof(WNDCLASSEXW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor       = LoadCursorW(0, IDC_ARROW);
    wc.hIcon         = LoadIconW(0, IDI_APPLICATION);
    wc.hInstance     = hInstance;
    wc.lpfnWndProc   = WndProc;
    wc.lpszClassName = L"Mainclass";
    if(!RegisterClassExW(&wc)) return 0;

    g_hInst = hInstance;
    hwnd = CreateWindowExW(0, L"Mainclass", L"Main window", WS_OVERLAPPEDWINDOW, 240, 240, 400, 200, 0, 0, hInstance, 0);
    if(!hwnd) return 0;

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

    while(GetMessageW(&msg, 0, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return (int)msg.wParam;
}

Upvotes: 0

Views: 1544

Answers (1)

RbMm
RbMm

Reputation: 33784

when you call DestroyWindow (assume with valid window handle) - all child windows of course will be destroyed. and all child windows of course received WM_DESTROY

ChildProc is not receiving WM_DESTROY.

this is false. i absolute sure it receive it.

What am I doing wrong?

debug diagnostic and call PostQuitMessage from wrong place.

you decide that ChildProc is "not receiving" WM_DESTROY only because you not view message box. but it will be just closed, even before shown, if you call PostQuitMessage(0); before it.

when a window is being destroyed WM_DESTROY is sent first to the owned windows (if any), then to window being destroyed and finally to the child windows (if any).

so in case you use child window - first parent window received WM_DESTROY and you call PostQuitMessage then child window call MessageBox which just returned without show due previous PostQuitMessage call.

if you use owned window - it receive WM_DESTROY first and show MessageBox normal. and only after you close it parent window receive WM_DESTROY finally and you call PostQuitMessage

for fix this, at first need call PostQuitMessage from WM_NCDESTROY - the parent window receive this message after all owned and child windows.

at second the MessageBox not the best for debug diagnostic. much better use DbgPrint, OutputDebugString or breakpoints in debugger


thank @RemyLebeau for link to Raymond Chen blog - why MessageBox() does not show anything if PostQuitMessage() was already called beforehand:

The other important thing about modality is that a WM_QUIT message always breaks the modal loop.

So, if PostQuitMessage() is called before MessageBox(), the latter will receive the WM_QUIT message, cancel its UI, re-post WM_QUIT, and exit.

Upvotes: 2

Related Questions