27

I have a console application in C# in which I run various arcane automation tasks. I am well aware that this should really be a Windows Service since it needs to run continuously, but I don't want to do that at this time. (So, don't suggest that as an answer).

In the meantime, I need some sample C# code that will allow me to determine if there's already an instance of the Application running.

In the old VB6.0 days, I would have used App.PrevInstance()

I want to be able to do this in my Main method:

static void Main()
{
  if(!MyApp.IsAlreadyRunning())
  {
    while(true)
    {
      RockAndRollAllNightAndPartyEveryDay();
    }
  }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jose Basilio
  • 50,714
  • 13
  • 121
  • 117

10 Answers10

28

The proper way to use a mutex for this purpose:

private static Mutex mutex;

static void Main()
{
    // STEP 1: Create and/or check mutex existence in a race-free way
    bool created;
    mutex = new Mutex(false, "YourAppName-{add-your-random-chars}", out created);
    if (!created)
    {
        MessageBox.Show("Another instance of this application is already running");
        return;
    }

    // STEP 2: Run whatever the app needs to do
    Application.Run(new Form1());

    // No need to release the mutex because it was never acquired
}

The above won't work for detecting if several users on the same machine are running the app under different user accounts. A similar case is where a process can run both under the service host and standalone. To make these work, create the mutex as follows:

        var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
        var mutexsecurity = new MutexSecurity();
        mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow));
        mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.ChangePermissions, AccessControlType.Deny));
        mutexsecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.Delete, AccessControlType.Deny));
        _mutex = new Mutex(false, "Global\\YourAppName-{add-your-random-chars}", out created, mutexsecurity);

Two differences here - firstly, the mutex needs to be created with security rights that allow other user accounts to open/acquire it. Second, the name must be prefixed with "Global" in the case of services running under the service host (not sure about other users running locally on the same machine).

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • It is not clear from the original question if "previous instance" means in this session, for this user or on this machine. Mutex names are default per session so a solution per machine should use a name like @"Global\YourAppName-{add-your-random-chars}" http://msdn.microsoft.com/en-us/library/aa382954%28VS.85%29.aspx – adrianm Mar 10 '10 at 10:57
  • http://stackoverflow.com/questions/2415984/is-it-a-good-idea-to-use-the-existence-of-a-named-mutex-as-an-indicator - my question to discuss whether it is appropriate to simply check the mutex's existence without acquiring it. – Roman Starkov Mar 11 '10 at 15:13
  • @romkyns: could you explain why the result of creating "Global\" mutex depends on the session where the application runs? The scenario: **1**. User A calls new Mutex(true, "Global\xxx", out created). *created* is TRUE on return **2**. User B in the SAME session calls new Mutex(true, "Global\xxx", out created). The call succeeds, and *created* is FALSE on return **3**. User B in a DIFFERENT session (switch user) calls new Mutex(true, "Global\xxx", out created). The result is an Exception 'Access to the path "Global\xxx" is denied' Why the result of (2) differs from (3) ? – mistika May 21 '13 at 19:13
  • @mistika I guess it's to make it possible for you to create a mutex that other users cannot take. That might be useful if you don't fully trust those users. – Roman Starkov May 21 '13 at 19:19
  • @romkyns: still don't understand. Let's suppose user A doesn't trust user B. Why user B doesn't get AccessDenied if it calls CreateMutex in the same session where user A runs? I don't see reasons why user A should trust user B's process when it runs in the same session as user A's one? – mistika May 21 '13 at 19:46
  • @mistika I see what you mean now. I don't know the answer to that; I suggest you post that as a question here. – Roman Starkov May 21 '13 at 21:11
16

Jeroen already answered this, but the best way by far is to use a Mutex... not by Process. Here's a fuller answer with code.

I've updated this answer after seeing some comments about a race condition to address that by instead using the Mutex Constructor

Boolean createdNew;
Mutex mutex;

