Prevent windows from going into sleep when my program is running?

Viewed 49461

I have to stop windows from going into sleep when my program is running.

And I don't only want to prevent the sleep-timer, I also want to cancel the sleep-event if I press the sleep-button or in any other way actively tell the computer to sleep. Therefore SetThreadExecutionState is not enough.

Or...I don't actually have to prevent the sleep completely, only delay it 5-10sec to allow my program to finish a task.

(I know that this is bad program behavior but it's only for personal use.)

8 Answers

I had a problem like this with a hardware device connected via usb. XP /Vista would sleep/hibernate right in the middle of ... Great you say, when it resumes it can just continue. If the hardware is still connected!!! Users have the habit of pulling cables out whenever they feel like it.

You need to handle XP and Vista

Under XP trap the WM_POWERBROADCAST and look for the PBT_APMQUERYSUSPEND wparam.

   // See if bit 1 is set, this means that you can send a deny while we are busy
   if (message.LParam & 0x1)
   {
      // send the deny message
      return BROADCAST_QUERY_DENY;
   } // if
   else
   {
      return TRUE;
   } // else

Under Vista use SetThreadExecutionState like this

// try this for vista, it will fail on XP
if (SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED) == NULL)
{
   // try XP variant as well just to make sure 
   SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
}  // if 

and when you app has finished set it back to normal

// set state back to normal
SetThreadExecutionState(ES_CONTINUOUS);

set wsc = CreateObject("WScript.Shell")

Do WScript.Sleep (60*1000) wsc.SendKeys ("{SCROLLLOCK 2}") Loop

-put the above code in notepad and save the file as .vbs and double click the file

Below is my attempt using the modern power availability request API (supersedes SetThreadExecutionState), as suggested by vim.

I'm using a nice P/Invoke NuGet I came across, Vanara.PInvoke.Kernel32:

using Vanara.PInvoke;
using static Vanara.PInvoke.Kernel32;

// create request object
using var request = PowerCreateRequest(new REASON_CONTEXT("App FOO is working"));
if (request.IsInvalid)
{
    throw new InvalidOperationException(
       $"Could not create power availability request: {Win32Error.GetLastError()}");
}

// send request
if (!PowerSetRequest(request, POWER_REQUEST_TYPE.PowerRequestSystemRequired))
{
    throw new InvalidOperationException(
       $"Could not send power availability request: {Win32Error.GetLastError()}");
}
    
// do stuff that required the machine to be up
Console.WriteLine("Doing stuff...");
await Task.Delay(5000);

// clear request
if (!PowerClearRequest(request, POWER_REQUEST_TYPE.PowerRequestSystemRequired))
{
    Console.WriteLine(
      "WARNING: Could not clear power availability request: {0}",
      Win32Error.GetLastError());
}

You can see your request in action by issuing powercfg /requests from an admin terminal.

If you need a display that should work until your application is running then try to set "ES_DISPLAY_REQUIRED" instead of away mode:

SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);

Once you are done with your application make sure to clear all other flags.

SetThreadExecutionState(ES_CONTINUOUS);
Related