Using EventWaitHandle to ensure a single instance across multiple users

1.5k views Asked by At

Collaborators have built a prototype using Processing that connects to a Sparkfun RFID reader, I think using a serial connection over USB. We've deployed the prototype into a number of trialists' homes and one common usage scenario I foolishly overlooked was user switching. Hence I am writing a wrapper that ensures only one instance of the prototype application is running across all users on the machine.

I’m testing out my first stab at this as a simple console app. Here’s the code:

    static void Main(string[] args)
    {
        // http://stackoverflow.com/a/2590446/575530
        var users = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
        var rule = new EventWaitHandleAccessRule(users, EventWaitHandleRights.FullControl, AccessControlType.Allow);
        var security = new EventWaitHandleSecurity();
        security.AddAccessRule(rule);
        bool createdStartup;
        using (var whStartup = new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppStartupEvent", out createdStartup, security))
        {
            bool createdShutdown;
            using (var whShutdown = new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppShutdownEvent", out createdShutdown, security))
            {
                Console.WriteLine("Let other instances shutdown");
                whStartup.Set();
                Console.WriteLine("If other instances exist wait for them to shutdown");
                if (!createdShutdown)
                {
                    whShutdown.WaitOne();
                }
                whShutdown.Reset();
                Console.WriteLine("Start tray app");
                var tokenProc = Process.Start(@"C:\Temp\FAMILY3_WIN\TokensApp.exe");
                Console.WriteLine(tokenProc.ProcessName);
                Console.WriteLine("Wait to see if another instance to tries to start");
                whStartup.Reset();
                whStartup.WaitOne();
                Console.WriteLine("Shutdown if another instance starts");
                //if (tokenProc != null) tokenProc.Kill();
                foreach (var process in Process.GetProcesses())
                {
                    if (process.ProcessName.StartsWith("javaw"))
                    {
                        process.Kill();
                    }
                }
                whShutdown.Set();
            }
        }
        Console.WriteLine("Done...");
        Console.ReadLine();
    }

(N.B. I know there are issues with this code around (1) killing Java processes that are not the running prototype and (2) there’s no code to respond to lots of instances starting simultaneously, just two at a time. But that’s not what my question is about.)

Testing this under a single user account works fine. I can start my app, it in turn starts the prototype, and if I start a second instance of my app the first one kills the initial instance of the prototype before the second one starts another instance of the prototype afresh.

But if I try doing this from two different user accounts it fails (silently). If I

  1. Start an instance of my application it starts the prototype
  2. Switch user
  3. Start an instance of my application then it starts the prototype without my app from step 1 first shutting down the existing instance.

Can anyone see what’s wrong with my code? How should I use EventWaitHandle across several simultaneous user sessions on the same machine?

1

There are 1 answers

0
dumbledad On BEST ANSWER

Isn't it always the way, minutes after writing a long question the answer leaps to mind!

I got the slash the wrong way around in the name of the EventWaitHandle. For example replacing the constructor call:

new EventWaitHandle(false, EventResetMode.AutoReset, "Global/AaltoTokensAppShutdownEvent", out createdShutdown, security)

with this one:

new EventWaitHandle(false, EventResetMode.AutoReset, @"Global\AaltoTokensAppShutdownEvent", out createdShutdown, security)

fixes my problem.