Delegate on instance method passed by P/Invoke - c#

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?

Does this mean that any such delegate is translated (marshalled?) individually to a static function...
Yes, you guessed at this correctly. Not exactly a "static function", there is a mountain of code inside the CLR that performs this magic. It auto-generates machine code for a thunk that adapts the call from native code to managed code. The native code gets a function pointer to that thunk. The argument values may have to be converted, a standard pinvoke marshaller duty. And always shuffled around to match the call to the managed method. Digging up the stored delegate's Target property to provide this is part of that. And it jiggers the stack frame, tying a link to the previous managed frame, so the GC can see that it again needs to look for object roots.
There is however one nasty little detail that gets just about everybody in trouble. These thunks are automatically cleaned-up again when the callback is not necessary anymore. The CLR gets no help from the native code to determine this, it happens when the delegate object gets garbage-collected. Maybe you smell the rat, what determines in your program when that happens?
var myFunctor = new MySystemFunctor();
That is a local variable of a method. It is not going to survive for very long, the next collection will destroy it. Bad news if the native code keeps making callbacks through the thunk, it won't be around anymore and that's a hard crash. Not so easy to see when you are experimenting with code since it takes a while.
You have to ensure this can't happen. Storing the delegate objects in your class might work, but then you have to make sure your class object survives long enough. Whatever it takes, no guess from the snippet. It tends to solve itself when you also ensure that you unregister these callbacks again since that requires storing the object reference for use later. You can also store them in a static variable or use GCHandle.Alloc(), but that of course loses the benefit of having an instance callback in a hurry. Feel good about having this done correctly by testing it, call GC.Collect() in the caller.
Worth noting is that you did it right by new-ing the delegate explicitly. C# syntax sugar does not require that, makes it harder to get this right. If the callbacks only occur while you make the pinvoke call into the native code, not uncommon (like EnumWindows), then you don't have to worry about it since the pinvoke marshaller ensures the delegate object stays referenced.