try
{      
   mutex = new Mutex(false, "SINGLEINSTANCE" out createdNew);
   if (createdNew == false)
   {
      Console.WriteLine("Error : Only 1 instance of this application can run at a time");
      Application.Exit();
   }

   // Run your application
}
catch (Exception e)
{
    // Unable to open the mutex for various reasons
}
finally 
{
    // If this instance created the mutex, ensure that
    // it's cleaned up, otherwise we can't restart the
    // application
    if (mutex && createdNew) 
    {
        mutex.ReleaseMutex();
        mutex.Dispose();
    }
}

Notice the try{} finally{} block. If you're application crashes or exits cleanly but you don't release the Mutex then you may not be able to restart it again later.

Ian
  • 33,605
  • 26
  • 118
  • 198
  • My understanding is that in NT based operating systems after a process terminates for any reason, all the kernal objects created by that process are released by the OS. Is that correct? – Jim In Texas Apr 23 '09 at 15:59
  • You can probably test it easily... Just found this. http://stackoverflow.com/questions/646480/is-using-a-mutex-to-prevent-multipule-instances-of-the-same-program-from-running/646500 – Ian Apr 23 '09 at 16:07
  • 4
    -1: there is a race condition in acquiring the mutex; see my alternative answer. Also, mentioning that "SINGLEINSTANCE" should be unique to the application is a must! – Roman Starkov Mar 10 '10 at 09:31
  • so you'd suggest wrapping the new Mutex in a try catch? As there isn't a way to synchronize across applications... – Ian Mar 10 '10 at 10:01
  • 1
    @Ian - what I'm suggesting is too long to post in a comment, which is why I posted an answer instead. Of course you can't use "lock" across processes, but you _can_ acquire the mutex and check its existence in one go, with no race conditions. – Roman Starkov Mar 10 '10 at 13:01
  • 1
    -1 This should not be the accepted answer, whether it is in a book or otherwise. It can lead to dangerous race conditions where multiple instances of your application end up successfully opening the same Mutex, which defeats the entire purpose of a global Mutex. – caesay Dec 07 '20 at 11:47
  • @caesay I've updated this answer to try and remove the race condition - as I don't want to be encouraging bad code. – Ian Dec 11 '20 at 08:56
4

The most simple (and reliable) way to do this, is using a Mutex. Use the WaitOne method of the Mutex class to wait until the mutex becomes available. An added advantage, this will not require any infinite loops

Jeroen Landheer
  • 9,160
  • 2
  • 36
  • 43
2

You can search process names of existing system process. For example code, see this blog post.

You can also used a named system Mutex to see if your process is already running.
Here is some sample code. This tends to be more reliable in my experience, and is much simpler, more understandable code.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
2

This article talks about it: Prevent a second process instance from running. It's in VB.net but you can convert it.

The problem in writing a generic function that checks whether the current application is already running comes from the fact that the ProcessName property of the Process object seems to be limited to 15 characters, so longer process names are truncated.
A safer way to retrieve a process name is to get the filename of its main module and dropping the extension. The following reusable routine uses this approach:

Function AppIsAlreadyRunning() As Boolean
    ' get the filename of the main module
    Dim moduleName As String = Process.GetCurrentProcess.MainModule.ModuleName

    ' discard the extension to get the process name
    Dim procName As String = System.IO.Path.GetFileNameWithoutExtension(moduleName)

    ' return true if there are 2 or more processes with that name
    If Process.GetProcessesByName(procName).Length > 1 Then
        Return True
    End If
End Function
Ron
  • 1,786
  • 19
  • 20
2
    // Allow running single instance
    string processName = Process.GetCurrentProcess().ProcessName;
    Process[] instances = Process.GetProcessesByName(processName);

    if (instances.Length > 1)
    {
        MessageBox.Show("Application already Running", "Error 1001 - Application Running");
        return;
    }

