我的应用需要阻止睡眠/休眠模式。我已准备好代码,但在成功捕获 WM_POWERBROADCAST 消息后, PBT_APMQUERYSUSPEND 和 PBT_APMQUERYSTANDBY 都未成功捕获。有趣的是,我的应用程序正在捕获 PBT_APMRESUMECRITICAL 和 PBT_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);
}
答案 0 :(得分:3)
现在适用于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
{
/// <summary>
/// Notify that machine power state is changing
/// </summary>
WM_POWERBROADCAST = 0x218,
/// <summary>
/// Message indicating that machine is trying to enter suspended state
/// </summary>
PBT_APMQUERYSUSPEND = 0x0,
PBT_APMQUERYSTANDBY = 0x0001,
/// <summary>
/// Message to deny broadcast query
/// </summary>
BROADCAST_QUERY_DENY = 0x424D5144
}
}
答案 1 :(得分:1)
尝试订阅PowerModeChanged事件:
How do I check when the computer is being put to sleep or wakes up?
答案 2 :(得分:0)
您是在Vista还是Windows Server 2008上运行? This page说
由于Windows Vista和Windows Server 2008的电源管理模型发生了变化,PBT-APMQUERYSUSPEND事件不再提供给应用程序。而是交付了BT_APMSUSPEND事件......
这可能就是你没有看到它的原因吗?
答案 3 :(得分:0)
我在我的(开发)机器和测试应用程序中尝试了相同的代码。在另一台(测试)机器上(也是winXP)。在我的机器上,它继续失败,这意味着机器进入睡眠状态。但在另一台机器上,它的工作原理!起初我认为这是一个调试与发布模式问题,但事实并非如此。
似乎我的开发机器有所不同,但我不知道它可能是什么。
神秘解决了... sorta。
答案 4 :(得分:0)
在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关闭以查看它们是否被发送时,您是否尝试过全面记录广播?