tags:

views:

143

answers:

2

Up to now, I've always decorated my .NET classes that I want to use from VB6 with the [AutoDual] attribute. The point was to gain Intellisense on .NET objects in the VB6 environment. However, the other day I googled AutoDual and the first answer is 'Do Not Use AutoDual'.

I've looked for coherent explanation of why I shouldn't use it, but could not find it.

Can someone here explain it?

+3  A: 

I think this sums it up:

Types that use a dual interface allow clients to bind to a specific interface layout. Any changes in a future version to the layout of the type or any base types will break COM clients that bind to the interface. By default, if the ClassInterfaceAttribute attribute is not specified, a dispatch-only interface is used.

http://msdn.microsoft.com/en-us/library/ms182205.aspx

It increases the possibility that changing something in that class with the auto dual attribute will break someone else's code when the class is changed. If gives the consumer the ability to do something that will quite possibly cause them issues in the future.

The next option is ClassInterfaceType.AutoDual. This is the quick and dirty way to get early binding support as well (and make the methods show up in VB6 IntelliSense). But it's also easy to break compatibility, by changing the order of methods or adding new overloads. Avoid using AutoDual.

http://www.dotnetinterop.com/faq/?q=ClassInterface

I finally found the link that talks about what is going on with AutoDual and how it works:

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/7fa723e4-f884-41dd-9405-1f68afc72597

The warning against AutoDual isn't the fact that dual interfaces is bad but the fact that it auto-generates the COM interface for you. That is bad. Each time the COM interface has to be regenerated you'll get a new GUID and potentially new members. If the GUID changes then you get a brand new interface/class as far as COM is concerned. For early binding you'd have to rebuild the clients each time the interface was regenerated. The preferred approach is to define the COM class interface explicitly with a GUID. Then all the early binding clients can use the defined interface and not worry about it changing on them during development. That is why the recommended option is None to tell the CLR not to auto-generate it for you. You can still implement the dual interface though if you need it.

Kevin
The part I am not clear on is this: ` Any changes in a future version to the layout of the type or any base types will break COM clients'. Meaning if I change a property from int to double, the client will break? Or does it mean that if I simply recompile the .NET piece, VB6 client will no longer be able to consume it?
AngryHacker
As long as you don't change the interface you should be ok.http://www.dotnetinterop.com/faq/?q=ClassInterface
Kevin
@Kevin, so simply recompiling my .NET library won't break the consumer than? And what does `changing the order of methods' really mean? Meaning change the order of methods in code? I still don't have a good understanding as to why we should avoid AutoDual. I think it is understood that if you change the interface, than the consumer is not going to work. It's pretty much always been that way in the VB6 world.
AngryHacker
@AngryHacker In theory it shouldn't. I found a quote that explains what happens with AutoDual.
Kevin
@Kevin So, in theory if I decorate the class with [ClassInterface(ClassInterfaceType.AutoDual)] and with [GuidAttribute("BA713700-522D-466e-8DD4-225884504678")], it should all be good then, correct?
AngryHacker
@AngryHacker I would try it and see, as I have never done it myself, but yes from what I understand that would be correct.
Kevin
@Kevin Yeah, I've tried and it works fine. And I've always done it that way. But you know, trying to avoid the "Works on my machine syndrome".
AngryHacker
@AngryHacker: That's how I usually do it when I wrote .NET classes that I need to use from VB6. So, it works on my machine too! At the very least, we know it works on two computers. ;)
Mike Spross
+2  A: 

I found a reliable way to both provide Intellisense for .NET objects in VB6, while at the same time not breaking the interface. The key is to mark each public method/property in the interface with DispatchID. Then the class must inherit from this interface - in the manner below.

[Guid("BE5E0B60-F855-478E-9BE2-AA9FD945F177")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICriteria
{
    [DispId(1)]
    int ID { get; set; }
    [DispId(2)]
    string RateCardName { get; set; }
    [DispId(3)]
    string ElectionType { get; set; }
}


[Guid("3023F3F0-204C-411F-86CB-E6730B5F186B")]    
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyNameSpace.Criteria")]
public class Criteria : ICriteria
{
    public int ID { get; set; }
    public string RateCardName { get; set; }
    public string ElectionType { get; set; }
}

What the dispatch ID gives you is the ability to move around items in the class, plus you can now add new things to the class and not break the binary compatibility.

AngryHacker