description | title | ms.date | f1_keywords | helpviewer_keywords | ms.assetid | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Learn more about: CComObjectRootEx Class |
CComObjectRootEx Class |
11/04/2016 |
|
|
894a3d7c-2daf-4fd0-8fa4-e6a05bcfb631 |
This class provides methods to handle object reference count management for both nonaggregated and aggregated objects.
template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase
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 server's default thread model by setting ThreadModel to CComObjectThreadModel or CComGlobalsThreadModel.
Function | Description |
---|---|
CComObjectRootEx | Constructor. |
InternalAddRef | Increments the reference count for 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. |
Function | Description |
---|---|
FinalConstruct | Override in your class to perform any initialization required by your object. |
FinalRelease | Override in your class to perform any cleanup required by your object. |
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. |
Function | Description |
---|---|
InternalQueryInterface | Delegates to the IUnknown of a nonaggregated object. |
ObjectMain | Called during module initialization and termination for derived classes listed in the object map. |
Data member | Description |
---|---|
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
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.
Header: atlcom.h
The constructor initializes the reference count to 0.
CComObjectRootEx();
You can override this method in your derived class to perform any initialization required for your object.
HRESULT FinalConstruct();
Return S_OK on success or one of the standard error HRESULT values.
By default, CComObjectRootEx::FinalConstruct
simply returns S_OK.
There are advantages to performing initialization in FinalConstruct
rather than the constructor of your class:
-
You cannot return a status code from a constructor, but you can return an HRESULT by means of
FinalConstruct
's return value. When objects of your class are being created using the standard class factory provided by ATL, this return value is propagated back to the COM client allowing you to provide them with detailed error information. -
You cannot call virtual functions through the virtual function mechanism from the constructor of a class. Calling a virtual function from the constructor of a class results in a statically resolved call to the function as it is defined at that point in the inheritance hierarchy. Calls to pure virtual functions result in linker errors.
Your class is not the most derived class in the inheritance hierarchy — it relies on a derived class supplied by ATL to provide some of its functionality. There is a good chance that your initialization will need to use the features provided by that class (this is certainly true when objects of your class need to aggregate other objects), but the constructor in your class has no way to access those features. The construction code for your class is executed before the most derived class is fully constructed.
However,
FinalConstruct
is called immediately after the most derived class is fully constructed allowing you to call virtual functions and use the reference-counting implementation provided by ATL.
Typically, override this method in the class derived from CComObjectRootEx
to create any aggregated objects. For example:
[!code-cppNVC_ATL_COM#40]
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 creation, the internal aggregated object increments the reference count then decrements the count to 0.
Here is a typical way to create an aggregate:
-
Add an
IUnknown
pointer to your class object and initialize it to NULL in the constructor. -
Override
FinalConstruct
to create the aggregate. -
Use the
IUnknown
pointer you defined as the parameter to the COM_INTERFACE_ENTRY_AGGREGATE macro. -
Override
FinalRelease
to release theIUnknown
pointer.
You can override this method in your derived class to perform any cleanup required for your object.
void FinalRelease();
By default, CComObjectRootEx::FinalRelease
does nothing.
Performing cleanup in FinalRelease
is preferable to adding code to the destructor of your class since the object is still fully constructed at the point at which FinalRelease
is called. This enables you to safely access the methods provided by the most derived class. This is particularly important for freeing any aggregated objects before deletion.
Increments the reference count of a nonaggregated object by 1.
ULONG InternalAddRef();
A value that may be useful for diagnostics and testing.
If the thread model is multithreaded, InterlockedIncrement
is used to prevent more than one thread from changing the reference count at the same time.
Retrieves a pointer to the requested interface.
static HRESULT InternalQueryInterface(
void* pThis,
const _ATL_INTMAP_ENTRY* pEntries,
REFIID iid,
void** ppvObject);
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 that accesses a map of available interfaces.
iid
[in] The GUID of the interface being requested.
ppvObject
[out] A pointer to the interface pointer specified in iid, or NULL if the interface is not found.
One of the standard HRESULT values.
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 or one of its variants.
Decrements the reference count of a nonaggregated object by 1.
ULONG InternalRelease();
In both non-debug and debug builds, this function returns a value which may be useful for diagnostics or testing. The exact value returned depends on many factors such as the operating system used, and may, or may not, be the reference count.
If the thread model is multithreaded, InterlockedDecrement
is used to prevent more than one thread from changing the reference count at the same time.
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 a private data member.
void Lock();
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.
Part of a union that accesses four bytes of memory.
long m_dwRef;
With m_pOuterUnknown
, part of a union:
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.
Part of a union that accesses four bytes of memory.
IUnknown*
m_pOuterUnknown;
With m_dwRef
, part of a union:
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.
For each class listed in the object map, this function is called once when the module is initialized, and again when it is terminated.
static void WINAPI ObjectMain(bool bStarting);
bStarting
[out] The value is TRUE if the class is being initialized; otherwise FALSE.
The value of the bStarting parameter indicates whether the module is being initialized or terminated. The default implementation of ObjectMain
does nothing, but you can override this function in your class to initialize or clean up resources that you want to allocate for the class. Note that ObjectMain
is called before any instances of the class are requested.
ObjectMain
is called from the entry point of the DLL, so the type of operation that the entry-point function can perform is restricted. For more information on these restrictions, see DLLs and Visual C++ run-time library behavior and DllMain.
[!code-cppNVC_ATL_COM#41]
Increments the reference count of the outer unknown of an aggregation.
ULONG OuterAddRef();
A value that may be useful for diagnostics and testing.
Retrieves an indirect pointer to the requested interface.
HRESULT OuterQueryInterface(REFIID iid, void** ppvObject);
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.
One of the standard HRESULT values.
Decrements the reference count of the outer unknown of an aggregation.
ULONG OuterRelease();
In non-debug builds, always returns 0. In debug builds, returns a value that may be useful for diagnostics or testing.
If the thread model is multithreaded, this method calls the Win32 API function LeaveCriticalSection, which releases ownership of the critical section object obtained through a private data member.
void Unlock();
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.
CComAggObject Class
CComObject Class
CComPolyObject Class
Class Overview