添加新function时是否必须更改COM接口的UID?

我有一个COM接口暴露从我的应用程序,由第三方插件使用。 现在,我需要添加一个新的方法到这个接口,但不能改变接口的GUID,因为它会打破所有现有的插件。 我被告知,如果我添加新的方法在接口的最后,它将工作没有问题,因为最终COM接口是一个函数指针的表。 这些新方法只能用于新编写的插件。 我读了这篇文章和Raymond Chen的博客中的第一个评论: http : //blogs.msdn.com/b/oldnewthing/archive/2005/11/01/487658.aspx,但评论中提到的情况不会发生在我的因为它是Windows唯一的应用程序。 我知道理论上我应该改变接口的GUID。 在这种情况下什么是正确的解决scheme? 或者这个方法会起作用吗?

通常可以避免将新方法添加到现有接口的末尾而不会破坏兼容性。 但是,正如你一直在阅读,有微妙的情况下,可以打破。 特别是当多重继承已被使用。

正确的解决方案是简单地为新方法声明一个新的接口。 单独保留现有的接口。 然后让你的现有对象实现这两个接口或使用继承,使新的接口从旧的继承。

例如,如果这是我们的原始代码。 (为了简洁起见,我会假装没有IDL文件)。

原始码:

class IPublicInterface : public IUnknown { public: virtual void M1() = 0; virtual void M2() = 0; } class MyPublicClass : IPublicInterface { public: // IPublicInterface void M1(); void M2(); // IUnknown HRESULT QueryInterface(...); ULONG AddRef(); ULONG Release(); }; 

现在让我们说,我们要添加一个新的方法,这个对象称为M3,而不会中断现有的接口和对象的用户。 正确的解决方案是添加一个新的界面。 为了方便起见,它可以继承原来的界面。

 class IPublicInterface2 : public IPublicInterface { public: virtual void M3() = 0; }; 

现在修改这个类以继承这个新的派生接口:

 class MyPublicClass : public IPublicInterface2 { public: // IPublicInterface void M1(); void M2(); // IPublicInterface2 void M3(); // IUnknown HRESULT QueryInterface(...); ULONG AddRef(); ULONG Release(); }; 

更新QueryInterface以同时支持IPublicInterface的原始UUID以及IPublicInterface2的调用。

 HRESULT MyPublicClass::QueryInterface(GUID& iid, void** ppv) { // QI request for original interface if ((iid == uuidof(IPublicInterface) || (iid == uuidof(IUnknown)) { *ppv = (IPublicInterface*)this; AddRef(); return S_OK; } else if (iid == uuidof(IPublicInterface2) { *ppv = (IPublicInterface2*)this; AddRef(); return S_OK; } return E_NOINTERFACE; } 

或者,IPublicInterface2不需要从原始IPublicInterface继承。 在这种情况下,实现类从两个接口继承。 在QueryInterface实现中,您需要保持一致,以确定如何处理可能会模​​糊的投射到IUnknown。