top of page

Stop the PC sleeping during a long-running task

4 days ago
2 min read
This post is one of a series providing implementation examples of Windows API Functions, Types, Enums and Consts using VBA. The code in this post can be used as-is, however, if you regularly (or even just occasionally) work with Windows API declarations in VBA, you may want to see the posts Automatically add Windows API declaration(s) and Using 'F1' to view Windows API web pages which explain some of the functionality that can be added to the VBE by VBE_Extras.

You kick off a long VBA job ... a big import, a slow run of web calls, an overnight rebuild ... walk away, and come back to find Windows has dimmed the screen or sent the machine to sleep half way through. VBA has no built-in way to say "don't sleep, I'm busy", but Windows does: a single call of SetThreadExecutionState keeps the machine (and, if you want, the display) awake until you say otherwise.


A few things to know before the code:


  • You're making a request, not issuing a command. You assert a "keep awake" state at the start of the task and clear it at the end ... it stops the machine idling to sleep, but it can't stop the user deliberately sleeping it (closing the lid, pressing the power button etc), and that's by design.

  • The behaviour is driven by three flag Consts, combined with Or: ES_SYSTEM_REQUIRED keeps the machine awake, ES_DISPLAY_REQUIRED also keeps the screen on, and ES_CONTINUOUS makes the state stick until you clear it. Without ES_CONTINUOUS the call just nudges the idle timer once, which isn't what you want for a long job.

  • You must clear the state when you're done, by calling the Function again with ES_CONTINUOUS on its own ... that restores normal power management (if you don't, the "keep awake" request is dropped when the host Application closes anyway).


The code


Add a standard Module and paste in all of the following ... the three flag Consts, the declaration, a Sub to test it, and two small helpers (one to prevent sleep, one to allow it again):


Things to note ...


Always clear the state, even if the task errors. The "keep awake" request lives with the running process, so the real-world pattern is to wrap your long running job in an error handler, and call AllowSleep on the way out (in your error-exit) so a failure half way through doesn't leave the machine permanently awake.


The display flag is optional. Pass False for bKeepDisplayOn (i.e. ES_SYSTEM_REQUIRED without ES_DISPLAY_REQUIRED) when you just need the machine to keep working but you're happy for the screen to switch off ... which saves power on a long unattended job.


It doesn't stop a screensaver. ES_DISPLAY_REQUIRED keeps the monitor powered on, but it does not prevent a screensaver from starting.


It's a request, and the system can still overrule it. Battery-saver, group policy, or the user pressing the power button or closing the lid can all win ... SetThreadExecutionState deliberately can't override those. Treat it as "please don't idle to sleep while I'm busy", which is exactly what a long task needs.

1 Comment


info
9 hours ago

hi John

Thanks for publishing this code. It looks perfect for one of my apps which often runs for several hours unattended


Colin Riddington

Like
bottom of page