views:

201

answers:

2

Hi,

I am really confused by the multitude of misinformation about native / managed interop.

I have a regular C++ exe which is NOT built using CLR stuff (it is neither Managed C++ nor C++/CLI and never will be). This C++ exe is "in charge", there is no managed wrapper for it.

I would like to access some code I have in a C# assembly from my C++ exe. I can access the C# assembly from my C++ code using COM. However, when my C# code detects an event I would like it to call back into my C++ code. The C++ function pointer to call back into will be provided at runtime. Note that the C++ function pointer is to a function found in the exe's execution environment. It may use static members from there. I don't want the managed code to try and load up some DLL to call a function (there is no DLL).

How do I pass this C++ function pointer to my C# code through COM/.NET and have my C# code successfully call it?

Thanks!

+4  A: 

You'll probably want to use Marshal.GetDelegateForFunctionPointer:

  1. Create a delegate type that matches the signature of the native function, keeping in mind the right way to marshal types and using MarshalAs as needed
  2. Communicate the native function pointer from your native code to your C# code however you can (in your case, it looks like you can use your COM -> C# connection)
  3. Use Marshal.GetDelegateForFunctionPointer to turn the pointer into a C#-callable delegate
  4. Invoke the delegate with your parameters

Junfeng Zhang has an example of doing this here.

Note the restrictions mentioned on MSDN:

The GetDelegateForFunctionPointer method has the following restrictions:

  • Generics are not supported in interop scenarios.
  • You cannot pass an invalid function pointer to this method.
  • You can use this method only for pure unmanaged function pointers.
  • You cannot use this method with function pointers obtained through C++ or from the GetFunctionPointer method.
  • You cannot use this method to create a delegate from a function pointer to another managed delegate.

The part about C++ is likely referring to function pointers for class methods. This should still work for global functions.

Chris Schmich
In step 2 will the function pointer initially arrive in C#-land as an IntPtr?
evilfred
To get the pointer from C/C++ to C#, it will be marshaled. Yes, C/C++ pointers are represented as a C# `IntPtr` whose size is platform-specific.
Chris Schmich
I'm probably doing something dumb. The C++ compiler complains that it can't convert my parameter from voic(__cdecl*)(UINT) to long (the method takes an IntPtr in C#). Also, Zhang's example involves a C++ function pointer retrieved in C# not one retrieved from C++...
evilfred
I casted my function pointer to a long in C++ and while the compiler complained that the type cast involved "pointer truncation", it seemed to work?
evilfred
The pointer truncation warning could be an issue if you move to a 64-bit platform. If you have to cast a pointer, use `UINT_PTR`. For more info: http://www.codeguru.com/forum/showthread.php?t=431298
Chris Schmich
If I use UINT_PTR then I get a regular "possible lost of data" warning :D
evilfred
+4  A: 

The standard COM approach is to subscribe to an event that's raised by the COM server. Use can use the event keyword in C#, CLR interop automatically implements the COM glue that's needed. Use the IConnectionPoint interface in your C++ code. Backgrounder is here.

Hans Passant