tags:

views:

6226

answers:

14

Using C# and WPF under .net (rather than WindowsForms or console), what is the correct way to create an application that can only be run as a single instance? I know it has something to do with some mythical thing called a mutex, rarely can I find someone that bothers to stop and explain what one of these are.

The code needs to also inform the already running instance that the user tried to start a second one, and maybe also pass any command line arguments if any existed.

+18  A: 

From here.

A common use for a cross-process Mutex is to ensure that only instance of a program can run at a time. Here's how it's done:

class OneAtATimePlease {

  // Use a name unique to the application (eg include your company URL)
  static Mutex mutex = new Mutex (false, "oreilly.com OneAtATimeDemo");

  static void Main()
  {
    // Wait 5 seconds if contended – in case another instance
    // of the program is in the process of shutting down.
    if (!mutex.WaitOne(TimeSpan.FromSeconds (5), false))
    {
        Console.WriteLine("Another instance of the app is running. Bye!");
        return;
    }

    try
    {    
        Console.WriteLine("Running - press Enter to exit");
        Console.ReadLine();
    }
    finally
    {
        mutex.ReleaseMutex();
    }    
  }    
}

A good feature of Mutex is that if the application terminates without ReleaseMutex first being called, the CLR will release the Mutex automatically.

jms
I've got to say, I like this answer a lot more than the accepted one simply due to the fact that it isn't dependent on WinForms. Personally most of my development has been moving to WPF and I don't want to have to pull in WinForm libraries for something like this.
slude
Of course, to be a full answer, you have to also describe passing the arguments to the other instance :)
Simon Buchan
+24  A: 

You could use the Mutex class, but you will soon find out that you will need to implement the code to pass the arguments and such yourself. Well, I learned a trick when programming in WinForms when I read Chris Sell's book. This trick uses logic that is already available to us in the framework. I don't know about you, but when I learn about stuff I can reuse in the framework, that is usually the route I take instead of reinventing the wheel. Unless of course it doesn't do everything I want.

When I got into WPF, I came up with a way to use that same code, but in a WPF application. This solution should meet your needs based off your question.

First, we need to create our application class. In this class we are going override the OnStartup event and create a method called Activate, which will be used later.

public class SingleInstanceApplication : System.Windows.Application
{
    protected override void OnStartup(System.Windows.StartupEventArgs e)
    {
        // Call the OnStartup event on our base class
        base.OnStartup(e);

        // Create our MainWindow and show it
        MainWindow window = new MainWindow();
        window.Show();
    }

    public void Activate()
    {
        // Reactivate the main window
        MainWindow.Activate();
    }
}

Second, we will need to create a class that can manage our instances. Before we go through that, we are actually going to reuse some code that is in the Microsoft.VisualBasic assembly. Since, I am using C# in this example, I had to make a reference to the assembly. If you are using VB.NET, you don't have to do anything. The class we are going to use is WindowsFormsApplicationBase and inherit our instance manager off of it and then leverage properties and events to handle the single instancing.

public class SingleInstanceManager : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
    private SingleInstanceApplication _application;
    private System.Collections.ObjectModel.ReadOnlyCollection<string> _commandLine;

    public SingleInstanceManager()
    {
        IsSingleInstance = true;
    }

    protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs)
    {
        // First time _application is launched
        _commandLine = eventArgs.CommandLine;
        _application = new SingleInstanceApplication();
        _application.Run();
        return false;
    }

    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
        // Subsequent launches
        base.OnStartupNextInstance(eventArgs);
        _commandLine = eventArgs.CommandLine;
        _application.Activate();
    }
}

Basically, we are using the VB bits to detect single instance's and process accordingly. OnStartup will be fired when the first instance loads. OnStartupNextInstance is fired when the application is re-run again. As you can see, I can get to what was passed on the command line through the event arguments. I set the value to an instance field. You could parse the command line here, or you could pass it to your application through the constructor and the call to the Activate method.

Third, it's time to create our EntryPoint. Instead of newing up the application like you would normally do, we are going to take advantage of our SingleInstanceManager.

public class EntryPoint
{
    [STAThread]
    public static void Main(string[] args)
    {
        SingleInstanceManager manager = new SingleInstanceManager();
        manager.Run(args);
    }
}

Well, I hope you are able to follow everything and be able use this implementation and make it your own.

Dale Ragan
This is the way we do it and I've never been too happy about it because of the dependency on WinForms.
Bob King
I'd stick with the mutex solution because it has nothing to do with forms.
Steven Sudit
A: 

Thanks Dale and to the rest of you, this sample should come in useful. :)

Nidonocu
A: 

Witty Twitter uses the solution from this Code Project article: Enforcing Single Instance of a Hidden-Window Application. It works well enough.

Alan Le
+2  A: 

You should never use a named mutex to implement a single instance application (or at least not for production code). Malicious code can easily DOS(Denial of Service) your ass...

Matt Davison
"You should never use a named mutex" - never say never. If malicious code is running on my machine, I'm probably already hosed.
Joe
Actually it doesn't even have to be malicious code. It could just be a accidental name collision.
Matt Davison
Then what should you do?
Kevin Berridge
The better question is what possible reason would you want that behavior. Don't design your app as a single instance application=). I know that's a lame answer but from a design standpoint it is almost always the correct answer. Without knowing more about the app its hard to say much more.
Matt Davison
At least under Windows, Mutexes have access control, so one one can toy with your object. As to name collisions themselves, that's why UUID/GUID's where invented.
NuSkooler
+22  A: 

Here is a very good article regarding the Mutex solution. The approach described by the article is advantageous for two reasons.

First, it does not require a dependency on the Microsoft.VisualBasic assembly. If my project already had a dependency on that assembly, I would probably advocate using the approach shown in the accepted answer. But as it is, I do not use the Microsoft.VisualBasic assembly, and I'd rather not add an unnecessary dependency to my project.

Second, the article shows how to bring the existing instance of the application to the foreground when the user tries to start another instance. That's a very nice touch that the other Mutex solutions described here do not address.

Matt Davis
On the basis that this answer uses less code and less libraries and provides the raise to top functionality, I'm going to make this the new accepted answer. If anyone knows a more correct way to bring the form to the top using API's, feel free to add that.
Nidonocu
That's a nice little example - works beautifully in my application. Add it's simple to implement.
Vidar
Not sure I understand - why use Native Messages? That's what events are for... (if it's for the decoupling, you should really be using cab or [EventBroker](http://www.codeproject.com/KB/dotnet/EventBroker.aspx)...)
BlueRaja - Danny Pflughoeft
@BlueRaja, you start up the first app instance. When you start up the second app instance, it detects that another instance is already running and prepares to shutdown. Before doing so, it sends a "SHOWME" native message to the first instance, which brings the first instance to the top. Events in .NET don't allow cross-process communication, which is why the native message is used.
Matt Davis
@Matt: Ah, I understand. Thank you.
BlueRaja - Danny Pflughoeft
Is there a way to pass the command lines from the other instance, maybe?
gyurisc
@matt david - don't worry about 'shipping' Microsoft.VisualBasic - it is already in the GAC. http://stackoverflow.com/questions/226517/is-the-microsoft-visualbasic-namespace-true-net-code
Simon_Weaver
@Simon_Weaver, the issue is not whether it is in the GAC or not, but the fact that it is delivered with the .NET Framework. I was not aware of that. Thanks for the link.
Matt Davis
@matt - i just wish they'd named the damn thing something else! i've just started using that component myself and it works quite well (my users will never know i stooped so low as to include a VB namespace - heh). its very convenient to be able to pass parameters and/or have the dormant application bring itself to the front without having to mess with any communication code yourself
Simon_Weaver
@Matt: How can we choose the name for the Mutex? In the sample it is `{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}` Where is it from :) ?
Nam Gi VU
@Nam, the `Mutex` constructor simply requires a string, so you could supply any string name you want, e.g., "This Is My Mutex". Because a 'Mutex' is a system object that is available to other processes, you typically want the name to be unique so it doesn't clash with other 'Mutex' names on the same system. In the article, the cryptic-looking string is a 'Guid'. You can generate this programmatically by calling `System.Guid.NewGuid()`. In the case of the article, the user probably generated it via Visual Studio as shown here: http://msdn.microsoft.com/en-us/library/ms241442(VS.80).aspx
Matt Davis
+2  A: 

Just some thoughts: There are cases when requiring that only one instance of an application is not "lame" as some would have you believe. Database apps, etc. are an order of magnitude more difficult if one allows multiple instances of the app for a single user to access a database (you know, all that updating all the records that are open in multiple instances of the app on the users machine, etc.). First, for the "name collision thing, don't use a human readable name - use a GUID instead or, even better a GUID + the human readable name. Chances of name collision just dropped off the radar and the Mutex doesn't care. As someone pointed out, a DOS attack would suck, but if the malicious person has gone to the trouble of getting the mutex name and incorporating it into their app, you are pretty much a target anyway and will have to do MUCH more to protect yourself than just fiddle a mutex name. Also, if one uses the variant of: new Mutex(true, "some GUID plus Name", out AIsFirstInstance), you already have your indicator as to whether or not the Mutex is the first instance.

Bruce
+1  A: 

See my solution for this problem...

Maxim
Very interesting solution. Sadly the comments seems to be a bit neglected?
Anders Rune Jensen
+3  A: 

Well, I have a disposable Class for this that works easily for most use cases:

Use it like this:

static void Main()
{
    using (SingleInstanceMutex sim = new SingleInstanceMutex())
    {
        if (sim.IsOtherInstanceRunning)
        {
            Application.Exit();
        }

        // Initialize program here.
    }
}

Here it is:

/// <summary>
/// Represents a <see cref="SingleInstanceMutex"/> class.
/// </summary>
public partial class SingleInstanceMutex
{
    #region Fields

    /// <summary>
    /// Indicator whether another instance of this application is running or not.
    /// </summary>
    private bool isNoOtherInstanceRunning;

