我有一台运行自定义服务的无头计算机,我希望使用电源按钮启用/禁用,而不是每次都必须远程连接。计算机也做其他事情,因此不能选择关闭它。
是否可以在Windows XP和Linux下挂钩系统电源按钮; up,这样我的程序会在 Windows启动掉电/睡眠事件(PBT_APMQUERYSUSPEND
事件发送之前)之前获得事件?
答案 0 :(得分:2)
这确实是可能的,但它有点hackish,需要两个完全不同的实现,具体取决于Windows版本。对于这两种方法,您需要设置电源按钮以使计算机在电源选项中处于睡眠状态。
Windows XP及以下版本:
您需要覆盖程序主窗口的WndProc
功能。在本机不支持此功能的IDE上,可以使用user32 API中的SetWindowLong
来完成此操作。在自定义WndProc
功能中,侦听WM_POWERBROADCAST (0x218)
消息。如果您收到wParam为PBT_APMQUERYSUSPEND (0x0)
的邮件,请调用您想要的函数,然后返回BROADCAST_QUERY_DENY (0x424D5144)
,而不是调用基本WndProc
函数。示例代码:
//At program start
//GWL_WNDPROC = -4
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)
//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_APMQUERYSUSPEND = 0x0
//BROADCAST_QUERY_DENY = 0x424D5144
if wMsg = WM_POWERBROADCAST && wParam = PBT_APMQUERYSUSPEND (
//CALL YOUR FUNCTION HERE!
return BROADCAST_QUERY_DENY
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)
//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)
Windows Vista& up: (感谢Remy Lebeau让我走上正轨)
你需要像XP一样覆盖WndProc
,但也需要在kernel32 API中调用SetThreadExecutionState
来禁用睡眠模式,在user32 API中调用RegisterPowerSettingNotification
来监听高级电源通知。特别是,您将收听GUID_SYSTEM_AWAYMODE
通知,该通知会在系统被要求进入睡眠状态时发出,但无法通知。要轻松地将字符串转换为正确形成的LPCGUID
,您可以在rpcrt4.dll API中使用UuidFromStringA
。示例代码:
typedef struct UUID{
int d1, d2, d3, d4
} LPCGUID;
//At program start
//GWL_WNDPROC = -4
//ES_CONTINUOUS = 0x80000000
//ES_SYSTEM_REQUIRED = 0x1
//ES_AWAYMODE_REQUIRED = 0x40
//GUID_SYSTEM_AWAYMODE = "98a7f580-01f7-48aa-9c0f-44352c29e5C0"
LPCGUID uid;
oldWndProc = SetWindowLong(this.hWnd, GWL_WNDPROC, &MyWndProc)
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
UuidFromStringA(*(GUID_SYSTEM_AWAYMODE), uid)
ps = RegisterPowerSettingNotification(this.hWnd, uid, 0)
//In MyWndProc(hWnd, wMsg, wParam, lParam)
//WM_POWERBROADCAST = 0x218
//PBT_POWERSETTINGCHANGE = 0x8013
if wMsg = WM_POWERBROADCAST && wParam = PBT_POWERSETTINGCHANGE (
//CALL YOUR FUNCTION HERE!
//You can additionally extract data from the lParam to verify
//this is the notification you're waiting for (see below)
)
return CallWindowProc(oldWndProc, hWnd, wMsg, wParam, lParam)
//Before exiting
SetWindowLong(Me.hWnd, GWL_WNDPROC, oldWndProc)
UnregisterPowerSettingNotification(ps)
此方法具有关闭物理屏幕的副作用(在无头机器上不是问题),也可能锁定会话。确保在睡眠后禁用提示输入密码以避免这种情况。有关RegisterPowerSettingNotification
可用here的其他有用信息,其中显示了如何从lParam
函数中的WndProc
中提取信息,以防您想要了解有关通知的其他信息。玩得开心;)