21

I'm trying to use the mutex method for only allowing one instance of my app to run. That is - I only want a max of one instance for all users on a machine. I've read through the various other threads on this issue and the solution seems straightforward enough but in testing I can't get my second instance to not run. Here is my code...

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        // check that there is only one instance of the control panel running...
        bool createdNew = true;
        using (Mutex instanceMutex = new Mutex(true, @"Global\ControlPanel", out createdNew))
        {
            if (!createdNew)
            {
                Application.Current.Shutdown();
                return;
            }
        }

        base.OnStartup(e);
    }
}
flobadob
  • 2,804
  • 2
  • 22
  • 23

7 Answers7

44

You're also disposing the mutex in the same method, so the mutex only lives for the duration of the method. Store the mutex in a static field, and keep it alive for the duration of your application.

Willem van Rumpt
  • 6,490
  • 2
  • 32
  • 44
33

Here is my new code which has the answer provided by @Willem van Rumpt (and @OJ)...

public partial class App : Application
{
    private Mutex _instanceMutex = null;

    protected override void OnStartup(StartupEventArgs e)
    {
        // check that there is only one instance of the control panel running...
        bool createdNew;
        _instanceMutex = new Mutex(true, @"Global\ControlPanel", out createdNew);
        if (!createdNew)
        {
            _instanceMutex = null;
            Application.Current.Shutdown();
            return;
        }

        base.OnStartup(e);
    }

    protected override void OnExit(ExitEventArgs e)
    {          
        if(_instanceMutex != null)
            _instanceMutex.ReleaseMutex();
        base.OnExit(e);
    }
}
flobadob
  • 2,804
  • 2
  • 22
  • 23
  • why wouldn't you put the duplication check in the constructor? should the `App` call `InitializeComponent` when it won't launch? – Maslow May 10 '18 at 13:50
  • 1
    When calling ReleaseMutex from OnExit you may get System.ApplicationException: Object synchronization method was called from an unsynchronized block of code. See [Releasing a named mutex created in WPF Application.OnStartUp(): Which thread owns it?](https://stackoverflow.com/questions/32535686/releasing-a-named-mutex-created-in-wpf-application-onstartup-which-thread-own/32535863#32535863) for a discussion of why. – Bill Menees May 27 '20 at 22:04
4

As extension sample:

public static class Extension
{
    private static Mutex mutex;

    public static bool IsOneTimeLaunch(this Application application, string uniqueName = null)
    {
        var applicationName = Path.GetFileName(Assembly.GetEntryAssembly().GetName().Name);
        uniqueName = uniqueName ?? string.Format("{0}_{1}_{2}",
            Environment.MachineName,
            Environment.UserName,
            applicationName);

        application.Exit += (sender, e) => mutex.Dispose();
        bool isOneTimeLaunch;
        mutex = new Mutex(true, uniqueName, out isOneTimeLaunch);
        return isOneTimeLaunch;
    }
}

App Class:

    protected override void OnStartup(StartupEventArgs e)
    {
        if (this.IsOneTimeLaunch())
        {
            base.OnStartup(e);
        }
        else
        {
            this.Shutdown();
        }
    }
Vildi
  • 41
  • 2
4

You're destroying the Mutex immediately after you've created it and tested it. You need to keep the Mutex reference alive for lifetime of your application.

Make the Mutex a member/field of your Application class. Release the mutex when your application shuts down.

OJ.
  • 28,944
  • 5
  • 56
  • 71
1

I was told to implement this mutex approach on an already developed WPF application that we had. The work around to the problem with using override of the OnStart() that I found was in

App.g.cs

This file is located in

obj\x86\debug\

and contains the main() function, so you just simply put this piece of code in your main function.

bool isOnlyInstance = false;
Mutex m = new Mutex(true, @"WpfSingleInstanceApplication", out isOnlyInstance);
if (!isOnlyInstance)
{
    MessageBox.Show("Another Instance of the application is already running.", 
                    "Alert", 
                    MessageBoxButton.OK, 
                    MessageBoxImage.Exclamation);
    return;
}
GC.KeepAlive(m);

but for this you need to keep the BUILD ACTION of your app.xaml set to ApplicationDefinition

NOTE: This might not be the best way, since I'm a beginner. (please tell me if there's something I should change)

slavoo
  • 5,798
  • 64
  • 37
  • 39
Faizan
  • 11
  • 1
1

I can suggest a much cleaner approach that also introduce the useful concept of overriding the Main method in WPF application. Also, if using your solution you take a look at the task manager, you will notice that the new instance actually reach the execution state (you can see a new process created in the list of task) and then suddenly close. The approach proposed in the post that follows will avoid this drawback too. http://blog.clauskonrad.net/2011/04/wpf-how-to-make-your-application-single.html

g1ga
  • 323
  • 3
  • 11
0

I did this from this link just add the given class and a single line in you App.Xaml.cs http://wpfsingleinstance.codeplex.com/

public partial class App : Application    
{
  protected override void OnStartup(StartupEventArgs e) 
  {
        WpfSingleInstance.Make(); //added this is the function of that class 
        base.OnStartup(e);
  }
}
S3ddi9
  • 2,121
  • 2
  • 20
  • 34
dnxit
  • 7,118
  • 2
  • 30
  • 34