点击关闭按钮时子窗口导致应用退出的解决方法
问题:关闭子窗口时主窗口同步退出的解决办法
我有一个按钮,希望点击该按钮时打开一个新窗口。子窗口能正常弹出,但尝试关闭子窗口时,主窗口也会关闭,应用随之退出。请问如何仅关闭新建的子窗口而不关闭主窗口?
附原代码:
HWND hwnd; void CreateChildWindow() { HWND hNewWindow = CreateWindow( _T("OtherSimpleWindowClass"), _T("Neues Fenster"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, 0, 0, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), 0); ShowWindow(hNewWindow, SW_SHOWNORMAL); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_COMMAND: if (LOWORD(wParam) == 1) { CreateChildWindow(); } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = _T("SimpleWindowClass"); RegisterClass(&wc); hwnd = CreateWindowEx( 0, _T("SimpleWindowClass"), _T("Button"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, hInstance, 0); ShowWindow(hwnd, nCmdShow); HWND hButton = CreateWindow( _T("BUTTON"), _T("Klick mich"), WS_CHILD | WS_VISIBLE, 50, 50, 100, 30, hwnd, (HMENU)1, // Der Identifier des Buttons ist 1 hInstance, NULL ); MSG msg = {}; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
问题原因
核心问题有两个:
- 子窗口与主窗口共用同一个窗口过程:原代码中
OtherSimpleWindowClass未注册,实际运行时大概率复用了主窗口的SimpleWindowClass,导致子窗口收到WM_CLOSE时执行PostQuitMessage(0)——这个函数会向全局消息队列投递WM_QUIT,直接终止整个应用的消息循环,主窗口随之退出。 - 主窗口的
WM_CLOSE处理不规范:直接调用PostQuitMessage跳过了窗口销毁的正常流程,不符合Win32窗口的标准处理逻辑。
解决方案
1. 为子窗口注册独立的窗口类和窗口过程
给子窗口单独编写窗口过程,处理WM_CLOSE时仅销毁当前窗口,不触发应用退出:
// 子窗口的窗口过程 LRESULT CALLBACK ChildWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: // 仅销毁当前子窗口,不发送退出消息 DestroyWindow(hwnd); return 0; case WM_DESTROY: // 子窗口销毁时可做清理操作,无需求则直接返回 return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }
然后在WinMain中注册这个子窗口类:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册主窗口类(原代码保留) WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = _T("SimpleWindowClass"); RegisterClass(&wc); // 注册子窗口类 WNDCLASS childWc = {}; childWc.lpfnWndProc = ChildWindowProc; childWc.hInstance = hInstance; childWc.lpszClassName = _T("OtherSimpleWindowClass"); childWc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 设置子窗口背景 RegisterClass(&childWc); // 后续主窗口创建、按钮创建等代码保留... }
2. 修正主窗口的WM_CLOSE处理逻辑
按照Win32标准流程,主窗口收到WM_CLOSE时先销毁窗口,在WM_DESTROY消息中再触发应用退出:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: // 销毁主窗口,之后会收到WM_DESTROY消息 DestroyWindow(hwnd); return 0; case WM_DESTROY: // 主窗口销毁时才退出应用 PostQuitMessage(0); return 0; case WM_COMMAND: if (LOWORD(wParam) == 1) { CreateChildWindow(); } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; // 补充返回值,避免分支遗漏导致的未定义行为 }
3. 优化子窗口创建参数(可选)
将子窗口的父窗口设为主窗口,这样子窗口会跟随主窗口进行最小化、关闭等联动操作,更符合用户预期:
void CreateChildWindow() { HWND hNewWindow = CreateWindow( _T("OtherSimpleWindowClass"), _T("Neues Fenster"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, hwnd, // 设置主窗口为父窗口 0, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), 0); if (hNewWindow != NULL) { ShowWindow(hNewWindow, SW_SHOWNORMAL); } }
完整修正后代码
#include <windows.h> HWND hwnd; // 子窗口窗口过程 LRESULT CALLBACK ChildWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: DestroyWindow(hwnd); return 0; case WM_DESTROY: return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } void CreateChildWindow() { HWND hNewWindow = CreateWindow( _T("OtherSimpleWindowClass"), _T("Neues Fenster"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, hwnd, 0, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), 0); if (hNewWindow != NULL) { ShowWindow(hNewWindow, SW_SHOWNORMAL); } } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: DestroyWindow(hwnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_COMMAND: if (LOWORD(wParam) == 1) { CreateChildWindow(); } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册主窗口类 WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = _T("SimpleWindowClass"); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); RegisterClass(&wc); // 注册子窗口类 WNDCLASS childWc = {}; childWc.lpfnWndProc = ChildWindowProc; childWc.hInstance = hInstance; childWc.lpszClassName = _T("OtherSimpleWindowClass"); childWc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); RegisterClass(&childWc); hwnd = CreateWindowEx( 0, _T("SimpleWindowClass"), _T("主窗口"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, hInstance, 0); if (hwnd != NULL) { ShowWindow(hwnd, nCmdShow); HWND hButton = CreateWindow( _T("BUTTON"), _T("点击打开子窗口"), WS_CHILD | WS_VISIBLE, 50, 50, 120, 30, hwnd, (HMENU)1, hInstance, NULL ); } MSG msg = {}; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
内容的提问来源于stack exchange,提问作者mbrain
相关产品推荐
相关产品推荐

