Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Single-Instance C# Application - for .NET 2.0

0.00/5 (No votes)
30 Jan 2006 7  
A quick and easy guide to creating a single-instance application in C#, with .NET 2.0.

Introduction

A single-instance application is one that allows the user to open only one instance at a time. Strictly speaking, a second instance is started, but it detects the presence of the first instance, and shuts itself down.

Visual Studio 2005 makes single-instance applications very easy. In VB, one simply checks a box on the project settings dialog, and then handles the appropriate events. The code that accomplishes this is in the Microsoft.VisualBasic namespace, but it can be used in a C# application. This article will show you how to do this, and show how to transfer command-line arguments from the second instance to the original one.

Background

Single-instance applications have been around even before .NET, and were accomplished in various ways. The key is the communication between instances. In .NET, this is typically done with remoting; the framework classes used here take this approach. Before .NET 2.0, you were on your own with single-instance apps. One excellent description is this code project article by Detlef Grohs. If you're stuck in .NET 1.1, or just interested in what's going on "under the hood", then that's a great place to start.

Using the code

The source code for this article consists of two files: a main Windows Form named (appropriately) MainForm, and a Main.cs, which holds the entry point function Main(), and the application class App.

If starting from a blank C# Windows project, the first step is to add a reference to the Microsoft.VisualBasic assembly. Right click on references in the Solution Explorer, choose "add reference", and scroll down in the .NET tab to "Microsoft.VisualBasic".

The Main() function creates an instance of the App class, and runs it, passing the command-line arguments:

static void Main(string[] args)
{
    App myApp = new App();
    myApp.Run(args);
}

App is derived from Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase, which contains all of the remoting code necessary to check for an existing instance of the application. This functionality just needs to be turned on in the constructor:

public App()
{
  // Make this a single-instance application

  this.IsSingleInstance = true; 
  this.EnableVisualStyles = true;
    
  // There are some other things available in 

  // the VB application model, for

  // instance the shutdown style:

  this.ShutdownStyle = 
    Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses;

  // Add StartupNextInstance handler

  this.StartupNextInstance += 
    new StartupNextInstanceEventHandler(this.SIApp_StartupNextInstance);
}

The last line of the constructor adds a handler for the StartupNextInstance event, which is fired if an existing instance is detected. It is used here to transfer command-line arguments, but if those aren't needed, then the event doesn't need to be handled.

The next thing to do is override the OnCreateMainForm() method. This is called only for the first instance of the application. An instance of the MainForm class is created, and saved to a property of WindowsFormsApplicationBase.

Command-line parameters are passed to the form by copying the ReadonlyCollection to a string array, and saving to a member variable of the form:

protected override void OnCreateMainForm()
{
    // Create an instance of the main form 

    // and set it in the application; 

    // but don't try to run() it.

    this.MainForm = new MainForm();

    // We want to pass along the command-line arguments to 

    // this first instance


    // Allocate room in our string array

    ((MainForm)this.MainForm).Args = 
          new string[this.CommandLineArgs.Count];
    
    // And copy the arguments over to our form

    this.CommandLineArgs.CopyTo(((MainForm)this.MainForm).Args, 0);
}

Additional instances of the application may want to pass command-line arguments to the first; for instance, a file viewer may want to open a new document window when a second file is opened, rather than a new instance of the application. This is done in the StartupNextInstance handler:

protected void SIApp_StartupNextInstance(object sender, 
    StartupNextInstanceEventArgs eventArgs)
{
    // Copy the arguments to a string array

    string[] args = new string[eventArgs.CommandLine.Count];
    eventArgs.CommandLine.CopyTo(args, 0);

    // Create an argument array for the Invoke method

    object[] parameters = new object[2];
    parameters[0] = this.MainForm;
    parameters[1] = args;

    // Need to use invoke to b/c this is being called 

    // from another thread.

    this.MainForm.Invoke(new MainForm.ProcessParametersDelegate(
        ((MainForm)this.MainForm).ProcessParameters), parameters );
}

The new instance is of course on a different thread, so delegates and the Invoke function are used. The MainForm.ProcessParameters method just adds the arguments to a textbox on the form.

Points of interest

My particular need for single-instance functionality is opening groups of files from the context menu in the explorer. This fires off multiple instances of the application at essentially the same time. The remoting communication and loading of additional instances require a lot of overhead; on my system, this demo application opens about five files per second.

At about 50 files, an exception is thrown; it appears that the remoting connection to the initial instance is timing out. I'll be on the lookout for a bombproof (and faster) method of implementing a single-instance application in C# - write an article for us if you know a better way!

History

  • 2006-01-30 - Initial release.

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