Introduction

Presented here is a C# class useful for monitoring and controlling the Windows screen saver.
The class provides methods for getting information about the screen saver, such as whether or
not it is active, it is running, and its time out setting. Additional methods are provided to
change these settings and to terminate the screen saver if it is running.

Background

Some things aren't always as straight forward as you might think going in. Such was the case
on a recent project where one of the requirements called for killing the screen saver on the occurrence
of a real time event. The project involved a radio dispatch console, and in this case the real time
event was a dispatch operator pressing the push-to-talk button on a radio handset. Also, the
screen saver time out needed to be reset if the screen saver wasn't actually running when the button
was pressed, similar to the action of a key press or mouse event.

The SystemParametersInfo API provided
by the user32.dll supports a set of functions for accessing screen saver settings, including getting
and setting activation, the time out value, and checking to see if the screen saver is running. However,
there doesn't seem to be a function for terminating the screen saver if it is running. The
SPI_SETSCREENSAVERRUNNING function oddly doesn't do the job as one might think, which instead
is suggested as an obscure technique to disable task switching
under Windows 95 and 98. Ultimately, the solution was found in another
knowledge base article discussing user32.dll functions which can be used to find the running screen
saver application and then force it to close. The main task now was to implement a class to call these unmanaged
functions using C#.

Using the code

To use the code, just copy the class ScreenSaver into your program and call the exposed methods, which for
the most part are just wrappers to the user32.dll functions:

The more interesting code here is the KillScreenSaver( ) method. Beginning with Microsoft Windows NT, you
cannot simply make a call to close the foreground window as you could under previous releases of Windows.
Windows NT introduces the concept of separate desktops. Applications can run on one desktop, and screen savers can run on
another. For example, under Windows XP, if you check the "On resume, display Welcome screen" option in the Screen Saver tab
of Display Properties, the screen saver will be running on a desktop other than the one for your application. In
this case, you need to find the screen saver desktop and close its foreground window to terminate the screen saver. If this
option is not checked, the screen saver is running on the same desktop as your application, and may be killed merely by
closing the foreground window in that desktop.

Another thing worth pointing out is in the KillScreenSaverFunc( ) callback function. Notice the call to
IsWindowVisible( hWnd ) just before closing what presumably is the screen saver window. Apparently it's possible
for the screen saver to be "running", yet not actually be seen as the foreground application on the desktop. As we'll see in
our Test Program, we need to keep this in mind for when the screen saver is running on the same desktop as our
application. Otherwise our application could end up being the one killed by the call to
PostMessage( GetForegroundWindow( ), WM_CLOSE, 0, 0 ), which might annoy the user.

The Test Program

The Screen Saver Test program demonstrates how to use the ScreenSaver class. It can also serve as a
convenient utility to edit the screen saver settings as you're testing your own application. Since it can modify the
screen saver values normally set with the Display Properties dialog, it saves off these values so
they may be restored on exit or manually using the Restore button. The form is set to be "TopMost" to make it easily
accessible when being used with full screen apps.

To change the screen saver timeout, enter the number of seconds in the NumericUpDown control on the right and click
the Write button. If the screen saver is "active", it should kick on that many seconds later. If any of the
settings are changed outside of the test program, for example by using the Display Properties dialog, click the Refresh
button to display the new values.

To facilitate testing the KillScreenSaver( ) method, the test program uses a periodic timer. The timeout
period can be set and the timer can be toggled using the Start/Stop Timer button. If the period is greater than the
screen saver timeout, a call to KillScreenSaver( ) will terminate the screen saver. If the period is less,
the screen saver timeout is reset by invoking SetScreenSaverActive( TRUE ), preventing the screen
saver from running until after a full timeout has expired.

As pointed out earlier, it's possible for the SPI_GETSCREENSAVERRUNNING call to return TRUE
before the screen saver actually becomes the foreground window. Perhaps this function should be renamed to SPI_GETSCREENSAVERSORTAKINDARUNNING. Anyways, make sure the foreground window isn't your own app before invoking
KillScreenSaver( ), otherwise it might get closed instead.

Share

About the Author

Kurt's programming career began in 1978, developing firmware for the Zilog Z80-A microprocessor on a Mostek development workstation. For 23 years, Kurt led the development of Human Machine Interface (HMI) programs used in factory automation, marketed and sold worldwide by CTC and Parker Hannifin as ScreenWare, Interact and InteractX. For the last 4 years, Kurt has been consulting on agile development practices and working as an independent software contractor focusing on graphical and user interface development.

Other passions include spending time with his wife Janice, daughters Erica and Laura, scuba diving, target shooting, guitar, travel, and digital photo imaging and restoration. Currently residing in southwestern Ohio.

Yes, this approach is suggested for preventing the Power Settings options from kicking on, possibly causing your display to blank, however it does not help control the screen saver which still must be done using the SystemParametersInfo calls. More specifically, this will not allow you to kill the screen saver once it has turned on. If you're interested in managing the Power Settings from code, here is a good reference. Thanks for pointing this out.

I just tried this method and it seems to work well. My only suggestion is to have GetScreenSaverFileName( ) return only the filename using Path.GetFilename( result ), as the full path is not used. Then KillProcessByName( GetScreenSaverFileName( ) ) is all that's needed. Thanks for the suggestion Kurt.

// Stops the screen saver by moving the cursor. Clean and simple, don't have to worry
// about reinitializing the screen saver, etc. Moves the cursor to a random position
// each time so you don't have to worry about calling it twice and having the cursor stay
// in the same spot.
SetCursorPos(new Random().Next(100), new Random().Next(100));