This section briefly describes extended objects and focuses on their role in ActiveX designers. The COM Programmer's Reference and a variety of other sources in the Microsoft Developer Network (MSDN) provide detailed explanations of aggregation and the controlling IUnknown; refer to those sources for additional information.
An extended object is an instance that has attached code (usually code that handles events) or added properties, methods, or events. For an ActiveX designer, an extended object has three parts: the ActiveX designer object; the extension, which the host adds; and the code written by the user to extend the designer. At run time, the host aggregates the parts as shown in the following diagram:
In the aggregate, the controlling extensible object determines how the object behaves and operates. It implements a special instance of the IUnknown interface called the controlling IUnknown. The controlling IUnknown must always be implemented as part of the new code when the aggregate is put together.
For the aggregate to work correctly, both the object and its extension must be written to cooperate with the controlling extensible object. Both the object and the extension implement IUnknown. Instead of acting independently, however, they should forward their AddRef, Release, and QueryInterface calls to the controlling IUnknown. The controlling IUnknown maintains a reference count for the aggregate as a whole, so that it can be kept alive if there are references to any of the interfaces supported by the controlling extensible object, the extension, or the object itself.
In the figure, the lines and circles that extend beyond the bounds of the aggregate indicate interfaces that are externally available. Both the object and the extension can expose interfaces. However, the controlling IUnknown is exposed to the outside world, while the object and extension IUnknown implementations are not. Within the aggregate, the controlling extensible object holds a pointer to the object's IUnknown implementation, indicated by the dotted line, and vice versa.
When an instance of the object is created at run time, the caller receives a pointer to the controlling IUnknown rather than to the object's IUnknown interface. Calls to the object's IUnknown methods are delegated through the controlling IUnknown as necessary. This process ensures that the object's IUnknown interface remains private and that reference counts are accurately tracked.