Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C#
Article

Single-Instance C# Application - for .NET 2.0

Rate me:
Please Sign up or sign in to vote.
4.73/5 (25 votes)
30 Jan 2006CPOL3 min read 221.6K   3.7K   91   32
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:

C#
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:

C#
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:

C#
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:

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Jim is a developer working in Auburn, Alabama, USA. He started working as a programmer in 1997; much of his early experience was with MFC and ASP, with brief forays into Java servlets, Borland's OWL, and plain-old windows API.

Since 2001 Jim has worked primarily with .NET, writing windows and web applications, windows services, and client-server apps. With a little bit of AS3/Flex code thrown in there.

Jim comments code in the first person (much to the amusement of his coworkers,) and feels especially weird writing about himself in the third.

Comments and Discussions

 
GeneralMy vote of 5 Pin
CaaSiOn5-Aug-13 23:57
CaaSiOn5-Aug-13 23:57 
GeneralMy vote of 5 Pin
Galina Zaytseva21-Sep-11 0:22
Galina Zaytseva21-Sep-11 0:22 
BugGetting the time stamp to appear Pin
astuart29-Jun-11 14:05
astuart29-Jun-11 14:05 
GeneralWorks unless app is in system tray! Pin
I_Need_Help3-Aug-10 10:24
I_Need_Help3-Aug-10 10:24 
GeneralMy Solution for Single Instance Application Pin
Member 293394818-Feb-10 23:08
Member 293394818-Feb-10 23:08 
GeneralA small mistake in the article's code Pin
emunews21-Dec-09 8:33
emunews21-Dec-09 8:33 
GeneralYou Are The One Thanks Its Solve My Media Player Problem Pin
asadkhanno13-Nov-09 18:38
asadkhanno13-Nov-09 18:38 
GeneralMy vote of 1 Pin
Paresh Gheewala9-Dec-08 18:44
Paresh Gheewala9-Dec-08 18:44 
GeneralGreat Article!! Pin
Richard Blythe18-Aug-08 19:26
Richard Blythe18-Aug-08 19:26 
GeneralWow it worked great! Pin
JoanComasFdz17-Apr-08 2:03
JoanComasFdz17-Apr-08 2:03 
QuestionHelp required Pin
Nouman Bhatti10-Apr-08 2:54
Nouman Bhatti10-Apr-08 2:54 
GeneralRe: Help required Pin
Jim Rogers10-Apr-08 16:07
Jim Rogers10-Apr-08 16:07 
Questionhow to do in .net 1.1? Pin
OwfAdmin7-Aug-07 2:57
OwfAdmin7-Aug-07 2:57 
AnswerRe: how to do in .net 1.1? Pin
Jim Rogers7-Aug-07 5:02
Jim Rogers7-Aug-07 5:02 
GeneralThanks Man! Pin
CodeProjectAdmirer31-May-07 10:44
CodeProjectAdmirer31-May-07 10:44 
GeneralProblem solved by your article Pin
Nouman Bhatti6-May-07 20:12
Nouman Bhatti6-May-07 20:12 
GeneralMicrosoft.VisualBasic Pin
TheCardinal18-Jun-06 18:38
TheCardinal18-Jun-06 18:38 
GeneralGetting exception Pin
loui3118-Feb-06 23:41
loui3118-Feb-06 23:41 
GeneralRe: Getting exception Pin
Jim Rogers19-Feb-06 3:09
Jim Rogers19-Feb-06 3:09 
GeneralRe: Getting exception Pin
loui3121-Feb-06 18:58
loui3121-Feb-06 18:58 
GeneralRe: Getting exception Pin
Steve Barnett7-Aug-06 3:30
Steve Barnett7-Aug-06 3:30 
GeneralRe: Getting exception Pin
jiva28-Feb-07 3:57
jiva28-Feb-07 3:57 
http://support.microsoft.com/?scid=kb%3Ben-us%3B832742&x=11&y=14 How to deploy a .NET Framework application to run from a network location
but I can not find it in .net 2.0

who can help me?
I need call it from web,thxs!
GeneralRe: Getting exception Pin
nuwanda6-Apr-06 11:26
nuwanda6-Apr-06 11:26 
GeneralThis is how I do it... Pin
Alexander Kojevnikov31-Jan-06 19:05
Alexander Kojevnikov31-Jan-06 19:05 
GeneralRe: This is how I do it... Pin
Jim Rogers1-Feb-06 2:28
Jim Rogers1-Feb-06 2:28 

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.