从 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 分钟现象只发生在服务上? 这个答案中的引用意味着 withES_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 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
System.Diagnostics.Process.Start() 从 Windows 服务调用时无法启动进程