template< class ThreadModel >
class CComObjectRootEx : public CComObjectRootBase
Parameters
ThreadModel 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 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 CComObject<CYourClass> for aggregated objects or an instance of CComAggObject<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.
The DECLARE_POLY_AGGREGATABLE macro is automatically added to your class definition by the ATL Object Wizard when you create a full control or Internet Explorer control.
If your object is aggregated, IUnknown is implemented by CComAggObject or CComPolyObject. These classes delegate QueryInterface, AddRef, and Release calls to CComObjectRootExs OuterQueryInterface, OuterAddRef, and OuterRelease to forward to the outer unknown. Typically, you override CComObjectRootExs FinalConstruct method in your class to create any aggregated objects, and override CComObjectRootExs 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 CComObjectRootExs InternalQueryInterface, InternalAddRef, and InternalRelease to perform the actual operations.
#include <atlcom.h>
See Also CComAggObject, CComObject, CComPolyObject
Methods | |
CComObjectRootEx | Constructor. |
InternalAddRef | Increments the reference count for a nonaggregated object. |
InternalQueryInterface | Delegates to the IUnknown of a nonaggregated object. |
InternalRelease | Decrements the reference count for a nonaggregated object. |
Lock | If the thread model is multithreaded, obtains ownership of a critical section object. |
Unlock | If the thread model is multithreaded, releases ownership of a critical section object. |
CComObjectRootBase Methods | |
FinalConstruct | Override in your class to create any aggregated objects. |
FinalRelease | Override in your class to release any aggregated objects. |
OuterAddRef | Increments the reference count for an aggregated object. |
OuterQueryInterface | Delegates to the outer IUnknown of an aggregated object. |
OuterRelease | Decrements the reference count for an aggregated object. |
Data Members | |
m_critsec | A CComAutoCriticalSection object or CComFakeCriticalSection object, depending on the thread model. |
m_dwRef | With m_pOuterUnknown, part of a union. Used when the object is not aggregated to hold the reference count of AddRef and Release. |
m_pOuterUnknown | With m_dwRef, part of a union. Used when the object is aggregated to hold a pointer to the outer unknown. |
CComObjectRootEx( );
Remarks
The constructor initializes the reference count to 0.
CComObjectRootEx Overview | Class Members
HRESULT FinalConstruct( );
Return Value
One of the standard HRESULT values.
Remarks
Typically, override this method in the class derived from CComObjectRootEx to create any aggregated objects. For example:
class CMyAggObject : public CComObjectRootEx< ... > { ... DECLARE_GET_CONTROLLING_UNKNOWN
HRESULT FinalConstruct( ) { return CoCreateInstance(CLSID_SomeServer, GetControllingUnknown(), CLSCTX_ALL, IID_ISomeServer, &m_pSomeServer); }
... };
If the construction fails, you can return an error. You can also use the macro DECLARE_PROTECT_FINAL_CONSTRUCT to protect your outer object from being deleted if (during construction) the internal aggregated object increments the reference count then decrements the count to 0.
By default, CComObjectRootEx::FinalConstruct simply returns S_OK.
Here is a typical way to create an aggregate:
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::FinalRelease, DECLARE_GET_CONTROLLING_UNKNOWN
void FinalRelease( );
Remarks
Typically, override this method in the class derived from CComObjectRootEx to free any aggregated objects before deletion.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::FinalConstruct
ULONG InternalAddRef( );
Return Value
A value that may be useful for diagnostics and testing.
Remarks
Increments the reference count of a nonaggregated object by 1. If the thread model is multithreaded, InterlockedIncrement is used to prevent more than one thread from changing the reference count at the same time.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::InternalRelease, CComObjectRootEx::InternalQueryInterface, InterlockedIncrement in the Win32 SDK
static HRESULT InternalQueryInterface( void* pThis, const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject ) ;
Return Value
One of the standard HRESULT values.
Parameters
pThis [in] A pointer to the object that contains the COM map of interfaces exposed to QueryInterface.
pEntries [in] A pointer to the _ATL_INTMAP_ENTRY structure, which accesses the map of interfaces.
iid [in] The GUID of the interface being requested.
ppvObject [out] A pointer to the interface pointer identified by iid, or NULL if the interface is not found.
Remarks
Retrieves a pointer to the requested interface.
InternalQueryInterface only handles interfaces in the COM map table. If your object is aggregated, InternalQueryInterface does not delegate to the outer unknown. You can enter interfaces into the COM map table with the macro COM_INTERFACE_ENTRY(InterfaceName) or one of its variants.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::InternalAddRef, CComObjectRootEx::InternalRelease
ULONG InternalRelease( );
Return Value
In non-debug builds, always returns 0. In debug builds, returns a value that may be useful for diagnostics or testing.
Remarks
Decrements the reference count of a nonaggregated object by 1. If the thread model is multithreaded, InterlockedDecrement is used to prevent more than one thread from changing the reference count at the same time.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::InternalAddRef, CComObjectRootEx::InternalQueryInterface, InterlockedDecrement in the Win32 SDK
void Lock( );
Remarks
If the thread model is multithreaded, this method calls the Win32 API function EnterCriticalSection, which waits until the thread can take ownership of the critical section object obtained through the m_critsec data member. When the protected code finishes executing, the thread must call Unlock to release ownership of the critical section.
If the thread model is single-threaded, this method does nothing.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::Unlock, CComObjectRootEx::m_critsec
ULONG OuterAddRef( );
Return Value
A value that may be useful for diagnostics and testing.
Remarks
Increments the reference count of the outer unknown of an aggregation.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::OuterRelease, CComObjectRootEx::OuterQueryInterface
HRESULT OuterQueryInterface( REFIID iid, void** ppvObject );
Return Value
One of the standard HRESULT values.
Parameters
iid [in] The GUID of the interface being requested.
ppvObject [out] A pointer to the interface pointer specified in iid, or NULL if the aggregation does not support the interface.
Remarks
Retrieves a pointer to the requested interface.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::OuterAddRef, CComObjectRootEx::OuterRelease
ULONG OuterRelease( );
Return Value
In non-debug builds, always returns 0. In debug builds, returns a value that may be useful for diagnostics or testing.
Remarks
Decrements the reference count of the outer unknown of an aggregation.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::OuterAddRef, CComObjectRootEx::OuterQueryInterface
void Unlock( );
Remarks
If the thread model is multithreaded, this method calls the Win32 API function LeaveCriticalSection, which releases ownership of the critical section object obtained through the m_critsec data member. To obtain ownership, the thread must call Lock. Each call to Lock requires a corresponding call to Unlock to release ownership of the critical section.
If the thread model is single-threaded, this method does nothing.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::Lock, CComObjectRootEx::m_critsec
_CritSec m_critsec;
Remarks
A CComAutoCriticalSection or CComFakeCriticalSection object. The critical section class _CritSec is determined by the thread model: CComAutoCriticalSection if multithreaded, and CComFakeCriticalSection if single-threaded.
If the thread model is multithreaded, m_critsec is a CComAutoCriticalSection object and provides access to CComAutoCriticalSection's methods and a CRITICAL_SECTION object.
If the thread model is single-threaded, a critical section is not needed and m_critsec is a CComFakeCriticalSection object.
CComObjectRootEx Overview | Class Members
See Also CComObjectRootEx::Lock, CComObjectRootEx::Unlock
long m_dwRef;
Remarks
Part of a union that accesses four bytes of memory.
union { long m_dwRef; IUnknown* m_pOuterUnknown; };
If the object is not aggregated, the reference count accessed by AddRef and Release is stored in m_dwRef. If the object is aggregated, the pointer to the outer unknown is stored in m_pOuterUnknown.
CComObjectRootEx Overview | Class Members
IUnknown* m_pOuterUnknown;
Remarks
Part of a union that accesses four bytes of memory.
union { long m_dwRef; IUnknown* m_pOuterUnknown; };
If the object is aggregated, the pointer to the outer unknown is stored in m_pOuterUnknown. If the object is not aggregated, the reference count accessed by AddRef and Release is stored in m_dwRef.