Click here to Skip to main content
15,895,557 members
Articles / Programming Languages / C# 3.5

Single Instance Application in C#

Rate me:
Please Sign up or sign in to vote.
4.87/5 (122 votes)
12 Dec 2004CPOL1 min read 585.8K   20K   131   131
An article demonstrating how to run a single instance of an application and activate previous one if already running.

Sample screenshot

Introduction

Single-instance an application means enabling the application to recognize, at startup, if another running instance of itself is already running, In this case, the new application stops its execution. Generally, for a form based application, the new instance activates (brings the application window to foreground) the previous instance, if its already running.

Using the code

To make a single instance application, add file SingleApplication.cs in your project. It adds a new class SingleApplication defined in namespace SingleInstance and adds the following code for a form based application to your startup code:

C#
static void Main() 
{
   SingleInstance.SingleApplication.Run(new FrmMain());
}

FrmMain is the main form class name. The Run method returns false if any other instance of the application is already running. For a console based application, call Run( ) without any parameter and check the return value, if it is true you can execute your application.

Using with console application:

C#
static void Main() 
{
   if(SingleInstance.SingleApplication.Run() == false)
   {
      return;
   }
   //Write your program logic here
}

History

  • June 29, 2003 - Initial release of article.
  • July 1, 2003 - Mutex support added.
  • December 11, 2004 - Improved performance on the basis of user feedback, special thanks to Mach005.
  • June 07. 2018 - Uploaded VS2015 project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Oracle
India India
Working with Oracle. Using C/C++, VC++, MFC, STL, C#, Java etc. on various platform like Windows, Unix, Macintosh etc. from last 13+ years to convert various type of requirements into running software components. My core expertise is multithreaded desktop product and large scale enterprises software development.

Comments and Discussions

 
GeneralRe: Room for improvement Pin
Anubhava Dimri5-Jun-09 19:42
Anubhava Dimri5-Jun-09 19:42 
GeneralRe: Room for improvement Pin
Manish K. Agarwal7-Jun-09 17:59
Manish K. Agarwal7-Jun-09 17:59 
GeneralRe: Room for improvement Pin
Anubhava Dimri7-Jun-09 18:14
Anubhava Dimri7-Jun-09 18:14 
GeneralRe: Room for improvement Pin
Manish K. Agarwal9-Jun-09 18:10
Manish K. Agarwal9-Jun-09 18:10 
GeneralRe: Room for improvement Pin
Anubhava Dimri9-Jun-09 18:30
Anubhava Dimri9-Jun-09 18:30 
GeneralSome comments Pin
Mach0052-Apr-04 1:33
Mach0052-Apr-04 1:33 
GeneralRe: Some comments Pin
Manish K. Agarwal2-Apr-04 3:24
Manish K. Agarwal2-Apr-04 3:24 
GeneralRe: Some comments Pin
Mach0054-Apr-04 23:12
Mach0054-Apr-04 23:12 
Hi,

Here is the class I created and use that is based on your code.

It caters for global or local single instance apps, as well as specifying your own optional application name to lock on, which could be a guid or whatever, or allowing it to automatically generate one from a guid and the full entry assembly name if not specified.

There are several Run overloads for different configurations. All three parameters are optional.

It also switches to the existing application in a slightly different way, without losing the maximise window state, which happens if you restore the window every time. It first checks if the app is minimised before restoring.

Also, to ensure that the window is forced to the foreground under almost all circustances, it attaches the thread input of our thread to that of the application we switching to before doing the switch.

Example use:

To create a global single instance application. That is only, one instance across all user sessions. That is, only one instance on the machine.

<br />
	[STAThread]<br />
	static void Main() <br />
	{<br />
		SingletonApplication.Run(new Form1(), true);<br />
	}<br />


To create a per user single instance application. This works with terminal services, XP sessions and Citrix.

<br />
	[STAThread]<br />
	static void Main() <br />
	{<br />
		SingletonApplication.Run(new Form1());<br />
	}<br />


The class:

C#
/*    
 *  File: SingletonApplication.cs    
 *     
 */    
    
using System;    
using System.Diagnostics;    
using System.Reflection;    
using System.Runtime.InteropServices;    
using System.Threading;    
using System.Windows.Forms;    
    
namespace CompanyName.Win32.Util    
{    
    #region SingletonApplication    
    
    public sealed class SingletonApplication    
    {    
        #region Public Members    
    
        #region Run    
    
