Click here to Skip to main content
11,648,094 members (73,621 online)
Click here to Skip to main content

COM Concept : Unleashing Aggregation

, 30 Oct 2003 65.9K 1.1K 55
Rate this:
Please Sign up or sign in to vote.
Unleashing Aggregation


Aggregation is one of the techniques to achieve reusability in COM. Aggregation is the specialized form of Containment, in which the programmer doesn’t have to implement code in the outer component to forward/delegate a call to the inner component and hence makes the life of a programmer easier. In Aggregation, the outer component hands over the control of the interface, which is being implemented by the inner component, to the client directly and the outer component gets out of the picture. In Aggregation, the interface to the inner component is exposed directly to the client, which is in contrast with the Containment.

This could lead to a problem, which can violate the basic QueryInterfacerules, which has been stated below:

Handing over the interface pointer on the inner component can give a different view of the component because the client can call the QueryInterfaceon that interface pointer to get the IUnknowninterface pointer on the inner component. The outer IUnknownand the Inner IUnknownwill be having the different implementation of the QueryInterfaceand hence the different pictures will be portrayed to the client. The basic concept behind the aggregation is that the client should be independent of the implementation of the aggregation technique and client shouldn’t know that the outer component is aggregating the inner component. The outer IUnknownand the Inner IUnknownimplements the different set of interfaces and hence gives the client a dual view of the component.


Consider the following case: There are two components called CScientificand CBasic, which provide the functionality for scientific and basic mathematical operations respectively. The CBasiccomponent exposes two interfaces called IAddSuband IMultiDiv. The CScientificclass implements an interface ITrignometryinterface to provide the trigonometric operations.

Now suppose, there are the clients who needs the scientific functionality along with the Addition and Subtraction operations of the basic functionality. The request of such a clients can be served by implementing the ITrignometryinterface and aggregating the IAddSubinterface. The implementation of the IAddSubis provided by the inner component and the outer component will be handing over the IAddSubinterface pointer directly to the client for providing the services of the inner component. The outer component will not be delegating the IMultiDivinterface and hence it will not be visible to the client.

The beauty of the aggregation lies in the implementation of IUnknown interface on the inner component. The inner IUnknownshouldn’t be exposed to the client and hence the client should see only one IUnknowninterface i.e. outer IUnknown(Controlling IUnknown).

The request for the IUnknownby calling a QueryInterfaceon the IAddSubinterface pointer should return an IUnknownof an outer component and hence the inner component should make a use of the implementation provided by the outer component for the IUnknown.

Outer IUnknown to the inner component

To forward/delegate calls to the outer IUnknown, the inner component needs the outer component’s IUnknowninterface pointer. The outer component passes its IUnknown interface pointer at the time of creating the inner component. The outer component calls CoCreateInstanceand passes its IUnknownpointer in the second argument of CoCreateInstance. If this parameter is non-NULL, then the component is being aggregated, otherwise the component is not aggregated.

Inner component implementation

The inner component needs to implement two IUnknowninterfaces to support the aggregation. The interface that will be controlling the lifetime of the inner component is called NonDelegating IUnknownand the interface, which forwards the calls on the IUnknown member functions, to the outer component, is called Delegating IUnknown.

The NonDelegating IUnknownis never exposed to the client and it is only the outer component, which can get a pointer to the NonDelegating IUnknowninterface pointer. The outer component controls the lifetime of the inner component via NonDelegating interface pointer. Whenever a client asks for the IUnknown pointer, by calling the QueryInterfaceon the IAddSubinterface pointer, the client should get the IUnknown pointer of the outer component. The implementation of NonDelegating IUnknown will be requiring the two IUnknown in the inner component and hence we will be defining the new interface called INonDelegateUnknown, which will be having the same virtual table layout as that of IUnknown. COM is all about the layout of the vtable layout and therefore the name of the member functions of INonDelegateUnknownwill be prefixed with “NonDelegate”.

