Monday, June 11, 2012

What is the correct way to create a single instance application?


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.


Source: Tips4all

12 comments:

  1. 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.

    ReplyDelete
  2. 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.

    ReplyDelete
  3. 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.

    ReplyDelete
  4. 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.

    ReplyDelete
  5. 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
    }

    ReplyDelete
  6. 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

    ReplyDelete
  7. 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...

    ReplyDelete
  8. 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.

    ReplyDelete
  9. See my solution for this problem...

    ReplyDelete
  10. This code should go to the main method. Look at here for more information about the main method in WPF.

    [DllImport("user32.dll")]
    private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);

    static void Main()
    {
    Process currentProcess = Process.GetCurrentProcess();
    var runningProcess = (from process in Process.GetProcesses()
    where
    process.Id != currentProcess.Id &&
    process.ProcessName.Equals(
    currentProcess.ProcessName,
    StringComparison.Ordinal)
    select process).FirstOrDefault();
    if (runningProcess != null)
    {
    ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED);
    return;
    }
    }


    Method 2

    static void Main()
    {
    string procName = Process.GetCurrentProcess().ProcessName;
    // get the list of all processes by that name

    Process[] processes=Process.GetProcessesByName(procName);

    if (processes.Length > 1)
    {
    MessageBox.Show(procName + " already running");
    return;
    }
    else
    {
    // Application.Run(...);
    }
    }

    ReplyDelete
  11. http://yogesh.jagotagroup.com/blog/post/2008/07/03/Ways-of-making-a-WPF-application-Single-Instance.aspx

    ReplyDelete
  12. 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();
    }
    }

    ReplyDelete