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

如何使用WM_QUERYENDSESSION或WM_ENDSESSION消息阻止Windows关机重启

阻止Windows关机的正确实现方式

你的代码无法生效有两个核心原因:

  • 你定义的WindowProc窗口过程没有绑定到任何实际创建的顶层窗口,且程序没有运行Windows标准消息循环,系统永远不会向你的进程投递WM_QUERYENDSESSION/WM_ENDSESSION消息,你写的消息处理逻辑是完全不会执行的死代码。
  • 从Windows Vista版本开始,仅响应WM_QUERYENDSESSION返回FALSE无法稳定阻止关机,必须调用专用API向系统声明阻塞原因,否则系统会直接忽略你的拒绝响应,继续执行关机流程。

另外需要提前说明:该方案仅能拦截常规用户发起的关机、重启、注销操作,无法阻止高权限强制关机(比如shutdown /f命令、系统更新触发的强制重启、系统崩溃重启)。


实现步骤

  1. 注册窗口类,将自定义窗口过程绑定到窗口类
  2. 创建一个可隐藏的顶层窗口,作为接收系统消息的载体
  3. 启动标准Windows消息循环,保证系统消息能被正常派发到窗口过程
  4. 收到WM_QUERYENDSESSION消息时,先调用ShutdownBlockReasonCreate注册阻塞提示文本,再返回FALSE拒绝关机请求
  5. 收到WM_ENDSESSION且wParam为TRUE时,说明关机已无法阻止,立刻执行资源释放、数据保存等收尾操作
  6. 不需要继续阻塞关机时,调用ShutdownBlockReasonDestroy释放资源

可运行修正代码

#include <Windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_QUERYENDSESSION:
        {
            // 向系统注册关机阻塞原因,该文本会显示在系统关机拦截提示页
            LPCWSTR blockReason = L"程序存在未完成任务,暂不允许关机";
            ShutdownBlockReasonCreate(hwnd, blockReason);
            // 返回FALSE拒绝关机请求
            return FALSE;
        }
        case WM_ENDSESSION:
        {
            if (wParam == TRUE)
            {
                // 关机已不可逆转,在此处执行紧急收尾逻辑
                ShutdownBlockReasonDestroy(hwnd);
            }
            return 0;
        }
        case WM_DESTROY:
            ShutdownBlockReasonDestroy(hwnd);
            PostQuitMessage(0);
            return 0;
        default:
            // 未处理的消息必须交给系统默认过程处理,否则窗口会异常
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    // 注册窗口类
    const wchar_t CLASS_NAME[] = L"ShutdownBlockWindow";
    WNDCLASSEXW wc = {0};
    wc.cbSize        = sizeof(WNDCLASSEXW);
    wc.lpfnWndProc   = WindowProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClassExW(&wc);

    // 创建隐藏的顶层窗口,不需要显示UI
    HWND hwnd = CreateWindowExW(
        0,
        CLASS_NAME,
        L"ShutdownBlockWindow",
        0, // 窗口样式置0,默认隐藏
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL
    );

    if (hwnd == NULL) return 0;

    // 启动消息循环,这是接收系统消息的必要前提
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

注意事项

  • 不要在WM_QUERYENDSESSION处理逻辑中弹出自定义模态框,新版本Windows会直接屏蔽这类弹窗,判定程序无响应后直接终止进程继续关机,阻塞提示统一通过ShutdownBlockReasonCreate传递即可。
  • 消息循环中不要加入长时间阻塞的逻辑,否则窗口无法及时响应系统消息,会被系统判定为无响应,直接被终止。
  • 运行在会话0的系统服务无法通过该方法拦截用户会话的关机流程,程序需要和当前登录用户运行在同一会话下才生效。
  • 不要尝试在消息处理中做耗时操作,系统给每个程序响应关机消息的时间有严格限制,超时会被强制杀掉。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:51:12