C# exposing to COM - interface inheritance

10,560

Solution 1

This is not a .NET problem, it is a consequence of the way COM works. It doesn't support inheritance. You would fix this at the client side, it needs to call QueryInterface() with the IID for IBaseClass to get an interface pointer to the IBaseClass interface so it can call GetA(). .NET interop automatically provides a QI implementation that makes this work. However, it is not very user-friendly in this case, design your C# side code to make it easy for the client to use your class instead of the other way around. You'd typically need a one-liner override method that delegates to the base C# class implementation.

Note that there's a problem with your method signatures and the use of the [PreserveSig] attribute. They are not callable through IDispatch nor can they be auto-marshaled. That requires a method with a HRESULT as the return value type. It is automatic when you remove the attribute.

Solution 2

This appears to be very similar to this question: Interface inheritance in ComVisible classes in C#

As you noted in your edit, this is a limitation on the .net to COM hop, that the COM interface does not include any inherited interfaces.

In some languages you could have solved this by inculding a block of code in all relevant interfaces, but as far as I am able to see this is not possible in C#.

Share:
10,560
jonathanpeppers
Author by

jonathanpeppers

Xamarin MVP and lead developer on the popular apps Hanx Writer and Draw a Stickman. I work at Microsoft on the Xamarin.Android team.

Updated on June 07, 2022

Comments

  • jonathanpeppers
    jonathanpeppers about 2 years

    Say I have a class BaseClass that implements IBaseClass

    Then I have an interface IClass that inherits IBaseClass.

    Then I have a class named class that implements IClass.

    For example:

    [ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")]
    public interface IBaseClass
    {
      [PreserveSig]
      string GetA()
    }
    
    [ComVisible(true), InterfaceType(ComInterfaceType.IsDual), Guid("XXXXXXX")]  
    public interface IClass : IBaseClass
    {
      [PreserveSig]
      string GetB()
    }
    
    [ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")]
    public class BaseClass : IBaseClass
    {
      public string GetA() { return "A"; }
    }
    
    [ComVisible(true), ClassInterface(ClassInterfaceType.None), Guid("XXXXXXX")]
    public class Class : BaseClass, IClass
    {
      public string GetB() { return "B"; }
    }
    

    When exposing to COM, if I make an instance of "Class" it does not allow me to call GetA().

    When looking my IDL in the .tlb file, my IClass interface looks like:

    [
      odl,
      uuid(XXXXXXXXXXXXXXXXXXXXX),
      version(1.0),
      dual,
      oleautomation,
    
    ]
    interface IClass : IDispatch {
        [id(0x60020000)]
        BSTR GetB();
    }
    

    It doesn't even look like IClass derives from IBaseClass!

    If I take out where IClass derives from IBaseClass and just add the methods to the interface, it works.

    How can I make C# enable this inheritance in COM? I'd rather not re-implement interfaces when I can inherit them.

    CRAP: check this link .Net COM Limitation

    If someone has an answer to why this is, or a better workaround than copy-paste to my "derived" interface, let me know. If not, I'll mark an answer in a couple days.