Using a C++ callback interface in C# - 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).

Related

Delegate on instance method passed by P/Invoke

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!

Is It Possible to Get the Currently Executing Delegate (not MethodBase/MethodInfo) by 3rd Party Library?

I have been wracking my brain over this, but I cannot find an answer to it.
I am aware of MethodBase.GetCurrentMethod but I am curious if there is an equivalent to get the currently executing Delegate (if there is one executing, that is).
Is this possible, by chance? (Edit: This appears conclusively to not be possible via core .NET, so I am wondering if there is a 3rd party library that might do this.)
For reference, I would like to do the following:
void Main()
{
var target = new Inner();
var reference = new Action( target.HelloWorld ); // Creates a System.Delegate reference.
reference();
}
class Inner
{
public void HelloWorld()
{
var method = MethodBase.GetCurrentMethod(); // Current method.
var current = DelegateContext.GetCurrentDelegate(); // <==== Magic happens here. Gets "reference" from above.
}
}
Why? As for why I want to do this: For each reference I want to associate some data specific to that Delegate (sort of like ambient data that is not an explicit passed in variable). When the Delegate executes, I then retrieve that data (by way of ConditionalWeakTable or equivalent lookup) and use it within the delegate.
What you're asking for doesn't actually make sense at execution time. The delegate is just a pointer to something so you can execute it later.
It's not possible for you to get the same reference which is used above - that's just a local variable which isn't accessible to you. The best you can do (which in practical terms is the same thing) is get the current object instance and create a new Action using Delegate.CreateDelegate.

Generic Methods that overwrite parameters without reference?

Okay this might be a really stupid quesion but I will risk my rep anyway. I'm pretty new to programming so take it easy will ya ;)
So I just got into TCP when I encountered something I dont quite understand.
To be specific:
int length = Socket.Receive(MyByteArray);
To my understanding this method returns the length of the data beeing received and writes the recieved data into my byte array. So how does it write into my byte array without me telling it to? After some research I learned that you can use references to do this kind of thing but this method doesn't require "ref MyByteArray" which leaves me puzzled. Is this a different kind of Method or is it what is going on inside the method (duh)?
Thanks in advance you utterly awesome person.
Passing a reference type into a method can sometimes be an unintuitive thing for developers. Consider these two pieces of code (neither of which use the ref keyword):
void Method1(SomeType myObj)
{
myObj = new SomeType();
}
void Method2(SomeType myObj)
{
myObj.SomeProperty = 1;
}
The first method has no side effects. The reference type was passed into the method, which for lack of a better term is basically a "pointer" (itself passed by value) to the object in memory. If you set the variable to a new object in memory, the original remains unchanged. There are then two objects in memory. (Though the new one will go away once the method ends, because nothing uses it.)
The second method, however, does have a side-effect. It uses the same reference to the object in memory, but it modifies the object itself. So anything which examines the object after the method is called will see that modification.
Presumably, Socket.Receive() does something similar to the second method above. It uses the reference to modify the object.
To illustrate how the ref keyword would change this:
void Method3(ref SomeType myObj)
{
myObj = new SomeType();
}
In this scenario, there is also a side-effect. Any code which calls the method and then, afterward, examines the object it sent to the method will then see that the object has been replaced with a new one. In this case there wasn't a second "pointer" to the same location in memory. The method used the actual pointer that the calling code used.

How do I pass a pointer to a COM interface to a method in C#