For the records: I have walked right into the trap, Hans Passant has mentioned. Forced garbage collection has led to a null reference exception because the delegate was transient:
KINInit(kinmem, myFunctor.SystemFunction, IntPtr.Zero);
// BTW: same with:
// KINInit(kinmem, new KINSysFn(myFunctor.SystemFunction), IntPtr.Zero);
GC.Collect();
GC.WaitForPendingFinalizers();
KINSol(/*...*); // BAAM! NullReferenceException
Luckily I had already wrapped the critical two P/Invokes, KINInit (which sets the callback delegate) and KINSolve (which actually uses the callback) into a dedicated managed class. The solution was, as already discussed, to keep the delegate referenced by a class member:
// 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(/*...*);
Thanks again, Hans, I'd never have noticed this flaw because it works as long as no GC happens!

Related

Where do I put GC.KeepAlive?

I need to register a callback in unmanaged code, but it looks like GC keeps collecting my reference. So I added GC.KeepAlive(callback_pin); but it has no effect. I'm not sure where should I put GC.KeepAlive.
This is the code where I register my own callback to the unmanaged event, it is called from a thread. (Some_Callback and Some_Method are external objects)
var callback_pin = new Some_Callback(MyManagedCallback);
GC.KeepAlive(callback_pin);
Some_Method(callback_pin);
return true;
And below is how I imported the unmanaged code. The documentation which came with it suggests that I use the above-mentioned code in order to keep the callback alive, but since the callback is never fired in my case I don't think it's the right way to do it. Any enlightenments?
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate void Some_Callback(Int32 line, [MarshalAs(UnmanagedType.LPWStr)] string msg);
[DllImport("SOME_DLL.dll", CharSet = CharSet.Unicode)]
public static extern Int32 Some_Method(MulticastDelegate funcPtr, Int32 mask);
Delegates are automatically "kept alive" (the technical term is "rooted") for the duration of native functions in which they participate as parameters.
You only need special code to keep them alive if the native function you're calling is only storing the pointer, then at some later point another function (or thread) uses the stored pointer. The framework could conceivably garbage collect your delegate by then.
Besides, your issue is different, if the delegate was garbage collected you'd be getting an access violation when calling it. If nothing is happening, your native function simply isn't calling it -- debug it!

Where function passed as UnmanagedFunctionPointer to C is executed?

In C, there is a function that accepts a pointer to a function to perform comparison:
[DllImport("mylibrary.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int set_compare(IntPtr id, MarshalAs(UnmanagedType.FunctionPtr)]CompareFunction cmp);
In C#, a delegate is passed to the C function:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int CompareFunction(ref IntPtr left, ref IntPtr right);
Currently, I accept Func<T,T,int> comparer in a constructor of a generic class and convert it to the delegate. "mylibrary.dll" owns data, managed C# library knows how to convert pointers to T and then compare Ts.
//.in ctor
CompareFunction cmpFunc = (ref IntPtr left, ref IntPtr right) => {
var l = GenericFromPointer<T>(left);
var r = GenericFromPointer<T>(right);
return comparer(l, r);
};
I also have an option to write a CompareFunction in C for most important data types that are used in 90%+ cases, but I hope to avoid modifications to the native library.
The question is, when setting the compare function with P/Invoke, does every subsequent call to that function from C code incurs marshaling overheads, or the delegate is called from C as if it was initially written in C?
I imagine that, when compiled, the delegate is a sequence of machine instructions in memory, but do not understand if/why C code would need to ask .NET to make the actual comparison, instead of just executing these instructions in place?
I am mostly interested in better understanding how interop works. However, this delegate is used for binary search on big data sets, and if every subsequent call has some overheads as a single P/Invoke, rewriting comparers in native C could be a good option.
I imagine that, when compiled, the delegate is a sequence of machine instructions in memory, but do not understand if/why C code would need to ask .NET to make the actual comparison, instead of just executing these instructions in place?
I guess you're a bit confused about how .NET works. C doesn't ask .NET to execute code.
First, your lambda is turned into a compiler-generated class instance (because you're closing over the comparer variable), and then a delegate to a method of this class is used. And it's an instance method since your lambda is a closure.
A delegate is similar to a function pointer. So, like you say, it points to executable code. Whether this code is generated from a C source or a .NET source is irrelevant at this point.
It's in the interop case when this starts to matter. P/Invoke won't pass your delegate as-is as a function pointer to C code. It will pass a function pointer to a thunk which calls the delegate. Visual Studio will display this as a [Native to Managed Transition] stack frame. This is needed for different reasons such as marshaling or passing additional parameters (like the instance of the class backing your lambda for instance).
As to the performance considerations of this, here's what MSDN says, quite obviously:
Thunking. Regardless of the interoperability technique used, special transition sequences, which are known as thunks, are required each time a managed function calls an native function, and vice-versa. Because thunking contributes to the overall time that it takes to interoperate between managed code and native code, the accumulation of these transitions can negatively affect performance.
So, if your code requires a lot of transitions between managed and native code, you should get better performance by doing your comparisons on the C side if possible, so that you avoid the transitions.

Using Managed Class Method as Callback

I'm currently working on a little Midi Project and just now I'm writing a little "SharpMidi" Library in C++/Cli to make it easier for me to use native Midi functions from Managed code.
I'm now stuck on the midiInOpen Function:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd798458%28v=vs.85%29.aspx
As you can see from the documentation, this function requires an unmanaged function as Callback and optional instance data.
I managed to convert a Managed Function Pointer to an unmanaged Function Pointer using
System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate
but I now have problems converting the this Pointer from my managed class to an unmanaged Pointer, I don't even know if its possibly they way I want it to work.
HMIDIIN _midiInDevice;
void MidiInProcNative(HMIDIIN midiInDevice, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
delegate void MidiInProc(HMIDIIN midiInDevice, UINT msg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
MidiInProc^ _midiInProc;
...
_midiInProc = gcnew MidiInDevice::MidiInProc(this, &MidiInDevice::MidiInProcNative);
cli::pin_ptr<HMIDIIN> midiInDevPtr = &_midiInDevice;
pin_ptr<???> thisPtr = this; // This is the line I'm struggling with
MMRESULT result = midiInOpen(midiInDevPtr, devId, (DWORD_PTR)System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(_midiInProc).ToPointer(), thisPtr, CALLBACK_FUNCTION);
As you can see I have experimented with pin_ptrs but I don't think this will work as the this pointer can't be used to initialize any pin_ptr.
I hope I could make clear what I want to try to achieve and maybe somebody can help me out.
Regards,
Xaser
I now have problems converting the this Pointer from my managed class to an unmanaged Pointer
Just don't, there's no need for it. The dwCallbackInstance argument of miniInOpen() is a convenience argument for native C++. You get it back in the static callback function, let's you call an instance method of a C++ class.
But delegates are far more powerful than member function pointers, they already encapsulate this. A delegate constructor takes two arguments, the target object and the target method. So that it can automatically call an instance method. You already took advantage of that, you indeed passed this as the first argument. So you can be sure that your MidiInProcNative() instance method uses the proper object reference.
Just pass nullptr for the argument.

Using a C++ callback interface in C#

I am writing an application that needs to record video using DirectShow - to do this, I am using the interop library DirectShowLib, which seems to work great.
However, I now have the need to get a callback notification as samples are written to a file, so I can add data unit extensions. According to the msdn documentation, in C++ this is done by implementing the IAMWMBufferPassCallback interface, and passing the resulting object to the SetNotify method of a pin's IAMWMBufferPass interface.
So, I created a small class that implements the IAMWMBufferPassCallback interface from DirectShowLib:
class IAMWMBufferPassCallbackImpl : IAMWMBufferPassCallback
{
private RecordingPlayer player;
public IAMWMBufferPassCallbackImpl(RecordingPlayer player)
{
this.player = player;
}
public int Notify(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd)
{
if (player.bufferPin == pPin && !player.firstBufferHandled)
{
player.firstBufferHandled = true;
//do stuff with the buffer....
}
return 0;
}
}
I then retrieved the IAMWMBufferPass interface for the required pin, and passed an instance of that class to the SetNotify method:
bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);
IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");
hr = bPass.SetNotify(bufferPassCallbackInterface);
DsError.ThrowExceptionForHR(hr);
No exception is thrown, indicating that the SetNotify method succeeded.
Now, the problem is, that the Notify method in my callback object never gets called. The video records without a problem, except for the fact that the callback is not getting executed at all.
Is it a problem with the way I am doing the interop?
I usually work with delegates for function pointers in unsafe C# code.
The only trick is that you need to make sure that the reference to the delegate does not get garbage-collected, as the reference in the unsafe code is not used when counting the references inside the garbage collector. Thus the function either needs to be either static or the object which holds the reference needs an additional artificial reference to ensure its availability.
This is a tutorial for using delegates on MSDN.
The way you are doing the interop looks totally fine. I looked at the MSDN docs and it also looks like you are going the right direction, so I don't know why it wouldn't make the callback.
Once you do get it doing the callback, however, you might want to make sure to call Marshal.ReleaseComObject(pNSSBuffer3). Sometimes sample buffers aren't released for processing until all other references have been removed. This is the case with the SampleGrabber, so might be the same for this.
You should probably be using a delegate:
delegate int NotifyDelegate(INSSBuffer3 pNSSBuffer3, IPin pPin, long prtStart, long prtEnd);
void run(){
bufferPassCallbackInterface = new IAMWMBufferPassCallbackImpl(this);
IAMWMBufferPass bPass = (IAMWMBufferPass)DSHelper.GetPin(pWMASFWriter, "Video Input 01");
NotifyDelegate d = new NotifyDelegate(bufferPassCallbackInterface.Notify);
hr = bPass.SetNotify(d);
DsError.ThrowExceptionForHR(hr);
}
However, I'm not quite sure how your implementing an unmanaged interface on a managed class. An INSSBuffer3* in C++ does not directly correlate to new INNSBuffer3() in C#.
Edit:
In response to your comment, the SetNotify function is defined as
HRESULT SetNotify(
[in] IAMWMBufferPassCallback *pCallback
);
So, it requires a pointer to an implementation of IAMWMBufferPassCallback.
MSDN says that pCallback is pCallback a
Pointer to the application's
IAMWMBufferPassCallback interface.
The delegate is (an attempt to be) the managed equivalent to a pointer to IAMWMBufferPassCallback. A call back is, generally, a method, not an object. So, passing in an instance of the delegate should work for you. Another similar example is with InternetSetStatusCallback, where you pass a pointer to an implementation of InternetStatusCallback.
I would try it, if it doesn't work, why not try a library where someone has already done all the hard work? DirectShowNet may be an option (I've never used it).

What is the difference between a delegate instance and a method pointer?

I thought that a delegate instance was interchangeable with a function instance.
Take the following code:
delegate int AddDelegate(int a, int b);
AddDelegate DelegateInstance;
public void DoStuff()
{
//I can call this without a delegate "instance":
MethodThatTakesAdd(Add);
//I can also call it WITH a delegate "instance"
DelegateInstance = Add;
MethodThatTakesAdd(DelegateInstance);
}
public int Add(int a, int b)
{
return a + b;
}
public void MethodThatTakesAdd(AddDelegate addFunction)
{
Console.WriteLine(addFunction(1, 2).ToString());
}
Both ways of calling it APPEAR to be equivalent, and if you're using only C#, you'll never see the difference (at least I have not up to this point). However, I was recently unmanaged code that was calling back into this managed code, they are treated differently. For example, in one scenario, I to get the error "A callback was made on a garbage collected delegate" if I use the function directly as a callback (even though my object instance is kept around). Using the "delegate instance" fixes the problem.
Is there someone out there that knows what the difference is?
Terminology Corretion: Instead of method pointer, the more appropriate term is method group.
In terms of functionality the two statements are equivalent. That is that they produce almost the same IL. The difference is where the delegate value is stored.
In the first case you pass the method group Add to MethodThatTakesAdd directly. This causes a temporary delegate value to be created and then passed to MethodThatTakesAdd. This delegate value is subject to garbage collection the moment the MethodThatTakesAdd returns since it does not store the value.
In the second case you assigned the delegate to a field on the outer instance. This will typically increase the lifetime of the delegate and hence reduce the chance it's garbage collected during your pinvoke call.
Delegates are classes that are callable, and have similar behavior to function pointers. The delegate internally stores the address of the function to call (i.e. the function pointer), but also provides other functionality such as multi-casting and storing an invocation list; you can essentially invoke many functions of the same signature with one delegate instance as follows.
public void DoStuff()
{
DelegateInstance += Add;
DelegateInstance += AnotherAdd;
DelegateInstance += YetAnotherAdd;
// Invoke Add(100, 200), AnotherAdd(100, 200), and YetAnotherAdd(100, 200)
DelegateInstance(100, 200);
}
Regarding your note about the equivalence of MethodThatTakesAdd(Add) and MethodThatTakesAdd(DelegateInstance),
if you look at the MSIL that the C# compiler generates for the line MethodThatTakesAdd(Add), you will notice that the compiler is creating a delegate and wrapping the Add() method for you.
While delegates provide synonymous functionality in C# as function pointers in C or C++, there are significant differences. Key among these is that a delegate is a class, not a pointer.
In short, casting a delegate to a pointer isn't going to give you a reference to a function or method, and as such it can't be used to call a method by reference from unmanaged code.

Categories

Resources