P/Invoke? No way! (Pt. 2)

[7/20/05: Additional comment added for Marshal::GetFunctionPointerForDelegate()]

There are some instances where Win32 requires a callback function pointer.  This frequently comes up in Enumeration APIs, such as EnumWindows.  In this post we’ll look at some code that makes this possible in Managed C++ (2005 -- C++/CLI).

One could create an unmanaged callback, but we’ll look at the completely managed route here.  (One could also use P/Invoke, but you know how I feel about that, no?)  (Don’t forget to read my earlier post on how to set up a C++ project for interop with the Win32 API if you haven’t already.)

You need to do just a few basic things:

  • Create a method that matches the desired callback signature.
  • Create a delegate type that matches the above method.
  • Create an instance of the delegate that points to your callback method.
  • Pin the delegate.
  • Convert the delegate into a function pointer.
  • Use it.

Here’s some sample code:

public ref class Window
   // Private flag for keeping track of when we're enumerating windows.
   static bool enumeratingWindows = false;
   // Private list of top level windows;
   static List<IntPtr>^ topLevelWindows = gcnew List<IntPtr>();
   // Delegate type for the EnumWindowsProc callback.
   // Matches the required signature of the API.  Note the use of ‘BOOL’, not ‘bool’.
   delegate BOOL EnumWindowsDelegate(HWND hwnd, LPARAM lParam);
   // Private method used for EnumWindows calls.
   static BOOL EnumWindowsProc(HWND hwnd, LPARAM lParam)
      // Not much to this.  Note the use of ‘TRUE’, not ‘true’.
      return TRUE;
   // Returns the top-level window handles.
   // Will return empty List if currently enumerating.
   static property List<IntPtr>^ TopLevelWindowHandles
      List<IntPtr>^ get()
         List<IntPtr>^ foundWindows = gcnew List<IntPtr>();
         if (Window::enumeratingWindows == true)
            return foundWindows;
         // Flag that we're currently enumerating windows.
         Window::enumeratingWindows = true;
         // Setup the managed callback.  Need to create the delegate we need.  (Step 1.)
         //  (This is a delegate to the managed method defined above.)
         EnumWindowsDelegate^ enumWindowsDelegate = gcnew EnumWindowsDelegate(Window::EnumWindowsProc);
         // Pin the delegate so the GC won’t move it. (Step 2.)
         pin_ptr<EnumWindowsDelegate^> pinnedDelegate = &enumWindowsDelegate;
         // Get the function pointer for the delegate and cast it to the type the API expects. (Step 3.)
         // 7/20: Note that you can also pass *pinnedDelegate here. It doesn't matter as they represent the
         // same object. Having a pin_ptr in scope is what keeps the object itself pinned.
         IntPtr delegatePointer = Marshal::GetFunctionPointerForDelegate(enumWindowsDelegate);
         WNDENUMPROC enumWindowsProc = static_cast<WNDENUMPROC>(delegatePointer.ToPointer());
         if (!EnumWindows(enumWindowsProc, 0))
            // Failed! Throw appropriate fit here...
         // Add what we found and return them.
         Window::enumeratingWindows = false;
         return foundWindows;


No unmanaged code used, no P/Invoke, I like it. 🙂  Hopefully you’ll find it useful too.

Some other potentially useful links:


Comments (2)

  1. I’ve already given the steps necessary to make this happen in an earlier post, but as this will come…

  2. Andrey DE says:

    Hey people ,the thins is so silmles as you  mean

    Get in the count C++ let you write non – class functions

    and classes not clr!!! So in these objects you just dive in

    the C++ native world It Just Work !!!(IJW), pivoke  NO WAY!!!

Skip to main content