Can a managed ref-class directly implement a COM i

2019-05-30 14:55发布

问题:

Is there a built-in way to allow a managed ref-class to implement and expose a COM inerface that is safely callable from native code?

Looking at the C# side, this is easily done by decorating the target interface with the proper COM-interop attributes, for example:

Native Interface

interface ISampleGrabberCB: public IUnknown
{
    virtual STDMETHODIMP SampleCB( double SampleTime, IMediaSample *pSample ) = 0;
    virtual STDMETHODIMP BufferCB( double SampleTime, BYTE *pBuffer, long BufferLen ) = 0;
}; 

static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,
  { 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };

Managed Equivalent Interface

 [Guid("0579154A-2B53-4994-B0D0-E773148EFF85")]
 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 [SuppressUnmanagedCodeSecurity]
 public interface ISampleGrabberCB {
    int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
    int SampleCB(double SampleTime, IMediaSample pSample);
 } 

Once this declaration is done, through the magic of P-Invoke you can do something like this:

public class FooClass : ISampleGrabberCB {
    int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {
       Console.WriteLine("BufferCB called");
    }
    int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) {
       Console.WriteLine("SampleCB called");
    }

   public void SomeMethod(IBaseFilter aDirectShowFilter) {
      ISampleGrabber sampleGrabber = (ISampleGrabber)aDirectShowFilter;
      // By the magic of PInvoke, this is possible and works! 
      // ISampleGrabber->SetCallback() is expecting an ISampleGrabberCB* COM interface
      // After the following line, native code is able to callback safely
      // into our managed code
      sampleGrabber.SetCallback(this, 0);
   }
}

Is there a way to mimic this behavior on C++/CLI?
Evidently, the Interop plumbing to make this possible exists as it is used by C#. Furthermore, the compiler could generate the necessary managed interface from inspecting the available native interfaces (I still think we would need to provide the relevant Guids, as this is not an attribute within the native interface)

回答1:

I just got curious about this topic and played around and I found out some minor differences:

I have IVI-COM class library on my PC, and always wanted to try to interface some of them, although the IVI also has .Net interfaces so it does not make too much sense...

I started with C#, where we get good IntelliSense support. I have added the necessary references and added a class to my project. With the object browser we can select an interface.

public class MyDmm : IIviDmmMultiPoint
{
}

After that just use IntelliSense (Ctrl-.) to add the ‘using’ statement and let them make the necessary properties and methods for us.

using Ivi.Dmm.Interop;
///...
public int Count
{
    get
    {
        throw new NotImplementedException();
    }
///...

So now we need the C++-CLI dialect :) Which is as follows:

using namespace IviDmmLib;
///...
public ref class Dmm : IIviDmmMultiPoint
{

Note that the name used by the using statement is different, we can obtain this by selecting the reference at the Solution Explorer and check the name shown at the ‘Properties’ below.

I did not fully complete the experiment but I saw that the COM library was x64 bit, so we may compile the project for the same.

Further interesting readings:

  • Windows Runtime C++ Template Library

Please, give me feedback if you find some more differences, so we can put them here too.