Enforcing single instance with argument passing

There are several implementations out there already for doing this, but for one reason or another they all did something I didn't like. Some use the registry, some can't pass parameters, some use P/Invoke, some use remoting and others use the VB libraries. Not quite high treason but even so, an all C# and very light implementation has got to be worth the effort.

The class that does all the work is, imaginatively, called SingleInstance. The single public constructor takes a Guid which is used to identify out application. Like some of the other examples out there I use a Mutex object to tell whether the application is already running or not.

mutex = new Mutex(true, identifier.ToString(), out ownsMutex);

The out parameter tells us whether we were able to create and own the Mutex or whether someone else (another instance of our app) already has. Given this, we have a simple property telling us if we're the first instance or not.

public Boolean IsFirstInstance

{ get { return ownsMutex; } }

The only piece left of the single instance puzzle is making sure that we release the mutex, if we happen to own it, and for this I implemented IDisposable and did the following in the dispose method:

if (mutex != null && ownsMutex)

{

    mutex.ReleaseMutex();

    mutex = null;

}

Couldn't be more simple, right? Next we need to handle passing any command line arguments onto the initial instance. For this I use the new NamedPipeClientStream and NamedPipeServerStream classes here is the client end:

using (NamedPipeClientStream client = new NamedPipeClientStream(identifier.ToString()))

using (StreamWriter writer = new StreamWriter(client))

{

    client.Connect(200);

 

    foreach (String argument in arguments)

        writer.WriteLine(argument);

}

On the server end it's pretty much just as simple, we read in all the arguments and the fire the ArgumentsReceived event which the class exposes.

using (NamedPipeServerStream server = new NamedPipeServerStream(identifier.ToString()))

using (StreamReader reader = new StreamReader(server))

{

    server.WaitForConnection();

 

    List<String> arguments = new List<String>();

    while (server.IsConnected)

        arguments.Add(reader.ReadLine());

 

    ThreadPool.QueueUserWorkItem(new WaitCallback(CallOnArgumentsReceived), arguments.ToArray());

}

Everything works really nicely, the only odd looking bit here is that we spawn a new thread to fire the event. I did this simply because I we need to create a new NamedPipeServerStream to handle any subsequent clients and I didn't want to wait for the app to have to process the event. That's all, we leave the responsibility of giving focus to the first instance to itself, should it so wish. Here is a snippet of how it looks in action.

static void Main(String[] args)

{

    Guid guid = new Guid("{6EAE2E61-E7EE-42bf-8EBE-BAB890C5410F}");

    using (SingleInstance singleInstance = new SingleInstance(guid))

    {

        if (singleInstance.IsFirstInstance)

        {

            singleInstance.ArgumentsReceived += singleInstance_ArgumentsReceived;

            singleInstance.ListenForArgumentsFromSuccessiveInstances();

 

            //Do whatever your application is supposed to do here...

        }

        else

            singleInstance.PassArgumentsToFirstInstance(args);

    }

}

 

static void singleInstance_ArgumentsReceived(object sender, ArgumentsReceivedEventArgs e)

{

    //Process the arguments here...

}

One thing to note, remember to make your own Guid to use, and make a new one for each application which uses this class (Tools->Create Guid->Registry Format->Copy)! Hope you like the excessively long method names, but hey, for a code sample on a blog it makes it much clearer...

Packaged with the code download is a simple Windows Forms application to demonstrate the functionality, the best way to see it work is to launch one instance in the debugger then minimise it. Next, drag and drop some jpeg files in explorer onto the exe.


And you should see the image viewer app jump to the front and open all the images you dragged!



I'm pleased with the class, hope it can help out some others. Enjoy.

SingleInstance.zip (18.77 kb)

kick it on DotNetKicks.com  

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList
February 11, 2008 13:06 by Sean
E-mail | Permalink | Comments (5) | Comment RSSRSS comment feed

Related posts

Comments

February 12. 2008 23:59

Hi Sean
As usual, it's all Greek (geek?) to me, but I'm impressed anyway!
Love
Mum

mum

February 13. 2008 21:31

Thankyou mother, however I think you'll find this is a forum for serious technical descussion, now clear off my blog!

Sean

March 7. 2008 23:15

Exactly what I was looking for, thanks for sharing the code! =)

Paul

March 7. 2008 23:21

Thanks for posting Paul, it's great to know someone is using the code, I really appreciate you taking the time to say thanks!

Sean

March 11. 2008 12:37

Pingback from alvinashcraft.com

Dew Drop - March 11, 2008 | Alvin Ashcraft's Morning Dew

alvinashcraft.com

Comments are closed