from
http://progtutorials.tripod.com/COM.htm
- CComObject<> Template Classes - Creatable Coclasses
- Create a COM Object Internally
- CComObjectRootBase
- FinalConstruct and FinalRelease
- InternalQueryInterface
- Support for aggregation
- COM map macro helper methods
- CComCoClass<>
1 CComObject<> Template Classes - Creatable Coclasses
The coclass you create with COM AppWizard does not contain the implementation of IUnknown methods. Therefore they are abstract classes. They can not be directly created. Instead a coclass is passed to one of a set of template classes, which inherits from the coclass passed as template parameter, and provides a specific implementation of the IUnknown methods. This template classes become the real creatable coclasses.
The reason behind these logic is to separate the custom implementation of coclasses from the implementation of IUnknown, so that the ATL coclasses are more portable.
The definition of the most commonly used template class CComObject<> is listed below:
template <class Base>
class CComObject : public Base
{
public:
typedef Base _BaseClass;
CComObject(void* = NULL)
{
_Module.Lock(); // _Module is the global CComModule
}
~CComObject() // Set refcount to 1 to protect destruction
{
m_dwRef = 1L;
FinalRelease();
_Module.DeleteNonAddRefThunk(_GetRawUnknown());
_Module.Unlock();
}
STDMETHOD_(ULONG, AddRef)()
{
return InternalAddRef();
}
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
return _InternalQueryInterface(iid, ppvObject);
}
template <class Q>
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
{
return QueryInterface(__uuidof(Q), (void**)pp);
}
static HRESULT WINAPI CreateInstance(CComObject<Base>** pp);
};
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;
}
2 Create a COM Object Internally
ATL¡¯s COM map macros make use of those CComObject<> templates to create real coclass instances, so you normally do not need to directly deal with them. However, if you need to create an instance of an ATL coclass which is defined within your project (in such case you do not need to go through COM run time by calling CoCreateInstance), you need to use one of these template classes manually:
CComObject<CAnyCoclass> * pAny = NULL;
CComObject<CAnyCoclass>::CreateInstance(&pAny);
The template classes are:
- CComObject<> - non-aggregated, heap-based, affects the server¡¯s object count;
- CComObjectNoLock<> - non-aggregated, does not adjust the server¡¯s object count;
- CComAggObject<> - can work as aggregate;
- CComObjectStack<> - stack-based;
- CComObjectGlobal<> - life time depends on the life time of the server;
- CComPolyObject<> - may or may not work as aggregate;
- CComTearOffObject<> - implements a tear-off interface.
3 CComObjectRootBase
The hierarchy of an ATL coclass looks like:
class ATL_NO_VTABLE CAny :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CAny, &CLSID_Any>,
public IDispatchImpl<IAny, &IID_IAny, &LIBID_TESTLib>
{
... As we have discussed before, template class CComObjectRootEx is responsible for providing threading support Increment, Decrement, Lock and Unlock. It inherits from class CComObjectRootBase, which provides the following functionality:
3.1 FinalConstruct and FinalRelease
In <atldef.h>, there are following lines:
#ifdef _ATL_DISABLE_NO_VTABLE
#define ATL_NO_VTABLE
#else
#define ATL_NO_VTABLE __declspec(novtable)
#endif If you do define _ATL_DISABLE_NO_VTABLE, macro _ATL_NO_VTABLE will extend to nothing. Otherwise it will extend to declarator __declspec(novtable), which stops the compiler from generating code to initialize the vPtr in the constructor(s) and destructor of the class. In many cases, this removes the only references to the vtable that are associated with the class and, thus, the linker will remove it. This can result in a significant reduction in code size. Only the most derived class needs vTable. ATL coclasses are not most derived classes, so they don¡¯t need a vTable.
After the constructor call, you will have a vTable to use.
However, without a vtable, you can not call any virtual methods in your constructor. That¡¯s why CComObjectRootBase provides method FinalConstruct and FinalRelease, in which you can call virtual methods and do initialization and clean up. The framework will call them after the instance is constructed or before it is destroyed.
3.2 InternalQueryInterface
CComObjectRootBase maintains a reference count m_dwRef for the coclass. It also provides method InternalQueryInterface, which turns around and calls AtlInternalQueryInterface, which iterates over the COM map and searches for an interface.
The abstract ATL coclass indirectly inherits from CComObjectRootBase, and is passed into and inherited by the template classes such as CComObject<>. The template class can then call InternalQueryInterface in its implementation of IUnknown::QueryInterface. InternalAddRef and InternalRelease are provided by the CComObjectRootEx<> itself.
3.3 Support for aggregation
CComObjectRootBase provides method OuterAddRef, OuterRelease and OuterQueryInterface and a public IUnknown pointer m_pOuterUnknown.
3.4 COM map macro helper methods
CComObjectRootBase provides a set of internal helper functions so that COM map macros can call to calculate vPtr for a given interface, including _Chain, _Break, _NoInterface, _Cache, _Delegate and _Creator.
4 CComCoClass<>
The other template class which the ATL coclass inherits from is CComCoClass<>. It provides mainly three services:
- It contains a call to macro DECLARE_CLASSFACTORY, which extends to typedef CComClassFactory to by your default class factory.
- It invokes macro DECLARE_AGGREGATABLE to instruct ATL framework how the colcass should function ? as a stand-alone or aggregated object.
- It provides a number of overloaded Error methods to return error information to the client.
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)