捕获显示器物理开关的WM_POWERBROADCAST消息异常排查
问题分析与解决方案
一、当前代码的核心错误
- 注册了错误的Power Setting GUID:你现在注册的是
GUID_ACDC_POWER_SOURCE(仅对应电源适配器/电池切换事件),但要捕获显示器开/关状态,必须注册GUID_MONITOR_POWER_ON(GUID字符串:02731015-4510-4526-99E6-E5A17EBD1AEA)。 - 未校验注册结果:
RegisterPowerSettingNotification返回IntPtr.Zero时表示注册失败,需添加校验逻辑排查问题。 - Data字段处理有误:显示器状态的
Data是单字节值,0代表关闭,1代表开启,需正确解析字节数组。
二、修正后的完整代码示例
1. 注册显示器电源通知(窗体加载事件)
Imports System.Runtime.InteropServices Public Class YourForm Private _hPowerNotify As IntPtr Const GUID_MONITOR_POWER_ON As String = "02731015-4510-4526-99E6-E5A17EBD1AEA" Const DEVICE_NOTIFY_WINDOW_HANDLE As Integer = 0 <DllImport("user32.dll", SetLastError:=True)> Private Shared Function RegisterPowerSettingNotification(hRecipient As IntPtr, ByRef PowerSettingGuid As Guid, Flags As Integer) As IntPtr End Function Private Sub YourForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim powerSettingGuid As New Guid(GUID_MONITOR_POWER_ON) _hPowerNotify = RegisterPowerSettingNotification(Me.Handle, powerSettingGuid, DEVICE_NOTIFY_WINDOW_HANDLE) ' 校验注册是否成功 If _hPowerNotify = IntPtr.Zero Then LogError($"注册失败,错误码:{Marshal.GetLastWin32Error()}") End If End Sub
2. 重写WndProc处理消息
Const WM_POWERBROADCAST As Integer = &H218 Const PBT_POWERSETTINGCHANGE As Integer = &H8013 <StructLayout(LayoutKind.Sequential)> Private Structure POWERBROADCAST_SETTING Public PowerSetting As Guid Public DataLength As UInteger <MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)> Public Data As Byte() End Structure Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = WM_POWERBROADCAST AndAlso m.WParam.ToInt32() = PBT_POWERSETTINGCHANGE Then Dim powerSetting As POWERBROADCAST_SETTING = Marshal.PtrToStructure(Of POWERBROADCAST_SETTING)(m.LParam) If powerSetting.PowerSetting = New Guid(GUID_MONITOR_POWER_ON) Then Dim monitorState As Byte = powerSetting.Data(0) Select Case monitorState Case 0 LogError("显示器已进入关闭/低功耗状态") Case 1 LogError("显示器已开启") End Select End If End If MyBase.WndProc(m) End Sub End Class
三、关于捕获显示器物理通电的通知
GUID_MONITOR_POWER_ON只能监听系统触发的显示器电源状态变化(比如系统自动关闭显示器、用户通过系统设置开启),无法直接捕获物理层面的通电/断电(如插拔电源线)。
若要检测物理连接变化,可通过RegisterDeviceNotification监听显示器设备的添加/移除事件,但这只能判断显示器是否与系统连接,无法区分是物理通电还是仅接口连接。精准的物理通电检测通常需要硬件厂商提供的专属API或驱动支持,普通用户态程序难以实现。
内容的提问来源于stack exchange,提问作者user3504017
相关产品推荐
相关产品推荐

