我添加了一个新接口IAEx,它从现有接口IA(从IDispatch派生)扩展而来。
idl有哪些变化? 我已经将coclass定义更改为从新的继承。 我更改了idl中的coclass条目,就像之前一样。
(我需要将deafult接口作为新接口)
coclass CAx
{
[default] interface IA
[default, source] dispinterface IAEvents;
};
并改为
coclass CAx
{
[default] interface IAEx
[default, source] dispinterface IAEvents;
};
我可以改变deafualt interafce吗?
coclass定义更改。 旧的
class ATL_NO_VTABLE CAx:
...
public CCIDispatchImpl<IA, &IID_IA, &LIBID_CCALib>,
新的。
class ATL_NO_VTABLE CAx:
...
public CCIDispatchImpl<IAEx, &IID_IAEx, &LIBID_CCALib>,
这样可以吗?
COM MAP条目修改: 旧的:
COM_INTERFACE_ENTRY(IA)
COM_INTERFACE_ENTRY2(IDispatch,IA)
新的:
COM_INTERFACE_ENTRY(IAEx)
COM_INTERFACE_ENTRY2(IDispatch,IAEx)
我是否还需要在COM MAP中添加旧界面?
答案 0 :(得分:2)
不,这是对客户端程序的彻底改变。要记住的黄金法则#1是名称在COM中非常重要,只有 uuids 很重要。规则#2是COM组件具有计算机范围,修改组件会影响使用该组件的计算机上的每个程序。另一种说法是COM具有强大的DLL Hell问题。
因此,当您在计算机上安装组件时,第一件事就是每个使用它的程序都将停止工作。他们仍在寻找“IA”界面uuid,它已经不存在了。他们以E_NOINTERFACE失败了。避免这种情况的唯一方法是使用新类型库重新编译客户端程序,并在部署更新的COM组件的同时部署它们。这通常很难安排,因为他们没有共同的程序员或公司。通常只有用户可以这样做,他们很少知道如何正确地执行此操作或知道如何解决故障。
如果您希望更新向后兼容,那么必须为您的coclass添加新界面。它不能是[默认]接口,因为现有客户端程序期望将旧接口作为默认接口。然而,这会导致新问题,使用IDispatch的客户端运行时通常不支持任何内容,只支持单个默认接口。通常是因为他们没有接口的概念作为主要语言构造。换句话说,您的客户端程序员无法调用IUnknown :: QueryInterface(),因此根本无法使用您的新接口。所以不是一般的解决方案。
技术上可能违反COM中的接口是不可变的规则。您可以在IDispatch接口的末尾添加新方法。现有的客户端代码不知道它们,因此永远不会调用它们并继续使用组件的旧版本和新版本正确运行。假设您知道如何在不导致行为改变的情况下维护遗留方法,通常比看起来更难。但是仍然存在DLL Hell问题,当客户端代码的更新版本符合旧版本的组件时,世界就会崩溃。乍一看这似乎不太可能,但是当机器被更换或重新成像时,这往往会出错。非常丑陋的情况,运行时故障是无法诊断的,任何最初参与的人都不在身边或者不记得细节。
只有真正安全的方法才能创建新版本。修改所有 uuids(LIBID,CLSID和IID)并更改DLL文件名。现在新旧版本可以共存,客户端程序员可以在闲暇时使用您的新版本。可能仍存在部署问题,但故障很容易诊断,客户端程序因“未注册类”而失败。
答案 1 :(得分:0)
您应该在COM MAP中包含旧接口,以及如果客户端尝试使用旧接口的QueryInterface,它应该会收到有用的结果而不是错误。添加COM_INTERFACE_ENTRY2(IA, IAEx)
。
否则看起来你拥有一切。我们将两个接口添加到IDL文件中的coclass条目中,但我没有真正使用它的东西。即:
coclass Ax
{
[default] interface IAEx;
interface IA;
};
答案 2 :(得分:0)
是否合适取决于目标究竟是什么。如果你担心不破坏与现有客户端的兼容性,更换接口就可以了,最重要的是你的服务器仍然实现旧的接口IA
。您应该在COM MAP上列出接口(因为您提到IAEx
是从IA
继承的,您可能需要COM_INTERFACE_ENTRY_IID
宏):
COM_INTERFACE_ENTRY(IAEx)
COM_INTERFACE_ENTRY_IID(__uuidof(IA), IAEx) //COM_INTERFACE_ENTRY(IA)
COM_INTERFACE_ENTRY2(IDispatch, IAEx)
这样您的服务器就可以实现IAEx
和IA
。继承接口之间的接口是我宁愿建议的,但你拥有的东西。
更新coclass
(正如patthoyts的回答中所建议的那样)使更新更加清晰,并且值得做,但是重建客户端更重要,而不是保持与现有构建代码的兼容性:工具导入类型库信息将能够看到两个接口,如果他们在乎,并能够处理那里的非默认接口。