3

In my file transfer application (WinSCP), I use SetThreadExecutionState(ES_SYSTEM_REQUIRED) to prevent the system from going into sleep mode while a file transfer is in progress. But this does not work anymore on Windows 11.

I didn't find any reference about different requirements for an application to prevent sleep mode on Windows 11.

My application is a C++ Win32 app. But I can reproduce the same problem with a trivial .NET 5 WinForms C# application.

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);
}

As long as the application is running on Windows 10, the system never goes into sleep mode. But Windows 11 goes to sleep as scheduled.

Windows File Explorer on Windows 11 successfully prevents the sleep while it is transferring files. So it's not like it's not possible to prevent Windows 11 from going into sleep mode.

Why doesn't SetThreadExecutionState(ES_SYSTEM_REQUIRED) work anymore on Windows 11? Is there a different API on Windows 11 for this task?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992

2 Answers2

2

It seems that the SetThreadExecutionState(ES_SYSTEM_REQUIRED) "reset the idle timer" API (i.e. without ES_CONTINUOUS flag) is broken in Windows 11.

The ES_CONTINUOUS API works. So I had to redesign my application to use that one. As my application can have multiple threads, each doing lengthy operation, repeatedly calling the SetThreadExecutionState(ES_SYSTEM_REQUIRED) from each of these threads during the operations was more convenient.

Now I have to have a separate thread whose sole purpose is to report the application state to the system. First time the SetThreadExecutionState(ES_SYSTEM_REQUIRED) would be previously called by any thread now triggers the "state thread" to call SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS). Further calls just reset an internal 5 seconds timer. If that timer eventually expires, the state thread calls SetThreadExecutionState(ES_CONTINUOUS).

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • FYI. One from Microsoft, 'This is by design. ES_CONTINUOUS is implemented as power requests. Prior to Windows 11 power requests were held an additional 2 minutes after they were dropped by the application. This caused issue as some applications would periodically take a power request for a short period keep systems out of sleep indefinitely. This behavior was removed in Windows 11 and now systems are eligible to sleep as soon as the last power request is dropped.' – YangXiaoPo-MSFT Dec 07 '22 at 01:36
  • @YangXiaoPo-MSFT But my question is about change in `ES_SYSTEM_REQUIRED` behavior, not `ES_CONTINUOUS`. – Martin Prikryl Dec 07 '22 at 07:06
0

According to SetThreadExecutionState,

Calling SetThreadExecutionState without ES_CONTINUOUS simply resets the idle timer; to keep the display or system in the working state, the thread must call SetThreadExecutionState periodically.

Alternatively, Calling SetThreadExecutionState as the document example shows:

// 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);
YangXiaoPo-MSFT
  • 1,589
  • 1
  • 4
  • 22
  • Thanks. Though I do *"call SetThreadExecutionState periodically"*. + If I understand the documentation correctly, you keep the system up by either repeatedly calling `SetThreadExecutionState` without `ES_CONTINUOUS`; or by calling it once with `ES_CONTINUOUS`. So while your code with `ES_CONTINUOUS` should work too (and it indeed seem to work), it does not explain why my code does not. Or do you have any reason to believe the API without `ES_CONTINUOUS` is not valid anymore on Windows 11? – Martin Prikryl May 31 '22 at 05:10
  • As far as I'm concerned, ES_SYSTEM_REQUIRED Forces the system to be in the working state by resetting the system idle timer **once**. – YangXiaoPo-MSFT May 31 '22 at 05:13
  • 1
    Yes, that's why I'm calling it on timer every second in the example code. And that works as expected on Windows 10. – Martin Prikryl May 31 '22 at 05:20
  • 1
    @MartinPrikryl I reproduced and I'm looking into the behavior. – YangXiaoPo-MSFT May 31 '22 at 07:04
  • "Away mode should be used only by media-recording and media-distribution applications" – Anders May 31 '22 at 12:57
  • Just to add some info I found out after trying the above in PowerShell, for multiple input arguments, the pipes aren't passed correctly by PowerShell. You have to use `-bor` in their place to represent bitwise or operators, e.g., `( $ES_CONTINUOUS -bor $ES_SYSTEM_REQUIRED )`, where the variables are the hexadecimal representations from the MSDocs. – Blaisem Sep 26 '22 at 10:57