Любой API для предотвращения перехода Windows 8 в режим ожидания?

Мне нужно отключить режим ожидания в режиме ожидания, пока мое настольное приложение не закончит. Желаемое поведение должно быть похоже на то, что происходит, когда я подключаюсь к этой машине через Remote Desktop. То есть экран выключается, но система не входит в спящий режим, пока я не отключусь.

Есть ли какой-либо документированный или недокументированный способ получить такое же поведение для моего приложения?

Я попробовал PowerSetRequest с помощью PowerRequestExecutionRequired и/или PowerRequestAwayModeRequired, но система по-прежнему переходит в режим ожидания в нескольких мин. В настоящее время я использую PowerRequestDisplayRequired, чтобы сохранить его, но экран всегда остается включенным.

EDITED. Это тестовое приложение. Таймер гаснет не более 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:

EXECUTION:
[PROCESS] \Device\HarddiskVolume4\Users\avo\Test\CsTestApp.exe
Disable Connected Standby

Ответ 1

По-видимому, существует (плохо) документированное значение таймаута, связанное с PowerRequestExecutionRequired, так что "неправильное использование" API не задерживает фактический запрос сна для машин AoAc.

В вашем случае, вероятно, лучше всего использовать PowerWriteACValueIndex для установки таймаута (-1 отключает таймаут):

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

Ответ 2

Вот аналогичный вопрос, без ответа. Я попробовал PowerSetRequest/PowerRequestExecutionRequired на моем планшете на базе Z3700, и я вижу то же самое, планшет переходит в режим ожидания в течение 5 минут независимо от этого запроса мощности.

В сети не так много информации о встроенных функциях подключенного режима, но я нашел следующий загружаемый документ: "Введение в подключенный резервный режим" . Ниже приведена соответствующая информация о входе в ждущий режим:

Имя фазы:
Фаза подключения.

Описание:
Система проверяет подключения к удаленному рабочему столу.

Выполненные задачи:
• Определите, существуют ли сеансы удаленного рабочего стола.
• Начните отслеживать выдающиеся запросы мощности.

Выход, когда:
Нет подключений удаленных рабочих столов.

...

Имя фазы:
Фаза замедлителя активности рабочего стола (DAM).

Описание:
Система приостанавливает работу настольных приложений.

Выполненные задачи:
• Проверьте выдающиеся запросы на питание (PowerRequestExecutionRequired).
• Ожидание выдающейся мощности Запросы должны быть удалены приложением или обеспечить максимальный тайм-аут от батареи (5 минут).

Выход из:
Все выдающиеся запросы мощности были очищены приложениями или был достигнут максимальный тайм-аут. их потребление при подключенном резервном режиме.

Итак, действительно есть специальная обработка для удаленных подключений, но для других сервисов у вас есть целых 5 минут, чтобы закончить или приостановить действие PowerRequestExecutionRequired. По моему опыту, это происходит даже при питании планшета.

IMO, это плохое дизайнерское решение. Это не планшет Windows RT, это полнофункциональная машина для Windows 8.1 Pro, и для обеспечения ее жизнедеятельности на батареях необходимо поддерживать ее, по крайней мере, для надежных настольных приложений. p >

Возможно, отключить режим ожидания в целом, но в этом случае кнопка аппаратного питания не может использоваться для выключения и включения монитора.

Так что, я ненавижу быть этим человеком, но это не возможно, но я думаю, что нет официального способа отключить подключенный режим ожидания, как это делает демон удаленного доступа. Я надеюсь, что кто-то опубликует лучший ответ.

Обновлено. В этом документе также упоминается "Фаза обслуживания":

Система выполняет задачи обслуживания.

• Дождитесь завершения задач обслуживания при запуске

(наиболее часто используется для питания переменного тока).

Выход, если... Нет задач обслуживания системы.

• Как правило, менее 1 секунды.

• Система, скорее всего, заблокирует фазу технического обслуживания от сети переменного тока.

Возможно, возможно запустить текущую задачу обслуживания через API планировщика заданий Windows, хотя неясно, будет ли режим CS не вводиться, если он работает от аккумулятора. Я не пробовал это.

Ответ 3

Это может быть самым трудоемким решением, но если вы держите музыкальное приложение для паз, играя в фоновом режиме, оно все равно должно поддерживать ваш компьютер для других процессов.