You need to enable JavaScript to run this app. 如何在单独线程中创建POPUP窗口并避免子窗口自动销毁
优惠活动
大模型
产品
解决方案
定价
更多

如何在单独线程中创建POPUP窗口并避免子窗口自动销毁

核心问题原因

  • Windows的窗口和创建它的线程强绑定,创建窗口的线程必须运行独立的消息循环来处理窗口消息,你的task1函数创建完窗口后直接退出,线程结束后绑定的子窗口自然被系统销毁。
  • 你在主窗口的WM_CREATE回调中直接调用t1.join(),会阻塞主线程,导致主线程的消息循环无法正常运行,主窗口也会卡住。
  • 子窗口的WM_DESTROY处理中调用了PostQuitMessage,会直接触发子线程消息循环退出,同时不符合子窗口跟随主窗口销毁的要求。

具体修改方案

1. 给子窗口线程添加消息循环

修改task1函数,在创建完子窗口之后添加消息循环,直到子窗口被销毁才退出线程:

int task1(MyStruct myStruct)
{
    sprintf_s(msgbuf_ansi, ("thread\n"));
    OutputDebugStringA(msgbuf_ansi);

    HWND hwnd_child;

    myStruct.wc.lpfnWndProc = WndProcChild;
    myStruct.wc.lpszClassName = g_szChildClassName;

    if (!RegisterClassEx(&myStruct.wc)) {
        MessageBox(NULL, L"thread - Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd_child = CreateWindowEx(0, g_szChildClassName, L"Child", WS_POPUP | WS_BORDER, 200, 0, 190, 110, myStruct.hWnd, 0, myStruct.hInst, 0);
    // 新增:保存子窗口句柄到全局变量
    g_hwndChild = hwnd_child;

    swprintf_s(msgbuf, _T("THREAD - CHILD -  hwnd: %02X\n"), (int)hwnd_child);
    OutputDebugString(msgbuf);

    if (hwnd_child == NULL) {
        MessageBox(NULL, L"thread - Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    SetWindowLong(hwnd_child, GWL_EXSTYLE, GetWindowLong(hwnd_child, GWL_EXSTYLE) | WS_EX_LAYERED);
    SetLayeredWindowAttributes(hwnd_child, 0, 128, LWA_ALPHA);
    ShowWindow(hwnd_child, myStruct.nCmdShow);
    UpdateWindow(hwnd_child);

    // 新增:子线程独立消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

2. 调整主窗口线程逻辑,移除阻塞的join调用

首先新增两个全局变量,用来保存子窗口句柄和子线程对象:

HWND g_hwndChild = NULL;
thread t1;

修改主窗口WM_CREATE回调,不要阻塞主线程:

case WM_CREATE: {
    swprintf_s(msgbuf, _T("WM_CREATE - PARENT \n"));
    OutputDebugString(msgbuf);
    t1 = thread(task1, g_myStruct);
    // 移除t1.join(),避免阻塞主线程消息循环
    return 0;
}

3. 调整销毁逻辑,实现子窗口跟随主窗口销毁

修改主窗口的WM_DESTROY回调,主动销毁子窗口并等待子线程退出:

case WM_DESTROY:
    swprintf_s(msgbuf, _T("WM_DESTROY - PARENT \n"));
    OutputDebugString(msgbuf);
    // 主动销毁子窗口
    if (g_hwndChild != NULL) {
        DestroyWindow(g_hwndChild);
    }
    // 等待子线程正常退出
    if (t1.joinable()) {
        t1.join();
    }
    PostQuitMessage(0);
    return 0;

子窗口的WM_DESTROY回调保留PostQuitMessage即可,仅用来退出子线程自身的消息循环,不会影响主进程运行。

其他优化建议

  • 多线程访问全局变量时建议加锁,避免线程安全问题。
  • 窗口操作尽量在创建它的线程中执行,跨线程控制窗口可以用SendMessage或PostMessage传递消息。
  • 全局变量g_fMouseTracking如果要创建多个子窗口会产生冲突,建议用SetWindowLongPtr将这个状态绑定到对应子窗口的额外存储空间中。

内容的提问来源于stack exchange,提问作者Derek007

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 11:15:04