0

I am trying to use a Mutex to only allow one instance of my program to be run at a time. I reused the Mutex code from another program I was writing, only to find out that it did not stop two instances of my program from being run at once. However, my Mutex code worked in my other program. Below is the entire code of Program.cs (the code for opening files is unrelated). May you please explain how I should properly use the Mutex to prevent multiple instances of my program from being run at once? Thanks!

Note: my original code was based on this SO answer: https://stackoverflow.com/a/819808/12946280

using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace NTCSAttendanceKiosk
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            // Make a mutex and detect if another instance of the program is running
            Mutex mutex = new Mutex(true, "AtteNTCSKioskMutex", out bool mutexResult);

            if (!mutexResult)
            {
                // Exit if it's already running
                return;
            }

            // Prevent the mutex from being released by the GC
            GC.KeepAlive(mutex);

            // Read the connection string from the file
            try
            {
                SqlConnectionInfo.ConnectionString = File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\kiosk_config\\connection_string.txt");
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show("The file connection_string.txt does not exist. Please place the connection string in that file and place it in <your user folder>\\kiosk_config\\. The kiosk program will now exit.", "Connection String File Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            catch (IOException)
            {
                MessageBox.Show("File I/O error when loading connection_string.txt. The kiosk program will now exit.", "File I/O Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Read the kiosk location name from the file
            try
            {
                SqlConnectionInfo.KioskLocation = File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\kiosk_config\\location.txt");
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show("The file location.txt does not exist. Please place the kiosk location name in that file and place it in <your user folder>\\kiosk_config\\. The kiosk program will now exit.", "Connection String File Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            catch (IOException)
            {
                MessageBox.Show("File I/O error when loading location.txt. The kiosk program will now exit.", "File I/O Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Application.Run(new KioskForm());
        }
    }
}
Felix An
  • 309
  • 4
  • 13

1 Answers1

1

You can test the below code by running several instances simultaneously.

static void Main(string[] args)
{
    using (var mutex = new Mutex(true, "UniqueSystemWideMutexName"))
    {
        //Timeout is set to zero so we don't block
        if (!mutex.WaitOne(0))
        {
            Console.WriteLine("Program already running");
            Console.ReadKey();
            return;
        }
        Console.WriteLine("This is the only program running");
        Console.ReadKey();
    }
}

If you can't use Dispose for whatever reason, which the using block does for us, be sure to call ReleaseMutex.

You can also use OpenExisting to check if the mutex has already been created, but it's not necessary for this simple use case.

Zer0
  • 7,191
  • 1
  • 20
  • 34