Click here to Skip to main content
15,889,034 members
Articles / Multimedia / GDI+
Article

How to develop a screen saver in C#

Rate me:
Please Sign up or sign in to vote.
4.59/5 (84 votes)
12 Nov 20046 min read 400.7K   6.9K   207   89
An article explaining how to develop a screensaver in C#, with a ready-to-code-screensaver source.

Issues covered

This article explains:

  • the basics of a screensaver
  • loading a screensaver
  • filling the whole screen
  • handling multiple monitors
  • handling events
  • some little intricacies

Additionally, the code provides a basic screensaver framework which you could use easily to create screensavers on your own.

Introduction

A screensaver in Windows® is simply an executable file with the extension .scr. The only difference between a normal executable and a screensaver is that a screensaver does some specific things, viz:

  • parses the command line to find out what Windows® wants it to do
  • loads the screensaver appropriate to that request
  • ends the screensaver (usually), when the user uses the mouse or the keyboard

The arguments Windows® passes to a screensaver are:

  • /s - load the screensaver
  • /c - load the configuration screen
  • /p - load the preview

Once we determine the argument passed, we load the screensaver appropriately. When there is some kind of activity, you end the screensaver or do something else.

The code explained

Step 1: Making the Main method accept command-line arguments

The first step in developing a screensaver in C# is to modify the Main method so that it could accept command-line arguments. The default Main method is like this:

C#
static void Main() 
{
  ...
}

As you can see, this Main method accepts no parameters. So, we add a string array parameter like this:

C#
static void Main(string[] args) 
{
  ...
}

Step 2: Checking the arguments

Now we need to find out what arguments were passed.

First, we check whether Windows did pass some arguments, by checking whether the length of the string array is zero or not. If it's zero, there were no arguments. A typical scenario where no arguments are passed to a screensaver is when users just double click on your screensaver file.

Secondly, if there indeed were arguments, we catch them. Windows may pass arguments in either the lower case or the upper case. So it's a good idea to induce generalization of some sort. We do this by changing the arguments to lower case (or upper case) first and then checking them. The complete Main method would look something like:

C#
static void Main(string[] args) 
{
  if (args.Length > 0)
  {
    // load the config stuff
    if (args[0].ToLower().Trim().Substring(0,2) == "/c") 
    {
      ...
    }
    else if (args[0].ToLower() == "/s") // load the screensaver
    {
      ...
    }
    else if (args[0].ToLower() == "/p") // load the preview
    {
      ...
    }
  }
  else // there are no arguments...nevertheless, do something!
  {
    ...
  }
}

Quite straight forward, isn't it? The only code you need to add here is what you would like to do for each argument.

Step 3: Invoking the screensaver

To run the screensaver, you call the System.Windows.Forms.Application.Run method. You pass a new form object as the argument. The code will look like:

C#
System.Windows.Forms.Application.Run(new frmScreenSaver());

where frmScreenSaver is the main screensaver form.

When the screensaver loads, we want it to fit the entire screen. For this, we need to figure out which screen our screensaver is running in right now and its dimensions. To access screens, we use the Screen class. Using the PrimaryScreen property of this class, we could access the primary screen of the system as well as its properties. Among those properties is Bounds, representing the size of the screen. What we do is set the form's Bounds property to that of this screen so that the form would be resized to occupy the entire screen. This procedure is usually executed in the form's Load event, for example:

C#
private void frmScreenSaver_Load(object sender, System.EventArgs e)
{
  ...
  Bounds = Screen.PrimaryScreen.Bounds;
  ...
}

We need to address one possibility though - the user may be using more than one screen. If that's true, and if we load the screensaver only on one screen, the whole point of using this screensaver is lost. Hence, we find out the number of screens available, and load the screensaver in each of them. To do this, we iterate through all the available screens in the Main method, where we repeatedly call the form's constructor passing the screen's index. The set of all screens available in the system is listed in the AllScreens property of the Screen class. Thus the code in the Main method invoking the screensaver will have to be modified as:

C#
...
...
for (int i = Screen.AllScreens.GetLowerBound(0); 
     i <= Screen.AllScreens.GetUpperBound(0); i++)
  System.Windows.Forms.Application.Run(new frmScreenSaver(i));
...
...

Note the change in the main screensaver form's constructor - it accepts an int parameter, which represents the screen's index onto which the screensaver is to be run. In response to this, we modify the form's class by adding an int member variable which will store the screen index. The form's constructor will then be modified to initialize this variable, like this:

C#
public frmScreenSaver(int scrn)
{
  ...
  ScreenNumber = scrn;
  ...
}

