OOPortal OOPortal


COM Aggregation   «Prev 

Aggregation: CoCreateInstance and IClassFactory::CreateInstance

When the outer object creates an instance of the inner object, it calls IClassFactory::CreateInstance directly or indirectly through CoCreateInstance. To indicate to the newly created COM object that the caller (the outer object) wants to aggregate it, both IClassFactory::CreateInstance and CoCreateInstance take an IUnknown pointer as a parameter. This parameter is NULL when a client creates a COM object. For aggregation, the outer COM object passes in its IUnknown pointer. A non-NULL value in this parameter tells the newly created COM object that the caller wants to aggregate it. Additionally, when an outer IUnknown pointer is passed in, the caller must ask for IUnknown that is, the nondelegating IUnknown of the object.

HRESULT IClassFactory::CreateInstance(IUnknown *pIOuterIUnknown, REFIID riid, VOID **ppv);

  1. pIOuterIUnknown: Pointer to outer object's IUnknown if you want to aggregate to the new object. Null if not aggregated.
  2. REFIID riid: Must be IID_IUnknown if pIOuterUnknown is NOT null. i.e. when aggregating an object the outer object must pass in its IUnknown and it must ask for the inner object's IUnknown
  3. VOID **ppv: Pointer to hold requested interface pointer in. This will be IUnknown if we aggregate the object.
Helper function CoCreateInstance can be used in place of the calls to CoGetClassObject and CreateInstance:
STDAPI CoCreateInstance(REFCLSID objCLSID,IUnknown *pOuterIUnknown,
DWORD clsctx,REFIID riid,VOID **ppv);
  1. REFCLSID objCLSID: CLSID of COM Object whose class factory you want.
  2. IUnknown *pOuterIUnknown: Pointer to outer object's IUnknown. NULL if not aggregating.
  3. DWORD clsctx: CLSCTX_INPROC_SERVER
  4. REFIID riid: Must be IID_IUnknown if pOuterIUnknown is non-NULL.
  5. VOID **ppv); Pointer to hold requested interface pointer in. Will be IUnknown if the object is being aggregated.

A common implementation technique, in outer COM objects, is to provide a non-COM member function called Init. After creating an instance of the outer COM object, the object's IClassFactory::CreateInstance method calls Init. In Init, the outer COM object creates and aggregates the inner COM object.

Nonaggregatable

A common clean-up technique is to release aggregated COM objects in a class destructor.
You can develop nonaggregatable COM objects by having the object's class factory return CLASS_E_NOAGGREGATION from CreateInstance.
You can code your COM objects in such a way that they can't be aggregated. The following pseudo-code demonstrates this:

class CInnerCOMObj : ... { ... }

class CInnerCOMObj_ClassFactory : public 
IClassFactory {
  ...
  HRESULT CreateInstance(IUnknown *pOuterIUnknown, 
    REFIID riid, VOID **ppv){
    /* first check for aggregation, 
	is pOuterIUnknown non-NULL? */
    if (pOuterIUnknown != NULL) {
      //Return a no-aggregation error
      return CLASS_E_NOAGGREGATION;
    }
    // Visual C++ Code
}
...
};