Click or drag to resize

Understanding COM Versioning

The goal of COM's versioning scheme is to allow end users to install updated versions of COM components without breaking existing code. Indeed, if properly done, COM versioning allows existing client applications to dynamically load a new COM component without even recompiling the application.

For COM versioning to work, new versions of COM interfaces must maintain binary compatibility with previous versions. Although other techniques for achieving this exist, by far the most common and straightforward technique uses simple interface inheritance.

In addition to the traditional versioning approach of interface inheritance, Nimbus supports a second mode of versioning that allows methods and properties to be deleted. Or, it may simply be the case that after multiple versioning sequences have been performed on an IVI-COM driver, the interface becomes cluttered with outdated references. In these cases, it may be desirable to break backwards compatibility in favor of a more presentable interface. The important consequence of this versioning approach is that client applications built against the driver may need to be recompiled.

This topic presents both versioning techniques available with Nimbus.

Using Interface Inheritance for COM Versioning

The fundamental limitation of COM versioning and the interface inheritance technique is that methods and properties can only be added -- they cannot be removed. This makes sense in general, considering that existing client applications may reference a method or property that gets removed, and these client applications would not compile against a new version. This is obviously not a restriction that is specific to COM -- any versioning scheme that allows deletion of published functionality will break client code.

Adding new methods and properties is far more common, and interface inheritance fits the bill here very nicely. Consider the following definition of an interface ICalc that has been released to customers: (Note the syntax used here is a simplied form of the IDL-like definitions that can be found in a Nimbus project's interface definition file (<project>.nimbus.idl) file.

C++
// Acme4321.nimbus.idl
[
  object, 
  uuid("79f6d7a2-bce6-4915-8906-8d5d8be61556"),    // This is the unique identifier for the ICalc interface ONLY
  // ...
]
interface ICalc : IUnknown
{
  HRESULT Add([in] int x, [in] int y, [out, retval] int* z);

  HRESULT Subtract([in] int x, [in] int y, [out, retval] int* z);
}

The ICalc interface defined above contains two methods -- Add and Subtract. If we wish to release a new version of a calculator component that adds new methods, then we define a new interface ICalc2 that derives from ICalc. Note that it is crucial to generate a new UUID for the ICalc2 interface, since it is distinct from ICalc.

C++
// Acme4321.nimbus.idl
[
  object, 
  uuid("9C4AE307-B366-41d5-9BAD-BD4CF59CF19C"),    // This is the unique identifier for the ICalc2 interface ONLY
  // ...
]
interface ICalc2 : ICalc
{
  HRESULT Multiply([in] int x, [in] int y, [out, retval] int* z);

  HRESULT Divide([in] int x, [in] int y, [out, retval] int* z);
}

The ICalc2 interface as defined above actually contains 4 methods total -- the Multiply and Divide methods defined directly on ICalc2 as well as the Add and Subtract methods inherited from ICalc. The net result of this inheritance-based versioning scheme is two-fold:

  1. New client applications can access all of the functionality defined on ICalc and ICalc2 by using ICalc2.

  2. Existing client applications that upgrade to the new component can continue using ICalc and will work without recompiling. This is because ICalc2 can be used anywhere an ICalc reference can be used -- this is, after all, the whole point of inheritance.

Versioning By Creating a New Interface

As previously discussed, it is sometimes necessary to remove functionality from an IVI-COM driver. This cannot be accomplished with the interface inheritance technique discussed above. Because the versioned interface derives from the original interface, it has all of the original interface members, and these are visible to the user.

Nimbus offers an alternate technique for versioning whereby a "clone" of the original interface is made and exposed from the driver. There is no inheritance relationship between the new interface and the old interface, so methods and properties can be removed from the revised interface. Nimbus preserves the original interface definition so that the existing applications do not need to be rewritten. It should be noted, however, that some types of applications may need to be recompiled when this mode of versioning is employed.

Download a complete CHM version of this documentation here.