Как вручную упаковать объект.NET как двойной интерфейс COM?

Я написал некоторый код C#, который возвращает объект.NET в неуправляемый код как IDispatch использование указателя Marshal.GetIDispatchForObjectоднако этот объект также реализует другие (не определенные в.NET) COM-интерфейсы. В неуправляемом мире QueryInterface для этих интерфейсов работает нормально, однако, вызов методов для них никогда не нарушает мой код.NET и, похоже, возвращает только значения по умолчанию (0).

Можно ли маршалировать объект.NET как двойной интерфейс, чтобы его можно было использовать через IDispatch или путем запроса для определенных интерфейсов? Мой тип публичный, ComVisible и я пытался подать заявку [ClassInterface(ClassInterfaceType.AutoDual)] без удачи

У меня не было проблем, заставляя вещи работать, используя UnmanagedType.Interface маршалинг, однако, поддерживая IDispatch также кажется проблематичным. Если есть простой способ "вручную" реализовать IDispatch это также было бы приемлемым решением.

1 ответ

Решение

Вы можете использовать интерфейс ICustomQueryInterface. Это позволит вам возвращать интерфейсы IUnknown "вручную" и при этом пользоваться преимуществами реализации IDispatch, предоставляемой.NET. Так, например, если у вас есть неуправляемый интерфейс IUnknown "IMyUnknown", который содержит один метод (в примере называемый "MyUnknownMethod"), вы можете объявить свой класс.NET следующим образом:

[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()
    {
       ...
    }
}
Другие вопросы по тегам