    /// <summary>
    /// The <see cref="Mutex"/> used to ask for other instances of this application.
    /// </summary>
    private Mutex singleInstanceMutex = null;

    /// <summary>
    /// An indicator whether this object is beeing actively disposed or not.
    /// </summary>
    private bool disposed;

    #endregion

    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="SingleInstanceMutex"/> class.
    /// </summary>
    public SingleInstanceMutex()
    {
        this.singleInstanceMutex = new Mutex(true, Assembly.GetCallingAssembly().FullName, out this.isNoOtherInstanceRunning);
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets an indicator whether another instance of the application is running or not.
    /// </summary>
    public bool IsOtherInstanceRunning
    {
        get
        {
            return !this.isNoOtherInstanceRunning;
        }
    }

    #endregion

    #region Methods

    /// <summary>
    /// Closes the <see cref="SingleInstanceMutex"/>.
    /// </summary>
    public void Close()
    {
        this.ThrowIfDisposed();
        this.singleInstanceMutex.Close();
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            /* Release unmanaged ressources */

            if (disposing)
            {
                /* Release managed ressources */
                this.Close();
            }

            this.disposed = true;
        }
    }

    /// <summary>
    /// Throws an exception if something is tried to be done with an already disposed object.
    /// </summary>
    /// <remarks>
    /// All public methods of the class must first call this.
    /// </remarks>
    public void ThrowIfDisposed()
    {
        if (this.disposed)
        {
            throw new ObjectDisposedException(this.GetType().Name);
        }
    }

    #endregion
}
BeowulfOF
A: 

So many answers to such a seemingly simple question. Just to shake things up a little bit here is my solution to this problem.

Creating a Mutex can be troublesome because the JIT-er only sees you using it for a small portion of your code and wants to mark it as ready for garbage collection. It pretty much wants to out-smart you thinking you are not going to be using that Mutex for that long. In reality you want to hang onto this Mutex for as long as your application is running. The best way to tell the garbage collector to leave you Mutex alone is to tell it to keep it alive though out the different generations of garage collection. Example:

var m = new Mutex(...);
...
GC.KeepAlive(m);

I lifted the idea from this page: http://www.ai.uga.edu/~mc/SingleInstance.html

Peter
Wouldn't it be easier to store a shared copy of it in the application class?
rossisdead
+2  A: 

Here is a new one that uses Mutex and IPC stuff, and also passes any command line args to the running instance:

http://blogs.microsoft.co.il/blogs/arik/archive/2010/05/28/wpf-single-instance-application.aspx

huseyint
A: 

Here is what I use. It combined process enumeration to perform switching and mutex to safeguard from "active clickers":

public partial class App
{
    [DllImport("user32")]
    private static extern int OpenIcon(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        var p = Process
           .GetProcessesByName(Process.GetCurrentProcess().ProcessName);
            foreach (var t in p.Where(t => t.MainWindowHandle != IntPtr.Zero))
            {
                OpenIcon(t.MainWindowHandle);
                SetForegroundWindow(t.MainWindowHandle);
                Current.Shutdown();
                return;
            }

            // there is a chance the user tries to click on the icon repeatedly
            // and the process cannot be discovered yet
            bool createdNew;
            var mutex = new Mutex(true, "MyAwesomeApp", 
               out createdNew);  // must be a variable, though it is unused - 
            // we just need a bit of time until the process shows up
            if (!createdNew)
            {
                Current.Shutdown();
                return;
            }

            new Bootstrapper().Run();
        }
    }
Sergey Aldoukhov
+2  A: 

MSDN actually has a sample application for both C# and VB to do exactly this: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx

The most common and reliable technique for developing single-instance detection is to use the Microsoft .NET Framework remoting infrastructure (System.Remoting). The Microsoft .NET Framework (version 2.0) includes a type, WindowsFormsApplicationBase, which encapsulates the required remoting functionality. To incorporate this type into a WPF application, a type needs to derive from it, and be used as a shim between the application static entry point method, Main, and the WPF application's Application type. The shim detects when an application is first launched, and when subsequent launches are attempted, and yields control the WPF Application type to determine how to process the launches.

  • For C# people just take a deep breath and forget about the whole 'I don't wanna include VisualBasic DLL'. Because of this and what Scott Hanselman says and the fact that this pretty much is the cleanest solution to the problem and is designed by people who know a lot more about the framework than you do.
  • From a usability standpoint the fact is if your user is loading an application and it is already open and you're giving them an error message like 'Another instance of the app is running. Bye' then they're not gonna be a very happy user. You simply MUST (in a GUI application) switch to that application and pass in the arguments provided - or if command line parameters have no meaning then you must pop up the application which may have been minimized.

The framework already has support for this - its just that some idiot named the DLL Microsoft.VisualBasic and it didn't get put into Microsoft.ApplicationUtils or something like that. Get over it - or open up Reflector.

Tip: If you use this approach exactly as is, and you already have an App.xaml with resources etc. you'll want to take a look at this too.

Simon_Weaver
I prefer your answer to be the selected one :)
Nam Gi VU