77

Possible Duplicate:
What is the correct way to create a single instance application?

How to force C# .net app to run only one instance in Windows?

Community
  • 1
  • 1
jinsungy
  • 10,717
  • 24
  • 71
  • 79

4 Answers4

122

I prefer a mutex solution similar to the following. As this way it re-focuses on the app if it is already loaded

using System.Threading;

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
   bool createdNew = true;
   using (Mutex mutex = new Mutex(true, "MyApplicationName", out createdNew))
   {
      if (createdNew)
      {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
         Application.Run(new MainForm());
      }
      else
      {
         Process current = Process.GetCurrentProcess();
         foreach (Process process in Process.GetProcessesByName(current.ProcessName))
         {
            if (process.Id != current.Id)
            {
               SetForegroundWindow(process.MainWindowHandle);
               break;
            }
         }
      }
   }
}
Mark Lakata
  • 19,989
  • 5
  • 106
  • 123
Mitchel Sellers
  • 62,228
  • 14
  • 110
  • 173
  • 10
    Just a little FYI about using the MainWindowHandle property in this way (as I just discovered): "If the associated process does not have a main window, *the MainWindowHandle value is zero*. The value is *also zero* for processes that have been hidden, that is, processes that are not visible in the taskbar. This can be the case for processes that appear as icons in the notification area, at the far right of the taskbar." – Nick Spreitzer Jul 03 '10 at 01:36
  • Good answer. I like the usage of SetForegroundWindow over the accept answer (if you follow that link plus what the next one links to) which uses a broadcast message and forces the window to topmost -- that will not actually focus the window. This answer should, because the newly running process has rights to pass the focus to another process in most cases. – eselk May 07 '12 at 20:40
  • 3
    SetForegroundWindow isn't working for me. Never has worked, actually. – jay_t55 Jun 18 '13 at 10:12
  • Works great. A question though; should `"MyApplicationName"` be the name of the assembly, or the solution/project, or the GUI window title? It seems to work either way (works with `"MyApplicationName"` too). – user1021726 Mar 27 '14 at 09:09
  • 1
    @user1021726 "MyApplicationName" should be anything unique to you. I'd suggest something meaningful followed by a GUID. – davidm_uk May 20 '14 at 08:31
  • 4
    If your application can be minimized, you may also want to make a call to `ShowWindow( process.MainWindowHandle, SW_RESTORE )` to restore it. http://stackoverflow.com/questions/4566632/maximize-another-process-window-in-net gives details. SW_RESTORE is 9 (from http://msdn.microsoft.com/en-gb/library/windows/desktop/ms633548%28v=vs.85%29.aspx). – davidm_uk May 20 '14 at 08:33
  • Better solution is to use Windows Events for this purpose: stackoverflow.com/a/646500/296924 – Thracx Feb 03 '15 at 20:18
  • SetForegroundWindow() isn't sufficient -- [this answer](http://stackoverflow.com/a/34414846/603828) gives the necessary magic song-and-dance to bring a window to the foreground. – ulatekh Aug 03 '16 at 16:16
  • This is nice for a [WPF application](https://www.codeproject.com/Articles/84270/WPF-Single-Instance-Application "WPF") – Alexander May 25 '17 at 17:57
  • Will this throw an exception if the user isn't an administrator? – newbieguy Dec 08 '19 at 03:02
33

to force running only one instace of a program in .net (C#) use this code in program.cs file:

public static Process PriorProcess()
    // Returns a System.Diagnostics.Process pointing to
    // a pre-existing process with the same name as the
    // current one, if any; or null if the current process
    // is unique.
    {
        Process curr = Process.GetCurrentProcess();
        Process[] procs = Process.GetProcessesByName(curr.ProcessName);
        foreach (Process p in procs)
        {
            if ((p.Id != curr.Id) &&
                (p.MainModule.FileName == curr.MainModule.FileName))
                return p;
        }
        return null;
    }

and the folowing:

[STAThread]
    static void Main()
    {
        if (PriorProcess() != null)
        {

            MessageBox.Show("Another instance of the app is already running.");
            return;
        }
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form());
    }
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
snir
  • 2,961
  • 1
  • 17
  • 10
  • 5
    This is incorrect way. I could run your program in two instances -- one launched as binary, second from VS. – greenoldman Aug 13 '11 at 14:11
  • 14
    Ok, @greenoldman, but since when do users/customers "debug" your apps and then choose to run a second one (binary) alongside it. This answer is pretty good compared to many of the Mutex-based anwsers I've seen on this website. – jay_t55 Jun 18 '13 at 09:55
  • 7
    I know this is years later but in case anyone finds this like I did: If the user isn't an administrator (at least in Win7) `Process.GetProcessesByName` will throw an exception. – George T Sep 17 '14 at 12:39
  • To make sure you don;t get 2 instances, make sure put Application.Exit() before return. – S Nash Jul 31 '23 at 21:46
10

This is what I use in my application:

static void Main()
{
  bool mutexCreated = false;
  System.Threading.Mutex mutex = new System.Threading.Mutex( true, @"Local\slimCODE.slimKEYS.exe", out mutexCreated );

  if( !mutexCreated )
  {
    if( MessageBox.Show(
      "slimKEYS is already running. Hotkeys cannot be shared between different instances. Are you sure you wish to run this second instance?",
      "slimKEYS already running",
      MessageBoxButtons.YesNo,
      MessageBoxIcon.Question ) != DialogResult.Yes )
    {
      mutex.Close();
      return;
    }
  }

  // The usual stuff with Application.Run()

  mutex.Close();
}
Martin Plante
  • 4,553
  • 3
  • 33
  • 45
2

another way to single instance an application is to check their hash sums. after messing around with mutex (didn't work as i want) i got it working this way:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetForegroundWindow(IntPtr hWnd);

    public Main()
    {
        InitializeComponent();

        Process current = Process.GetCurrentProcess();
        string currentmd5 = md5hash(current.MainModule.FileName);
        Process[] processlist = Process.GetProcesses();
        foreach (Process process in processlist)
        {
            if (process.Id != current.Id)
            {
                try
                {
                    if (currentmd5 == md5hash(process.MainModule.FileName))
                    {
                        SetForegroundWindow(process.MainWindowHandle);
                        Environment.Exit(0);
                    }
                }
                catch (/* your exception */) { /* your exception goes here */ }
            }
        }
    }

    private string md5hash(string file)
    {
        string check;
        using (FileStream FileCheck = File.OpenRead(file))
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] md5Hash = md5.ComputeHash(FileCheck);
            check = BitConverter.ToString(md5Hash).Replace("-", "").ToLower();
        }

        return check;
    }

it checks only md5 sums by process id.

if an instance of this application was found, it focuses the running application and exit itself.

you can rename it or do what you want with your file. it wont open twice if the md5 hash is the same.

may someone has suggestions to it? i know it is answered, but maybe someone is looking for a mutex alternative.

Thyrador
  • 121
  • 1
  • 11