6

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

底线问题:我的应用程序是否有任何原因无法捕获待机/挂起消息,但成功捕获了恢复消息?

顺便说一句,这个问答[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);
    }
4

5 回答 5

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


    }
}
于 2009-04-08T21:59:11.440 回答
1

尝试订阅 PowerModeChanged 事件:

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

于 2010-10-11T19:31:11.840 回答
0

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

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

这就是你看不到它的原因吗?

于 2009-04-07T19:59:12.203 回答
0

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

我的开发机器似乎有些不同,尽管我不知道它可能是什么。

谜团解开了……有点。

于 2009-04-08T15:20:09.993 回答
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 关闭时全局记录广播以查看它们是否正在发送?

于 2009-04-08T16:00:03.800 回答