This is the code I implemented so far to create a single instance WPF application:
#region Using Directives using System; using System.Globalization; using System.Reflection; using System.Threading; using System.Windows; using System.Windows.Interop; #endregion namespace MyWPF { public partial class MainApplication : Application, IDisposable { #region Members private Int32 m_Message; private Mutex m_Mutex; #endregion #region Methods: Functions private IntPtr HandleMessages(IntPtr handle, Int32 message, IntPtr wParameter, IntPtr lParameter, ref Boolean handled) { if (message == m_Message) { if (MainWindow.WindowState == WindowState.Minimized) MainWindow.WindowState = WindowState.Normal; Boolean topmost = MainWindow.Topmost; MainWindow.Topmost = true; MainWindow.Topmost = topmost; } return IntPtr.Zero; } private void Dispose(Boolean disposing) { if (disposing && (m_Mutex != null)) { m_Mutex.ReleaseMutex(); m_Mutex.Close(); m_Mutex = null; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion #region Methods: Overrides protected override void OnStartup(StartupEventArgs e) { Assembly assembly = Assembly.GetExecutingAssembly(); Boolean mutexCreated; String mutexName = String.Format(CultureInfo.InvariantCulture, "Local\\{{{0}}}{{{1}}}", assembly.GetType().GUID, assembly.GetName().Name); m_Mutex = new Mutex(true, mutexName, out mutexCreated); m_Message = NativeMethods.RegisterWindowMessage(mutexName); if (!mutexCreated) { m_Mutex = null; NativeMethods.PostMessage(NativeMethods.HWND_BROADCAST, m_Message, IntPtr.Zero, IntPtr.Zero); Current.Shutdown(); return; } base.OnStartup(e); MainWindow window = new MainWindow(); MainWindow = window; window.Show(); HwndSource.FromHwnd((new WindowInteropHelper(window)).Handle).AddHook(new HwndSourceHook(HandleMessages)); } protected override void OnExit(ExitEventArgs e) { Dispose(); base.OnExit(e); } #endregion } }
Everything works perfectly... but I have some doubts about it and I would like to receive your suggestions about how my approach could be improved.
1) I was asked by Code Analysis to implement IDisposable
interface because I was using IDisposable
members (the Mutex
). Is my Dispose()
implementation good enough? Should I avoid it because it's never going to be called?
2) It's better to use m_Mutex = new Mutex(true, mutexName, out mutexCreated);
and check for the result or to use m_Mutex = new Mutex(false, mutexName);
and then check for m_Mutex.WaitOne(TimeSpan.Zero, false);
? In case of multithreading I mean...
3) RegisterWindowMessage
API call should return UInt32
... but HwndSourceHook
is only accepting Int32
as message value... should I be worried about unexpected behaviors (like a result bigger than Int32.MaxValue
)?
4) In OnStartup
override... should I execute base.OnStartup(e);
even if another instance is already running and I'm going to shutdown the application?
5) Is there a better way to bring the existing instance to the top that doesn't need to set Topmost
value? Maybe Activate()
?
6) Can you see any flaw in my approach? Something concerning multithreading, bad exceptions handling and something like that? For example... what happens if my application crashes between OnStartup
and OnExit
?
There are Several choices,
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.
Single Instance Application C#.Net along with Win32
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 :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With