Search code examples
c#.netwinapisynchronizationinter-process-communicat

Cannot find named event when created in Windows Service


I am developing a Windows Service in C# to centrally manage some application connectivity. It's a sleeper service in general, which performs some actions when awoken by an external executable. To this end I'm using named events, specifically the .NET EventWaitHandle. My code boils down to, at the service end:

        EventWaitHandleSecurity sec = new EventWaitHandleSecurity();
        sec.AddAccessRule(new EventWaitHandleAccessRule(
                  new SecurityIdentifier(WellKnownSidType.WorldSid, null),
                  EventWaitHandleRights.FullControl,
                  AccessControlType.Allow));
        evh = new EventWaitHandle(false, EventResetMode.AutoReset, EVENT_NAME, 
                                  out created, sec);

        Log(created ? "Event created" : "Event already existed?");

As it's an internal application on trusted servers I don't mind that granting 'Full Control' to 'World' in general wouldn't be smart.

At the client end I have:

EventWaitHandle.TryOpenExisting(EVENT_NAME, EventWaitHandleRights.Modify, out evh)

The code above works perfectly when I run my service in console-based interactive mode. The event is found on both ends, the client can set, and the service kicks to work. Everybody's happy.

When installing the service however it doesn't work. The logging still reports that the event was created anew, but the client cannot find the event. As I thought it was security-related I added the World Full Control Allow access rule, but it didn't change anything. I changed the service to run as Local Admin, even as my own user account, but nothing - the client cannot find the event even though logs show the service is happily polling away on it. If I change the TryOpenExisting to OpenExisting I get an explicit exception:

System.Threading.WaitHandleCannotBeOpenedException: No handle of the given name exists.

What am I missing?


Solution

  • Starting with Windows Vista, services are isolated and run in Session 0 (see Service Changes for Windows Vista). When calling CreateEvent (which EventWaitHandle does), the event object is created in the local namespace by default, also called session namespace. An event object created by a service in session 0 with a name in the session namespace is visible in session 0 only. It is invisible to applications running in an interactive user session.

    To create an event object by a service (running in session 0) that can be discovered by application code (running in an interactive user session), you have to create it into the global namespace. This is done by prefixing the event name with "Global\", as documented under CreateEvent.


    A helpful tool to track down kernel object-related bugs is Sysinternal's WinObj.