Search code examples
c#.netcomidispatch

How to manually marshal a .NET object as a dual COM interface?


I have written some C# code which returns a .NET object to unmanaged code as an IDispatch pointer using Marshal.GetIDispatchForObject, however, this object also implements other (non .NET defined) COM interfaces. In the unmanaged world QueryInterface for these interfaces works fine, however, calling methods on them never breaks into my .NET code and seems to return default values only (0).

Is it possible to Marshal a .NET object as a dual interface, such that it may be used through IDispatch or by querying for particular interfaces? My type is public, ComVisible and I tried applying [ClassInterface(ClassInterfaceType.AutoDual)] without luck.

I've had no problems getting things to work using UnmanagedType.Interface marshaling, however, supporting IDispatch as well seems problematic. If there is an easy way to "manually" implement IDispatch this would also be an acceptable solution.


Solution

  • You can use the ICustomQueryInterface interface. It will allow you to return IUnknown interfaces "manually" and still benefit from the IDispatch implementation provided by .NET. So, for example, if you have an unmanaged IUnknown interface "IMyUnknown" that contains one method (named "MyUnknownMethod" in the sample), you can declare your .NET class like this:

    [ComVisible(true)]
    public class Class1 : ICustomQueryInterface, IMyUnknown
    {
        CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv)
        {
            if (iid == typeof(IMyUnknown).GUID)
            {
                ppv = Marshal.GetComInterfaceForObject(this, typeof(IMyUnknown), CustomQueryInterfaceMode.Ignore);
                return CustomQueryInterfaceResult.Handled;
            }
    
            ppv = IntPtr.Zero;
            return CustomQueryInterfaceResult.NotHandled;
        }
    
        // an automatic IDispatch method
        public void MyDispatchMethod()
        {
           ...
        }
    
        // the IMyUnknown method
        // note you can declare that method with a private implementation
        public void MyUnknownMethod()
        {
           ...
        }
    }