如何监听显示器唤醒事件?为何显示器点亮时收不到WM_SYSCOMMAND消息
问题原因
你当前的实现收不到显示器唤醒事件,是Windows系统本身的消息机制设计导致的:WM_SYSCOMMAND消息下的SC_MONITORPOWER指令,仅会在系统主动将显示器切到节能模式(待机、关闭)时才会广播,显示器唤醒的流程不会触发该消息,所以你代码里的MONITOR_ON分支永远不会被触发。
正确实现方案
监听WM_POWERBROADCAST消息的PBT_POWERSETTINGCHANGE事件,就可以捕获显示器开关的所有状态变化,步骤如下:
- 首先定义所需的API、常量和结构体:
Private Const WM_POWERBROADCAST = &H218 Private Const PBT_POWERSETTINGCHANGE = &H8013 Private Const DEVICE_NOTIFY_WINDOW_HANDLE = &H0 ' 结构体和GUID定义 Private Type GUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type Private GUID_MONITOR_POWER As GUID = (&H2731015, &H4510, &H4526, &H99, &HE6, &HE5, &HA1, &H7E, &HBD, &H1A, &HEA) ' API声明 Private Declare Function RegisterPowerSettingNotification Lib "user32.dll" (ByVal hRecipient As Long, ByRef PowerSettingGuid As GUID, ByVal Flags As Long) As Long Private Declare Function UnregisterPowerSettingNotification Lib "user32.dll" (ByVal Handle As Long) As Long Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
- 窗口初始化时注册电源状态监听:
Dim hNotify As Long hNotify = RegisterPowerSettingNotification(Me.hWnd, GUID_MONITOR_POWER, DEVICE_NOTIFY_WINDOW_HANDLE) ' 注意窗口销毁时要调用UnregisterPowerSettingNotification(hNotify)释放资源
- 在你的子类化消息处理逻辑中添加
WM_POWERBROADCAST的判断分支:
If uMsg = WM_SYSCOMMAND Then ' 原有处理显示器关闭的逻辑保留即可 If (wParam = SC_MONITORPOWER) Then If (lParam = MONITOR_OFF) Then Debug.Print("显示器已关闭") End If End If ElseIf uMsg = WM_POWERBROADCAST Then If wParam = PBT_POWERSETTINGCHANGE Then ' 解析lParam指向的POWERBROADCAST_SETTING结构体的Data字段 ' Data值定义:0=显示器关闭,1=显示器点亮,2=显示器待机 Dim monitorState As Long ' POWERBROADCAST_SETTING结构偏移20字节就是Data字段的值 CopyMemory monitorState, ByVal lParam + 20, 4 If monitorState = 1 Then Debug.Print "显示器已点亮" End If End If End If
内容的提问来源于stack exchange,提问作者tmighty
相关产品推荐
相关产品推荐

