C DestroyWindow()未销毁子窗口

C DestroyWindow()未销毁子窗口,c,winapi,C,Winapi,WndProc是主窗口的窗口过程ChildProc是子窗口的窗口过程ChildProc未接收到WM\u DESTROY。我做错了什么 编辑:如果我从hChild=CreateWindowExW(…)中删除WS_子窗口window样式0) { 翻译信息(&msg); DispatchMessageW(&msg); } 返回(int)msg.wParam; } 当您调用DestroyWindow(假设具有有效的窗口句柄)-当然,所有子窗口都将被销毁。当然,所有子窗口都收到了WM\u DESTROY

WndProc
是主窗口的窗口过程
ChildProc
是子窗口的窗口过程
ChildProc
未接收到
WM\u DESTROY
。我做错了什么

编辑:如果我从
hChild=CreateWindowExW(…)中删除
WS_子窗口
window样式hChild=CreateWindowExW(…,WS_可见,…)我确实在
ChildProc
中得到了
WM\u DESTROY

另外,我正在使用Windows10和VisualStudio2008

#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;
}
#包括
辛辛斯特;
LRESULT回调ChildProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM)
{
开关(msg)
{
案例WM_油漆:
{
HDC-HDC;
PAINTSTRUCT-ps;
hdc=开始喷漆(hwnd和ps);
如果(hdc)
{
RECT-rc;
GetClientRect(hwnd和rc);
SetBkMode(hdc,透明);
FillRect(hdc,&rc,getsyscolorbush(COLOR_GRAYTEXT));
文本输出(hdc,0,0,文本(“子”),5);
端漆(hwnd和ps);
}
}
打破
案例WM_销毁:
MessageBoxW(0,L“子WM_DESTROY”,0,MB_OK);
打破
违约:
返回DefWindowProcW(hwnd、msg、wParam、lParam);
}
返回0;
}
LRESULT回调WndProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM)
{
静态HWND-hChild;
开关(msg)
{
案例WM_创建:
{
WNDCLASSEXW wc;
SecureZeroMemory(&wc,sizeof(WNDCLASSEXW));
wc.cbSize=sizeof(WNDCLASSEXW);
wc.hCursor=LoadCursorW(0,IDC_箭头);
wc.hInstance=g_hInst;
wc.lpfnWndProc=ChildProc;
wc.lpszClassName=L“Childclass//”;
if(!RegisterClassExW(&wc))返回-1;
hChild=CreateWindowExW(0,L“Childclass//”,0,WS_可见| WS_CHILD,
0,0,200,100,hwnd,0,g_hInst,0);
如果(!hChild)返回-1;
}
打破
案例WM_销毁:
PostQuitMessage(0);
打破
违约:
返回DefWindowProcW(hwnd、msg、wParam、lParam);
}
返回0;
}
int WINAPI wWinMain(HINSTANCE HINSTANCE、HINSTANCE hPrevInstance、LPWSTR lpCmdLine、int nCmdShow)
{
WNDCLASSEXW wc;
HWND-HWND;
味精;
SecureZeroMemory(&wc,sizeof(WNDCLASSEXW));
wc.cbSize=sizeof(WNDCLASSEXW);
wc.hbrBackground=(HBRUSH)(彩色窗口+1);
wc.hCursor=LoadCursorW(0,IDC_箭头);
wc.hIcon=LoadIconW(0,IDI_应用);
wc.hInstance=hInstance;
wc.lpfnWndProc=WndProc;
wc.lpszClassName=L“Mainclass”;
如果(!RegisterClassExW(&wc))返回0;
g_hInst=hInstance;
hwnd=CreateWindowExW(0,L“Mainclass”,L“Main window”,WS_OVERLAPPEDWINDOW,240,240,400,200,0,0,hInstance,0);
如果(!hwnd)返回0;
显示窗口(hwnd、nCmdShow);
更新窗口(hwnd);
while(GetMessageW(&msg,0,0,0)>0)
{
翻译信息(&msg);
DispatchMessageW(&msg);
}
返回(int)msg.wParam;
}

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

ChildProc未接收到
WM\u DESTROY

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

我做错了什么

调试诊断并从错误位置调用
PostQuitMessage

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

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

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

如果您使用自有窗口-它首先接收
WM_DESTROY
并显示
MessageBox
normal。只有在您关闭它之后,父窗口才能接收
WM_DESTROY
最终并调用
PostQuitMessage

要解决此问题,首先需要从
WM\u NCDESTROY
调用
PostQuitMessage
-父窗口在所有拥有的和子窗口之后接收此消息

第二步,
MessageBox
不是调试诊断的最佳选择。最好在调试器中使用
DbgPrint
OutputDebugString
或断点


感谢@RemyLebeau链接到Raymond Chen博客-如果事先已经调用了
PostQuitMessage()
,MessageBox()将不会显示任何内容:

关于模态的另一个重要方面是
WM\u退出
消息 总是打破模态循环


因此,如果在
MessageBox()
之前调用
PostQuitMessage()
,后者将收到
WM\u QUIT
消息,取消其用户界面,重新发布
WM\u QUIT
,然后退出。

当您调用
Destroy window
时(假设具有有效的窗口句柄)-当然所有子窗口都将被销毁。当然,所有子窗口都收到了
WM\u DESTROY

ChildProc未接收到
WM\u DESTROY

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

我做错了什么

调试诊断并从错误位置调用
PostQuitMessage

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