Code for Making a Single Instance WPF Application
I spent a few hours yesterday piecing together the needed code to create a single instance (non-re-entrant) WPF desktop application. There are lots of examples out there of how to do this. All the ones I could find fall short however, in that, if they detect that a prior instance is open, the just display a message box telling the user that another instance is already running. I wanted something more user friendly, namely to bring the running instance to the foreground. In my experience, this is the expected behavior for non-reentrant applications.
I discovered that the reason all the examples take the easy way out is that it can’t be done in .Net directly. To bring another window to the foreground, you have to make native Win32 API calls. Ugh!
I finally found this worth-while article on how to do what I wanted in WinForms, and combining that with the information found in this StackOverflow post, I updated the solution for Windows Presentation Foundation and encapsulated it all in a the following handy class.
using System; using System.Runtime.InteropServices; using System.Threading; using System.Windows; using System.Windows.Interop; namespace SIPC.SLS.ClaimsProcessing.ProcessorWpfApp.Application { internal class SingleInstanceEnforcementUtility : IDisposable { private Mutex _mutex; private Window _mainApplicationWindow; private bool _isDisposed; #region Win32 API Interop private const int HWND_BROADCAST = 0xffff; private const string UNIQUE_MUTEX_NAME = "{490D60C5-A51C-4c10-ADDE-47B4EECF9EE0}"; private static readonly int WM_MOVE_TO_TOP = RegisterWindowMessage("WM_MOVE_TO_TOP" + UNIQUE_MUTEX_NAME); [DllImport("user32")] private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32")] private static extern int RegisterWindowMessage(string message); #endregion public void EnforceSingleApplicationInstance() { bool isOwned; _mutex = new Mutex(true, UNIQUE_MUTEX_NAME, out isOwned); if (isOwned) return; //Broadcast to all open windows the custom move to top command //(Will be ignored by any window that does not recongize it); PostMessage((IntPtr)HWND_BROADCAST, WM_MOVE_TO_TOP, IntPtr.Zero, IntPtr.Zero); Environment.Exit(0); } public void RegisterMainApplicationWindow(Window window) { //Hook into window message processing loop to watch for our custom message _mainApplicationWindow = window; var source = PresentationSource.FromVisual(window) as HwndSource; if (source != null) source.AddHook(HandleWindowsMessage); } private IntPtr HandleWindowsMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_MOVE_TO_TOP) MoveWindowToTopOfDesktop(); return IntPtr.Zero; } private void MoveWindowToTopOfDesktop() { if (_mainApplicationWindow.WindowState == WindowState.Minimized) { _mainApplicationWindow.WindowState = WindowState.Normal; } // get our current "TopMost" value var top = _mainApplicationWindow.Topmost; // make our form jump to the top of everything _mainApplicationWindow.Topmost = true; // set it back to whatever it was _mainApplicationWindow.Topmost = top; } public void Dispose() { if(_isDisposed) return; _isDisposed = true; if(_mutex != null) _mutex.ReleaseMutex(); } } } |
With this class in place, you can a create a non-reentrant WPF application like so:
[System.STAThreadAttribute()] static void Main() { using(var sieu = new SingleInstanceEnforcementUtility()) { sieu.EnforceSingleApplicationInstance(); var app = new MyApplication(); app.InitializeComponent(); sieu.RegisterMainApplicationWindow(app.MainWindow); app.Run(); } } |
You will probably also want to change the UNIQUE_MUTEX_NAME, just in case you application ever gets installed on the same machine as mine! 🙂
Happy coding!
–Ken
June 11th, 2010 at 5:47 pm
In doing some research while writing this post, I came across the below implementation which avoids the native API calls by using RPC remoting! It then turns around and uses other native calls to get the command line arguments passed to the second instance so it can pass them on to the first instance. In any case, it seems like it may be a more robust solution so have a look.
http://blogs.microsoft.co.il/blogs/arik/archive/2010/05/28/wpf-single-instance-application.aspx
September 18th, 2012 at 7:40 am
Hi,
Really useful code.
I tried with the sample WPF Windows application. This code work fine with only one instances. When i try to run the second instance, its not bringing the first instance window on TOP of all window.
It will be great if you have some sample applications.
Thanks in advance.