Gracefully exit application with messagebox as shown above if application is already running

Suneet
  • 165
  • 4
1

You can use Process.GetProcessesByName("MyProcessName"); in the System.Diagnostics namespace to check if there is an instance of your process running.

EDIT: Very good observations in the comments! This is a (very) simplistic way of doing it, and certainly doesn't cover all the bases.

Andy Mikula
  • 16,796
  • 4
  • 32
  • 39
  • From the article in my comment... The problem in writing a generic function that checks whether the current application is already running comes from the fact that the ProcessName property of the Process object seems to be limited to 15 characters, so longer process names are truncated. For example, create the default ConsoleApplication1 application and run this code: – Ron Apr 22 '09 at 19:48
  • This also returns the current process, so make sure to filter out your current Process's ID from this list as well (or check to make sure the returned array's length is >1, not >0) – Reed Copsey Apr 22 '09 at 19:49
  • 1
    This doesn't work if two copies of the application exist and one has been renamed. – Murray Apr 22 '09 at 19:55
1

Using a kernal object is the only correct way to implement single instance protection in Windows.

This statement:

mutex = Mutex.OpenExisting("SINGLEINSTANCE");

won't work if someone else copies this line from Stackoverflow and runs their program before your program, since that other guy grabbed "SINGLEINSTANCE" before you did. You want to include a GUID in your mutex name:

mutex = Mutex.OpenExisting("MyApp{AD52DAF0-C3CF-4cc7-9EDD-03812F82557E}");

This technique will prevent the current user from running more than one instance of your program, but will not prevent another user from doing so.

To ensure that only one instance of your application can run on the local computer, you need to do this:

mutex = Mutex.OpenExisting("Global\MyApp{AD52DAF0-C3CF-4cc7-9EDD-03812F82557E}");

See the help for the CreateMutex api.

Jim In Texas
  • 1,524
  • 4
  • 20
  • 31
0

In one of my projects I used SingleInstance Component

Mahtar
  • 1,901
  • 1
  • 18
  • 17
-3

Another way to do it is to bind to an address on the local machine (as a TCP listener would). Only one process at a time can bind to a port/address combination. So pick a port on the loopback adapter and have at it.

This has the nice side-effects of:

  • Working even if someone renames the executable
  • Resetting itself when the application crashes
  • The technique is portable across other operating systems

On the down-side, it can fail if there's another application that binds to that particular port.


As requested, some code to bind to a address/port is below. This is ripped out of something else. It is incomplete, but the necessary bits are here.

using System.Net;
using System.Net.Sockets;

[...]

// Make up a number that's currently unused by you, or any 
// well-known service. i.e. 80 for http, 22 for ssh, etc..
int portNum = 2001;  

// This binds to any (meaning all) adapters on this system 
IPAddress ipAddress = IPAddress.Any;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, portNum);
Socket listener = new Socket(AddressFamily.InterNetwork,
    SocketType.Stream, ProtocolType.Tcp );

// The next statement will throw an exception if anyone has done this Bind!
listener.Bind(localEndPoint);

As long as listener is not garbage collected (falls out of scope) or the program doesn't terminate: that port on that adapter is yours and only yours. If anything should happen to listener then it becomes available for someone else to use. For purposes of a lock, you should probably have listener be static somewhere.

Clinton Pierce
  • 12,859
  • 15
  • 62
  • 90
  • Do you have any sample code on how to do this? Also, What do you mean by "Resetting itself when the application crashes"? – Jose Basilio Apr 22 '09 at 20:51
  • 3
    This techinque is pretty fragile, the mutex technique is much better. – Jim In Texas Apr 23 '09 at 15:26
  • 2
    Would be pretty annoying if an app I installed on my machine failed to run just because I had configured VNC to listen on that port (which I do for various reasons). I suspect this might also trigger firewall prompts. Please use the mutex approach instead. – Roman Starkov Jul 31 '10 at 00:01