向现有COM接口添加新函数会破坏其二进制兼容性吗?

向现有COM接口添加新函数会破坏其二进制兼容性吗?,com,Com,我想在所有现有方法不变的情况下,向COM接口添加一个新方法,这会破坏其在本次更新之前对使用者的兼容性吗?它肯定会破坏派生接口,因此即使它看起来可行,也不应该这样做 相反,派生一个包含附加方法的新接口,并使客户端需要新IID的附加功能QI。这取决于:如果这是一个内部未发布的接口,只要控制与该接口交互的所有代码,您就可以随意更改它 然而,一旦发布,规则是严格的:每个接口都有自己的IID。您可以通过修改、添加或删除方法以任何方式更改该接口,它是一个全新的接口,需要一个新的IID 但是:COM并不关心新

我想在所有现有方法不变的情况下,向COM接口添加一个新方法,这会破坏其在本次更新之前对使用者的兼容性吗?

它肯定会破坏派生接口,因此即使它看起来可行,也不应该这样做


相反,派生一个包含附加方法的新接口,并使客户端需要新IID的附加功能QI。

这取决于:如果这是一个内部未发布的接口,只要控制与该接口交互的所有代码,您就可以随意更改它

然而,一旦发布,规则是严格的:每个接口都有自己的IID。您可以通过修改、添加或删除方法以任何方式更改该接口,它是一个全新的接口,需要一个新的IID

但是:COM并不关心新接口是如何实现的:因此您可以让您的类将其实现为只添加新方法的旧接口的派生,并让您的实现类实现该派生,只要QI在请求旧接口或新接口时返回合适的接口

例如:

class IInterfaceOriginal: public IUnknown
{
public:
    ...
    // lots of methods
    ...
};

class IInterfaceUpdated: public IInterfaceOriginal
{
public:
    // Add just one additional method
    STDMETHOD(AdditionalMethod)(...) = 0;
};


class CImplementation: IInterfaceNew // this was IInterfaceOld
{
    // Also add implemention of AdditionalMethod somewhere here...

    HRESULT STDMETHODCALLETYPE QueryInterface( REFIID riid, void **ppvObject )
    {
        *ppvObject = NULL;
        if(riid == __uuidof(IUnknown)
        || riid == __uuidof(IInterfaceOriginal)
        || riid == __uuidof(IInterfaceUpdated)) // This is added
        {
            // Return a IInterfaceUpdated in response to a QI for either of IUnknown,
            // or the old or new interface. This works because in C++, any IInterfaceUpdaed
            // is also both of those two other interfaces.
            *ppvObject = static_cast<IInterfaceUpdated*>(this);
        }
        else
            return E_UNKNOWN;
        return ((IUnknown*)*ppvObject)->AddRef();
    }

    ...
}
class IIInterfaceOriginal:公共IUnknown
{
公众:
...
//很多方法
...
};
II类界面更新:公共界面原创
{
公众:
//只添加一个附加方法
标准方法(附加方法)(…)=0;
};
类CImplementation:IInterfaceNew//这是IInterfaceOld
{
//在这里的某个地方还添加了AdditionalMethod的实现。。。
HRESULT STDMETHODCALLETYPE查询接口(refid riid,void**ppvObject)
{
*ppvObject=NULL;
如果(riid==\uuuuIdof(IUnknown)
||riid==\uuuuIdof(IInterfaceOriginal)
||riid==\uuuuIdof(IInterfaceUpdated))//这是添加的
{
//返回IInterfaceUpdated,以响应IUnknown中任何一个的QI,
//或旧的或新的接口。这是因为C++中的任何接口。
//也是这两个其他接口中的一个。
*ppvObject=静态投影(此);
}
其他的
返回E_未知;
return((IUnknown*)*ppvObject)->AddRef();
}
...
}

因此,当您在技术上“添加另一个接口”时,实际上在这里添加了一些代码:只定义一个从旧接口派生的新接口,将类实现的接口更改为新接口(并为新方法添加实现),最后更新QI以支持旧方法和新方法-为两者返回相同的接口(也为IUnknown返回相同的接口)。

只要添加了新方法,COM接口就应该向后兼容。如果客户端应用程序想要使用新的COM接口,它们必须更新头文件(C++)或向新的COM接口重新添加引用(.NET)。此外,如果COM接口更改而未更新IID,则可能需要重新启动操作系统。总之,在不改变IID的情况下,它会起作用,但改变IID可能更“正确”

这听起来不错,现有接口中有很多函数,我只添加了一个。添加一个新接口似乎是一个很大的变化。这是允许派生接口的实现者保持二进制兼容的方法。:)COM接口是不可变的@TownCube那么,如果我真的改变了它,到底会有什么破坏呢?