Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Would adding a new function to the existing COM interface break its binary compatibility?

Tags:

com

I want to add a new method to a COM interface with all the existing one unchanged, will this break its compatibility for the consumer before this update?

like image 573
Thomson Avatar asked Feb 21 '23 12:02

Thomson


2 Answers

It depends: if this is an internal unpublished interface, you are free to change it at will so long as you control all the code that interacts with that interface.

Once published, however, the rules are strict: every interface has its own IID. You change that interface in any way - by modifying, adding or removing methods - it's a whole new interface, and requires a new IID.

However: COM does doesn't care how that new interface is implemented: so you can have your class implement it as a derivation of the old interface that just adds a new method, and have your implementation class implement the derivation, so long as QI returns a suitable interface when asked for either the old or new interface.

For example:

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();
    }

    ...
}

So, while you are technically "adding another interface", you're actually adding little code here: just defining a new interface that derived from the old one, changing the interface your class implements to the new one (and adding the implementation for the new method), and finally updating QI to support both the old and new methods - returning the same interface for both (and for IUnknown too).

like image 144
BrendanMcK Avatar answered Apr 27 '23 21:04

BrendanMcK


It would certainly break derived interfaces, so it should not be done even if it appears to work.

Instead, derive a new interface containing the additional method(s), and have clients that require the additional functionality QI for the new IID.

like image 28
Simon Richter Avatar answered Apr 27 '23 22:04

Simon Richter