views:

75

answers:

2

This is just a question on how to write my code for a COM import.

My understanding of the correct implementation of interop interfaces is that the main criteria is that:

  1. All method signatures must match in a compatible way
  2. Methods must appear in exactly the same order in the .Net interface as they do in the unmanaged interface
  3. When the unmanaged interface inherits from another unmanaged interface, the managed implementation must first declare the base-level interface members, starting with the base-most interface.

My question is; what do I do, with respect to the order in which the members appear, if the interface I am importing is inherited from another interface and overrides/hides one or more of the members in the base interface? Where does the interface member declaration go? First, where the base interface declared it? Or removed from its original position and placed where the derived interface declares it?

[uuid(31d1c294-1dd2-11b2-be3a-c79230dca297)]
interface BaseComInterface
{
    void method1();
    void method2();
    void method3();
}

[uuid(fab51c92-95c3-4468-b317-7de4d7588254)]
interface DerivedComInterface : BaseComInterface
{
    void method1();
    void method4();
    void method5();
}

Now for the C# code:

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDerivedComInterface
{
    void method1(); // do I remove this one?
    void method2();
    void method3();
    void method1(); // or this one?
    void method4();
    void method5();
}
A: 

I suggest you use explicit interface member implementations to avoid conflict.

Sheng Jiang 蒋晟
I don't think you read the question. I'm talking about interop code here, not pure managed inheritance.
Nathan Ridley
Then why are you talking about implementing interface in C#? The interface is implemented by someone else. You just need to cast the COM object's RCW to your desired interface. .Net will call QueryInterface for you.
Sheng Jiang 蒋晟
+1  A: 

Do you have an example of someone actually doing this? While it is perfectly legal in COM to have the same name for a method in an interface and in another interface derived from it, it makes working with the derived interface difficult or impossible in pretty much all development environments. That includes implementing as well as calling any COM objects based on the interface.

There is no such thing as overriding or hiding in a COM interface. A COM interface is just a contract for how an object's binary interface will be laid out in memory, the names of the methods in the interface definition are meaningless except to tools. In your case the BaseComInterface promises a 'vtable' with six methods the first three match the signatures of the IUnknown methods and the next three match the signatures of the three methods you have given, all in the correct order. On the other hand DerivedComInterface promises a 'vtable' that includes nine methods, again the first three signatures match the IUnknown methods, the next three match the signatures of the BaseComInterface methods and the last three match the three methods unique to DerivedComInterface. The names of these methods are immaterial except to your IDE, tools and compiler which need the names to find the 'vtable' pointers.

So basically, in C# as well as C, C++ and some other languages, in order to implement DerivedComInterface one of the method names would need to be decorated to distinguish it's 'vtable' slot from the other.

To answer your question - you would remove neither method since they are both required to be there to fulfill the COM contract:

[Guid("fab51c92-95c3-4468-b317-7de4d7588254"), ComImport,  InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDerivedComInterface
{
    void method1(); 
    void method2();
    void method3();
    void method1_2(); //Decorated to distinguish from base interface method.
    void method4();
    void method5();
}

This ignores what would happen if these interfaces derived from IDispatch rather than IUnknown, a mess I wouldn't want to get into. Also, remember that if your idl really defines the methods as returning void you must decorate your C# methods with the PreserveSig attribute.

Stephen Martin
Great answer, very informative, thanks!
Nathan Ridley