Single-Instance Applications

So what's a Single-Instance application?  Imagine launching an application where additional attempts to launch the app while the first one is running doesn't actually launch a new instance of the app.  Instead the original instance of the app gets notified that another launch attempt occurred.  When we introduced an application model for Visual Basic in VB 2005, one of the things we wanted to do is make it drop-dead easy to create single-instance applications.

It's easier to understand single-instance apps with an example.  I don't know for certain that Word is a single-instance app but it seems to behave like one.  If you crank up the task manager and launch Word you'll see WinWord.exe show up.  But if you launch it again while an instance of Word is already running, you won't see another WinWord.exe show up in the task manager.  You can see the memory footprint of Word go up but it only goes up a little.  I assume that is memory needed just for the new document.  How Word manages its single-instance behavior is frankly not something I know anything about so I'm only guessing at what it is doing based on watching the task manager.  But it has the tale-tale signs of a single-instance app.

Single-Instance apps are useful in situations where you don't want to have multiple instances of the app running.  Maybe you can only have one running on the machine at any given time.  Or maybe you have a scenario where you have an app that can manage multiple documents.  In that case a single-instance app would provide a nice way to avoid loading multiple copies of your exe just to manage one more document.  Instead, the currently running app could just be told to load another document. Less memory consumption, faster subsequent document load times.  It's goodness.

You can find code samples on the internet to create single-instance apps.  Previously you had to hunt down the code, wire it into your own startup code, and then decide whether it used a technique that you think is robust enough or secure enough for your purposes.  We decided we wanted to provide a robust/secure single-instance capability that you could just turn on by clicking on a checkbox.  This switch lives on the application page in the project designer under Windows application framework properties and is called:  Make single instance application.  That's a lot of intro for the issue I want to talk about.''

One of the questions that comes up is: So how do we determine whether a subsequent instance of an application has launched?  Do we key off of the path where the app was launched from, or what?

We don't key off of the path where the app was launched from.  Single-Instance apps have a single-instance application identity.   When a single-instance app launches, it checks to see if an app with the same identity is already running.  If it is, we call that app's StartupNextInstance() event (which will be raised on the main thread of the original instance) and pass it the command line.  The subsequent instance then just exits; leaving the original instance to decide what it wants to do about the fact that somebody tried to launch another instance of itself.  A common thing to do would be to examine the command line passed into the StartupNextInstance() event and try to load the document specified.

What does this single-instance application identity look like?  It is comprised of the assembly guid and the assembly (not file) major and minor version number.  You can see the assembly guid and assembly version information by selecting the Assembly Information button on the application page in the project designer.  Taken together these three pieces of information identify the identity of the single-instance application.

There are some ramifications from all of this.  Different versions of an application won't act as single instances against each other.  For instance, if you launch version 1.0 of Foo.exe, and then launch version 1.1 of Foo.exe, you won't get the single instance behavior.  You'll have two versions of foo.exe running.

If you have two copies of foo.exe on the machine in c:\foo1 and c:\foo2, and then launch c:\foo1\foo.exe followed by c:\foo2\foo.exe, you will get single-instance behavior between the two.  That is, you'll only get one instance of foo.exe running, the one in c:\foo1\foo.exe.  Launching c:\foo2\foo.exe will simply raise the event on the first and then terminate.  The application startup directory is not part of the single-instance application identity so it has no bearing on whether an application thinks another instance of itself is already running.

This means that you can't easily contrive a situation where c:\foo1\foo.exe only exhibits single instance behavior when foo.exe is launched from c:\foo1 instead of c:\foo2 merely because they are in different directories.  If you wanted c:\foo2\foo.exe to be considered a different app then c:\foo1\foo.exe, you'd have to differentiate the two foo.exes by either changing the assembly version number or assembly guid of one of them.

Currently there is no user facing way of setting the single-instance identity.  In practice do people find that this is terribly limiting?

Comments (6)

  1. tzagotta says:

    Does this technique apply to C# in the same way?

  2. Tyler Whitney says:

    You can use the VB application model class from C# to get the same effect, but you have to do some work. I think this will be common question so I’ve written a post to address it:

  3. Neil says:

    With regards to "..and pass it the command line. " Why are you not passing the ActivationURI if it’s network deployed?

  4. Tyler says:

    Now is this a delayed response, or what.  My apologies.  It would take too long to explain why it has taken so long to respond 😉  But with regards to your question, we talked about doing that and it just didn’t make the schedule last time with everything else going on.  It won’t make it in Orcas because the VB runtime falls into the red-bit category and so we aren’t modifying it.  

    The short answer is that this is a ‘consider’ for Hawaii (the version after the next one).  If you haven’t moved onto other things (a new life, a new career) in the time it took me to respond to this, shoot me an example of what you’d like to do so I can incorporate it into the feature request to give it even more weight.

  5. Frank says:

    I can’t seem to find any information on how single instance applications function on a Terminal Server.  If we’re using Word as an example, it would seem that a single instance application would function per session, but if we’re using your "foo.exe" example, it would will seem that a single instance application would work across sessions because foo.exe has the same assembly guid and versioning on the machine.  I’m hoping that the Word example is the more accurate example.  Can anyone clarify?

  6. Tyler says:

    Hi Frank,

    Our single instance apps are per session in a terminal server environment.  In terminal-server sessions, global OS objects (which we use as our signaling and identity mechanism for single-instance apps) are per session.  The fallout is that even if you have multiple sessions running simultaneously under the same login credentials, each session is in isolation so far as single-instance apps goes.

Skip to main content