How to make a screen saver in C#, one very similar to the Windows XP screen saver. Tutorial and source code.
Making a screen saver in C# is rather simple, but only if you know the ‘secret’.
When Windows loads the screen saver it actually passes an argument – ‘/s’. Also, you know from Display Properties in Windows that some screen savers have settings you can set. When Windows wants to access this settings it passes another argument – ‘/c’. Also in Display Properties there is a small picture representing a display where the user can view a preview of the screen saver – the preview is called using the argument ‘/p’.
Any screen saver is actually an executable (.exe) file with the extension changed to .scr. If you let the extension unchanged after you compile the program and you execute the .exe file, the screen saver will still work of course, but if you add it to the System32 folder in your Windows directory, the screen saver won’t appear in the list at Display Properties. After changing the extension to .scr Windows will add the screen saver to the list.
Also, when you execute the screen saver while it has the .exe extension, windows won’t pass the ‘/s’ argument, the argument is passed only when the file is a .scr file.
You can see that in the first lines of the program we check for passed arguments. First it checks if Windows passes any arguments at all, because as I said earlier if the application is started as an .exe file no arguments are passed. As you can see from the code, even if no arguments are passed we still want the screen saver to start.
Start a new Windows Application project named ‘scrSaver’. To the project add a new class named ‘scrClass’. Use the following code in the new class:
using System;
using System.Windows.Forms;
namespace scrSaver
{
public class scrClass
{
[STAThread]
static void Main(string[] args)
{
     // If Windows passes arguments...
     if (args.Length > 0)
     {
     // If argument is /c...
          if (args[0].ToLower().Trim().Substring(0,2) == "/c")
          {
          // Add code here if you want your screen saver to have settings
          }
          // If argument is /s...
          else if (args[0].ToLower() == "/s")
          {
               // Start the screen saver on all the displays the computer has
               for (int x = Screen.AllScreens.GetLowerBound(0); x <= Screen.AllScreens.GetUpperBound(0); x++)
               {
               // Pass the number of the display to Form1()
               System.Windows.Forms.Application.Run(new Form1(x));
               }
          }
     }
     // If there are no arguments just start the screen saver
     else
     {
          // Start the screen saver on all the displays the computer has
          for (int x = Screen.AllScreens.GetLowerBound(0); x <= Screen.AllScreens.GetUpperBound(0); x++)
          {
          // Pass the number of the display to Form1()
          System.Windows.Forms.Application.Run(new Form1(x));
          }
     }
}
}
}
The screen saver is actually a form. So let’s open it in Design mode and add a PictureBox to it named ‘pictureBox1’. Set the BackColor property of the PictureBox to any color you wish. Now also change the BackColor property of the form to black, the ShowInTaskbar property to False and the FormBorderStyle property to None. The form should look similar to this one now:
Now it’s time to add a timer to our form for the animation to work. So add a timer named timer1 and set the Enabled property to True and the Interval property to 7000 (7 seconds).
Let’s get into the code of Form1.cs now.
This is the code we use in Form1 class. So select all the code created by Visual Studio and delete it, then paste the code below, we will review it after.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace scrSaver
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;
// Store the mouse coordinates
private Point mouseCoords;
// Store the number of displays
private int displayNum;
// Random number that will change the position of the PictureBox
Random rand = new Random();
// Accept one argurment - the number of displays
public Form1(int display)
{
InitializeComponent();
// Assign the number to an accessible variable
displayNum = display;
}
protected override void Dispose( bool disposing )
{
    if( disposing )
    {
        if (components != null)
        {
        components.Dispose();
        }
    }
    base.Dispose( disposing );
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(192)), ((System.Byte)(0)), ((System.Byte)(0)));
this.pictureBox1.Location = new System.Drawing.Point(8, 8);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(80, 80);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 7000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.pictureBox1});
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form1";
this.ShowInTaskbar = false;
this.Text = "Form1";
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.Load += new System.EventHandler(this.Form1_Load);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
this.ResumeLayout(false);
}
#endregion
private void Form1_Load(object sender, System.EventArgs e)
{
    // Set the bounds of the form, fill all the screen
    this.Bounds = Screen.AllScreens[displayNum].Bounds;
    // The form should be on top of all
    TopMost = true;
    // We don't need the cursor
    Cursor.Hide();
}
private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
    // If mouseCoords is empty don't close the screen saver
    if(!mouseCoords.IsEmpty)
    {
        // If the mouse actually moved
        if(mouseCoords != new Point(e.X, e.Y))
        {
            // Close
            this.Close();
        }
    }
    // Set the new point where the mouse is
    mouseCoords = new Point(e.X, e.Y);
}
// If a key was pressed...
private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
    // ...close the screen saver
    this.Close();
}
// Every 7 seconds...
private void timer1_Tick(object sender, System.EventArgs e)
{
    // set the new X position of the PictureBox to random number
    int newX = rand.Next(0, (this.Size.Width - pictureBox1.Size.Width));
    // set the new Y position of the PictureBox to random number
    int newY = rand.Next(0, (this.Size.Height - pictureBox1.Size.Height));
    // and actually move the PictureBox to the new position
    pictureBox1.Location = new Point(newX, newY);
}
}
}
From the above code let’s first review the following piece:
private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
    // If mouseCoords is empty don't close the screen saver
    if(!mouseCoords.IsEmpty)
    {
        // If the mouse actually moved
        if(mouseCoords != new Point(e.X, e.Y))
        {
            // Close
            this.Close();
        }
    }
    // Set the new point where the mouse is
    mouseCoords = new Point(e.X, e.Y);
}
What happens here? You ask yourself. Sure, when the mouse moves we want the screen saver to exit – that makes sense – but that looks a bit complicated, a simple Close() should do it, you cry. Well, for this piece of code I’m indebted to Rakesh Rajan with his tutorial that you might also want to consider.
If you simply use Close(), when the screen saver starts it gets closed immediatly, that’s because the mouse coordinates are passed to the application immediatly and the event fires. The Point variable saves the day because it is used to check the changes in mouse coordinates, therefore not considering the mouse coordinates passed to our screen saver, because at that time the if conditions will return false.
A screen saver should usually be animated, that is actually the original purpose of a screen saver, to save your display from developing permanent etching of a pattern. This is why we change the position of the PictureBox every 7 seconds (using the timer) to a random place on the screen:
// Every 7 seconds...
private void timer1_Tick(object sender, System.EventArgs e)
{
    // set the new X position of the PictureBox to random number
    int newX = rand.Next(0, (this.Size.Width - pictureBox1.Size.Width));
    // set the new Y position of the PictureBox to random number
    int newY = rand.Next(0, (this.Size.Height - pictureBox1.Size.Height));
    // and actually move the PictureBox to the new position
    pictureBox1.Location = new Point(newX, newY);
}
We don’t want the PictureBox to go to some place not visible on the screen, so we generate a random number between 0 and the difference between the width of the form and the size of the PictureBox (because the position of the PictureBox is considered from the top – left corner of it). If you have no ideea what I’m talking about, check a tutorial about C# graphics and GDI.
What’s left for you to do? Insert an image into the PictureBox, compile the program, change the extension from .exe to .scr and copy it to your System32 directory where the other screen savers reside.
The transparent screen saver
Something pretty interesting is a transparent screen saver. Just set the opacity property of the form to 85% perhaps and check out the results.
Geekpedia screen saver
We have a screen saver with the Geekpedia logo using this source code.
There are two versions of this screen saver. The standard version:
And the transparent version:
(14.5 KB). Extract them to your System32 directory and open from Display Properties.
Good luck 😉