How to Prevent Screen-Savers and Sleeps During My Program Execution

how do i prevent screen-savers and sleeps during my program execution?

Don't mess with the screensaver settings, use SetThreadExecutionState. This is the API for informing windows on the fact that your application is active:

Enables an application to inform the
system that it is in use, thereby
preventing the system from entering
sleep or turning off the display while
the application is running.

, and

Multimedia applications, such as video
players and presentation applications,
must use ES_DISPLAY_REQUIRED when they
display video for long periods of time
without user input

How to suppress the ŝcreensaver right way

No, it is not.

On XP and later, use SetThreadExecutionState() instead:

Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.

...

Multimedia applications, such as video players and presentation applications, must use ES_DISPLAY_REQUIRED when they display video for long periods of time without user input.

Despite what the documentation says ("This function does not stop the screen saver from executing"), this DOES stop the screensaver.

On earlier versions of Windows, you can handle the WM_SYSCOMMAND message instead. When the wParam is set to SC_SCREENSAVE, if you don't pass the message to DefWindowProc(), the screensaver will not be run, unless the screensaver is password protected, in which case it is run regardless of what happens to the WM_SYSCOMMAND message:

If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification— even if fails to pass it to DefWindowProc.

Another option is to use SystemParametersInfo() to set SPI_SETSCREENSAVEACTIVE to TRUE so Windows thinks a screensaver is already running so it won't start the default screensaver.

Prevent screen from sleeping with C#

You can make use of SetThreadExecutionState

Enables an application to inform the system that it is in use, thereby
preventing the system from entering sleep or turning off the display
while the application is running.

Remarks

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.

To run properly on a power-managed computer, applications such as fax
servers, answering machines, backup agents, and network management
applications must use both ES_SYSTEM_REQUIRED and ES_CONTINUOUS when
they process events. Multimedia applications, such as video players
and presentation applications, must use ES_DISPLAY_REQUIRED when they
display video for long periods of time without user input.
Applications such as word processors, spreadsheets, browsers, and
games do not need to call SetThreadExecutionState.

DllImport

[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);

Enums

[FlagsAttribute]
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
}

Usage

void PreventSleep ()
{
// Prevent Idle-to-Sleep (monitor not affected) (see note above)
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_AWAYMODE_REQUIRED);
}

UPDATE 02/08/2021:

In case anyone is looking for a complete example, here is a project I found on github that has implemented this: https://github.com/pedrolcl/screensaver-disabler

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

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

Interrupt (NOT prevent from starting) screensaver

The Windows operating system has a hierarchy of objects. At the top of the hierarchy is the "Window Station". Just below that is the "Desktop" (not to be confused with the desktop folder, or even the desktop window showing the icons of that folder). You can read more about this concept in the documentation.

I mention this because ordinarily only one Desktop can receive and process user input at any given time. And, when a screen saver is activated by Windows due to a timeout, Windows creates a new Desktop to run the screen saver.

This means any application associated with any other Desktop, including your Python script, will be unable to send input to the new Desktop without some extra work. The nature of that work depends on a few factors. Assuming the simplest case, a screen saver that's created without the "On resume, display logon screen", and no other Window Station has been created by a remote connection or local user login, then you can ask Windows for the active Desktop, attach the Python script to that Desktop, move the mouse, and revert back to the previous Desktop so the rest of the script works as expected.

Thankfully, the code to do this is easier than the explanation:

import win32con, win32api, win32service
import random
# Get a handle to the current active Desktop
hdesk = win32service.OpenInputDesktop(0, False, win32con.MAXIMUM_ALLOWED);
# Get a handle to the Desktop this process is associated with
hdeskOld = win32service.GetThreadDesktop(win32api.GetCurrentThreadId())
# Set this process to handle messages and input on the active Desktop
hdesk.SetThreadDesktop()
# Move the mouse some random amount, most Screen Savers will react to this,
# close the window, which in turn causes Windows to destroy this Desktop
# Also, move the mouse a few times to avoid the edge case of moving
# it randomly to the location it was already at.
for _ in range(4):
win32api.SetCursorPos((random.randint(0, 100), random.randint(0, 100)))
# Revert back to the old desktop association so the rest of this script works
hdeskOld.SetThreadDesktop()

However, if the screen saver is running on a separate Window Station because "On resume, display logon screen" is selected, or another user is connected either via the physical Console or has connected remotely, then connecting to and attaching to the active Desktop will require elevation of the Python script, and even then, depending on other factors, it may require special permissions.

And while this might help your specific case, I will add the the core issue in the general case is perhaps more properly defined as asking "how do I notify the user of the state of something, without the screen saver blocking that notification?". The answer to that question isn't "cause the screen saver to end", but rather "Use something like SetThreadExecutionState() with ES_DISPLAY_REQUIRED to keep the screen saver from running. And show a full-screen top-most window that shows the current status, and when you want to alert the user, flash an eye-catching graphic and/or play a sound to get their attention".

Here's what that looks like, using tkinter to show the window:

from datetime import datetime, timedelta
import ctypes
import tkinter as tk

# Constants for calling SetThreadExecutionState
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
ES_DISPLAY_REQUIRED= 0x00000002

# Example work, show nothing, but when the timer hits, "alert" the user
ALERT_AT = datetime.utcnow() + timedelta(minutes=2)

def timer(root):
# Called every second until we alert the user
# TODO: This is just alerting the user after a set time goes by,
# you could perform a custom check here, to see if the user
# should be alerted based off other conditions.
if datetime.utcnow() >= ALERT_AT:
# Just alert the user
root.configure(bg='red')
else:
# Nothing to do, check again in a bit
root.after(1000, timer, root)

# Create a full screen window
root = tk.Tk()
# Simple way to dismiss the window
root.bind("<Escape>", lambda e: e.widget.destroy())
root.wm_attributes("-fullscreen", 1)
root.wm_attributes("-topmost", 1)
root.configure(bg='black')
root.config(cursor="none")
root.after(1000, timer, root)
# Disable the screen saver while the main window is shown
ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED)
root.mainloop()
# All done, let the screen saver run again
ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS)

While more work, doing this will solve issues around the secure desktop with "On resume, display logon screen" set, and also prevent the system from going to sleep if it's configured to do so. It just generally allows the application to more clearly communicate its intention.

Disabling Screen Saver and Power Options in C#

Not sure if there is a better .NET solution but here is how you could use that API:

The required usings:

using System.Runtime.InteropServices;

The P/Invoke:

public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_SYSTEM_REQUIRED = 0x00000001;
public const uint ES_DISPLAY_REQUIRED = 0x00000002;

[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint SetThreadExecutionState([In] uint esFlags);

And then disable screensaver by:

SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);

Finnaly enable screensaver by reseting the execution state back to original value:

SetThreadExecutionState(ES_CONTINUOUS);

Note that I just picked one of the flags at random in my example. You'd need to combine the correct flags to get the specific behavior you desire. You will find the description of flags on MSDN.



Related Topics



Leave a reply



Submit