I am writing an a small utility app for a class room type of environment. It's purpose is to ensure that all of the systems start each day with the correct baseline for audio capture. The captured audio is in relation to foreign language skills and need to be very consistent. This app will be used in several different classes with upwards of 30 machines each.
I am using C# on Win7 systems to access the Core Audio APIs. Part of what I need was found in a wrapper dll, CoreAudioAPI.dll, which handles MMDevice and EndpointVolume APIs. With that I am able to set the Microphone and speaker volumes.
The last setting I need to set is Microphone Boost which, on most system's UI, shows as a slider for a DB+ value of 0 to 40. In order to get to this setting I needed to add to the existing wrapper dll to access the DeviceTopology API. I have been able to work out everything with this except for one problem. I can get to the setting but to be able to see it's values and set it I have to be able to pass a pointer to one of the interfaces.
I am calling a routine in a separate class that does the work of connecting to the device and finding the setting I need.
Calling line:
mbs.DecibelLevel(ref IAudioVolumeLevel pInterface);
The value passed needs to be a pointer to the interface not a reference to the interface itself.
The work is done here looping through the various topologies until microphone boost is found the line below returns a pointer value for the IAudioVolumeLevel interface that should get passed in from the calling line.
public void DecibelLevel(ref IntPtr audioVolumeLevelPtr)
{
...
_PartNext.Activate(CLSCTX.ALL, ref IID_IAudioVolumeLevel, out audioVolumeLevelPtr);
...
}
How do I pass a pointer to IAudioVolumeLevel in C# from the calling routine to the worker routine so I can get and then set this.
Thank you in advance for your help.
EDIT:
I tried this example I found to get a pointer object but the second line failed with an 8004:
// Use the CLSID to instantiate the COM object using interop.
Type type = Type.GetTypeFromCLSID(IID_IAudioVolumeLevel);
Object comObj = Activator.CreateInstance(type);
// Return a pointer to the objects IUnknown interface.
IntPtr pIUnk = Marshal.GetIUnknownForObject(comObj);
IntPtr pInterface;
Int32 result = Marshal.QueryInterface(pIUnk, ref IID_IAudioVolumeLevel, out pInterface);
This is supposed to give me a pointer for the other call but is errors on the Activator.CreateInstance call with an 80040154 against the interface. As this is on a basic windows interface to the audio APIs I don't see why any missing components would be the issue.
Help please!
I want to thank those that looked at the question and especially those that provided some feedback. I was able to resolve this initial problem and i am getting the pointer back. It appears that I just had to send and IntPtr as a ref parameter and use that.
That leaves me with one other problem that I haven't yet found a clear answer to. Now that I have my pointer value, how do I use it to get to the actual interface? i have defined the C# interface to be able to access COM:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CoreAudioApi.Interfaces
{
[Guid("7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioVolumeLevel : IPerChannelDbLevel { }
}
This coorsponds to the COM interface and is how my other interfaces are set up. The C++ example I am working from sends a pointer defined from the interface:
IAudioVolumeLevel* pIaudioVolumeLevel;
getMicrophoneBoostVolumeLevel(defaultDevice, &pIaudioVolumeLevel);
On returning the volume setting for this particular part can be examined and set:
pIaudioVolumeLevel->GetLevelRange(0, &fMinDb, &fMaxDb, &fStepDb);
pIaudioVolumeLevel->GetLevel(0, &pfCurrentDb);
pIaudioVolumeLevel->SetLevel(0, pfCurrentDb, NULL);
Assuming i am getting the correct value in the returned pointer, how do I now set the level through C#?
Thank you

COM Object Clean Up

What is the difference between the two lines of code below:
CComPtr< IInterface > m_interface;
IInterface* m_interface;
I know that CComPtr help eliminate memory leaks, but I am getting inconsistent results. When declaring the pointer with CComPtr< IInterface > m_interface;
and using the interface in my C# code there are no errors, however using the Interface in VC++ I get an unhandled exception error, even if I comment out the instance creation of IInterface.
I am pretty sure the problem is in here somewhere:
STDMETHODIMP CSomeClass::get_IClass(IClass** var)
{
return m_class_var->QueryInterface(var);
}
STDMETHODIMP CSomeClass::putref_IClass(IClass* var)
{
m_class_var = var;
return S_OK;
}
When I declare the interface pointer with: IInterface* m_interface;
I get a RPC_E_SERVERFAULT error when testing the Interface in C# and have to explicitly call GC.Collect() to avoid the error being thrown after instantiation of a few objects. When testing the Interface in VC++ the error is consistent however when it occurs is different. If I comment out the instance creation of IInterface the code runs fine, however when I try to create an instance I get same error as before, just a vague unhandled exception error. What am I doing wrong here?
CComPtr is a smart pointer designed to do the 'right' thing when used with COM idioms.
Your code for get_IClass looks good, but putref_IClass needs to call AddRef on the IClass as you're storing it. If you used CComPtr that would happen automatically.
You'll need to add more details about your VC++ unhandled exception.
IInstance* m_instance is a simple pointer to an IInstance object. You have to manage the lifetime of this pointer yourself. You don't new and delete COM objects like you would ordinary objects. Instead, the operating system allocates the object when you call the WINAPI function `CoCreateInstance' :
// instantiate the CoClass which implements IInstance...
IInstance* instance = 0;
HRESULT hr = CoCreateInstance(__uuidof(mylibrary::MyCoClass), 0, CLSCTX_INPROC_SERVER, __uuidof(mylib::IInstance), &instance);
: :
// We're done, so release the object...
instance->Release();
instance = 0;
Each COM object implements reference counting. When the last reference to an object has been Release()ed, the COM object destroys itself.
Using CComPtr<> simplifies how you manage the lifetime of the COM objects. It is a smart pointer similar in nature to std::auto_ptr or Boost's shared_ptr, but it works with COM objects. Typically when using a CComPtr you would call the CreateInstance member function rather than calling the WINAPI function, and you would not explicitly call Release when you are done. Just let the CComPtr go out of scope, and when it's destructor is called it will call Release for you:
void function()
{
// instantiate the CoClass which implements IMyInterface...
CComPtr<IInstance> instance;
instance.CoCreateInstance(__uuidof(mylibrary::MyCoClass));
: :
// We're done, so release the object...
// dont have to do anything, it will be released when function() exits
}
CComPtr< IInterface > m_interface is an object. Whereas IInterface* m_interface is a pointer.
The first will have its destructor called when it goes out of scope and I think (a long time since I used it) it will automatically call m_interface ->Release().
The latter is a pointer to an interface and you have to manage when m_interface->Release() is called.
Can you confirm that the COM object is not being released before access?

Categories

Resources