Disabling Screen Saver and Power Options in C#

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.

Need to disable the screen saver / screen locking in Windows C#/.Net

theoldnewthing has your answer: Use SetThreadExecutionState(ES_DISPLAY_REQUIRED).

This is used by video players and PowerPoint.

Use NativeWindow to disable screensaver

The proper way to do this is by telling Windows that your thread needs to have the display active. Commonly used by video players. P/Invoke the SetThreadExecutionState() API function, pass ES_DISPLAY_REQUIRED. And ES_SYSTEM_REQUIRED to keep the machine from shutting down automatically. Visit pinvoke.net for the required declarations.

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

Turn Display On and Kill Screensaver

The following code will:

  • interrupt a running screensaver
  • turn on a turned-off screen ("turn off" as mentioned in power options)
private static readonly ILog Log = LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);

public void TurnOnScreenAndInterruptScreensaver()
{
TryTurnOnScreenAndResetDisplayIdleTimer();

TryInterruptScreensaver();
}

/// <summary>
/// Moves the mouse which turns on a turned-off screen and also resets the
/// display idle timer, which is key, because otherwise the
/// screen would be turned off again immediately.
/// </summary>
private static void TryTurnOnScreenAndResetDisplayIdleTimer()
{
var input = new SendInputNativeMethods.Input {
type = SendInputNativeMethods.SendInputEventType.InputMouse, };
try
{
SendInputNativeMethods.SendInput(input);
}
catch (Win32Exception exception)
{
Log.Error("Could not send mouse move input to turn on display", exception);
}
}

private static void TryInterruptScreensaver()
{
try
{
if (ScreensaverNativeMethods.GetScreenSaverRunning())
{
ScreensaverNativeMethods.KillScreenSaver();
}

// activate screen saver again so that after idle-"timeout" it shows again
ScreensaverNativeMethods.ActivateScreensaver();
}
catch (Win32Exception exception)
{
Log.Error("Screensaver could not be deactivated", exception);
}
}

SendInputNativeMethods:

public static class SendInputNativeMethods
{
public static void SendInput(params Input[] inputs)
{
if (SendInput((uint)inputs.Length, inputs, Marshal.SizeOf<Input>())
!= (uint)inputs.Length)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern uint SendInput(
uint nInputs,
[MarshalAs(UnmanagedType.LPArray), In] Input[] pInputs,
int cbSize);

[StructLayout(LayoutKind.Sequential)]
public struct Input
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}

[StructLayout(LayoutKind.Explicit)]
public struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;

[FieldOffset(0)]
public KEYBDINPUT ki;

[FieldOffset(0)]
public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
public struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
public enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
public enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}

ScreensaverNativeMethods:

internal static class ScreensaverNativeMethods
{
private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
private const int SPI_SETSCREENSAVEACTIVE = 0x0011;
private const int SPIF_SENDWININICHANGE = 0x0002;
private const uint DESKTOP_WRITEOBJECTS = 0x0080;
private const uint DESKTOP_READOBJECTS = 0x0001;
private const int WM_CLOSE = 0x0010;
private const int TRUE = 1;

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
ref IntPtr pvParam,
uint fWinIni);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool PostMessage(
IntPtr hWnd,
uint msg,
IntPtr wParam,
IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr OpenDesktop(
string lpszDesktop,
uint dwFlags,
[In, MarshalAs(UnmanagedType.Bool)]bool fInherit,
uint dwDesiredAccess);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseDesktop(IntPtr hDesktop);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumDesktopWindows(
IntPtr hDesktop,
EnumDesktopWindowsProc callback,
IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetForegroundWindow();

private delegate bool EnumDesktopWindowsProc(IntPtr hDesktop, IntPtr lParam);

public static bool GetScreenSaverRunning()
{
IntPtr isRunning = IntPtr.Zero;

if (!SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}

return isRunning != IntPtr.Zero;
}

public static void ActivateScreensaver()
{
SetScreenSaverActive(TRUE);
}

private static void SetScreenSaverActive(uint active)
{
IntPtr nullVar = IntPtr.Zero;

// Ignoring error since ERROR_OPERATION_IN_PROGRESS is expected.
// Methode is called to reset timer and to prevent possible errors
// as mentioned in Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
SystemParametersInfo(
SPI_SETSCREENSAVEACTIVE,
active,
ref nullVar,
SPIF_SENDWININICHANGE);
}

// From Microsoft's Knowledge Base article #140723:
// http://support.microsoft.com/kb/140723
// "How to force a screen saver to close once started
// in Windows NT, Windows 2000, and Windows Server 2003"
public static void KillScreenSaver()
{
IntPtr hDesktop = OpenDesktop(
"Screen-saver",
0,
false,
DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
if (hDesktop != IntPtr.Zero)
{
if (!EnumDesktopWindows(hDesktop, KillScreenSaverFunc, IntPtr.Zero)
|| !CloseDesktop(hDesktop))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
TerminateWindow(GetForegroundWindow());
}
}

private static bool KillScreenSaverFunc(IntPtr hWnd, IntPtr lParam)
{
if (IsWindowVisible(hWnd))
{
TerminateWindow(hWnd);
}

return true;
}

private static void TerminateWindow(IntPtr hWnd)
{
if (!PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}

How do I turn off the windows screen saver if it is running using C#?

The easiest way is to fake a mouse move event with x=y=0 by calling SendInput().



Related Topics



Leave a reply



Submit