DestroyWindow()不会破坏子窗口

时间:2018-01-29 22:20:59

标签: c winapi

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

编辑:如果我从hChild = CreateWindowExW(...);移除hChild = CreateWindowExW(..., WS_VISIBLE, ...);窗口样式,那么WM_DESTROY我会在ChildProc中获得#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; }

此外,我正在使用Windows 10和Visual Studio 2008

to_dict

1 个答案:

答案 0 :(得分:2)

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

  

ChildProc未收到WM_DESTROY

这是假的。我绝对相信它会收到它。

  

我做错了什么?

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

您认为ChildProc是&#34;没有收到&#34; WM_DESTROY只是因为您没有查看消息框。但如果您在之前致电PostQuitMessage(0); ,它就会被关闭,即使在展示之前也是如此。

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

所以如果您使用子窗口 - 收到WM_DESTROY的第一个父窗口并且您调用PostQuitMessage,那么之前返回的子窗口调用MessageBox没有显示,因为之前的PostQuitMessage调用

如果您使用拥有的窗口 - 它会先收到WM_DESTROY并显示MessageBox正常。只有在您关闭之后,父窗口才会收到WM_DESTROY,然后您致电PostQuitMessage

要解决此问题,首先需要从PostQuitMessage拨打WM_NCDESTROY - 父窗口会在所有拥有和子窗口之后收到此消息

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

感谢@RemyLebeau链接到Raymond Chen博客 - why MessageBox()在事先已调用PostQuitMessage()时没有显示任何内容:

  

关于模态的另一个重要的事情是WM_QUIT消息   总是打破模态循环。

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