Python 3下Windows系统显示器电源状态检测实现求助
监测Windows显示器电源状态的Python实现
嘿,我来帮你搞定这个需求!要在Python里监测Windows显示器的电源状态(比如屏幕关闭时触发事件),咱们确实得靠Windows API的RegisterPowerSettingNotification配合消息循环来实现,下面是完整的可运行代码,我会一步步给你解释关键部分。
完整代码示例
import ctypes from ctypes import wintypes # 定义Windows API所需的常量和结构体 USER32 = ctypes.WinDLL('user32', use_last_error=True) KERNEL32 = ctypes.WinDLL('kernel32', use_last_error=True) # 窗口相关常量 WC_DIALOG = '#32770' WS_OVERLAPPEDWINDOW = 0x00CF0000 CW_USEDEFAULT = 0x80000000 COLOR_WINDOW = 5 # 电源消息相关常量 WM_POWERBROADCAST = 0x0218 PBT_POWERSETTINGCHANGE = 0x8013 # 显示器电源状态的GUID(系统固定值) GUID_MONITOR_POWER_ON = ctypes.GUID("{02731015-4510-4526-99E6-E5A17EBD1AEA}") # 定义MSG结构体,用于消息循环 class MSG(ctypes.Structure): _fields_ = [ ("hwnd", wintypes.HWND), ("message", wintypes.UINT), ("wParam", wintypes.WPARAM), ("lParam", wintypes.LPARAM), ("time", wintypes.DWORD), ("pt", wintypes.POINT) ] # 定义POWERBROADCAST_SETTING结构体,解析电源通知数据 class POWERBROADCAST_SETTING(ctypes.Structure): _fields_ = [ ("PowerSetting", ctypes.GUID), ("DataLength", wintypes.DWORD), ("Data", wintypes.BYTE * 1) ] # 窗口过程函数,处理收到的系统消息 def WindowProc(hwnd, msg, wParam, lParam): if msg == WM_POWERBROADCAST: if wParam == PBT_POWERSETTINGCHANGE: # 解析电源设置变化的数据 setting = ctypes.cast(lParam, ctypes.POINTER(POWERBROADCAST_SETTING)).contents if setting.PowerSetting == GUID_MONITOR_POWER_ON: # 获取显示器状态:0=关闭,1=打开 monitor_state = setting.Data[0] if monitor_state == 0: print("屏幕已关闭!触发自定义事件...") # 这里可以添加你需要执行的代码,比如调用其他函数、发送通知等 elif monitor_state == 1: print("屏幕已打开!") return True elif msg == 0x0010: # WM_CLOSE:窗口关闭消息 USER32.DestroyWindow(hwnd) return 0 elif msg == 0x0002: # WM_DESTROY:窗口销毁消息 USER32.PostQuitMessage(0) return 0 else: return USER32.DefWindowProcW(hwnd, msg, wParam, lParam) def main(): # 注册窗口类 WNDCLASSEXW = ctypes.Structure() WNDCLASSEXW._fields_ = [ ("cbSize", wintypes.UINT), ("style", wintypes.UINT), ("lpfnWndProc", ctypes.WINFUNCTYPE(wintypes.LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)), ("cbClsExtra", wintypes.INT), ("cbWndExtra", wintypes.INT), ("hInstance", wintypes.HINSTANCE), ("hIcon", wintypes.HICON), ("hCursor", wintypes.HCURSOR), ("hbrBackground", wintypes.HBRUSH), ("lpszMenuName", wintypes.LPCWSTR), ("lpszClassName", wintypes.LPCWSTR), ("hIconSm", wintypes.HICON) ] wndclass = WNDCLASSEXW() wndclass.cbSize = ctypes.sizeof(WNDCLASSEXW) wndclass.style = 0 wndclass.lpfnWndProc = ctypes.WINFUNCTYPE(wintypes.LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)(WindowProc) wndclass.cbClsExtra = 0 wndclass.cbWndExtra = 0 wndclass.hInstance = KERNEL32.GetModuleHandleW(None) wndclass.hIcon = None wndclass.hCursor = None wndclass.hbrBackground = ctypes.cast(COLOR_WINDOW + 1, wintypes.HBRUSH) wndclass.lpszMenuName = None wndclass.lpszClassName = "MonitorPowerMonitorClass" wndclass.hIconSm = None USER32.RegisterClassExW(ctypes.byref(wndclass)) # 创建隐藏窗口(不需要显示,仅用于接收消息) hwnd = USER32.CreateWindowExW( 0, wndclass.lpszClassName, "MonitorPowerMonitor", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, None, None, wndclass.hInstance, None ) if not hwnd: raise ctypes.WinError(ctypes.get_last_error()) # 注册显示器电源状态通知 h_notify = USER32.RegisterPowerSettingNotification( hwnd, ctypes.byref(GUID_MONITOR_POWER_ON), 0 # DEVICE_NOTIFY_WINDOW_HANDLE:通知发送给窗口句柄 ) if not h_notify: raise ctypes.WinError(ctypes.get_last_error()) print("开始监测显示器电源状态...") print("按Ctrl+C退出程序") # 消息循环:持续接收系统发送的消息 msg = MSG() while USER32.GetMessageW(ctypes.byref(msg), None, 0, 0) > 0: USER32.TranslateMessage(ctypes.byref(msg)) USER32.DispatchMessageW(ctypes.byref(msg)) # 清理资源:注销电源通知 USER32.UnregisterPowerSettingNotification(h_notify) if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\n程序已退出")
关键部分解释
1. 为什么需要创建窗口?
Windows的电源通知是绑定窗口句柄发送的,所以咱们必须创建一个窗口(哪怕是隐藏的)来接收这些系统消息。代码里创建的窗口可以最小化或者隐藏,完全不影响监测功能。
2. 注册电源通知的核心逻辑
RegisterPowerSettingNotification函数的三个关键参数:
hwnd:接收通知的窗口句柄,就是咱们刚创建的窗口- GUID参数:
GUID_MONITOR_POWER_ON是系统预定义的、专门用于监测显示器电源状态的标识 - 通知类型:
0对应DEVICE_NOTIFY_WINDOW_HANDLE,表示通知会发送给指定的窗口
3. 处理电源状态变化
在窗口过程函数WindowProc里,咱们重点监听WM_POWERBROADCAST消息:
- 当收到
PBT_POWERSETTINGCHANGE类型的通知时,解析lParam里的结构体 Data[0]的值直接对应显示器状态:0代表屏幕关闭,1代表屏幕打开- 你可以在对应的分支里添加自己的业务逻辑,比如触发告警、执行特定脚本等
4. 消息循环的作用
GetMessageW、TranslateMessage、DispatchMessageW组成的消息循环是Windows程序的核心,它会持续捕获系统发送给窗口的所有消息,直到收到退出信号(比如关闭窗口、按下Ctrl+C)。
运行注意事项
- 支持Windows 10+、Python 3.x环境
- 不需要管理员权限,普通用户权限即可运行
- 退出程序可以按Ctrl+C,或者直接关闭控制台窗口
内容的提问来源于stack exchange,提问作者Victor Marcelino
相关产品推荐
相关产品推荐

