Figure 1   A Poorly Designed Interface

[
    object,
    uuid(9F56969F-339A-11D2-B37E-006008A667FD),
    dual,
    pointer_default(unique)
]
interface IBankAccounts : IDispatch
{
    [propget, id(1)] HRESULT Savings([out, retval] CURRENCY *pVal);
    [propput, id(1)] HRESULT Savings([in] CURRENCY newVal);
    [propget, id(1)] HRESULT Checking([out, retval] CURRENCY *pVal);
    [propput, id(1)] HRESULT Checking([in] CURRENCY newVal);
    [propget, id(1)] HRESULT CreditLine([out, retval] CURRENCY *pVal);
    [propput, id(1)] HRESULT CreditLine([in] CURRENCY newVal);
};

Figure 3   An Improved Version


[
    object,
    uuid(9F56969F-339A-11D2-B37E-006008A667FD),
    dual,
    pointer_default(unique)
]
interface IBankAccounts : IDispatch
{
    [propget, restricted, id(DISPID_NEWENUM)] HRESULT _NewEnum(
        [out, retval] IUnknown** pVal);
    [id(DISPID_VALUE)] HRESULT Item([in] VARIANT index, 
        [out, retval] IDispatch** ppItem);
    [propget, id(1)] HRESULT Count([out, retval] long *pVal);
    [id(2)] HRESULT AddAccount([in] BSTR name, [out, retval] IDispatch** ppItem);
    [id(3)] HRESULT RemoveAccount([in] VARIANT index);
};

interface IBankAccount : IDispatch
{
    [propget, id(1)] HRESULT Name([out, retval] BSTR* pbstrName);
    [propget, id(2)] HRESULT Balance([out, retval] CURRENCY* pVal);
    [id(3)] HRESULT MakeDeposit([in] CURRENCY amount, [in] DATE date);
    [id(4)] HRESULT MakeWithdrawal([in] CURRENCY amount, [in] DATE date);
    [id(5)] HRESULT TransferTo([in] IBankAccount* pAccount], 
        [in] CURRENCY amount);
    [id(6)] HRESULT TransferFrom([in] IBankAccount* pAccount], 
        [in] CURRENCY amount);
};

Figure 4   Handling Component Versioning

Versioning Technique Requirements Advantages Disadvantages
Support both old and new interfaces in a single component that replaces the old one. Must still support old CLSID through use of the TreatAs registry keyword or by giving the new component the same CLSID as the old component. No need to rewrite the setup program or rename the COM server because you simply install it on top of the old one. You must extensively test the new component with old clients to make sure that the recompilation (even though it supports the old interface) does not introduce bugs into the system.
Support new interface in separate component, leaving the old one alone. Must use a new CLSID. Must install the COM server using a different installation path. Using same ProgID is inadvisable because legacy clients may create the component using the versionless ProgID. Because old clients still use the old component, backwards-compatibility testing is almost trivial. The new component does not carry the baggage imposed by the old interface. Over time, this approach tends to clutter up the system with different versions of the component.