主窗口,子窗口,拥有窗口关闭消息顺序

发布时间 2023-09-20 14:44:53作者: talenth

参考自:

https://baijiahao.baidu.com/s?id=1751789480271344172

1 先说结论, 主窗口执行 DestroyWindow函数, 拥有窗口跟子窗口以及主窗口收到 WM_DESTROY, WM_NCDESTROY的顺序是有区别, 顺序如下:

main WM_CLOSE
owned WM_DESTROY
owned WM_NCDESTROY
main WM_DESTROY
sub WM_DESTROY
sub WM_NCDESTROY
main WM_NCDESTROY

2 验证核心代码如下, 在程序运行时, 点击主窗口的关闭按钮

  1 #include "stdafx.h"
  2 #include "msgTest.h"
  3 
  4 #define MAX_LOADSTRING 100
  5 #define SUB_WIN_CLASS L"subWinClass"
  6 #define SUB_WIN_NAME L"subWinName"
  7 
  8 #define OWNED_WIN_CLASS L"ownedWinClass"
  9 #define OWNED_WIN_NAME L"ownedWinName"
 10 
 11 // 全局变量: 
 12 HINSTANCE hInst = NULL; // 当前实例
 13 WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
 14 WCHAR szWindowClass[MAX_LOADSTRING];// 主窗口类名
 15 
 16 HWND gHMainWnd = NULL; //主窗口句柄
 17 HWND gSubWnd = NULL; // 子窗口句柄
 18 HWND gOwnedWnd = NULL; // 拥有的窗口
 19 
 20 // 此代码模块中包含的函数的前向声明: 
 21 ATOM MyRegisterClass(HINSTANCE hInstance);
 22 BOOL InitInstance(HINSTANCE, int);
 23 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
 24 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
 25 
 26 LRESULT CALLBACK WndProcSub(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 27 {
 28     switch (message)
 29     {
 30     case WM_CLOSE:
 31         OutputDebugStringW(L"sub WM_DESTROY\n");
 32         DestroyWindow(hWnd);
 33         break;
 34     case WM_DESTROY:
 35         OutputDebugStringW(L"sub WM_DESTROY\n");
 36         break;
 37     case WM_NCDESTROY:
 38         OutputDebugStringW(L"sub WM_NCDESTROY\n");
 39         break;
 40     default:
 41         return DefWindowProc(hWnd, message, wParam, lParam);
 42     };
 43 
 44     return 0;
 45 }
 46 
 47 bool CreateSubWnd(HINSTANCE hInstance, int nCmdShow)
 48 {
 49     WNDCLASSEXW wcex;
 50     wcex.cbSize = sizeof(WNDCLASSEX);
 51     wcex.style = CS_HREDRAW | CS_VREDRAW;
 52     wcex.lpfnWndProc = WndProc;
 53     wcex.cbClsExtra = 0;
 54     wcex.cbWndExtra = 0;
 55     wcex.hInstance = hInstance;
 56     wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGTEST));
 57     wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
 58     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
 59     wcex.lpszMenuName = NULL;
 60     wcex.lpszClassName = SUB_WIN_CLASS;
 61     wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 62 
 63     if (!RegisterClassExW(&wcex))
 64         return false;
 65 
 66     gSubWnd = CreateWindowExW(WS_EX_CLIENTEDGE,SUB_WIN_CLASS, SUB_WIN_NAME, WS_CHILDWINDOW, 10, 10, 100, 100, gHMainWnd, nullptr, hInstance, nullptr);
 67     if (!gSubWnd)
 68         return false;
 69 
 70     ShowWindow(gSubWnd, nCmdShow);
 71     UpdateWindow(gSubWnd);
 72 
 73     return true;
 74 }
 75 
 76 LRESULT CALLBACK WndProcOwned(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 77 {
 78     switch (message)
 79     {
 80     case WM_CLOSE:
 81         OutputDebugStringW(L"owned WM_DESTROY\n");
 82         DestroyWindow(hWnd);
 83         break;
 84     case WM_DESTROY:
 85         OutputDebugStringW(L"owned WM_DESTROY\n");
 86         break;
 87     case WM_NCDESTROY:
 88         OutputDebugStringW(L"owned WM_NCDESTROY\n");
 89         break;
 90     default:
 91         return DefWindowProc(hWnd, message, wParam, lParam);
 92     };
 93 
 94     return 0;
 95 }
 96 
 97 bool CreateOwnedWnd(HINSTANCE hInstance, int nCmdShow)
 98 {
 99     WNDCLASSEXW wcex;
100     wcex.cbSize = sizeof(WNDCLASSEX);
101     wcex.style = CS_HREDRAW | CS_VREDRAW;
102     wcex.lpfnWndProc = WndProc;
103     wcex.cbClsExtra = 0;
104     wcex.cbWndExtra = 0;
105     wcex.hInstance = hInstance;
106     wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGTEST));
107     wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
108     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
109     wcex.lpszMenuName = NULL;
110     wcex.lpszClassName = OWNED_WIN_CLASS;
111     wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
112 
113     if (!RegisterClassExW(&wcex))
114         return false;
115 
116     gOwnedWnd = CreateWindowExW(0, OWNED_WIN_CLASS, OWNED_WIN_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, gHMainWnd, nullptr, hInstance, nullptr);
117     if (!gOwnedWnd)
118         return false;
119 
120     ShowWindow(gOwnedWnd, nCmdShow);
121     UpdateWindow(gOwnedWnd);
122 
123     return true;
124 }
125 
126 int APIENTRY wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nCmdShow)
127 {
128     UNREFERENCED_PARAMETER(hPrevInstance);
129     UNREFERENCED_PARAMETER(lpCmdLine);
130 
131     // TODO: 在此放置代码。
132 
133     // 初始化全局字符串
134     LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
135     LoadStringW(hInstance, IDC_MSGTEST, szWindowClass, MAX_LOADSTRING);
136     MyRegisterClass(hInstance);
137 
138     // 执行应用程序初始化: 
139     if (!InitInstance(hInstance, nCmdShow))
140     {
141         return FALSE;
142     }
143 
144     HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MSGTEST));
145 
146     // 主消息循环: 
147     MSG msg;
148     while (GetMessageW(&msg, NULL, 0, 0))
149     {
150         //if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg))
151         {
152             TranslateMessage(&msg);
153             DispatchMessageW(&msg);
154         }
155     }
156 
157     return (int) msg.wParam;
158 }
159 
160 ATOM MyRegisterClass(HINSTANCE hInstance)
161 {
162     WNDCLASSEXW wcex;
163 
164     wcex.cbSize = sizeof(WNDCLASSEX);
165 
166     wcex.style          = CS_HREDRAW | CS_VREDRAW;
167     wcex.lpfnWndProc    = WndProc;
168     wcex.cbClsExtra     = 0;
169     wcex.cbWndExtra     = 0;
170     wcex.hInstance      = hInstance;
171     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MSGTEST));
172     wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
173     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
174     wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MSGTEST);
175     wcex.lpszClassName  = szWindowClass;
176     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
177 
178     return RegisterClassExW(&wcex);
179 }
180 
181 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
182 {
183    hInst = hInstance; // 将实例句柄存储在全局变量中
184 
185    gHMainWnd = CreateWindowExW(0,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 400, 200, nullptr, nullptr, hInstance, nullptr);
186    if (!gHMainWnd)
187    {
188       return FALSE;
189    }
190 
191    CreateSubWnd(hInstance, nCmdShow);
192    CreateOwnedWnd(hInstance, nCmdShow);
193 
194    ShowWindow(gHMainWnd, nCmdShow);
195    UpdateWindow(gHMainWnd);
196 
197    return TRUE;
198 }
199 
200 
201 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
202 {
203     if (hWnd == gSubWnd)
204         return WndProcSub(hWnd, message, wParam, lParam);
205     else if (hWnd == gOwnedWnd)
206         return WndProcOwned(hWnd, message, wParam, lParam);
207 
208     switch (message)
209     {
210     case WM_CREATE:
211         break;
212     case WM_COMMAND:
213     {
214         int wmId = LOWORD(wParam);
215         // 分析菜单选择: 
216         switch (wmId)
217         {
218         case IDM_ABOUT:
219             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
220             break;
221         case IDM_EXIT:
222             DestroyWindow(hWnd);
223             break;
224         default:
225             return DefWindowProc(hWnd, message, wParam, lParam);
226         }
227     }
228     break;
229     case WM_PAINT:
230     {
231         PAINTSTRUCT ps;
232         HDC hdc = BeginPaint(hWnd, &ps);
233         // TODO: 在此处添加使用 hdc 的任何绘图代码...
234         EndPaint(hWnd, &ps);
235     }
236     break;
237     case WM_CLOSE:
238         OutputDebugStringW(L"main WM_CLOSE\n");
239         DestroyWindow(hWnd);
240         break;
241     case WM_DESTROY:
242         //PostQuitMessage(0);
243         OutputDebugStringW(L"main WM_DESTROY\n");
244         break;
245     case WM_NCDESTROY:
246         PostQuitMessage(0);
247         OutputDebugStringW(L"main WM_NCDESTROY\n");
248         break;
249     default:
250         return DefWindowProc(hWnd, message, wParam, lParam);
251     }
252     return 0;
253 }
254 
255 // “关于”框的消息处理程序。
256 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
257 {
258     UNREFERENCED_PARAMETER(lParam);
259     switch (message)
260     {
261     case WM_INITDIALOG:
262         return (INT_PTR)TRUE;
263 
264     case WM_COMMAND:
265         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
266         {
267             EndDialog(hDlg, LOWORD(wParam));
268             return (INT_PTR)TRUE;
269         }
270         break;
271     }
272     return (INT_PTR)FALSE;
273 }