无法捕捉睡眠/暂停消息(winXP)

我的应用程序需要阻止睡眠/hibernate模式。 我有代码,但成功捕获WM_POWERBROADCAST消息后, PBT_APMQUERYSUSPENDPBT_APMQUERYSTANDBY都没有被成功捕获。 有趣的是,我的应用程序正在捕获PBT_APMRESUMECRITICALPBT_APMRESUMEAUTOMATIC消息。

底线问题:为什么我的应用程序无法捕获备用/暂停消息,但成功捕获恢复消息是否有任何原因?

这个Q&A [stackoverflow.com]有帮助,顺便说一句,但是这些消息似乎没有进入我的应用程序。

我的代码(为了简洁起见删除了事件日志代码):

protected override void WndProc(ref System.Windows.Forms.Message m) { // Power status event triggered if (m.Msg == (int)NativeMethods.WindowMessage.WM_POWERBROADCAST) { // Machine is trying to enter suspended state if (m.WParam.ToInt32() == (int)NativeMethods.WindowMessage.PBT_APMQUERYSUSPEND || m.WParam.ToInt32() == (int)NativeMethods.WindowMessage.PBT_APMQUERYSTANDBY) { // Have perms to deny this message? if((m.LParam.ToInt32() & 0x1) != 0) { // If so, deny broadcast message m.Result = new IntPtr((int)NativeMethods.WindowMessage.BROADCAST_QUERY_DENY); } } return; // ?! } base.WndProc(ref m); } 

它现在适用于XP和Vista。 我创建了一个带有相关代码的存根winform应用程序(显然可以清理,但它传达了这一点)。

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace standbyTest { public partial class Form1 : Form { [DllImport("Kernel32.DLL", CharSet = CharSet.Auto, SetLastError = true)] protected static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE state); [Flags] public enum EXECUTION_STATE : uint { ES_CONTINUOUS = 0x80000000, ES_DISPLAY_REQUIRED = 2, ES_SYSTEM_REQUIRED = 1, ES_AWAYMODE_REQUIRED = 0x00000040 } public Form1() { if(Environment.OSVersion.Version.Major > 5) { // vista and above: block suspend mode SetThreadExecutionState(EXECUTION_STATE.ES_AWAYMODE_REQUIRED | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS); } InitializeComponent(); //MessageBox.Show(string.Format("version: {0}", Environment.OSVersion.Version.Major.ToString() )); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); if(Environment.OSVersion.Version.Major > 5) { // Re-allow suspend mode SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); } } protected override void WndProc(ref System.Windows.Forms.Message m) { // Power status event triggered if(m.Msg == (int)WindowMessage.WM_POWERBROADCAST) { // Machine is trying to enter suspended state if(m.WParam.ToInt32() == (int)WindowMessage.PBT_APMQUERYSUSPEND || m.WParam.ToInt32() == (int)WindowMessage.PBT_APMQUERYSTANDBY) { // Have perms to deny this message? if((m.LParam.ToInt32() & 0x1) != 0) { // If so, deny broadcast message m.Result = new IntPtr((int)WindowMessage.BROADCAST_QUERY_DENY); } } return; } base.WndProc(ref m); } } internal enum WindowMessage { ///  /// Notify that machine power state is changing ///  WM_POWERBROADCAST = 0x218, ///  /// Message indicating that machine is trying to enter suspended state ///  PBT_APMQUERYSUSPEND = 0x0, PBT_APMQUERYSTANDBY = 0x0001, ///  /// Message to deny broadcast query ///  BROADCAST_QUERY_DENY = 0x424D5144 } } 

尝试订阅PowerModeChanged事件:

如何检查计算机何时进入睡眠状态或唤醒?

您是在Vista还是Windows Server 2008上运行? 这个页面说

由于Windows Vista和Windows Server 2008的电源管理模型发生了变化,PBT-APMQUERYSUSPEND事件不再提供给应用程序。 而是交付BT_APMSUSPEND事件……

这可能就是你没有看到它的原因吗?

我在我的(开发)机器和不同(测试)机器(也是winXP)上的测试应用程序中尝试了相同的代码。 在我的机器上,它继续失败,这意味着机器进入睡眠状态。 但在另一台机器上,它的工作原理! 起初我认为这是一个调试与发布模式问题,但事实并非如此。

看起来我的开发机器有些不同,虽然我不知道它可能是什么。

神秘解决了… sorta。

在Vista中调用SetThreadExecutionState来通知WPM系统没有空闲。

在Windows XP / 2000中:
应用程序可以返回BROADCAST_QUERY_DENY以拒绝PBT_APMQUERYSUSPEND或PBT_APMQUERYSUSPENDFAILED请求。

MSDN:Windows XP及更早版本:系统广播PBT_APMQUERYSUSPEND事件以请求暂停系统操作的权限。 系统希望每个应用程序和驱动程序确定是否应该发生请求的事件,如果发生则返回TRUE,否则返回BROADCAST_QUERY_DENY。 应用程序不应拒绝此请求。 如果应用程序拒绝此请求,系统将广播PBT_APMQUERYSUSPENDFAILED事件。 此事件通知应用程序和驱动程序继续操作。

另外我不认为Win2K中支持PBT_APMQUERYSTANDBY或PBT_APMSTANDBY。 当Windows关闭以查看是否正在发送广播时,您是否尝试过全面记录广播?