This class provides methods to handle object reference count management for both nonaggregated and aggregated objects.
template< class ThreadModel > class CComObjectRootEx : public CComObjectRootBase
The class whose methods implement the desired threading model. You can explicitly choose the threading model by setting ThreadModel to CComSingleThreadModel, CComMultiThreadModel, or CComMultiThreadModelNoCS. You can accept the server's default thread model by setting ThreadModel to CComObjectThreadModel or CComGlobalsThreadModel.
CComObjectRootEx handles object reference count management for both nonaggregated and aggregated objects. It holds the object reference count if your object is not being aggregated, and holds the pointer to the outer unknown if your object is being aggregated. For aggregated objects, CComObjectRootEx methods can be used to handle the failure of the inner object to construct, and to protect the outer object from deletion when inner interfaces are released or the inner object is deleted.
A class that implements a COM server must inherit from CComObjectRootEx or CComObjectRoot.
If your class definition specifies the DECLARE_POLY_AGGREGATABLE macro, ATL creates an instance of CComPolyObject<CYourClass> when IClassFactory::CreateInstance is called. During creation, the value of the outer unknown is checked. If it is NULL, IUnknown is implemented for a nonaggregated object. If the outer unknown is not NULL, IUnknown is implemented for an aggregated object.
If your class does not specify the DECLARE_POLY_AGGREGATABLE macro, ATL creates an instance of CAggComObject<CYourClass> for aggregated objects or an instance of CComObject<CYourClass> for nonaggregated objects.
The advantage of using CComPolyObject is that you avoid having both CComAggObject and CComObject in your module to handle the aggregated and nonaggregated cases. A single CComPolyObject object handles both cases. Therefore, only one copy of the vtable and one copy of the functions exist in your module. If your vtable is large, this can substantially decrease your module size. However, if your vtable is small, using CComPolyObject can result in a slightly larger module size because it is not optimized for an aggregated or nonaggregated object, as are CComAggObject and CComObject.
If your object is aggregated, IUnknown is implemented by CComAggObject or CComPolyObject. These classes delegate QueryInterface, AddRef, and Release calls to CComObjectRootEx's OuterQueryInterface, OuterAddRef, and OuterRelease to forward to the outer unknown. Typically, you override CComObjectRootEx::FinalConstruct in your class to create any aggregated objects, and override CComObjectRootEx::FinalRelease to free any aggregated objects.
If your object is not aggregated, IUnknown is implemented by CComObject or CComPolyObject. In this case, calls to QueryInterface, AddRef, and Release are delegated to CComObjectRootEx's InternalQueryInterface, InternalAddRef, and InternalRelease to perform the actual operations.