WPF Single Instance Best Practices
There are Several choices,
- Mutex
- Process manager
- Named Semaphore
- Use a listener socket
Mutex
Mutex myMutex ;private void Application_Startup(object sender, StartupEventArgs e){ bool aIsNewInstance = false; myMutex = new Mutex(true, "MyWPFApplication", out aIsNewInstance); if (!aIsNewInstance) { MessageBox.Show("Already an instance is running..."); App.Current.Shutdown(); }}
Process manager
private void Application_Startup(object sender, StartupEventArgs e){ Process proc = Process.GetCurrentProcess(); int count = Process.GetProcesses().Where(p=> p.ProcessName == proc.ProcessName).Count(); if (count > 1) { MessageBox.Show("Already an instance is running..."); App.Current.Shutdown(); }}
Use a listener socket
One way to signal another application is to open a Tcp connection to it. Create a socket, bind to a port, and listen on a background thread for connections. If this succeeds, run normally. If not, make a connection to that port, which signals the other instance that a second application launch attempt has been made. The original instance can then bring its main window to the front, if appropriate.
“Security” software / firewalls might be an issue.
I wanted to have a bit better user experience - if another instance is already running let's activate it rather than showing an error about the second instance. Here is my implementation.
I use named Mutex for making sure that only one instance is running and named EventWaitHandle to pass notification from one instance to another.
App.xaml.cs:
/// <summary>Interaction logic for App.xaml</summary>public partial class App{ #region Constants and Fields /// <summary>The event mutex name.</summary> private const string UniqueEventName = "{GUID}"; /// <summary>The unique mutex name.</summary> private const string UniqueMutexName = "{GUID}"; /// <summary>The event wait handle.</summary> private EventWaitHandle eventWaitHandle; /// <summary>The mutex.</summary> private Mutex mutex; #endregion #region Methods /// <summary>The app on startup.</summary> /// <param name="sender">The sender.</param> /// <param name="e">The e.</param> private void AppOnStartup(object sender, StartupEventArgs e) { bool isOwned; this.mutex = new Mutex(true, UniqueMutexName, out isOwned); this.eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName); // So, R# would not give a warning that this variable is not used. GC.KeepAlive(this.mutex); if (isOwned) { // Spawn a thread which will be waiting for our event var thread = new Thread( () => { while (this.eventWaitHandle.WaitOne()) { Current.Dispatcher.BeginInvoke( (Action)(() => ((MainWindow)Current.MainWindow).BringToForeground())); } }); // It is important mark it as background otherwise it will prevent app from exiting. thread.IsBackground = true; thread.Start(); return; } // Notify other instance so it could bring itself to foreground. this.eventWaitHandle.Set(); // Terminate this instance. this.Shutdown(); } #endregion}
And BringToForeground in MainWindow.cs:
/// <summary>Brings main window to foreground.</summary> public void BringToForeground() { if (this.WindowState == WindowState.Minimized || this.Visibility == Visibility.Hidden) { this.Show(); this.WindowState = WindowState.Normal; } // According to some sources these steps gurantee that an app will be brought to foreground. this.Activate(); this.Topmost = true; this.Topmost = false; this.Focus(); }
And add Startup="AppOnStartup" (thanks vhanla!):
<Application x:Class="MyClass.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Startup="AppOnStartup"> <Application.Resources> </Application.Resources></Application>
Works for me :)
For WPF just use:
public partial class App : Application{ private static Mutex _mutex = null; protected override void OnStartup(StartupEventArgs e) { const string appName = "MyAppName"; bool createdNew; _mutex = new Mutex(true, appName, out createdNew); if (!createdNew) { //app is already running! Exiting the application Application.Current.Shutdown(); } base.OnStartup(e); } }