Windows下阻止休眠常用SetThreadExecutionState,但主动关屏需向桌面窗口发送WM_SYSCOMMAND消息(SC_MONITORPOWER=-1),仅关闭显示器而非系统休眠;SetSuspendState会整机挂起,不满足“仅黑屏”需求,且跨会话或无GUI环境易失效。

Windows下用SetThreadExecutionState阻止休眠更常见,但真要触发休眠得靠SendMessage发WM_SYSCOMMAND
直接让显示器休眠不是调用一个函数就能完成的事——Windows没有公开的、推荐的API专门做“立刻黑屏休眠”,SetThreadExecutionState只能防止系统进入空闲休眠,反向触发反而要绕道窗口消息。
实际可行路径是:向桌面窗口(GetDesktopWindow())发送WM_SYSCOMMAND消息,参数SC_MONITORPOWER设为-1(关闭显示器),系统会按策略进入低功耗状态。这并非“系统休眠”,而是显示器物理断电或背光关闭,用户感知就是黑屏。
-
SC_MONITORPOWER值为0xF170,需配合wParam传-1(关闭)、1(开启)、2(关闭后不唤醒) - 必须以管理员权限运行?不一定,但若当前无交互式桌面会话(如服务进程),
GetDesktopWindow()可能返回NULL,消息无效 - 该操作不触发系统睡眠(
Sleep状态),只影响显示器;想进系统休眠要用SetSuspendState,但那是另一回事
为什么不用SetSuspendState?它控制的是整机休眠,不是显示器
很多人搜“C++休眠显示器”却误用SetSuspendState,结果电脑整个睡过去,键盘鼠标都失灵——这不是显示器休眠,是系统挂起。它需要SE_SYSTEM_ENVIRONMENT_NAME权限,且默认会同时关闭显示器、硬盘、CPU,不可单独隔离显示器。
-
SetSuspendState(FALSE, FALSE, FALSE):进入睡眠(S3),恢复时需按键/鼠标唤醒 -
SetSuspendState(TRUE, FALSE, FALSE):进入休眠(S4,写入磁盘),耗时长,依赖休眠文件 - 两者都不满足“仅关屏”的需求,且失败时返回
FALSE,GetLastError()常为ERROR_PRIVILEGE_NOT_HELD
跨用户会话下SendMessage失效怎么办?
在Windows服务、计划任务或远程桌面断开后,GetDesktopWindow()拿到的句柄属于会话0,而用户桌面在会话1+,消息根本送不到目标窗口。这是最常踩的坑——代码本地测试成功,部署到服务里就静默失败。
立即学习“C++免费学习笔记(深入)”;
- 确认当前进程运行在交互式用户会话中:
WTSGetActiveConsoleSessionId()对比ProcessIdToSessionId(GetCurrentProcessId(), &session) - 若不在活动会话,可尝试用
WTSSendMessage向指定会话弹窗(但不能关屏),或通过RunAs以目标用户身份启动辅助进程 - 无GUI环境(如WSL、Docker)完全无法使用该方案,
GetDesktopWindow()返回NULL,后续全跳过
完整最小可运行示例(仅关屏)
#include <windows.h>
int main() {
HWND hwnd = GetDesktopWindow();
if (hwnd) {
// -1: 关闭显示器;1: 恢复;2: 关闭且禁止唤醒(部分系统不支持)
SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)-1);
}
return 0;
}
编译时确保链接User32.lib,无需额外权限。但注意:某些电源策略(如“接通电源时不关闭显示器”)可能覆盖该调用;部分笔记本合盖时该消息被系统拦截;Win10/11中若启用了“动态刷新率”或HDR,关屏响应可能延迟1–2秒。
真正难的不是发这条消息,而是确认你发给了谁、对方是否在线、有没有被策略拦住——调试时先用IsWindow(hwnd)和GetLastError()查句柄有效性,比硬刚权限更有用。


















