Click here to Skip to main content
Click here to Skip to main content

Single-Instance C# Application - for .NET 2.0

By , 30 Jan 2006
Rate this:
Please Sign up or sign in to vote.

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

About the Author

Jim Rogers
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 PinmemberCaaSiOn5-Aug-13 23:57 
GeneralMy vote of 5 PinmemberGalina Zaytseva21-Sep-11 0:22 
BugGetting the time stamp to appear Pinmemberastuart29-Jun-11 14:05 
GeneralWorks unless app is in system tray! PinmemberI_Need_Help3-Aug-10 10:24 
GeneralMy Solution for Single Instance Application PinmemberMember 293394818-Feb-10 23:08 
GeneralA small mistake in the article's code Pinmemberemunews21-Dec-09 8:33 
GeneralYou Are The One Thanks Its Solve My Media Player Problem Pinmemberasadkhanno13-Nov-09 18:38 
GeneralMy vote of 1 PinmemberParesh Gheewala9-Dec-08 18:44 
GeneralGreat Article!! PinmemberRichard Blythe18-Aug-08 19:26 
GeneralWow it worked great! Pinmemberk^s17-Apr-08 2:03 
QuestionHelp required PinmemberNouman Bhatti10-Apr-08 2:54 
GeneralRe: Help required PinmemberJim Rogers10-Apr-08 16:07 
Questionhow to do in .net 1.1? PinmemberOwfAdmin7-Aug-07 2:57 
AnswerRe: how to do in .net 1.1? PinmemberJim Rogers7-Aug-07 5:02 
GeneralThanks Man! PinmemberCodeProjectAdmirer31-May-07 10:44 
GeneralProblem solved by your article PinmemberNouman Bhatti6-May-07 20:12 
GeneralMicrosoft.VisualBasic PinmemberTheCardinal18-Jun-06 18:38 
GeneralGetting exception Pinmemberloui3118-Feb-06 23:41 
GeneralRe: Getting exception PinmemberJim Rogers19-Feb-06 3:09 
GeneralRe: Getting exception Pinmemberloui3121-Feb-06 18:58 
GeneralRe: Getting exception PinmemberSteve Barnett7-Aug-06 3:30 
GeneralRe: Getting exception Pinmemberjiva28-Feb-07 3:57 
GeneralRe: Getting exception Pinmembernuwanda6-Apr-06 11:26 
GeneralThis is how I do it... PinmemberAlexander Kojevnikov31-Jan-06 19:05 
GeneralRe: This is how I do it... PinmemberJim Rogers1-Feb-06 2:28 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 30 Jan 2006
Article Copyright 2006 by Jim Rogers
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid