代码之家  ›  专栏  ›  技术社区  ›  Garrett

无法捕获睡眠/挂起消息(WinXP)

  •  6
  • Garrett  · 技术社区  · 15 年前

    我的应用程序需要阻止睡眠/休眠模式。我已经准备好了代码,但是在成功地捕获了 功率广播 消息,两者都不是 PBT_APMQuerySuspend(PBT_APMQuerySuspend) 也不 PBT_APMQuerysandby公司 正在成功捕获。有趣的是, PBT-Apmresumecritical(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);
        }
    
    5 回复  |  直到 10 年前
        1
  •  3
  •   Garrett    15 年前

    它现在可以工作了,适用于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
    
    
        }
    }
    
        2
  •  1
  •   Community CDub    7 年前
        3
  •  0
  •   JeffH    15 年前

    您在Vista或Windows Server 2008上运行吗? This page

    由于Windows Vista和Windows Server 2008的电源管理模式发生了变化,PBT-APMQuerySuspend事件不再提供给应用程序。相反,bt_apmsuspend事件被传递…

    这就是为什么你没有看到它吗?

        4
  •  0
  •   Garrett    15 年前

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

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

    神秘解决了…索塔

        5
  •  0
  •   miPwn    15 年前

    在Vista中,调用sethreadeExecutionState通知WPM系统没有空闲。

    在Windows XP/2000中:
    应用程序可以返回broadcast_query_deny以拒绝PBT_apmQuerySuspend或PBT_apmQuerySuspendfailed请求。

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

    另外,我不认为在win2k中支持pbt_apmquerysandby或pbt_apmstandby。您是否尝试在Windows关闭时将广播记录下来以查看是否正在发送广播?

    推荐文章