CComObject Classes

[Previous] [Next]

At the bottom of an ATL object instance inheritance tree you'll find CComObject or some variation of it. CComObject classes are the entry point for all the IUnknown methods on an object. Because the implementation of QueryInterface varies depending on whether the object is being aggregated, the particular flavor of CComObject you use is determined based on the object's declared aggregation support and the context in which the creation occurs. Aggregation support is declared statically with one of a set of aggregation macros. Table 6-2 shows the available aggregation macros, the corresponding CComObject class that is used as the base class for the object, and the resulting ATL base class used with the associated aggregation macro. In most cases, the base class varies depending on whether the object is instantiated as an aggregate.

Table 6-2. Aggregation Macros.

Macro Normal Case Aggregated Case
DECLARE_NOT_AGGREGATABLE CComObject Not supported
DECLARE_AGGREGATABLE CComObject CComAggObject
DECLARE_ONLY_AGGREGATABLE Not supported CComAggObject
DECLARE_POLY_AGGREGATABLE CComPolyObject CComPolyObject

Each macro declares a typedef for the creator class that is used in normal and aggregated cases. Creators work with class objects to create an object instance when a client requests it. (Creators and class objects are covered in more detail in Chapter 7.) By default, objects inherit DECLARE_AGGREGATABLE from CComCoClass. You can override the default by inserting one of the other macros in your object header file or by making a choice other than "Yes" for aggregation on the Attributes tab in the Object Wizard. By implementing QueryInterface, AddRef, and Release, the CComObject classes relieve us from writing the boilerplate code over and over again, and they also offer free aggregation support. CComObject also handles incrementing and decrementing the module count when the object is created and destroyed—that's more boilerplate code you don't have to write.

Each CComObject class has a static CreateInstance member that is used to create the object. If the object is created by means of CoCreate, the class object makes the call in its IClassFactory::CreateInstance method. If you're creating objects internally, however, you can also call this function directly and bypass the class object entirely. CreateInstance returns a pointer to a newly created CComObject, as shown here:

 template <class Base> HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp) {     ATLASSERT(pp != NULL);     HRESULT hRes = E_OUTOFMEMORY;     CComObject<Base>* p = NULL;     ATLTRY(p = new CComObject<Base>())     if(p != NULL)     {         p->SetVoid(NULL);         p->InternalFinalConstructAddRef();         hRes = p->FinalConstruct();         p->InternalFinalConstructRelease();         if(hRes != S_OK)         {             delete p;             p = NULL;         }     }     *pp = p;     return hRes; } 

You can then use the returned object as you would any other COM object. Notice that CreateInstance doesn't call AddRef on the object, so you might want to call QueryInterface after creation to get the automatic deletion when the reference count reaches 0. The following code shows how you can use CreateInstance directly:

 CComObject<CSimpleObject> *pObj; HRESULT hr = CComObject<CSimpleObject>::CreateInstance(&pObj); if(SUCCEEDED(hr)) {     CComPtr<ISimpleObj> pISimple;     hr =  pObj->QueryInterface(&pISimple);     if(SUCCEEDED(hr))         pISimple->Test(); } 

The use of the CComObject QueryInterface override allows the use of a typedef pointer. Using CComObject as shown in the preceding code does save some cycles by not creating a class object through the CoCreate mechanism. Even so, this process is somewhat tedious for a stack-based object. ATL provides the CComObjectStack class to simplify object creation and usage within a stack frame. We can write the same code using CComObjectStack.

 CComObjectStack<CSimpleObject> Obj; Obj.Test(); 

Use CComObjectStack when the lifetime of the object is contained in a stack frame. When an object's lifetime is contained in a stack frame, reference counting isn't required and therefore isn't implemented. QueryInterface isn't allowed on CComObjectStack instances.

ATL has several other variations of CComObject to handle specific reference counting, module locking, and QueryInterface cases. These variations and their descriptions are listed here:

  • CComObjectCached This class doesn't increment the module lock count until the reference count reaches 2 and thus allows an instance of an object to exist without keeping the module loaded. ATL wraps DLL class objects in this way to provide faster access via the cached instance. We'll look at this more in Chapter 7 when we examine class objects and module locks.
  • CComObjectNoLock This class does no module locking whatsoever. ATL uses it for class objects in EXE servers, which can't allow a class object instance to keep the module running.
  • CComObjectGlobal This class doesn't keep an internal reference count separate from the module lock count. The object's lifetime must be managed externally. ATL uses this class in its singleton implementation, holding the single object instance wrapped in CComObjectGlobal.
  • CComTearOffObject This class delegates its QueryInterface calls to an owner object. CComTearOffObject allows a separate implementation for an interface, which is created only when a client requests the interface through QueryInterface. The tear-off is reference counted and deleted when the reference count is 0. When created, the tear-off object calls AddRef on its owner to ensure that the owner object doesn't delete itself with an outstanding tear-off reference.
  • CComCachedTearOffObject This class reuses a tear-off object instance once an instance is created. Using CComTearOffObject results in a new object being created every time the tear-off interface is queried for.

One of the fundamental tasks of the CComObject classes is to appropriately route QueryInterface. Our next step is to look more closely at the implementation of QueryInterface once CComObject hands it off. We'll start by examining how ATL uses the COM map to manage the list of interfaces available from an object.



Inside Atl
Inside ATL (Programming Languages/C)
ISBN: 1572318589
EAN: 2147483647
Year: 1998
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net