Click here to Skip to main content
15,887,027 members
Articles / Desktop Programming / MFC
Article

Interop: Waiting in C# on External Win32 Events

Rate me:
Please Sign up or sign in to vote.
4.37/5 (12 votes)
31 Aug 20052 min read 97.6K   2.7K   40   14
An article on catching external process events from within .NET (C#) code.

Sample Image - MfcEventSource.gif

Introduction

I found several examples of how to Open and Set named Win32 events from within .NET code, but I also needed to catch Win32 events in my .NET application. That is, I wanted to do the equivalent of Win32's (C++) WaitForMultipleObjects(), only in C#. I found no examples of this at Microsoft or on the Internet at large. All of the discussion of WaitHandle and its derivatives, AutoResetEvent and ManualResetEvent only talked about multi-threading, not about inter-process communication. I was left unsure if it was possible (or at any rate whether it was simple, most things are possible with enough contortions and excursions into managed C++...); so I gave it a try. The result? It's remarkably simple ...

Background

Our environment uses an executive process to control which other processes are running, and in what state they are running, e.g. as "primary" or "secondary", the latter being a warm back up that can be quickly switched over to primary should the first copy fail.

There are a handful of named events used to communicate between the executive and the worker processes, e.g. one event to tell them to transition from "secondary" to "primary" and another to tell them to shut down. This executive process uses well known environment variables to communicate the names of the events to its worker processes.

Historically, all these processes were Win32/MFC applications. Now some are becoming .NET apps, but it is most convenient to keep the same communications mechanism for the time being.

Using the code

Since the way to do this is so simple, I'll just show the code. The bold part was to just go ahead and assign the result from the Win32 OpenEvent() call to an AutoResetEvent.Handle property:

C#
uint unEventPermissions = 2031619;
// Same as EVENT_ALL_ACCESS value
// in the Win32 realm IntPtr hEvent = IntPtr.Zero; 

// Get a handle to the Win32 Event.
// The name, "MfcEventSource", is known in advance 
hEvent = OpenEvent(unEventPermissions, 
                   false, "MfcEventSource"); 
if (IntPtr.Zero == hEvent) 
{
  Console.WriteLine("OpenEvent failed"); 
  return; // Exit 
}
// Create an AutoResetEvent object to wrap
// the handle we got from OpenEvent 
AutoResetEvent arEvent = new AutoResetEvent(false); 
// Set the Handle property to the external event HANDLE 
arEvent.Handle = hEvent;

That's it! Now you can put this AutoResetEvent object into a WaitHandle array and use WaitAny() (or use WaitOne() directly on the AutoResetEvent object or use WaitAll(), etc.). Here's an example:

C#
WaitHandle[] waitHandles;
waitHandles = new WaitHandle[1];
//Put it in our array for WaitAny()
waitHandles[0] = arEvent;
bool bDone = false;
while ( !bDone )
{
  Console.WriteLine("Top of while");
  int waitResult = WaitHandle.WaitAny(waitHandles, 2000, false);
  //For timeout, just loop and wait again
  if (waitResult == WaitHandle.WaitTimeout)
  {
    Console.WriteLine(" WaitAny timed out.");
  }
  else if (0 == waitResult)
  {
    Console.WriteLine("0 == waitResult. Yippee !!!");
    // Do Something
  }
  else if (1 == waitResult)
  {
    Console.WriteLine("1 == waitResult !!!");
    // Do Something Else
  }
  else
  {
    Console.WriteLine("Error else");
  }
}

If you download the demo project you'll actually get three solutions, one that is the MFC/Win32 (C++) application that is the source of the named event, another that is the .NET (C#) event sink application that opens and waits on the external event, and a third that is an MFC/Win32 (unmanaged C++) event sink application, it is the logical equivalent of the C# app. Be sure to run the MfcEventSource program first, then start either of the other two.

Points of Interest

I guess that Microsoft can't be expected to provide examples and practical descriptions of all the available classes, but in this case the fact that WaitHandle objects are only described for use with multi-threading but there is no mention of multi-process usage seems misleading. On the other hand, once you see what is available on these classes and boldly go ahead and use those features, it seems to work quite well. Any one knows any reason to fear otherwise? Thanks.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Chip Patton
Software Engineer
Intergraph Public Safety

Comments and Discussions

 
QuestionHow to track the windows login event? Pin
jasnavp10-Feb-08 23:52
jasnavp10-Feb-08 23:52 
GeneralHandle Mutiple Named Events Pin
Ashu v23-Sep-07 21:11
Ashu v23-Sep-07 21:11 
General.NET 2.0 Alternative Pin
Lee Clark27-Jan-07 16:02
Lee Clark27-Jan-07 16:02 
This nice article gave the direction to look in for setting the security attributes of the EventWaitHanlde to mimic the "CreateEvent" call with the old NULL default. I haven't seen too many good examples around so I'll share what I came up with:
using System.Threading;
using System.Security.AccessControl;
using System.Security.Principal;

    // Create a security object to hold the event security rules
    EventWaitHandleSecurity security = new EventWaitHandleSecurity();
    EventWaitHandleAccessRule rule;
    String user;

    // Add a rule that grants SYSTEM processes full rights
    user = "NT AUTHORITY\\SYSTEM";
    rule = new EventWaitHandleAccessRule(user, 
        EventWaitHandleRights.FullControl, 
        AccessControlType.Allow);
    security.AddAccessRule(rule);

    // Add a rule that grants user at time of creation full rights
    user = Environment.UserDomainName + "\\" + Environment.UserName;
    rule = new EventWaitHandleAccessRule(user,
        EventWaitHandleRights.FullControl,
        AccessControlType.Allow);
    security.AddAccessRule(rule);

    // Create the named event 
    Boolean bNewlyCreated;
    EventWaitHandle evh = new EventWaitHandle(false, EventResetMode.AutoReset, 
        "TheSystemEventName", out bNewlyCreated, security);

This results in an event equivalent to a the API call:
::CreateEvent(NULL, FALSE, TRUE, "TheSystemEventName");

Of course, once one is actively defining the security attributes, using a set that allows only what is needed makes sense to keep the system secure. I needed an event created in a service which could be set by a C++ application from the desktop. The following rule was used in the service to create the event:
// Add a rule that grants current INTERACTIVE processes right to signal the event.
user = "NT AUTHORITY\\INTERACTIVE";
rule = new EventWaitHandleAccessRule(user,
    EventWaitHandleRights.Modify,
    AccessControlType.Allow);
security.AddAccessRule(rule);

// Create the named event
Boolean bNewlyCreated;
EventWaitHandle evh = new EventWaitHandle(false, EventResetMode.AutoReset,
    "Global\\TheSystemEventName",
    out bNewlyCreated, security);


and the c++ application set the event:
HANDLE hEvent = ::OpenEvent(EVENT_MODIFY_STATE, FALSE, _T("Global\\TheSystemEventName") );
if (hEvent)
{
    // successful open, set and close event
    ::SetEvent(hEvent);
    ::CloseHandle(hEvent);
}
else
{
    // error handling...
}

The service created a thread and used WaitHandle.WaitAny to wait for the event to be signaled.
GeneralHandle leak [modified] Pin
Leo Davidson4-Jul-06 7:13
Leo Davidson4-Jul-06 7:13 
QuestionHow do you learn/determine an external event's name? Pin
barnabya3-May-06 23:55
barnabya3-May-06 23:55 
AnswerRe: How do you learn/determine an external event's name? Pin
Chip Patton4-May-06 10:37
Chip Patton4-May-06 10:37 
GeneralRe: How do you learn/determine an external event's name? Pin
barnabya4-May-06 10:43
barnabya4-May-06 10:43 
GeneralUse CreateEvent if you don't know the sequence of starting Pin
ihristov12-Dec-05 7:19
ihristov12-Dec-05 7:19 
GeneralI need help Pin
Yuragel31-Oct-05 2:52
Yuragel31-Oct-05 2:52 
GeneralRe: I need help Pin
Chip Patton31-Oct-05 6:26
Chip Patton31-Oct-05 6:26 
GeneralWin32 events Pin
Gil Orlev22-Oct-05 21:24
Gil Orlev22-Oct-05 21:24 
GeneralRe: Win32 events Pin
Chip Patton31-Oct-05 6:12
Chip Patton31-Oct-05 6:12 
GeneralPInvoke Alternative Pin
Ryan L. Schneider31-Aug-05 12:23
Ryan L. Schneider31-Aug-05 12:23 
GeneralRe: PInvoke Alternative Pin
Chip Patton1-Sep-05 4:13
Chip Patton1-Sep-05 4:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.