c - DestroyWindow() 没有销毁子窗口

标签 c winapi

WndProc是主窗口的窗口过程。 ChildProc是子窗口的窗口过程。 ChildProc 未收到 WM_DESTROY。我做错了什么?

编辑:如果我从 hChild = CreateWindowExW(...); 中删除 WS_CHILD 窗口样式,那么它就是 hChild = CreateWindowExW(..., WS_VISIBLE , ...); 我确实在 ChildProc 中得到了 WM_DESTROY

此外,我正在使用 Windows 10 和 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;
}

最佳答案

当您调用 DestroyWindow(假设具有有效的窗口句柄)时 - 当然所有子窗口都将被销毁。当然,所有子窗口都收到了 WM_DESTROY

ChildProc is not receiving WM_DESTROY.

这是错误的。我绝对确定它收到了。

What am I doing wrong?

调试诊断并从错误的地方调用 PostQuitMessage

您决定 ChildProc“未接收”WM_DESTROY 只是因为您没有查看消息框。但如果您调用 PostQuitMessage(0); before 它就会关闭,甚至在显示之前。

当一个窗口被销毁时,WM_DESTROY 首先被发送到拥有的窗口(如果有的话),然后是被销毁的窗口,最后是子窗口(如果有的话)。

因此,如果您使用子窗口 - 第一个父窗口收到 WM_DESTROY 并且您调用 PostQuitMessage 然后子窗口调用 MessageBox,它刚刚返回而没有显示由于之前的 PostQuitMessage 调用。

如果您使用自有窗口 - 它首先收到 WM_DESTROY 并正常显示 MessageBox。只有在你关闭它之后,父窗 Eloquent 会收到 WM_DESTROY 最后你调用 PostQuitMessage

为了解决这个问题,首先需要从 WM_NCDESTROY 调用 PostQuitMessage - 父窗口在所有拥有的和子窗口之后收到此消息。

第二,MessageBox 不是调试诊断的最佳选择。更好地使用 DbgPrintOutputDebugString 或调试器中的断点


感谢@RemyLebeau 提供 Raymond Chen 博客的链接 - why如果预先调用了 PostQuitMessage(),则 MessageBox() 不会显示任何内容:

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

因此,如果在 MessageBox() 之前调用了 PostQuitMessage(),后者将收到 WM_QUIT 消息,取消其 UI,重新-发布 WM_QUIT,然后退出。

关于c - DestroyWindow() 没有销毁子窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48510974/

相关文章:

python - 使用 wxpython 传递参数来创建窗口?

c++ - 为什么 Shell_NotifyIcon 气球提示不起作用?

c++ - 什么是无效,更新方法在 VC++ 中做什么

windows - 如何在 Windows 中检测何时连接了新硬件?

C 数组传递

c - c中指针的声明

c - 计算矩阵乘法时出现段错误(核心转储)错误

c - 在套接字编程中从客户端获取用户输入

c - 之前完美的C程序在Ubuntu上编译后无法运行

c++ - 带有 SetParent() 的 WS_EX_LAYERED 不显示窗口