MFC and .NET: Handling .NET Events

In a previous article, I explained and illustrated how to use .NET Delegates and Events types from C++ Managed Extensions. This week's column covers some standard problems you'll face when attempting to use events from a mixed-mode (MFC and Managed Extensions) application.

Figure 1: Demo application illustrating the subscribing to and catching of the event that is fired when a file is deleted from disk

Let's say that you have an MFC application with the /CLR flag set (the "Use Managed Extensions" option in the Project Settings). You then want to subscribe to the FileSystemWatcher::Deleted event so that your application is notified each time a file is deleted in the specified path.

However, if you attempt to specify an event handler within one of your MFC classes (such as the application, view, or dialog class) and then attempt to instantiate the delegate using that class, you'll receive a compiler error stating that you can't instantiate a delegate from a "non-member function or a member of an unmanaged class". Therefore, you'll need to create a managed class (__gc) wrapper for the event handler similar to the following:

#using <system.dll>
using namespace System::IO;


__gc class FileWatcherEvents
  public: static void OnDeleted (Object* source, FileSystemEventArgs* e)
    AfxMessageBox("A file was deleted!");

Note that I made the member method static so that I don't need to instantiate the FileWatcherEvents class. Obviously, if you're going to have instance data associated with the class (and specifically this method), you'll need to make this an instance method.

I then can subscribe to the event as follows:

#pragma push_macro("new")
#undef new
  FileSystemWatcher* pWatcher = new FileSystemWatcher("d:\\");
  pWatcher->Deleted += new FileSystemEventHandler(
            NULL, FileWatcherEvents::OnDeleted);
#pragma pop_macro("new")

You can plug this code directly into a mixed-mode application and a message box will appear any time a file is deleted from the D: root folder (specified in the FileSystemWatcher constructor). However, chances are you'll want to do something other than display a message to this effect. Therefore, the next task is figuring out how to communicate between the managed object and the desired MFC object (such as the dialog object in the download demo).

One obvious way of handling this problem would be to pass the MFC object to the handling wrapper object. However, that would couple the two classes a little too tightly for my taste. Another—more generic—way would be to pass the HWND of the client window to the wrapper object. Now, we're onto something! That would at least decouple the wrapper from a specific MFC class. We could take that notion a step further and create a base event-handling class from which all of our event-handling wrappers would derive. Then, we could instantiate each derived class with the HWND of the client window, as well as a message ID that the wrapper could use in sending a message to signal that an event had been raised. Here's an example of such a base class:

__gc class EventBase
  EventBase(HWND subscriberWindow, UINT messageID)
    this->subscriberWindow = subscriberWindow;
    this->messageID = messageID;
    HWND subscriberWindow;
    UINT messageID;
    void SendEventInfo(String* info)
    const __wchar_t __pin * path = PtrToStringChars(info);
    ::SendMessage(subscriberWindow, messageID, (WPARAM)path, NULL);

Note that the base class has a SendEventInfo method that allows all derived classes to send a string back to the client. (As I explained in the article, "Converting Between MFC/C++ and .NET Types," the __pin keyword and PtrToStringChars functions are used to convert a managed String object to an unmanaged char array.) Obviously, you can supply other methods if you wish to send more complex types to the client.

Now, you can derive each of your event-handling wrapper classes from the EventBase class. Using our FileSystemWatcher example, we could define the following class to handle the FileSystemWatcher::Deleted event:

__gc class FileWatcherEvents : public EventBase
  FileWatcherEvents(FileSystemWatcher* watcher,
                    HWND subscriberWindow, UINT messageID)
  : EventBase(subscriberWindow, messageID)

  void OnDeleted (Object* source, FileSystemEventArgs* e)

Note how the FileSystemWatcher-specific code, such as which event to subscribe to (Deleted) and the setting of the EnableRaisingEvents property, are placed in this derived class.

The client code then would instantiate the event-handler wrapper as follows:

#pragma push_macro("new")
#undef new
  FileSystemWatcher* pWatcher = 
    new FileSystemWatcher("d:\\");

  FileWatcherEvents* fileEvents = 
    new FileWatcherEvents(pWatcher, GetSafeHwnd(), WM_FILE_DELETED);

  pWatcher->Deleted += 
    new FileSystemEventHandler(fileEvents, 
#pragma pop_macro("new")

At this point, the FileWatcherEvents will automatically send a message to the client window (as specified in its constructor) when a file is deleted from the D: root folder.

You need only define the message ID and implement a handler. Here's an example from the article's download demo:



BEGIN_MESSAGE_MAP(CHandlingEventsInMFCDlg, CDialog)


LRESULT CHandlingEventsInMFCDlg::OnFileDeleted(WPARAM wp, LPARAM)
  const __wchar_t * path = (const __wchar_t *)wp; 

  int idx = m_lstEvents.InsertItem(0, _T("Deleted"));
  m_lstEvents.SetItemText(idx, 1, (CString)path);

  return 0L;

As you can see, the handler simply converts the WPARAM first to its original unmanaged char array form and then casts it to a CString object so that it can be displayed in the demo's list control.

Easier with Practice

While not terribly intuitive at first blush, once you get the hang of handling events in a managed object and then communicating the desired information between that managed object and your unmanaged MFC objects, you'll see that subscribing and dealing with events in mixed-mode applications becomes easy. In addition, while my first swing at a generic base class is far from perfect, it should get you started in the right direction to making this task more generic for your programming needs.

About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.



  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds