Click here to Skip to main content
Licence 
First Posted 15 Aug 2006
Views 70,547
Downloads 409
Bookmarked 37 times

Single Instance Application, Passing Command Line Arguments

By kian01 | 15 Aug 2006
This article shows how to make sure that only one instance of an application will run, and if a second instance is started, it will call a callback function in the first instance, passing its command line arguments. The solution uses .NET Remoting for the callback.
1 vote, 9.1%
1

2

3
4 votes, 36.4%
4
6 votes, 54.5%
5
4.50/5 - 11 votes
1 removed
μ 3.92, σa 2.08 [?]

Problem

I wanted to make sure that only one instance of a program is running on my machine, and when a second instance would be started, it would pass its command line arguments to the original instance and then terminate. Thus, the original instance can handle everything else, such as opening a file, bringing itself to the foreground, etc. Also, the solution should not employ outdated techniques such as DDE, and should not use any unmanaged code as I had seen in so many other solutions to this problem.

Solution

Part 1: Many solutions I have seen walk through the process list in order to identify a previous instance. Others use Mutex, which I found appealing as it is a lot faster and is completely managed code. This solution uses the full path of the executing assembly as the Mutex name, so it is definitely unique.

Part 2: Other solutions use DDE to communicate with the previous instance. I chose .NET remoting because, again, it is fully managed code and not a Windows legacy, and it also works with console applications, while DDE would require a window.

The whole functionality is encapsulated in a class, written in C# using .NET 2.0. To make this work with .NET 1.1, you would have to change some namespaces, otherwise it is fully compatible.

To demonstrate the principle, I created a simple console application. Of course, you'd need to enhance the class a little for general use. This example has, for instance, a fixed port number, and certainly other flaws for generic usage. But it should only demonstrate the principle.

Using the Code

The class that handles the whole thing is named SingletonController, and it has some static methods that would be used by the calling program (your main program).

// test if this is the first instance and register receiver, if so.
if(SingletonController.IamFirst(new 
   SingletonController.ReceiveDelegate(myReceive)))
{
    // OK, this is the first instance, now run whatever you want ...
    // Your application code goes here ...
}
else
{
    // send command line args to running app, then terminate
    SingletonController.Send(args);
}

SingletonController.Cleanup();

The test whether this is the first instance, as you can see above, creates a delegate (callback) function. This function will be called whenever a second instance is opened.

The else branch handles the second instance, which will pass its arguments before terminating.

The SingletonController class has a couple of building blocks:

  • it defines a ReceiveDelegate, which will be set to the original instance's callback function
  • the IamFirst() function, which returns true if this is the first instance of your application
  • the CreateInstanceChannel() function, which creates a small remoting listener; this receives the arguments from any subsequent instances
  • the Send() function, which sends all arguments from a second instance to the initial instance before it terminates itself.
public static bool IamFirst()
{
    string m_UniqueIdentifier;
    string assemblyName = 
      System.Reflection.Assembly.GetExecutingAssembly().GetName(false).CodeBase;
    m_UniqueIdentifier = assemblyName.Replace("\\", "_");

    m_Mutex = new Mutex(false, m_UniqueIdentifier);

    if (m_Mutex.WaitOne(1, true))
    {
        //We locked it! We are the first instance!!!
        CreateInstanceChannel();
        return true;
    }
    else
    {
        //Not the first instance!!!
        m_Mutex.Close();
        m_Mutex = null;
        return false;
    }
}

This function creates a Mutex based on the full path name of the executing assembly, then tries to lock it. If successful, it calls CreateInstanceChannel(), which will create a small remoting listener. This listener is later responsible for calling your main program's callback function.

private static void CreateInstanceChannel()
{
    m_TCPChannel = new TcpChannel(1234);
    ChannelServices.RegisterChannel(m_TCPChannel, false);
    RemotingConfiguration.RegisterWellKnownServiceType(
        Type.GetType("SingletonApp.SingletonController"),
        "SingletonController",
        WellKnownObjectMode.SingleCall);
}

This function creates the remoting listener. I hard-coded the port as 1234, this is what you want to put into your configuration file.

public static void Send(string[] s)
{
    SingletonController ctrl;
    TcpChannel channel = new TcpChannel();
    ChannelServices.RegisterChannel(channel, false);
    try
    {
        ctrl = (SingletonController)Activator.GetObject(
                typeof(SingletonController), 
                "tcp://localhost:1234/SingletonController");
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception: " + e.Message);
        throw;
    }
    ctrl.Receive(s);
}

