COM Aggregation   «Prev  Next»
Lesson 9 Aggregation guidelines: IUnknown information exchange
ObjectiveList the guidelines for inner and outer IUnknown information exchange.

Aggregation Guidelines - IUnknown information Exchange

Up to this point, we have looked at aggregation guidelines for both the inner and the outer objects. The inner object needs the outer object's IUnknown pointer for use with its delegating IUnknown interface. The outer object needs the inner object's nondelegating IUnknown pointer for interface navigation and to release the aggregated object. The inner and outer COM objects need to exchange IUnknown pointers. That is exactly what the last aggregation guideline states:
The inner and outer objects must exchange IUnknown pointers.
Specifically, the inner object gives the outer object its nondelegating IUnknown pointer, receiving the outer object's IUnknown pointer in exchange. This happens when the outer object creates the inner object.

As part of its instantiation process, the outer object creates an instance of the inner object. The inner and outer objects exchange IUnknown pointers at this time. CoCreateInstance and IClassFactory::CreateInstance take a parameter specifically dedicated to supporting aggregation. To aggregate an object, the outer object passes in a pointer to its IUnknown pointer and asks the inner object for its IUnknown pointer.
The aggregated (inner) object's class factory sees a request for aggregation in its implementation of CreateInstance.

Implementing IClassFactory::CreateInstance in the inner object

A standard development practice is to have the C++ class that implements the inner COM object take in a pointer to the outer IUnknown in its constructor. CreateInstance will pass this into the constructor of the C++ class that implements the inner object. In its constructor, the COM object saves the outer object's pointer and uses it in all delegating IUnknown methods.

class CInnerCOMObj : ... { 
public:
CInnerCOMObj(IUnknown *pOuterIUnknown) { ... }
...
};

The following pseudo-code demonstrates how the inner object class factory implements IClassFactory::CreateInstance:
class CInnerCOMObj_ClassFactory : public IClassFactory {
             ...
  /* We do not have to specify CreateInstance as virtual and __stdcall. 
  We inherit these attributes from IClassFactory. */
  HRESULT CreateInstance(IUnknown *pOuterIUnknown,REFIID riid,VOID **ppv) {
    /* first check for aggregation - i.e. is pOuterIUnknown non-NULL */      
    if (pOuterIUnknown != NULL) {
      /* now make sure they are asking for IUnknown. If not - fail the call */
      if (riid != IID_IUnknown) {
        return E_NOINTERFACE;
      }
    }
    /* Now create the COM object - passing the outer object's IUnknown into it. NOTE: this 
    call will work for the non-aggregated case too - i.e. when pOuterIUnknown is NULL*/
    CInnerCOMObj *pc = new CInnerCOMObj(pOuterIUnknown);
    /* Call QueryInterface in the COM object to get the caller's requested interface */
    HRESULT hr = pc->QueryInterface(riid, ppv);
    if (FAILED(hr)) {
      delete pc;
      return hr;
    }
    return S_OK;
   }
...
};

Notice how the creation and destruction of the inner objects and the outer object are kept in synch. The outer object creates inner objects when it is created. The outer object will destroy inner objects when it is destroyed (recall from the previous lesson that the outer object releases aggregated objects when it is released). These steps, along with the inner object's delegating IUnknown interfaces and the outer object's uses of the aggregated object's nondelegating IUnknown interface, support the goal of aggregation: multiple objects combining into a composite object.

Analyze Inner Com Object - Exercise

Click the Exercise link below to apply what you've learned to fixing a buggy inner COM object.
Analyze Inner Com Object - Exercise