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

捕获显示器物理开关的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 13:34:51