Instance delegation method passed by P / Invoke

To my surprise, today I discovered a powerful feature. Since this looks too good to be true, I want to make sure that it does not just work due to some strange coincidence.

I always thought that when my p / invoke (to the c / C ++ library) calls a function (callback), I will have to pass the delegate to the C # static function. For example, in the following case, I would always refer to the KINSysFn delegate as a static function of this 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 the delegate using the instance method, and it works too! For instance:

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);

, , "this" .

, "this" MySystemFunctor.SystemFunction dll, "this" .

, (?) , "this" - ? , ,

var myFunctor01 = new MySystemFunctor();
// ...
var myFunctor99 = new MySystemFunctor();

KINInit(kinmem, myFunctor01.SystemFunction, IntPtr.Zero);
// ...
KINInit(kinmem, myFunctor99.SystemFunction, IntPtr.Zero);

. , MySystemFunctor ? "" / ?

+4
2

, (?) ...

, . " ", CLR , . thunk, . . , , . , . Targetate this . , , GC , .

, , , , . thunks , . CLR , , , . , , , ?

 var myFunctor = new MySystemFunctor();

. , . , thunk, , . , , .

, . , , . , , . , , , , , . GCHandle.Alloc(), , , . , , , GC.Collect() .

, , . # , . , pinvoke , (, EnumWindows), , pinvoke , - .

+8

: , . , :

KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
// BTW: same with:
// KINInit(kinmem, new KINSysFn(myFunctor.SystemFunction), IntPtr.Zero);

GC.Collect();
GC.WaitForPendingFinalizers();

KINSol(/*...*); // BAAM! NullReferenceException

, P/Invokes, KINInit ( callback) KINSolve ( ) . , , , :

// ksf is a class member of delegate type KINSysFn that keeps ref to delegate instance
ksf = new KINSysFn(myFunctor.SystemFunction); 
KINInit(kinmem, ksf, IntPtr.Zero);

GC.Collect();
GC.WaitForPendingFinalizers();

KINSol(/*...*);

, , , , GC !

+1

Source: https://habr.com/ru/post/1695281/


All Articles