【问题标题】:Is it must to change COM interface UID when adding new functions添加新功能时是否必须更改COM接口UID
【发布时间】:2013-12-01 06:28:42
【问题描述】:

我的应用程序公开了一个 COM 接口,供第三方插件使用。现在,我需要向这个界面添加一个新方法,但不能更改界面的 GUID,因为它会破坏所有现有的插件。有人告诉我,如果我在接口末尾添加新方法,它将毫无问题地工作,因为最终 COM 接口是一个函数指针表。这些新方法只会被新编写的插件使用。我在 Raymond Chen 的博客中阅读了这篇文章和第一条评论:http://blogs.msdn.com/b/oldnewthing/archive/2005/11/01/487658.aspx 但评论中提到的情况不会发生在我的案例中,因为它是仅限 Windows 的应用程序。我知道理论上我应该更改界面 GUID。在这种情况下,正确的解决方案是什么?还是这种方法行得通?

【问题讨论】:

    标签: windows com backwards-compatibility


    【解决方案1】:

    通常可以在不破坏兼容性的情况下向现有接口的end添加新方法。但是正如您一直在阅读的那样,在某些微妙的情况下这可能会中断。尤其是在已经使用多重继承的情况下。

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

    例如,如果这是我们的原始代码。 (为简洁起见,我假设这是在没有 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 模棱两可转换的方式上保持一致。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      • 2018-10-20
      • 2018-08-31
      • 2016-05-16
      • 2016-12-28
      • 1970-01-01
      相关资源
      最近更新 更多