0

Requirement:

A. 1 user login can open 0-1 System.Windows.Form instances on 1 physical machine in ProcessName.
B. 2 different user logins are each able to open 0-1 System.Windows.Form instances on 1 physical machine in ProcessName.
C. MutexChecker is in its own class rather than a member of Form because the responsibility for disposing of the Mutex changes from one form to a different form based on user actions.
D. Said Form's are launched asynchrously after the creation of the Mutex. So I cannot implement a using statement.

Problem:

On other SO posts, I've seen code similar to the below labeled as "unsafe". However, the reasons for the code being labeled "unsafe" are not given. Rather, a global mutex is offered as the solution. A global mutex works machine-wide, therefore it does not meet the requirement.

What I have tried:

Call mutexChecker.RunCheck() from said System.Windows.Form

public class MutexChecker:IDisposable
{
    private Mutex mutex;

    public bool RunCheck()
    {
        bool createdNew;
        mutex = new Mutex(initiallyOwned: true, name: "AppName", createdNew: out createdNew);

        if (!createdNew)
        {
            MessageBox.Show("AppName is already running.  Please complete the other note before opening a new window.");
        }

        return createdNew;
    }

    public void Dispose()
    {
        mutex.ReleaseMutex();//ERROR: safe handle has been disposed
        mutex.Dispose();//Does not always release the mutex for some unknown reason
    }

Dispose on the mutex during Form.Dispose.

Question

How can I safely create a mutex that fulfills the requirement?

Community
  • 1
  • 1
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • P Brian Mackey look at this stackoverflow post and see the Accepted Answer on this page you should be able to copy paste the working answer to fit your needs http://stackoverflow.com/questions/12340043/how-to-run-one-instance-of-a-c-sharp-winform-application – MethodMan Feb 06 '13 at 15:51
  • @DJKRAZE - I clarified the question. I don't believe that will work for reasons in the update. – P.Brian.Mackey Feb 06 '13 at 15:59
  • Is it a stupid suggestion to use (global) mutex, and make them pseudo-local by using the user id as part of the mutex name? This would make sure different user ids can open 0-1 instances on one physical machine. (Of course, you´d need an additional (global, and rightly so!) mutex or semaphore to make sure a maximum logged-in user count is not exceeded. – TheBlastOne Feb 06 '13 at 16:46
  • Just append the user name to the mutex name. Your code crashes when you dispose more than once, use a *disposed* variable. And don't call ReleaseMutex when you didn't acquire it. – Hans Passant Feb 06 '13 at 17:15

1 Answers1

0

In order to handle multiple forms dealing with disposal of my Mutex in an asynchronous fashion, I raise an event to designate the time of disposal. Otherwise, I just dump the unecessary mutex immediately after construction:

public class MutexChecker
{
    private Mutex mutex;
    private const string instanceName = "AppName";
    private bool createdNew = false;

    public bool RunCheck()
    {            
        mutex = new Mutex(initiallyOwned: true, name: instanceName, createdNew: out createdNew);

        if (createdNew)
        {
            HelperClass.shutdown += Dispose;
        }
        else
        {
            MessageBox.Show("AppName is already running.  Please complete the other note before opening a new window.");
            mutex.Dispose();//dump...I don't need this instance
        }

        return createdNew;
    }

    void Dispose()
    {
        HelperClass.shutdown -= Dispose;
        mutex.Dispose();        
    }
}
P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348