添加新功能时是否必须更改COM接口UID?

4
我有一个COM接口在我的应用程序中,第三方插件使用它。现在,我需要向此接口添加一个新方法,但不能更改接口的GUID,因为这将破坏所有现有插件。据说如果我将新方法添加到接口的末尾,它将可以正常工作,因为最终COM接口是一个函数指针表。这些新方法只会被新编写的插件使用。我读了Raymond Chen博客中的这篇文章和第一个评论:http://blogs.msdn.com/b/oldnewthing/archive/2005/11/01/487658.aspx,但评论中提到的情况不会发生在我的情况下,因为这是一个仅限于Windows的应用程序。我知道理论上我应该更改接口GUID。在这种情况下,正确的解决方案是什么?或者说这种方法可行吗?
1个回答

5
通常情况下,您可以在现有接口的末尾添加新方法而不会破坏兼容性。但正如您所阅读的那样,有些微妙的情况可能会导致破坏,特别是当已经使用多重继承时。正确的解决方案是为新方法声明一个新的接口,不要改动您现有的接口。然后让您现有的对象实现这两个接口或使用继承让新接口从旧接口继承。例如,如果以下是我们的原始代码(为了简洁起见,我假装没有使用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的可能模糊转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接