You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击关闭按钮时子窗口导致应用退出的解决方法

问题:关闭子窗口时主窗口同步退出的解决办法

我有一个按钮,希望点击该按钮时打开一个新窗口。子窗口能正常弹出,但尝试关闭子窗口时,主窗口也会关闭,应用随之退出。请问如何仅关闭新建的子窗口而不关闭主窗口?

附原代码:

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;
}

问题原因

核心问题有两个:

  1. 子窗口与主窗口共用同一个窗口过程:原代码中OtherSimpleWindowClass未注册,实际运行时大概率复用了主窗口的SimpleWindowClass,导致子窗口收到WM_CLOSE时执行PostQuitMessage(0)——这个函数会向全局消息队列投递WM_QUIT,直接终止整个应用的消息循环,主窗口随之退出。
  2. 主窗口的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:37:02