2

I am building a library which needs to be referenced from VBA so I need to provide a type library to support early binding. Most of the examples I have seen define a interface for classes which are exposed to COM e.g.

[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]     
[InterfaceType(ComInterfaceType.InterfaceIsDual)]     
public interface IMyClass 

[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]     
[ClassInterface(ClassInterfaceType.None)]     
[ProgId("MyNamespace.MyClass")]     
public class MyClass : IMyClass

Is there any disadvantage in having a class implement the interface directly using ClassInterface.AutoDual? For more complex classes I like having interfaces to clearly define which members are exposed com without having to use the ComVisible attribute everywhere. But I will also have a number of fairly trivial data classes like event args which will be exposed to COM in their entirety. I have also seen examples which explicitly set dispids on interfaces - is there any advantage in doing this?

Shane
  • 2,271
  • 3
  • 27
  • 55
  • 1
    Please see this question http://stackoverflow.com/q/1435295/57428 about why you need an interface and `ClassInterfaceType.None`. – sharptooth Apr 26 '11 at 05:26

1 Answers1

5

Yes, there's a big one: DLL Hell is nasty with early binding. The COM client directly calls the method through the v-table pointer. If an outdated COM server that uses the same interface IIDs (which in itself is a crime) is resident then this may call a wrong or non-existing method. The runtime failure, usually an AccessViolation, is very hard to diagnose.

This doesn't happen with late binding, there will (usually) be a reasonable diagnostic, like DISP_E_MEMBERNOTFOUND or DISP_E_BADPARAMCOUNT. Which is why Microsoft heavily favors ComInterfaceType.InterfaceIsIDispatch. The disadvantage is that late binding is quite slow. Another one is that errors are only caught at runtime, not compile time.

Setting the DispIDs is very rarely useful. Some legacy Microsoft products used dispid binding, pre-compiling the dispid into the code. It is roughly twice as fast as late binding because there's no need for the IDispatch::GetIDsOfNames() call. It is very unlikely you'll still encounter them in the wild, certainly not any VBA version.

A decent KB article on the topic is here.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I read the article - thanks for the pointer. Guess you are talking about binary compatibility - so if I install a new version without updating the type library then with by using an interface the vtable layout of the code implementing the COM interface remains the same and function calls still work? – Shane Apr 26 '11 at 14:10
  • I am a bit confused by your remark about reusing IIDs. What do you mean by IID - the GUIDs applied to the interface in my example above? Are you saying that that the GUID on the interface should be changed when a new version of the code is released when you say “which in itself is a crime”? Wouldn't that also break compatibility between versions? – Shane Apr 26 '11 at 14:11
  • I think I know what you mean about not re-using IIDs – interfaces should be immutable i.e. once an IID has been assigned to an interface it should never change in future versions of the component – only new interfaces can be added. Is this correct? – Shane May 04 '11 at 04:52
  • I’ve accepted you answer as I guess it answers my question, but I think my use case is a bit of special case. The sole purpose of the creating the lib is to provide functionality to excel – it does need to support c++ clients (for example) which import the type lib on compilation and create code relying on the layout of interface. Need to find out more but I suspect that as long as the machine on which excel code is run has a compatible version of the assembly and its type library installed things should be fine – I don’t think info about the binary layout is not stored in .xls files. – Shane May 04 '11 at 04:54