        public static bool Run(string name, System.Windows.Forms.Form form, bool global)    
        {    
            if (InternalIsRunning(name, global))    
            {    
                SwitchToCurrentInstance();    
                return false;    
            }    
            Application.Run(form);    
            return true;    
        }    
    
        public static bool Run(string name, System.Windows.Forms.Form form)    
        {    
            return Run(name, form, false);    
        }    
    
        public static bool Run(System.Windows.Forms.Form form, bool global)    
        {    
            return Run(GetApplicationName(), form, global);    
        }    
    
        public static bool Run(System.Windows.Forms.Form form)    
        {    
            return Run(GetApplicationName(), form, false);    
        }    
    
        public static bool Run(string name, bool global)    
        {    
            return !InternalIsRunning(name, global);    
        }    
    
        public static bool Run(string name)    
        {    
            return Run(name, false);    
        }    
    
        public static bool Run(bool global)    
        {    
            return Run(GetApplicationName(), global);    
        }    
    
        public static bool Run()    
        {    
            return Run(GetApplicationName(), false);    
        }    
    
        #endregion    
    
        #region IsRunning    
    
        public static bool IsRunning(string name, bool global)    
        {    
            // Create temporary mutex to test if application matching    
            // specified parameters is currently running.    
            bool createdNew;    
            Mutex _mutex = new Mutex(true, GetMutexName(name, global), out createdNew);    
            if (createdNew)    
                _mutex.ReleaseMutex();    
            return !createdNew;    
        }    
    
        public static bool IsRunning(string name)    
        {    
            return IsRunning(name, false);    
        }    
    
        public static bool IsRunning(bool global)    
        {    
            return IsRunning(GetApplicationName(), global);    
        }    
    
        public static bool IsRunning()    
        {    
            return IsRunning(GetApplicationName(), false);    
        }    
    
        #endregion    
    
        #region GetApplicationName    
    
        public static string GetApplicationName()    
        {    
            // Attempt to gaurantee a unique name, by using a static guid as well as the    
            // full name of the entry assembly with version info, culture info and public    
            // key token. Using the entry assembly, rather than the executing assembly    
            // allows this class to be packaged in another assembly.    
            return string.Format("a37e5577-a9c5-4837-ad17-288b9eb7b682, {0}",     
                Assembly.GetEntryAssembly().GetName().FullName);    
        }    
    
        #endregion    
    
        #endregion    
    
        #region Private Members    
    
        #region InternalIsRunning    
    
        private static bool InternalIsRunning(string name, bool global)    
        {    
            if (mutex == null)    
            {    
                mutex = new Mutex(true, GetMutexName(name, global));    
                // Mark the mutex as ineligable for garbage collection.    
                // Not technically necessary, since it is a static    
                // member, however, this may improve performace (unknown?)    
                // by elliminating unecessary checking of the member    
                // for garbage collection, since it must be alive as along    
                // as the application is alive.    
                GC.KeepAlive(mutex);    
            }    
            return !mutex.WaitOne(0, false);    
        }    
    
        #endregion    
    
        #region GetMutexName    
    
