【问题标题】:SetThreadExecutionState is not working when called from windows service从 Windows 服务调用时,SetThreadExecutionState 不起作用
【发布时间】:2011-08-17 17:40:36
【问题描述】:

我想阻止系统从 Windows 服务进入睡眠/休眠状态。 我正在调用 SetThreadExecutionState 函数来做到这一点。 但它似乎没有任何效果。 我只想知道函数SetThreadExecutionState 是否适用于Windows 服务。如果不是,那还有什么替代方法。

下面是我正在使用的 C# 代码。我在Onstart 服务方法上调用它。

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint SetThreadExecutionState(EXECUTION_STATE esFlags);
private void KeepAlive() 
{
     SetThreadExecutionState(EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS)
}

【问题讨论】:

  • 返回 0 吗?如果是,GetLastError() 返回什么?
  • @Tony Lee 它返回一个非零值。
  • 你用的是什么Windows系统?

标签: c# windows windows-services


【解决方案1】:

在没有 ES_CONTINUOUS 的情况下调用 SetThreadExecutionState 只会重置空闲计时器;为了使显示器或系统保持在工作状态,线程必须定期调用SetThreadExecutionState。

(source)

您需要不时调用此函数。这不是一劳永逸。

【讨论】:

  • 我在调用时包含 ES_CONTINUOUS 标志
  • @Prasad 是的,你是。使用该标志每 5 分钟调用一次,它会起作用。
  • 那么如果需要定期调用,这是否意味着MSDN文档有误?还是这种奇怪的 5 分钟现象只发生在服务上?
  • 这个答案中的引用意味着 with ES_CONTINUOUS, SetThreadExecutionState() 只需要调用一次。 OP 正确地做到了这一点。 然而,他在OnStart 中调用它,我假设它在一个短暂的线程上运行,并且在线程结束时状态到期。定时器解决方案使用了一个长期存在的线程池线程,但这是一个糟糕的解决方案。
  • @KayZed 这是一个有趣的理论。 ES_CONTINUOUS 是对的;看起来即使只调用一次它也应该可以工作。
【解决方案2】:

SetThreadExecutionState 只对调用它的线程有效。如果在工作线程中调用,即使使用 ES_CONTINUOUS,一旦工作线程死了,设置就不再有效,然后屏幕保护程序将再次打开。

从 Timer 调用此 API 将在前一个线程死亡之前唤醒一个工作线程,从而使其工作。

因此,如果您在主线程中调用 SetThreadExecutionState,例如客户端应用程序中的 UI 线程,则不需要计时器。

【讨论】:

  • 对。最好是在OnStart 中启动一个新线程并让它调用SetThreadExecutionState()。然后线程应该保持活动状态;为此,可以使用EventWaitHandle。设置在OnStop
【解决方案3】:

这是我的解决方案,希望对您有所帮助。似乎可以在 Windows 10 上运行。用法:

PowerUtilities.PreventPowerSave();

...然后以后

PowerUtilities.Shutdown();

不可重新调用。

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace KeepAlive
{
    public static class PowerUtilities
    {
        [Flags]
        public enum EXECUTION_STATE : uint
        {
            ES_AWAYMODE_REQUIRED = 0x00000040,
            ES_CONTINUOUS = 0x80000000,
            ES_DISPLAY_REQUIRED = 0x00000002,
            ES_SYSTEM_REQUIRED = 0x00000001
            // Legacy flag, should not be used.
            // ES_USER_PRESENT = 0x00000004
        }
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern uint SetThreadExecutionState(EXECUTION_STATE esFlags);

        private static AutoResetEvent _event = new AutoResetEvent(false);

        public static void PreventPowerSave()
        {
            (new TaskFactory()).StartNew(() =>
                {
                    SetThreadExecutionState(
                        EXECUTION_STATE.ES_CONTINUOUS
                        | EXECUTION_STATE.ES_DISPLAY_REQUIRED
                        | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
                    _event.WaitOne();

                },
                TaskCreationOptions.LongRunning);
        }

        public static void Shutdown()
        {
            _event.Set();
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2021-08-19
    • 2021-12-13
    • 2013-04-05
    相关资源
    最近更新 更多