Function pointers and Delegates - Closing the gap!

Explains the usage of the Marshal class methods GetFunctionPointerForDelegate and GetDelegateForFunctionPointer, and compares their performance with the P/Invoke mechanism.

Introduction

3 years ago, I had written an article titled
Implementing Callback functions using IJW (avoiding DllImport) that
described a technique by which you could call API functions requiring callbacks
without using the DllImport mechanism. The technique I used involved declaring
an __gc class with an inner __nogc class with the
__gc class wrapping the inner class and exposing a managed
interface to the outer world. While it was rather contorted a technique, it was
the only option at that time. But today, with the release of Whidbey around the
corner, things have got a whole lot better, with the introduction of two new
methods in the Marshal class - GetFunctionPointerForDelegate
and GetDelegateForFunctionPointer. Now you can take a function
pointer and wrap a delegate around it, or the reverse - take a delegate and use
it as a function pointer. This article demonstrates both techniques using the
almost proverbial EnumWindows example everyone uses when they want
to demonstrate something to do with callback functions.

Sample usage

delegate BOOL EnumWindowsDelegateProc(HWND hwnd,LPARAM lParam);

I've declared the delegate type that'll be exposed to the .NET world (or at
least to the C++ .NET world given that I've used some native types). The
delegate type matches the callback prototype for the EnumWindows
function

I have a non-trivial event (WindowFound) that's of the delegate
type declared earlier - the reason I had to use a non-trivial event is that C++/CLI
does not treat an event as a regular class member and won't allow operations
like & (address of) on an event member. Notice how I check for
nullptr before assigning the event handler - this is done to ensure
that there is only one delegate associated with the event. The crux of the
code is in the Init method where I've called EnumWindows
directly and have used GetFunctionPointerForDelegate to convert the
delegate object into a function pointer. If you look at the mscorlib
source using Reflector or ILDasm, you'll see that

GetFunctionPointerForDelegate

does a nullptr check and then calls an extern function

GetFunctionPointerForDelegateInternal

.

GetFunctionPointerForDelegateInternal

creates a native callable stub
around the delegate that has been passed in and my best guess as to where it's
defined in would be mscorwks.dll (just a guess, someone who works in the
CLR team will know better). Notice how I pin the delegate object using a
temporary pin_ptr variable, this is because I do not want the
delegate object to be moved around on the CLR heap while I am using the function
pointer in native code.

This class simply defines a staticHandleFoundWindow
method that matches the delegate prototype expected by the

WindowEnumerator

class. Notice that I could have used

Console::WriteLine

here, but I wanted to use a delegate that wrapped a
function pointer (so I could demonstrate the use of the

GetDelegateForFunctionPointer

method. After having
written so many articles and a technical book, I've lost any traces of shame
when I invent unusually contorted examples to demonstrate coding techniques.
Many others like me who do technical authoring are notorious for creating the
most beautiful pieces of code that'll never ever serve any purpose in a
real-world production environment. So, kindly have mercy on me guys.

I get a pointer to the printf function using LoadLibrary/GetProcAddress
and call GetDelegateForFunctionPointer to create a delegate that
wraps this function pointer. If you look at the implementation of

GetDelegateForFunctionPointer

, you'll see that it does some nullptr
checks, then checks to see that you've actually passed in a Delegate
type and then calls an extern function

GetDelegateForFunctionPointerInternal

.

GetDelegateForFunctionPointerInternal

creates a new delegate that wraps a
native function pointer (similar to the P/Invoke mechanism) and is defined in an
undocumented DLL - my best guess, as I mentioned earlier is mscorwks.dll,
but I might be wrong there. MSDN says that the function pointer that's passed
must be a pure unmanaged function pointer - means you cannot safely pass in a
native pointer in a mixed-mode module. Though when I tested it with a local
function in a mixed-mode project, things worked pretty smooth - but it's safer
to follow MSDN guidelines - you never know when something'll break otherwise.

Performance improvement

I did a little speed test to see which is more performant. I wrote two
classes - both of them enumerating windows using the EnumWindows
API, one of which used P/Invoke while the other used the

Marshal::GetFunctionPointerForDelegate

method to manually do the delegate
to function pointer conversion. Just as I expected, the latter method was more
efficient and this efficiency improvement was seen to be pretty consistent as I increased the
iterations.

License

Share

About the Author

Nish Nishant is a Principal Software Architect based out of Columbus, Ohio. He has over 17 years of software industry experience in various roles including Lead Software Architect, Principal Software Engineer, and Product Manager. Nish was a Microsoft Visual C++ MVP between 2002 and 2015.

Nish is an industry acknowledged expert in the Microsoft technology stack. He authored C++/CLI in Action for Manning Publications in 2005, and had previously co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is vastly experienced in team management, mentoring teams, and directing all stages of software development.

Contact Nish : If you are interested in hiring Nish as a consultant, you can reach him via his google email id voidnish.

Comments and Discussions

I have a win32 application that uses a C# library. The win32 application call a method in the C# library that uses the Action<t> delgate as a parameter.. I need to used a method from the Win32 application to pass to the Action<t> parameter. Any idea on how to do this?
Email me directly at srf46@live.com or post here a solution

I have a win32 application that uses a C# library. The win32 application call a method in the C# library that uses the Action<t> delgate as a parameter.. I need to used a method from the Win32 application to pass to the Action<t> parameter. Any idea on how to do this?
Email me directly at srf46@live.com or post here a solution

This article, while quite informative, stops short at one limitation. What if the delegate needs to be used from a managed-only language like C#? Obviously, the managed app is not going to understand what HWND (and other unmanaged types) is.

How would you go about making the delegate/event visible to a managed-only library?

I believe pinning the delegate in the GetFunctionPointerForDelegate is useless : The delegate must be kept in memory (ie, it must not be freed while it might be called back by the unmanaged code), but it can be moved freely by the GC.

I really appreciate this article but lets consider the use of pin_ptr.

As pin_ptr are stored on the stack rather then in the heap I assume that it looses its function after the scope of the init method.
At the time the callback is triggered it wont protect the address of the delegate any more.

In your example for Marshal::GetDelegateForFunctionPointer you're wrapping printf, which is a C style funciton pointer. What would one do when you need to wrap a pointer to a non-static C++ member function?

Thanks in advance.

Oh, and before I forget, I just discovered your book. Is there any plans for a second edition that covers C++/CLI for .NET 2.0?

I searched far and wide for the answer but, like you, all I found were examples to static member functions and C style functions. The search stopped when our company decided to rewrite our native code in C#, so I haven't had a need to continue.

I wanted to paste the code for this article into a solution and step through it, but am getting a long list compile errors when building it (default Win32 console app in VC++). I feel like a complete idiot since I assume this should be a fairly easy thing to do and no one else apparently has had a problem doing so

Would it be possible to attach a zipped VC++ 2005 solution with the example code here?

appology my poor knowledge on your syntax, but you use a "strange" notation using a ^ accent behind some types, and as i've already seen this and never understood it, i told to myself it was the time to ask !!

The ^ punctuator (pronounced as hat or cap) represents a handle to a managed object. According to the CLI specification a handle is a managed object reference. C++/CLI handles are the equivalent of __gc pointers in the now obsolete MC++ syntax.