where ScreenNumber is the int member variable.

After this, the Load event handler will have to be modified to resize the form to the bounds of not the primary screen, but that of the screen represented by the index, like this:

C#
private void frmScreenSaver_Load(object sender, System.EventArgs e)
{
  ...
  Bounds = Screen.AllScreens[ScreenNumber].Bounds;
  ...
}

Once this is done, we have added multiple screen display functionality to our screensaver.

You will want to make the form topmost and hide the cursor. Just call the additional methods in the Load handler like this:

C#
private void frmScreenSaver_Load(object sender, System.EventArgs e)
{
  ...
  Bounds = Screen.AllScreens[ScreenNumber].Bounds;
    Cursor.Hide();
    TopMost = true;
  ...
}

Step 4: Handling events

Once you have loaded your screensaver, you have to handle events. This is because when the user uses the mouse or hits the keyboard, you probably want to do something, like ending the screensaver. To do this, you add event handlers to the KeyDown, MouseMove and MoveDown events of the screensaver form. In the event handlers, you could use the form's Close method to end the screensaver.

There is one point to note here. When an application is executed, the current mouse parameters are passed to it by Windows. This naturally triggers a mouse event, which would close the screensaver. To handle this, add a Point variable in the class, initialize it when the application executes, and check the mouse position and mouse clicks when mouse events occur. If there happens to be any change, then call Close. The code would look something like:

C#
private void OnMouseMove(object sender, 
                         System.Windows.Forms.MouseEventArgs e)
{
  if (!MouseXY.IsEmpty)
  {
    if (MouseXY != new Point(e.X, e.Y))
       Close();
  }
  MouseXY = new Point(e.X, e.Y);
}

where MouseXY is the Point variable we use to store the initial mouse position temporarily. Initially, MouseXY is null; and thus is assigned the current mouse position through this code. In the next call of this event handler, MouseXY is not empty; so we check whether the position has changed; if yes, close the form.

As mentioned earlier, you should handle both MouseMove and MouseDown events in a screensaver. But since both have the same arguments, you could use the same event handler for handling both events. Such a code would look like:

C#
private void OnMouseEvent(object sender, 
                          System.Windows.Forms.MouseEventArgs e)
{
  if (!MouseXY.IsEmpty)
  {
    if (MouseXY != new Point(e.X, e.Y))
      Close();
    if (e.Clicks > 0)
        Close();
  }
  MouseXY = new Point(e.X, e.Y);
}

where OnMouseEvent is the event handler which is called on mouse move as well as mouse down events.

Step 5: Finally...

The last step of developing a screensaver is short and sweet...rename the file to an .scr extension. :)

You are done!

Using the bundled code

The code provided just loads a black form. To change it and implement your own features, follow these simple steps:

  1. Change the code in the Main method to handle different arguments
  2. Add a configuration form if necessary, and add the code to load it in the Main method
  3. Modify the main screensaver form so as to display what you want it to
  4. Rename the extension from .exe to .scr.
  5. Go!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
Rakesh Rajan is a Software Engineer from India working at Technopark, Trivandrum in Kerala. He is a Microsoft MVP and an MCSD (.NET) with a few other certifications, and had been working in .NET for the past 3 years. He graduated majoring in Computer Science during his memorable days at Ooty (a wonderful hill station in Southern India). You can find him posting at newgroups, writing articles, working on his own projects or taking some time off by listening to music by Enya or Yanni, or reading an Archer or Sheldon.

Find his online publications here.

Rakesh blogs at http://rakeshrajan.com/blog/ and maintains a site http://rakeshrajan.com/.
He used to blog at http://www.msmvps.com/rakeshrajan/.

Drop him a mail at rakeshrajan {at} mvps {dot} org.

Comments and Discussions

 
QuestionRuns OK, but ... Pin
Gluups19-Apr-24 11:41
Gluups19-Apr-24 11:41 
AnswerRe: Runs OK, but ... Pin
Gluups19-Apr-24 12:07
Gluups19-Apr-24 12:07 
Questionnot existing in current context Pin
Member 1455580410-Aug-19 2:15
Member 1455580410-Aug-19 2:15 
AnswerRe: not existing in current context Pin
Gluups19-Apr-24 11:43
Gluups19-Apr-24 11:43 
GeneralMy vote of 1 Pin
Deja29-Jun-09 8:12
Deja29-Jun-09 8:12 
Generalbanks screen saver Pin
WalterThizo1-Oct-08 0:12
WalterThizo1-Oct-08 0:12 
GeneralRe: banks screen saver Pin
Gluups19-Apr-24 12:35
Gluups19-Apr-24 12:35 
GeneralThe article is not sufficient [modified] Pin
User 25755224-Sep-06 0:33
User 25755224-Sep-06 0:33 
QuestionRe: The article is not sufficient Pin
Mika24-Apr-07 0:29
Mika24-Apr-07 0:29 
AnswerRe: The article is not sufficient Pin
PHenry22-May-07 6:54
PHenry22-May-07 6:54 
GeneralRe: The article is not sufficient Pin
kesterd27-May-08 10:25
kesterd27-May-08 10:25 
QuestionAny way to detect scn svr running? Pin
tomsmaily12325-Aug-06 5:21
tomsmaily12325-Aug-06 5:21 
AnswerRe: Any way to detect scn svr running? Pin
Gluups19-Apr-24 12:37
Gluups19-Apr-24 12:37 
GeneralI want to add screensaver into display properties windows Pin
DungVinh18-Aug-06 16:46
DungVinh18-Aug-06 16:46 
GeneralRe: I want to add screensaver into display properties windows Pin
User 25755224-Sep-06 0:36
User 25755224-Sep-06 0:36 
GeneralThanks, BTW Pin
Ennis Ray Lynch, Jr.2-Aug-06 5:02
Ennis Ray Lynch, Jr.2-Aug-06 5:02 
GeneralRe: Thanks, BTW Pin
Gluups19-Apr-24 12:39
Gluups19-Apr-24 12:39 
QuestionMouseEvent [modified] Pin
TheEagle25-May-06 20:47
TheEagle25-May-06 20:47 
QuestionMouseEvent Pin
TheEagle29-Apr-06 4:54
TheEagle29-Apr-06 4:54 
QuestionHow to update screen? Pin
bekiser22-Feb-06 4:40
bekiser22-Feb-06 4:40 
AnswerRe: How to update screen? Pin
Gluups19-Apr-24 11:32
Gluups19-Apr-24 11:32 
GeneralDeployment Pin
ivan 4512-Dec-05 3:36
ivan 4512-Dec-05 3:36 
GeneralRe: Deployment Pin
Rakesh Rajan12-Dec-05 16:45
Rakesh Rajan12-Dec-05 16:45 
Generalfire Screensaver event c#.net Pin
sweety782-Aug-05 23:59
sweety782-Aug-05 23:59 
GeneralSolved the multi-monitor issue. Pin
Garry Freemyer11-Jun-05 21:45
Garry Freemyer11-Jun-05 21:45 
We all know the one, where one monitor hogs all the CPU cycles to the expense of the other monitor.

Here is a copy of my post I emailed incase email get bounced. I that to do a lot of work typing a help article only to discover that it bounced in email ....

http://www.codeproject.com/useritems/SwarmScreenSaver.asp

Feel tree to check out the article in the post above.

Basically, the issue involves a few mods ...

1. As normal, put the drawing routines or those that call your drawing class in the paint event or override the onpaint method of the saverform.

2. Create an array of your form objects, one form per screen.

3. Then call the show method on each form, this much you know about and here is where things begin to differ ...

4. Using Invalidate() method of the form, works fine for the primary screen, but fails to work for the secondary screen.

5. Instead, use the Refresh() method of the forms. This works an all the forms and invokes the paint object, so that you will see drawing activity on all monitors (Well at least two since most cards only support two outputs).

Feel free to download the code, I believe Iv'e given you credit where credit is due, for your screensaver template was quite helpful in solving the issues involved.

The project is written in C#, VS 2003, and includes source code only.

I wanted to let you know so you too will be able to create a multi-monitor screensaver. This particular program is capable of executing an array of up to 100 instances of my drawing program, though I think you would need a supercomputer that does not exist to run it.

It uses XML to save the configs, the xml is self-recovering and so as it tries to read the config, it detects missing config or corrupted config or out of dated config files and replaces them with a new default value one.

All functions are enabled except the welcome screen for reason I explain in the article, not wanting to lock some poor soul out of their system due to a but in the OS or my program.

I hope it is of great help to you. Before I sign off, I'm going to give you credit in a reply. I am pretty sure I've given you credit, but being a ditz as I am, I might have erased a few references.

I hope you enjoy the program and thanks for your post.

Oh, I almost FORGOT the most important thing!! After calling Refresh for multiple screens or Invalidate in the case of a single monitor system, the EntryPoint's Main method must call Application.DoEvents() to get the graphics to display.

Thanks again, let me know how you like it.
[^]

Been there, done that, forgot why!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.