I've inherited an existing application which is a WPF implementation of toast notifications. This application is installed to multiple client PCs across the estate and, once installed, runs in the background. The notifier then works regardless of who is logged onto the machine. One of the improvements I have been asked to make is to prevent the application from being started more than once.
I am considering using a mutex to do this. I've implemented a solution that functionally works at startup using inspiration from MSDN and Stack Overflow but would like to identify any potential weaknesses or scenarios which could break the code. Ultimately, I don't want some crash to occur that might fail to dispose the mutex or leave the application unable to start, although I think I have catered as best possible.
public partial class MainWindow : Window
{
// unique id for application mutex
private static string mutexId = string.Format("Local\\{{{0}}}", "1109F104-B4B4-4ED1-920C-F4D8EFE9E833");
private static string applicationName = "My App";
private bool hasHandle;
private Mutex mutex;
/// <summary>
/// Initializes a new instance of the MainWindow class.
/// N.B. Inspiration for this implementation sourced from:
/// https://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c/229567
/// </summary>
public MainWindow()
{
this.mutex = new Mutex(false, mutexId);
// Allow all users of the system to access the mutex with full control.
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
mutex.SetAccessControl(securitySettings);
try
{
try
{
hasHandle = this.mutex.WaitOne(1000, false);
if (!hasHandle)
{
MessageBox.Show("Application is already running.", applicationName);
Application.Current.Shutdown();
}
}
catch (AbandonedMutexException)
{
// Log the fact the mutex was abandoned in another process, it will still get aquired
hasHandle = true;
}
// Perform your work here.
InitializeComponent();
Closing += (s, e) => Shutdown();
}
catch (Exception e)
{
//If InitializeComponent throws an error, gracefully cleanup the application.
Shutdown();
}
}
private void Shutdown()
{
ViewModelLocator.Cleanup();
// Release the mutex if a handle was aquired while the application was running.
if (this.hasHandle)
{
this.mutex.ReleaseMutex();
}
this.mutex.Dispose();
}
}
For brevity I've omitted using statements and namespace declarations, as well as the .xaml files and existing solution, as I want to focus on this new improvement, which is self-contained. I'm also conscious of trying to keep startup and shutdown as simple as possible, so would happily consider improvements to remove unneeded code.
Finally, I have seen this similar question and would be happy with an answer to use this example if this is the best way of meeting the requirement.