To my surprise I have discovered a powerful feature today. Since it looks too good to be true I want to make sure that it is not just working due to some weird coincidence.
I have always thought that when my p/invoke (to c/c++ library) call expects a (callback) function pointer, I would have to pass a delegate on a static c# function. For example in the following I would always reference a delegate of KINSysFn to a static function of that signature.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int KINSysFn(IntPtr uu, IntPtr fval, IntPtr user_data );
and call my P/Invoke with this delegate argument:
[DllImport("some.dll", EntryPoint = "KINInit", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int KINInit(IntPtr kinmem, KINSysFn func, IntPtr tmpl);
But now I just tried and passed a delegate on an instance method and it worked also! For example:
public class MySystemFunctor
{
double c = 3.0;
public int SystemFunction(IntPtr u, IntPtr v, IntPtr userData) {}
}
// ...
var myFunctor = new MySystemFunctor();
KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
Of course, I understand that inside managed code there is no technical problem at all with packaging a "this" object together with an instance method to form the respective delegate.
But what surprises me about it, is the fact that the "this" object of MySystemFunctor.SystemFunction finds its way also to the native dll, which only accepts a static function and does not incorporate any facility for a "this" object or packaging it together with the function.
Does this mean that any such delegate is translated (marshalled?) individually to a static function where the reference to the respective "this" object is somehow hard coded inside the function definition? How else could be distinguished between the different delegate instances, for example if I have
var myFunctor01 = new MySystemFunctor();
// ...
var myFunctor99 = new MySystemFunctor();
KINInit(kinmem, myFunctor01.SystemFunction, IntPtr.Zero);
// ...
KINInit(kinmem, myFunctor99.SystemFunction, IntPtr.Zero);
These can't all point to the same function. And what if I create an indefinite number of MySystemFunctor objects dynamically? Is every such delegate "unrolled"/compiled to its own static function definition at runtime?