This function needs to be called by your main program in case it is the second instance (IamFirst() == false). It will send the arguments supplied to the first instance (the remoting listener), which in turn will call your callback function of the first instance. You will notice that this is the only call to a non-static function (ctrl.Receive()), your own code never needs to instantiate the SingletonController class.

The Receive() function finally calls your callback using the delegate member:

public void Receive(string[] s)
{
    if (m_Receive != null)
    {
        m_Receive(s);
    }
}

Running the Sample Code

After you compile the sample code, do this:

  • open two command windows.
  • run SingletonApp.exe in one of the windows; it will start saying "Hi: 0, Hi: 1, ..." every second and will terminate after 10 iterations.
  • within 10 seconds after the above application runs, start SingletonApp.exe in a second command window and supply some command line arguments; watch the first window printing out the arguments supplied in the second window.

If you supply more than one argument, you will notice that the "Hi: 0, Hi: 1, ..." loop and the loop that prints the arguments run in separate threads, the "Hi" messages and arguments will be printed in an alternating fashion.

Points of Interest

None, this solution has been put together from different solutions I had found on the net, none of which combined it the way I wanted it to be. So, this is basically nothing new, just a new combination.

History

No changes (yet).

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

About the Author

kian01

Program Manager
The Boston Consulting Group
Germany Germany

Member


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionGood article, but... PinmemberMember 25834889:04 14 Oct '11  
QuestionLaunching SingletonApp already with args PinmemberAres5321:31 3 Aug '11  
GeneralAnother approach without mutexes/remoting PinmemberFanatiX9:24 31 Oct '08  
GeneralRe: Another approach without mutexes/remoting Pinmemberdan2010here19:52 12 Apr '09  
QuestionHTTP Channel? PinmemberOmid.Q.Rose15:23 8 Dec '06  
QuestionShowing a form within the static method myReceive Pinmemberneilault0:10 8 Nov '06  
GeneralVery good. An addition PinmemberDaniel Ruehmer23:01 24 Oct '06  
GeneralIssues when trying to use implement SingletonController.cs Pinmembernip900:37 9 Oct '06  
AnswerRe: Issues when trying to use implement SingletonController.cs PinmemberDaniel Ruehmer22:51 24 Oct '06  
GeneralNice, but a few suggestions... Pinmembermav.northwind0:43 16 Aug '06  
GeneralRe: Nice, but a few suggestions... PinmemberGamerX8713:35 25 Jun '07  
GeneralDo not use mutexes for this! PinmemberRamon Smits22:27 15 Aug '06  
GeneralRe: Do not use mutexes for this! Pinmembermav.northwind6:38 16 Aug '06  
GeneralRe: Do not use mutexes for this! Pinmemberkian0122:07 16 Aug '06  
GeneralRe: Do not use mutexes for this! PinmemberAaron Sulwer8:04 12 Sep '06  
GeneralRe: Do not use mutexes for this! PinmemberAaron Sulwer11:04 11 Sep '06  
GeneralRe: Do not use mutexes for this! PinmemberAres5327:08 2 Aug '11  
GeneralUse an IPC Channel -- not a tcp channel PinmemberIan MacLean18:55 15 Aug '06  
GeneralRe: Use an IPC Channel -- not a tcp channel Pinmemberkian0122:09 16 Aug '06  
GeneralRe: Use an IPC Channel -- not a tcp channel [modified] PinmemberAaron Sulwer11:06 11 Sep '06  
Generalgood idea... but using remoting is a pain PinmemberMichael Moreno13:59 15 Aug '06  
Hi,
I do the same: use Mutex to be sure I have only one instance running.
But I would be weary about using remoting to send to the running instance parameters. There are many problems with .Net remoting. Mainly the channel port may already be used by another application and it is pain to reset it to a different port even if using config files.
With COM we did not have to handle the port problem. We suffered other security settings problems though. I believe in .Net 2 there is a new .Net remoting channel called IPX or something like this that may solve the problem mentioned before. It may be worth looking at it.
regards,
MM

GeneralRe: good idea... but using remoting is a pain PinmemberMarkJCaplin6:45 13 Oct '06  

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.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120210.1 | Last Updated 15 Aug 2006
Article Copyright 2006 by kian01
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid