0

0

C++如何实现跨平台获取系统锁屏状态?(Windows LockWorkStation监听)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-02-24 16:15:10

|

840人浏览过

|

来源于php中文网

原创

应使用系统提供的会话状态通知机制:windows 用 wtsregistersessionnotification 监听 wm_wtssession_change 消息,macos 用 cgsessioncopycurrentdictionary 轮询 kcgsessionislockedkey 并辅以 iokit 监听,linux 通过 systemd-logind d-bus 接口监听 locksession/unlocksession 信号。

c++如何实现跨平台获取系统锁屏状态?(windows lockworkstation监听)

Windows 上怎么检测用户是否锁屏?用 WTSRegisterSessionNotification 而不是轮询 GetAsyncKeyState

直接轮询键盘或鼠标状态来“猜”锁屏是错的——锁屏后系统仍可能有后台输入(比如远程桌面唤醒),而且 GetAsyncKeyState 在服务进程里根本不可靠。Windows 提供了会话状态变更通知机制,这才是正路。

关键点:必须在 UI 线程注册,且窗口需处理 WM_WTSSESSION_CHANGE 消息;不能在无窗口的控制台程序或服务里直接用(除非自己创建隐藏窗口)。

  • WTSRegisterSessionNotification 需传入一个 HWND,所以哪怕你写的是控制台程序,也得创建一个不可见窗口(用 CreateWindowEx + WS_POPUP
  • 注册后,锁屏/解锁会发 WM_WTSSESSION_CHANGEwParamWTS_SESSION_LOCKWTS_SESSION_UNLOCK
  • 别忘了调用 WTSUnregisterSessionNotification 清理,否则下次注册失败
  • 注意:该 API 从 Windows XP 开始支持,但 Vista+ 才稳定;Win7 及以后无需管理员权限

macOS 怎么拿到屏幕锁定事件?靠 CGSession + IORegistry 监听,不是 ScreenSaver 框架

macOS 没有类似 Windows 的会话通知,ScreenSaver 框架只管屏保启动,和系统锁屏(如 Cmd+Ctrl+Q)无关。真实锁屏由 loginwindow 进程触发,信号藏在 IOKit 的 IORegistry 里,同时 CGSession 提供轻量级轮询接口。

推荐组合:用 CGSessionCopyCurrentDictionary 获取当前会话状态(含 kCGSessionOnConsoleKeykCGSessionIsLockedKey),再配合 IOPMConnectionCreate 监听电源/显示状态变化作为辅助判断。

立即学习C++免费学习笔记(深入)”;

Img.Upscaler
Img.Upscaler

免费的AI图片放大工具

下载
  • CGSessionCopyCurrentDictionary 返回字典,查 kCGSessionIsLockedKey 的布尔值即可,每秒查一次足够(别高频调用)
  • 纯监听方案要用 IOServiceAddInterestNotification 订阅 IOPlatformExpertDeviceIOGeneralInterest,但实现复杂、易漏事件
  • 注意:沙盒应用无法访问 CGSession API,需在 entitlements 中添加 com.apple.security.temporary-exception.mach-lookup.global-name(不推荐)或改用无沙盒进程协作
  • macOS 12+ 对 CGSession 的调用更敏感,建议加 @autoreleasepool 防止内存泄漏(C++ 混编 ObjC 时)

Linux 下没有统一锁屏 API,logind D-Bus 接口是唯一靠谱选择

X11 或 Wayland 自身都不暴露锁屏状态,桌面环境(GNOME/KDE)各自为政。唯一跨桌面的途径是通过 systemd-logind 的 D-Bus 接口,它由 logind 守护进程统一管理会话生命周期。

重点监听 org.freedesktop.login1.ManagerLockSessionUnlockSession 信号,或者轮询 GetSession 方法返回的 LockedHint 属性。

  • 必须连接到系统总线(dbus_system_bus_get),不是会话总线;普通用户默认有权限,但某些发行版(如 RHEL/CentOS)需在 /etc/dbus-1/system.d/ 配置策略
  • 信号监听比轮询更及时,但首次连接后要先调用 ListSessions 获取当前状态,避免启动时错过初始锁态
  • Wayland 下部分场景(如 GNOME 的 “锁屏后黑屏”)可能延迟几秒才发出信号,建议加 500ms 去抖
  • 别依赖 XScreenSaverQueryInfo —— 它只反映屏保,且在 Wayland 上完全失效

C++ 跨平台封装要注意什么?别把平台逻辑塞进同一个函数里

最常见错误是写一个 isSystemLocked() 函数,里面用 #ifdef 堆砌三套逻辑,结果 Windows 编译过、macOS 运行崩溃、Linux 测试时发现 D-Bus 连接超时没处理。

真正可行的做法是分层:抽象出 LockStateObserver 接口,每个平台实现独立类(WindowsLockObserverMacOSSessionObserverLinuxLogindObserver),初始化时动态选型。

  • 各平台初始化失败(如 macOS 没权限、Linux D-Bus 不可用)必须返回明确错误,不能静默降级为“始终未锁屏”
  • 锁屏状态不是瞬时值,而是带时间戳的事件流;缓存最新状态 + 更新时间,避免频繁查询引发性能抖动
  • Windows 的 WM_WTSSESSION_CHANGE 可能被其他消息淹没,确保消息循环不阻塞;macOS 的 CGSession 调用要放在主线程(GCD main queue);Linux 的 D-Bus 回调必须用异步 dispatch 避免阻塞主循环
  • 测试时最容易忽略的是“锁屏中重启”场景:Windows 会话可能变成 WTSDisconnected,macOS 会话字典可能为空,Linux 的 logind 会话 ID 可能重置——这些都要单独处理

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1630

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

485

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2304

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

40

2026.01.19

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

422

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

595

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

719

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

719

2023.08.10

Golang 生态工具与框架:扩展开发能力
Golang 生态工具与框架:扩展开发能力

《Golang 生态工具与框架》系统梳理 Go 语言在实际工程中的主流工具链与框架选型思路,涵盖 Web 框架、RPC 通信、依赖管理、测试工具、代码生成与项目结构设计等内容。通过真实项目场景解析不同工具的适用边界与组合方式,帮助开发者构建高效、可维护的 Go 工程体系,并提升团队协作与交付效率。

0

2026.02.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 9.6万人学习

Excel 教程
Excel 教程

共162课时 | 18.7万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 2.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号