struct INonDelegateUnknown {
      virtual HRESULT __stdcall NonDelegateQueryInterface ( const IID&, 
      virtual ULONG __stdcall NonDelegateAddRef()=0;
      virtual ULONG __stdcall NonDelegateRelease()=0;

The NonDelegateAddRefand NonDelegateReleaseimplementation will increments and decrements the reference count of the inner component respectively.

The NonDelegateQueryInterfaceimplementation needs to be modified so that whenever the outer component asks for the IUnknowninterface pointer on the inner component, the inner component should hands over the NonDelegate IUnknownpointer to the outer component rather than IUnknownpointer. The outer component can get the NonDelegate IUnknownpointer on the inner component only at the time of the creation of the inner component and hence the NonDelegateQueryInterfacewill be called in the CreateInstanceof the class object, which will corresponds to the inner component. The NonDelegateQueryInterfaceshould performs the check for IUnknowninterface and IAddSubinterface because the outer component can get only these two interfaces from the inner component and for other interface pointer (i.e. IMultiDiv), the QueryInterfaceshould return E_NOINTERFACE.

HRESULT __stdcall CBasic::NonDelegateQueryInterface (const IID& iid,
    void **ppv)
      if (iid == IID_IUnknown) {

  // When the AddRef will be called on the ppv before returning
  // from this function,the reference count of the inner component
  // is incremented by 1.

             *ppv = static_cast < INonDelegateUnknown*>(this);
      else if (iid = IID_IAddSub) {

  // When the AddRef will be called on the ppv before 
  // returning from this function,the reference count of the outer component
  // is incremented by 1. This is because that the IUnknown
  // implementation of IAddSub interface on inner component should 
  // delegate to the outer component’s controlling IUnknown implementation. 
             *ppv = static_cast < IAddSub*<(this);
      else {
             *ppv = NULL;
             return E_NOINTERFACE;
    reinterpret_cast < IUnknown*<(*ppv)->AddRef();
    return S_OK;

Why do we need to typecast thispointer into INonDelegateUnknown?

Typecasting thispointer ensures that the INonDelegateUnknowninterface pointer is returned.

When the outer component queries for the interfaces, other than the INonDelegateUnknownpointer, belonging to the inner component, the reference count of the outer component is incremented. The reference count of the outer component will never reaches 0 and hence it will never be released from the memory. And therefore the outer component should call Releaseon its controlling IUnknownpointer, whenever it queries for any of the interfaces implemented by the inner component. Whenever an outer component queries for the INonDelegateUnknownpointer on the inner component, the reference count of the inner component is incremented.

The implementation of IClassFactoryon the inner component’s class object is modified to pass the INonDelegateUnknownpointer to the outer component. The outer component can ask for only the IUnknowninterface pointer at the time of the creation of the inner component because after its creation, all the QueryInterfacecalls will be delegated to the outer Unknown. The class factory needs to return a pointer to the nondelegating unknown and hence it will call NonDelegateQueryInterfacein the implementation of CreateInstance.

Before executing the client application (AggregationClient.exe), the COM Servers (AggregationSample.dll & AggregableObject.dll) needs to be registered by regsvr32 utility. The code has been commented out properly to explain the crucial steps involved in the Aggregation technique.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Dinesh Ahuja
India India
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralBrilliant! Pin
Red Prince24-Aug-12 15:23
memberRed Prince24-Aug-12 15:23 
GeneralIAMVideoProcAMP and IAMCameraControl, aggregation Pin
roboticEDAR26-Jun-09 13:14
memberroboticEDAR26-Jun-09 13:14 
hello how would one aggregate these two interfaces in a source filter ?
QuestionAggregation doubt Pin
D.Lakshmankumar15-Oct-07 23:05
memberD.Lakshmankumar15-Oct-07 23:05 
GeneralNice one Pin
Anand Todkar5-Aug-07 8:01
memberAnand Todkar5-Aug-07 8:01 
GeneralUse Containment and Aggregation Pin
Anonymous28-Aug-05 20:35
sussAnonymous28-Aug-05 20:35 
GeneralExcellent Pin
Saurabh Panthri24-Jul-05 23:11
memberSaurabh Panthri24-Jul-05 23:11 
Generalsmile Pin
Anonymous11-Jan-05 2:11
sussAnonymous11-Jan-05 2:11 
Generalgood article Pin
Rajesh match31-Oct-03 18:34
memberRajesh match31-Oct-03 18:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150804.4 | Last Updated 31 Oct 2003
Article Copyright 2003 by Dinesh Ahuja
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid