从 Windows 服务调用时,SetThreadExecutionState 不起作用

Posted

技术标签:

【中文标题】从 Windows 服务调用时,SetThreadExecutionState 不起作用【英文标题】:SetThreadExecutionState is not working when called from windows service 【发布时间】: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系统? 【参考方案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();
        
    

【讨论】:

以上是关于从 Windows 服务调用时,SetThreadExecutionState 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

无法访问显示组件 - 从 Windows 服务调用

System.Diagnostics.Process.Start() 从 Windows 服务调用时无法启动进程

从 Windows 服务调用时出现 WCF 安全异常

XpsDocumenWriter从Windows服务挂起,但从控制台运行时工作正常

无法从 Windows 服务调用动态加载的 DLL 中的类

打开 Windows 身份验证时使用 ajax 调用 Web 服务?