C# 如何告诉vb6不要每次创建dll时都创建interfaces/com对象的新版本?

C# 如何告诉vb6不要每次创建dll时都创建interfaces/com对象的新版本?,c#,.net,vb6,binary-compatibility,C#,.net,Vb6,Binary Compatibility,我有.NET代码使用的vb6 com服务器(ActiveX DLL项目) 每次我将更改放入vb6代码并生成dll时,我也必须重新编译.NET客户端代码,因为vb6似乎会生成新的GUI或接口和com对象的版本 我承认这是一个很好的做法,因为会进行更改,但我想禁用此行为,以便在每次更新vb6 dll时使.NET客户端代码保持不变 我如何告诉VB6,无论对COM对象或COM接口做了什么更改,ActiveX dll的所有GUID和版本都保持不变 项目+属性、组件选项卡中的选择很重要。您必须在这里选择“二

我有.NET代码使用的vb6 com服务器(ActiveX DLL项目)

每次我将更改放入vb6代码并生成dll时,我也必须重新编译.NET客户端代码,因为vb6似乎会生成新的GUI或接口和com对象的版本

我承认这是一个很好的做法,因为会进行更改,但我想禁用此行为,以便在每次更新vb6 dll时使.NET客户端代码保持不变


我如何告诉VB6,无论对COM对象或COM接口做了什么更改,ActiveX dll的所有GUID和版本都保持不变

项目+属性、组件选项卡中的选择很重要。您必须在这里选择“二进制兼容性”,以强制它重用旧的guid。并保留一份DLL副本作为提供GUI的“主控”,将其签入源代码管理

当添加新类时,还必须更新该副本,以便将来的版本能够为这些添加的类重用相同的guid。很容易忘记,很难诊断


这是非常危险的,重用guid是一个非常强大的DLL地狱诱因。只要小心避免更改现有方法,就可以让旧的客户端程序继续使用新的DLL。不仅是它们的方法签名,还有它们的实现。遇到旧版本DLL的更新客户端将以一种非常糟糕的方式失败,访问冲突崩溃几乎无法诊断。

使用二进制兼容性只会为您带来很多好处。长期维护接口兼容性只适用于非常简单的库,或者当您的接口从一开始就经过很好的规划和未来验证时。看着一些人的VB6库,看到界面版本号高达数百(GUI和版本号都用来标识界面),即使他们认为自己已经小心地管理了二进制兼容性,也会让人感到害怕

如果你有一个共享库的程序系统,情况会变得更糟。一个新的需求,甚至是一个bug修复,可能需要对一个程序库的接口进行突破性的更改,而不是其他12或20个程序

您必须通过显式的手动版本控制来适应这一点,在这里您实际上更改了库的名称,以反映具有全新guid集的新版本。通常,这是通过编号来完成的,这样像“FuddInvLib1.DalRoot”这样的ProgId可以与新的“FuddInvLib2.DalRoot”共存于两个具有完全不同的GUID集的库中:FuddInvLib1.dll和FuddInvLib2.dll


由于每个版本都是为了支持而更改的,因此您可以在每个版本中随时间保持二进制兼容的版本控制,最终完全淘汰FuddInvLib1.dll。当然,这意味着随着时间的推移,要迁移客户端代码以使用较新的库,但您可以按照计划的速度增量地执行此操作。

COM合同规定接口定义是不可变的(方法名称、参数列表、方法顺序、方法数量不变),但这种实现可以自由更改。天真,但真实。(VB二进制兼容性不允许您更改接口中的方法签名或方法顺序,尽管它允许您向接口中附加新方法——见图)。然而,对正在生产的DLL的接口或其方法进行任何更改都是“最糟糕的做法”,多年的DLL地狱已经证明了这一点,正如Hans所解释的那样

通过版本更改保持二进制兼容性的一种方法是向组件添加新接口,并且一旦DLL的任何版本投入生产,就永远(永远)不要接触旧接口。旧客户机将乐于使用旧接口,而新客户机可以使用新接口

使用旧接口错误的新客户端可以通过使用iUnknown.QueryInterface方法进行捕获。在VB中,可以执行以下操作:

If Not TypeOf myObjectReference Is myNewInterface Then
    'gracefully handle the error
End If
这将调用QueryInterface方法,如果引用的是较旧版本的DLL,则返回false。您可以通知用户需要安装较新版本的DLL并退出。您可以将此功能包装成函数,并在新客户端中初始化对象时调用它。如果不支持新接口,则为旧版本的DLL;您可以向用户发送消息,让其安装新版本并继续安装。

请参阅和项目与二进制兼容选项的说明。