        private static string GetMutexName(string name, bool global)    
        {    
            // Create valid mutex name. Replace all "\" with "_".    
            // Add Global or Local prefix.    
            return string.Format(@"{0}\{1}",     
                global ? "Global" : "Local", name.Replace(@"\", "_"));    
        }    
    
        #endregion    
    
        #region SwitchToCurrentInstance    
    
        private static void SwitchToCurrentInstance()    
        {    
            IntPtr hWnd = GetCurrentInstanceWindowHandle();    
            if (hWnd != IntPtr.Zero)    
            {    
                // get current foreground window    
                IntPtr _hWnd = GetForegroundWindow();    
    
                // Restore window if minimised. Do not restore if already in    
                // normal or maximised window state, since we don't want to    
                // change the current state of the window.    
                if (IsIconic(hWnd) != 0)    
                    ShowWindow(hWnd, SW_RESTORE);    
    
                // Set foreground window. Attach thread input to ensure we can    
                // force the window to the foreground.    
                int hThread = GetWindowThreadProcessId(hWnd, IntPtr.Zero);    
                int _hThread = GetWindowThreadProcessId(_hWnd, IntPtr.Zero);    
            
                if (hThread != _hThread)    
                {    
                    AttachThreadInput(_hThread, hThread, 1);    
                    SetForegroundWindow(hWnd);    
                    AttachThreadInput(_hThread, hThread, 0);    
                }    
                else    
                    SetForegroundWindow(hWnd);    
            }    
        }    
    
        #endregion    
    
        #region GetCurrentInstanceWindowHandle    
    
        private static IntPtr GetCurrentInstanceWindowHandle()    
        {    
            IntPtr hWnd = IntPtr.Zero;    
            Process process = Process.GetCurrentProcess();    
            Process[] processes = Process.GetProcessesByName(process.ProcessName);    
            foreach(Process _process in processes)    
            {    
                // Get the first instance that is not this instance, has the    
                // same process name and was started from the same file name    
                // and location. Also check that the process has a valid     
                // window handle in this session to filter out other user's    
                // processes.    
                if (_process.Id != process.Id &&    
                    _process.MainModule.FileName == process.MainModule.FileName &&    
                    _process.MainWindowHandle != IntPtr.Zero)    
                {    
                    hWnd = _process.MainWindowHandle;    
                    break;    
                }    
            }        
            return hWnd;    
        }    
    
        #endregion    
    
        #region API Imports    
    
        [DllImport("user32.dll")]    
        private static extern int ShowWindow(IntPtr hWnd, int nCmdShow);    
    
        [DllImport("user32.dll")]    
        private static extern int SetForegroundWindow(IntPtr hWnd);    
    
        [DllImport("user32.dll")]    
        private static extern IntPtr GetForegroundWindow();    
    
        [DllImport("user32.dll")]    
        private static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);    
    
        [DllImport("user32.dll")]    
        private static extern int IsIconic(IntPtr hWnd);    
    
        [DllImport("user32.dll")]    
        private static extern int AttachThreadInput(int idAttach, int idAttachTo, int fAttach);    
    
        #endregion    
    
        #region Constructor    
    
        // Instances of this class cannot be constructed.    
        private SingletonApplication()    
        {}    
    
        #endregion    
    
        private const int SW_RESTORE = 9;    
        private static Mutex mutex;    
    
        #endregion    
    }    
    
    #endregion    
}    

GeneralRe: Some comments Pin
szabelin10-May-04 7:45
szabelin10-May-04 7:45 
GeneralRe: Vast Improvement Pin
laduran16-Dec-05 6:56
laduran16-Dec-05 6:56 
GeneralRe: Vast Improvement Pin
Mach00517-Dec-05 20:55
Mach00517-Dec-05 20:55 
QuestionRe: Vast Improvement Pin
popoli1-Jan-06 21:51
popoli1-Jan-06 21:51 
QuestionRe: Vast Improvement Pin
JoeKau14-Mar-06 2:10
JoeKau14-Mar-06 2:10 
GeneralRe: Vast Improvement Pin
Dave Midgley1-Nov-06 22:01
Dave Midgley1-Nov-06 22:01 
QuestionRe: Some comments Pin
striker776-Jan-06 8:29
striker776-Jan-06 8:29 
GeneralAbsolutely Superb !!!!!! Pin
Maharishi Bhatia30-Jan-04 4:30
Maharishi Bhatia30-Jan-04 4:30 
Generalpb with notifyicon Pin
jcmag30-Jun-03 23:03
jcmag30-Jun-03 23:03 
GeneralRe: pb with notifyicon Pin
Manish K. Agarwal1-Jul-03 0:23
Manish K. Agarwal1-Jul-03 0:23 
GeneralRe: pb with notifyicon Pin
jcmag1-Jul-03 0:36
jcmag1-Jul-03 0:36 
GeneralRe: pb with notifyicon Pin
Manish K. Agarwal1-Jul-03 1:17
Manish K. Agarwal1-Jul-03 1:17 
GeneralRe: pb with notifyicon Pin
Frode N. Rosand12-Jul-03 16:39
Frode N. Rosand12-Jul-03 16:39 
GeneralRe: pb with notifyicon Pin
Manish K. Agarwal12-Jul-03 23:27
Manish K. Agarwal12-Jul-03 23:27 
GeneralRe: pb with notifyicon Pin
Mach0055-Apr-04 0:34
Mach0055-Apr-04 0:34 
GeneralRe: pb with notifyicon Pin
bschubarg30-Mar-06 9:08
bschubarg30-Mar-06 9:08 
GeneralI rated the article a 4, but... Pin
kbuchan30-Jun-03 4:38
kbuchan30-Jun-03 4:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.