【问题标题】:Any API to prevent Windows 8 from going into connected standby mode?是否有任何 API 可以防止 Windows 8 进入连接待机模式?
【发布时间】:2014-06-17 09:57:33
【问题描述】:

我需要禁用connected standby 模式,直到我的桌面应用程序完成。所需的行为应该类似于我通过远程桌面连接到该机器时发生的情况。也就是说,屏幕已关闭,但系统在我断开连接之前不会进入睡眠状态。

是否有任何记录或未记录的方式可以让我的应用程序获得相同的行为?

我尝试使用PowerSetRequestPowerRequestExecutionRequired 和/或PowerRequestAwayModeRequired,但系统在几分钟后仍会进入连接待机模式。我目前使用PowerRequestDisplayRequired 使其保持活动状态,但屏幕始终亮着。

已编辑。这是测试应用程序。在我按下硬件电源按钮并且屏幕关闭(依靠电池运行)后,计时器的计时不超过 5 分钟。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace CsTestApp
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            this.Load += MainForm_Load;
        }

        void MainForm_Load(object sender, EventArgs e)
        {
            // init timer

            var timer = new System.Windows.Forms.Timer();
            timer.Interval = 1000;
            timer.Tick += delegate 
            { 
                System.Diagnostics.Trace.WriteLine("CsTestApp: " + DateTime.Now); 
            };
            timer.Start();

            // set GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT

            IntPtr pActiveSchemeGuid;
            var hr = PowerGetActiveScheme(IntPtr.Zero, out pActiveSchemeGuid);
            if (hr != 0)
                Marshal.ThrowExceptionForHR((int)hr);
            Guid activeSchemeGuid = (Guid)Marshal.PtrToStructure(pActiveSchemeGuid, typeof(Guid));
            LocalFree(pActiveSchemeGuid);

            int savedTimeout;
            hr = PowerReadDCValueIndex(
                IntPtr.Zero,
                activeSchemeGuid,
                GUID_IDLE_RESILIENCY_SUBGROUP,
                GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT,
                out savedTimeout);
            if (hr != 0)
                Marshal.ThrowExceptionForHR((int)hr);

            hr = PowerWriteDCValueIndex(
                IntPtr.Zero,
                activeSchemeGuid,
                GUID_IDLE_RESILIENCY_SUBGROUP,
                GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT,
                -1);
            if (hr != 0)
                Marshal.ThrowExceptionForHR((int)hr);

            // create power request

            var powerRequestContext = new POWER_REQUEST_CONTEXT();
            powerRequestContext.Version = POWER_REQUEST_CONTEXT_VERSION;
            powerRequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
            powerRequestContext.SimpleReasonString = "Disable Connected Standby";
            var powerRequest = PowerCreateRequest(ref powerRequestContext);
            if (powerRequest == IntPtr.Zero)
                ThrowLastWin32Error();

            // set PowerRequestExecutionRequired

            if (!PowerSetRequest(powerRequest, PowerRequestType.PowerRequestExecutionRequired))
                ThrowLastWin32Error();

            this.FormClosed += delegate
            {
                timer.Dispose();

                PowerClearRequest(powerRequest, PowerRequestType.PowerRequestExecutionRequired);
                CloseHandle(powerRequest);

                hr = PowerWriteDCValueIndex(
                    IntPtr.Zero,
                    activeSchemeGuid,
                    GUID_IDLE_RESILIENCY_SUBGROUP,
                    GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT,
                    savedTimeout);
                if (hr != 0)
                    Marshal.ThrowExceptionForHR((int)hr);

            };
        }


        // power API interop

        static void ThrowLastWin32Error()
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        enum PowerRequestType
        {
            PowerRequestDisplayRequired = 0,
            PowerRequestSystemRequired = 1,
            PowerRequestAwayModeRequired = 2,
            PowerRequestExecutionRequired = 3,
            PowerRequestMaximum
        }

        [StructLayout(LayoutKind.Sequential)]
        struct PowerRequestContextDetailedInformation
        {
            public IntPtr LocalizedReasonModule;
            public UInt32 LocalizedReasonId;
            public UInt32 ReasonStringCount;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string[] ReasonStrings;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct POWER_REQUEST_CONTEXT_DETAILED
        {
            public UInt32 Version;
            public UInt32 Flags;
            public PowerRequestContextDetailedInformation DetailedInformation;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct POWER_REQUEST_CONTEXT
        {
            public UInt32 Version;
            public UInt32 Flags;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SimpleReasonString;
        }

        const int POWER_REQUEST_CONTEXT_VERSION = 0;
        const int POWER_REQUEST_CONTEXT_SIMPLE_STRING = 0x1;
        const int POWER_REQUEST_CONTEXT_DETAILED_STRING = 0x2;

        static readonly Guid GUID_IDLE_RESILIENCY_SUBGROUP = new Guid(0x2e601130, 0x5351, 0x4d9d, 0x8e, 0x4, 0x25, 0x29, 0x66, 0xba, 0xd0, 0x54);
        static readonly Guid GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT = new Guid(0x3166bc41, 0x7e98, 0x4e03, 0xb3, 0x4e, 0xec, 0xf, 0x5f, 0x2b, 0x21, 0x8e);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr PowerCreateRequest(ref POWER_REQUEST_CONTEXT Context);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool PowerSetRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool PowerClearRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr LocalFree(IntPtr hMem);

        [DllImport("PowrProf.dll", CharSet = CharSet.Unicode)]
        static extern UInt32 PowerWriteDCValueIndex(IntPtr RootPowerKey,
            [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid,
            [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid,
            [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid,
            int AcValueIndex);

        [DllImport("PowrProf.dll", CharSet = CharSet.Unicode)]
        static extern UInt32 PowerReadDCValueIndex(IntPtr RootPowerKey,
            [MarshalAs(UnmanagedType.LPStruct)] Guid SchemeGuid,
            [MarshalAs(UnmanagedType.LPStruct)] Guid SubGroupOfPowerSettingsGuid,
            [MarshalAs(UnmanagedType.LPStruct)] Guid PowerSettingGuid,
            out int AcValueIndex);

        [DllImport("PowrProf.dll", CharSet = CharSet.Unicode)]
        static extern UInt32 PowerGetActiveScheme(IntPtr UserPowerKey, out IntPtr ActivePolicyGuid);
    }
}

这是powercfg.exe /requests的输出:

执行: [过程] \Device\HarddiskVolume4\Users\avo\Test\CsTestApp.exe 禁用连接待机

【问题讨论】:

  • 你试过SetThreadExecutionState吗?
  • @EricBrown,是的,我在PowerSetRequest 之前先尝试过,但没有帮助。
  • @EricBrown,这是一个 8" ASUS VivoTab Note 8,这个使用 Intel Z3740 CPU。我认为它对于任何 Bay Trail SoC 设备都是一样的,因为驱动程序几乎相同并且由英特尔提供。
  • 查看我可用的资源,大多数地方只是使用PowerRequestExecutionRequired,然后执行正常活动(通常使用网络/文件系统)。有几个地方同时使用PowerRequestExecutionRequiredPowerRequestDisplayRequired;从当地情况来看,它是否真的在显示某些东西(例如播放媒体)并不清楚。
  • @EricBrown,它出现在 PowerRequestExecutionRequired is limited to 5 mins only

标签: c# c++ .net windows winapi


【解决方案1】:

显然,与PowerRequestExecutionRequired 关联的超时值(很少记录),因此“滥用”API 不会延迟 AoAc 机器的实际睡眠请求。

在您的情况下,您最好的选择可能是使用PowerWriteACValueIndex 设置超时(-1 禁用超时):

    ReturnCode = PowerWriteACValueIndex(NULL,
                                   pGuidActivePowerScheme,
                                   &GUID_IDLE_RESILIENCY_SUBGROUP,
                                   &GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT,
                                   -1);

【讨论】:

  • 谢谢 Eric,我试过了,但没有帮助。我用代码更新了问题,我在那里使用PowerWriteDCValueIndex,因为我需要使用电池运行设备。非常感谢您的帮助,很高兴有一位 MSFT 人员对此进行调查。
  • @avo - 你快到了 - 你需要使用 PowerSetActiveScheme 设置活动方案以提交对电源方案的任何更改。 (完成后不要忘记恢复超时......)
  • 两个问题:1) 这仍然是在 Windows 10 中处理此问题的最佳方法吗? 2) 这会阻止 Windows 10 由于更新而重新启动吗?我有一个用于监控可以持续 24 小时或更长时间的工业流程的应用程序。我们遇到过 Windows 10 在非工作时间更新并重新启动并使数据无效的情况。我怀疑我们需要使用 Win 10 Pro 并关闭更新,因为这会扰乱关键任务数据收集。
【解决方案2】:

这里是a similar question, unanswered。我在基于 Z3700 的平板电脑上尝试了PowerSetRequest / PowerRequestExecutionRequired,我看到了相同的行为,无论此电源请求如何,平板电脑都会在大约 5 分钟内进入连接待机模式。

网络上没有太多关于连接模式内部的信息,但我找到了以下可下载文档:"Introduction to Connected Standby"。以下是有关进入连接待机模式的相关部分:

阶段名称
连接阶段。

说明
系统正在检查远程桌面连接。

执行的任务
• 确定远程桌面会话是否存在。
• 开始跟踪未完成的电源请求。

何时退出
没有连接远程桌面会话。

...

阶段名称
桌面活动主持人 (DAM) 阶段。

说明
系统暂停桌面应用程序以减少。

执行的任务
• 检查未完成的电源请求 (PowerRequestExecutionRequired)。
• 等待未完成的电源 请求被应用程序丢弃,或强制执行最大值 电池电量超时(5 分钟)。

退出时间
所有未完成的电源请求已被应用程序清除 或已达到最大超时。他们在连接待机期间的消耗。

因此,对于远程连接确实有一些特殊处理,但对于其他服务,您有多达 5 分钟的时间来完成或暂停您的 PowerRequestExecutionRequired 活动。根据我的经验,即使在平板电脑通电时也会发生这种情况。

IMO,这是一个糟糕的设计决定。它不是 Windows RT 平板电脑,它是功能齐全的 Windows 8.1 Pro 机器,如果我们愿意的话,必须有一种方法让它靠电池保持活力,至少对于受信任的桌面应用程序来说是这样。 p>

可以disable connected standby mode altogether,但在这种情况下,硬件电源按钮不能用于关闭和打开显示器。

所以,我讨厌成为一个不可能的人,但我认为没有官方方法可以像远程访问守护程序那样禁用连接待机。我希望有人会发布更好的答案。

更新,该文档还提到了“维护阶段”:

系统执行维护任务。

• 如果正在运行,请等待维护任务完成

(最常见于交流电源)。

Exited when... 没有系统维护任务正在运行。

• 通常少于 1 秒。

• 系统最有可能在交流电源的维护阶段阻塞。

也许,可以通过 Windows 任务计划程序 API 启动正在进行的维护任务,但不清楚如果 使用电池供电 是否仍不会进入 CS 模式。这个我没试过。

【讨论】:

    【解决方案3】:

    这可能是最蹩脚的解决方法,但如果你让 Groove 音乐应用程序在后台播放,它仍然应该让你的电脑为其他进程保持清醒

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-21
      • 2017-09-02
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-12
      • 2013-08-01
      相关资源
      最近更新 更多