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

Win32开发:如何在最后一个窗口销毁后退出应用程序

解决Win32应用最后一个窗口关闭时退出的问题

在Win32开发中,确实没有直接的原生API自动实现“所有窗口关闭后退出程序”的逻辑,但有两种可靠的方案可以实现需求——手动计数是行业内的常用方案,简单高效;另一种则是通过系统API动态检查窗口数量。

方案一:手动维护窗口计数(推荐)

这种方法简单、线程安全,是大多数Win32应用(包括你提到的Chromium)的实现方式:

  • 定义一个全局的线程安全计数变量,初始值为0
  • 每次成功创建窗口时,用InterlockedIncrement原子递增计数
  • 在每个窗口的WM_DESTROY消息处理中,原子递减计数,当计数为0时调用PostQuitMessage(0)触发程序退出

代码示例:

#include <windows.h>

// 全局线程安全计数,避免多线程创建/销毁窗口时的竞态问题
LONG g_windowCount = 0;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            // 原子递减计数,判断是否为最后一个窗口
            if (InterlockedDecrement(&g_windowCount) == 0)
            {
                PostQuitMessage(0);
            }
            break;
        // 其他消息处理逻辑...
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// 创建窗口的示例函数
HWND CreateMyWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wcex = {0};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = hInstance;
    wcex.lpszClassName = L"MyWindowClass";
    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindowEx(0, L"MyWindowClass", L"Window", WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    if (hWnd)
    {
        // 窗口创建成功,递增计数
        InterlockedIncrement(&g_windowCount);
        ShowWindow(hWnd, SW_SHOW);
        UpdateWindow(hWnd);
    }
    return hWnd;
}

方案二:通过系统API动态检查窗口数量

如果你不想维护计数,可以通过GetGuiResources或EnumWindows来动态统计当前进程的顶层窗口数量:

方法A:使用GetGuiResources

GetGuiResources可以直接获取当前进程的顶层窗口数量,注意在WM_DESTROY消息中,当前窗口尚未完全销毁,所以需要将返回值减1后判断是否为0:

case WM_DESTROY:
    DWORD topLevelCount = GetGuiResources(GetCurrentProcess(), GR_GUIRESOURCES_TOPLEVELWINDOWS);
    // 当前窗口正在销毁,实际剩余窗口数为返回值减1
    if (topLevelCount - 1 == 0)
    {
        PostQuitMessage(0);
    }
    break;

方法B:使用EnumWindows枚举窗口

通过枚举所有顶层窗口,筛选出属于当前进程的窗口并计数,同样需要减去当前正在销毁的窗口:

// 枚举窗口的回调函数
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    DWORD procId;
    GetWindowThreadProcessId(hWnd, &procId);
    if (procId == (DWORD)lParam)
    {
        // 找到当前进程的窗口,计数加1
        *(LONG*)lParam += 1;
    }
    return TRUE;
}

// WM_DESTROY消息处理
case WM_DESTROY:
    LONG windowCount = 0;
    EnumWindows(EnumWindowsProc, (LPARAM)&windowCount);
    if (windowCount - 1 == 0)
    {
        PostQuitMessage(0);
    }
    break;

注意事项

  • 方案一的原子操作确保了多线程环境下的计数准确性,适合有多个窗口线程的应用
  • 方案二的GetGuiResources在部分旧系统版本中可能存在小兼容性问题,EnumWindows更可靠但效率略低,适合窗口数量较少的应用
  • Win32的消息循环本身不会自动退出,必须通过PostQuitMessage触发,所以无论哪种方案,最终都需要调用这个函数来结束程序

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 22:10:30