1

I am trying to make it so that if another instance of my program is running, it should close down the instance that's already running and start the new instance. I currently tried this:

[STAThread]
static void Main()
{
    Mutex mutex = new System.Threading.Mutex(false, "supercooluniquemutex");
    try
    {
        if (mutex.WaitOne(0, false))
        {
            // Run the application
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new fMain());
        }
        else
        {
            foreach (Process proc in Process.GetProcesses())
            {
                if (proc.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && proc.Id != Process.GetCurrentProcess().Id)
                {
                    proc.Kill();
                    break;
                }
            }
            // Run the application
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new fMain());
        }
    }
    finally
    {
        if (mutex != null)
        {
            mutex.Close();
            mutex = null;
        }
    }
}

But for some reason it doesn't kill the already running instance, it just kills itself most of the time and sometimes it doesn't do anything at all.

What do I do to get this to work?

EDIT: I know the usual way of doing it is showing a message that the application is already running, but in this application it is vital that it kills the old process instead of showing a message.

Dysanix Official
  • 842
  • 1
  • 10
  • 18
  • So are you saying that when you're debugging and it hits the `proc.Kill();` statement, it doesn't result in the process being killed? – rory.ap Mar 01 '17 at 13:29
  • 2
    I would think you would just not want to start the new instance instead of pulling the rug from under an already executing instance. You could show a message to the user and then close down to make it clear that it can't be started.... Unless you just do not care about what that other app instance is doing (saving something to a store, serving some request, user doing something, etc). Think also about possible terminal server implications... (server that hosts multiple simultaneous logons). – Igor Mar 01 '17 at 13:30
  • 2
    You do realise that the *common* pattern for this is for the new instance to close in favour of the old (having transferred any parameters/brought the old one to the front). It would be deeply surprising for users for yours to act the other way. – Damien_The_Unbeliever Mar 01 '17 at 13:32
  • I agree with Igor. Id rather show an error "Process is already running" and exit rather than kill the existing process. Im also not sure why you have a Mutex there. However your current code should work. Let me try it out. – CathalMF Mar 01 '17 at 13:36
  • I know, that's the usual way of doing it, but my application's intentions require it so that it gets reversed (the new one has to kill the old one) – Dysanix Official Mar 01 '17 at 13:40
  • @CathalMF - one issue with the current code is, if it decides to go on its process killing spree, it doesn't then claim the mutex for itself - so the next instance that runs will find a claimable mutex. – Damien_The_Unbeliever Mar 01 '17 at 13:40
  • @Damien_The_Unbeliever -- This isn't an inter-process mutex... – rory.ap Mar 01 '17 at 13:42
  • @Damien_The_Unbeliever Yes it is. – CathalMF Mar 01 '17 at 13:43
  • @rory.ap it doesn't make sense to edit away my comment that makes my intentions clearer to new visitors. Rolled back. – Dysanix Official Mar 01 '17 at 13:44
  • Does your application start another application? – Chibueze Opata Mar 01 '17 at 13:57
  • It's also impossible that your application will kill itself with this. So something is missing – Chibueze Opata Mar 01 '17 at 14:01

1 Answers1

2

First of all you need to wait for mutex again after killing the previous process. When you that you will get AbandonedMutexException. For details of that please check this link I am assuming it is OK to continue after that exception.

You can try .

Mutex mutex = new System.Threading.Mutex(false, "supercooluniquemutex");
        try
        {
            bool tryAgain = true;
            while (tryAgain)
            {
                bool result = false;
                try
                {
                    result = mutex.WaitOne(0, false);
                }
                catch (AbandonedMutexException ex)
                {
                    // No action required
                    result = true;
                }
                if (result)
                {
                    // Run the application
                    tryAgain = false;
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new fMain());
                }
                else
                {
                    foreach (Process proc in Process.GetProcesses())
                    {
                        if (proc.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && proc.Id != Process.GetCurrentProcess().Id)
                        {
                            proc.Kill();
                            break;
                        }
                    }
                    // Wait for process to close
                    Thread.Sleep(2000);
                }
            }
        }
        finally
        {
            if (mutex != null)
            {
                mutex.Close();
                mutex = null;
            }
        }

In that example if I get AbandonedMutexException, I get ownership of the mutext and it is ok to continue.

Also, you use local Mutex, another user can run same application under another Terminal server session. MSDN says

On a server that is running Terminal Services, a named system mutex can have two levels of visibility. If its name begins with the prefix "Global\", the mutex is visible in all terminal server sessions. If its name begins with the prefix "Local\", the mutex is visible only in the terminal server session where it was created. In that case, a separate mutex with the same name can exist in each of the other terminal server sessions on the server. If you do not specify a prefix when you create a named mutex, it takes the prefix "Local\". Within a terminal server session, two mutexes whose names differ only by their prefixes are separate mutexes, and both are visible to all processes in the terminal server session. That is, the prefix names "Global\" and "Local\" describe the scope of the mutex name relative to terminal server sessions, not relative to processes.

Community
  • 1
  • 1
fofik
  • 998
  • 11
  • 17
  • Omg this actually works! However, there is one single problem left.. if someone renames the executable, it would still run 2 instances. How do I counter that? Thank you very much for the answer so far, though! – Dysanix Official Mar 01 '17 at 14:14
  • It will not run, it will try to find and kill the old process but would not find that with the same name. (There should be some limit maybe - Check all processes just for once.) Form will not be shown until mutex acquired. – fofik Mar 01 '17 at 14:21