在Windows 11上,SetThreadExecutionState(ES_SYSTEM_REQUIRED)不能防止系统进入睡眠状态。

3
在我的文件传输应用程序(WinSCP)中,我使用SetThreadExecutionState(ES_SYSTEM_REQUIRED)来防止系统在文件传输过程中进入睡眠模式。但这在Windows 11上不再起作用。
我没有找到有关应用程序防止Windows 11进入睡眠模式的不同要求的任何参考资料。
我的应用程序是一个C ++ Win32应用程序。但我可以使用微不足道的.NET 5 WinForms C#应用程序复现同样的问题。
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.Label label1;

public enum EXECUTION_STATE : uint
{
    ES_SYSTEM_REQUIRED = 0x00000001
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint SetThreadExecutionState(EXECUTION_STATE esFlags);

// The timer ticks every second.
private void timer1_Tick(object sender, EventArgs e)
{
    label1.Text = (int.Parse(label1.Text) + 1).ToString();
    SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED);
}

只要应用程序在Windows 10上运行,系统就不会进入睡眠模式。但是Windows 11会按计划进入睡眠模式。
在Windows 11上,Windows文件资源管理器在传输文件时可以成功阻止睡眠。因此,并非不可能防止Windows 11进入睡眠模式。
为什么在Windows 11上SetThreadExecutionState(ES_SYSTEM_REQUIRED)不再起作用?是否有其他API可用于此任务?
2个回答

2
似乎在Windows 11操作系统中,没有ES_CONTINUOUS标志的SetThreadExecutionState(ES_SYSTEM_REQUIRED)“重置空闲计时器”API存在问题。ES_CONTINUOUS API可行,因此我重新设计了应用程序以使用该API。由于我的应用程序可以拥有多个线程,每个线程都会执行长时间操作,在操作期间反复从每个线程调用SetThreadExecutionState(ES_SYSTEM_REQUIRED)更为方便。现在,我必须有一个单独的线程,其唯一目的是向系统报告应用程序状态。第一次任何线程之前调用SetThreadExecutionState(ES_SYSTEM_REQUIRED)现在会触发“状态线程”调用SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS)。进一步的调用只会重置内部5秒钟计时器。如果该计时器最终到期,则状态线程将调用SetThreadExecutionState(ES_CONTINUOUS)。请注意保留HTML标签。

FYI。来自微软的一位表示,“这是设计上的问题。ES_CONTINUOUS被实现为电源请求。在Windows 11之前,电源请求在应用程序放弃后会额外保持2分钟。这会导致问题,因为某些应用程序会定期短暂地获取电源请求,使系统无限期地保持清醒状态。在Windows 11中删除了此行为,现在系统可以在最后一个电源请求被放弃后立即进入睡眠状态。” - YangXiaoPo-MSFT
@YangXiaoPo-MSFT,但我的问题是关于ES_SYSTEM_REQUIRED行为的更改,而不是ES_CONTINUOUS - Martin Prikryl

0
根据 SetThreadExecutionState
调用不带 ES_CONTINUOUS 的 SetThreadExecutionState 只会重置空闲计时器;为了保持显示器或系统处于工作状态,线程必须定期调用 SetThreadExecutionState。
或者,按照文档示例所示,调用 SetThreadExecutionState。
// Enable away mode and prevent the sleep idle time-out.
//
SetThreadExecutionState(ES_CONTINUOUS | ES_AWAYMODE_REQUIRED);

//
// ...
//

//
// Clear EXECUTION_STATE flags to disable away mode and allow the system to idle to sleep normally.
//
SetThreadExecutionState(ES_CONTINUOUS);

谢谢。虽然我会“定期调用 SetThreadExecutionState”,但如果我正确理解文档,您可以通过重复调用没有 ES_CONTINUOUS 的 SetThreadExecutionState 或者使用一次带有 ES_CONTINUOUS 的调用来保持系统运行。因此,虽然您的代码带有 ES_CONTINUOUS 也应该可以工作(而且它看起来确实可以工作),但这并不能解释为什么我的代码不能工作。或者您有没有理由相信在Windows 11上不再使用不带ES_CONTINUOUS的API? - Martin Prikryl
就我所知, ES_SYSTEM_REQUIRED 通过重置系统空闲计时器 一次 来强制系统处于工作状态。 - YangXiaoPo-MSFT
1
是的,这就是为什么在示例代码中我每秒钟都会调用它的定时器。并且在Windows 10上按预期工作。 - Martin Prikryl
1
@MartinPrikryl 我已经重现了问题并正在研究其行为。 - YangXiaoPo-MSFT
“离线模式应该只被媒体录制和媒体分发应用程序使用。” - Anders
只是想在尝试上述PowerShell代码后添加一些信息,对于多个输入参数,管道符号在PowerShell中无法正确传递。您必须使用“-bor”代替它们来表示按位或运算符,例如( $ES_CONTINUOUS -bor $ES_SYSTEM_REQUIRED ),其中变量是来自MSDocs的十六进制表示。 - Blaisem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接