ATL对COM实体身份的支持(四)—— CComObject及其伙伴
有了CComObjectRootBase、CComObjectRootEx和线程模型特征类这些基础原料,CComObject和它的伙伴们便可以自由的发挥它们的想象了。
1.CComObject —— 普通堆对象
下面是精简的CComObject模板类的定义:
template
<
class
Base
>
class CComObject : public Base
{
public :
CComObject( void * = NULL) throw ()
{
_pAtlModule -> Lock();
}
virtual ~ CComObject() throw ()
{
FinalRelease();
_pAtlModule -> 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) throw ()
{ return _InternalQueryInterface(iid, ppvObject);}
static HRESULT WINAPI CreateInstance(CComObject < Base >** pp) throw ();
};
class CComObject : public Base
{
public :
CComObject( void * = NULL) throw ()
{
_pAtlModule -> Lock();
}
virtual ~ CComObject() throw ()
{
FinalRelease();
_pAtlModule -> 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) throw ()
{ return _InternalQueryInterface(iid, ppvObject);}
static HRESULT WINAPI CreateInstance(CComObject < Base >** pp) throw ();
};
“普通堆对象”是使用最为频繁的类,它有如下特征:
(1)在堆中分配内存 —— 计数归零时用delete销毁
(2)支持独立存在的对象 —— 使用InternalXXX来实现IUnknown功能
(3)产生时锁定服务器,销毁时解锁服务器 —— 适用于大多数COM对象
2. CComAggObject —— 被聚合堆对象
template
<
class
contained
>
class CComAggObject :
public IUnknown,
public CComObjectRootEx < typename contained::_ThreadModel::ThreadModelNoCS >
{
public :
CComAggObject( void * pv) : m_contained(pv)
{
_pAtlModule -> Lock();
}
HRESULT FinalConstruct()
{
CComObjectRootEx < contained::_ThreadModel::ThreadModelNoCS > ::FinalConstruct();
return m_contained.FinalConstruct();
}
void FinalRelease()
{
CComObjectRootEx < contained::_ThreadModel::ThreadModelNoCS > ::FinalRelease();
m_contained.FinalRelease();
}
virtual ~ CComAggObject()
{
FinalRelease();
_pAtlModule -> 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)
{
HRESULT hRes = S_OK;
if (InlineIsEqualUnknown(iid))
{
* ppvObject = ( void * )(IUnknown * ) this ;
AddRef();
}
else
hRes = m_contained._InternalQueryInterface(iid, ppvObject);
return hRes;
}
static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject < contained >** pp);
CComContainedObject < contained > m_contained;
};
class CComAggObject :
public IUnknown,
public CComObjectRootEx < typename contained::_ThreadModel::ThreadModelNoCS >
{
public :
CComAggObject( void * pv) : m_contained(pv)
{
_pAtlModule -> Lock();
}
HRESULT FinalConstruct()
{
CComObjectRootEx < contained::_ThreadModel::ThreadModelNoCS > ::FinalConstruct();
return m_contained.FinalConstruct();
}
void FinalRelease()
{
CComObjectRootEx < contained::_ThreadModel::ThreadModelNoCS > ::FinalRelease();
m_contained.FinalRelease();
}
virtual ~ CComAggObject()
{
FinalRelease();
_pAtlModule -> 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)
{
HRESULT hRes = S_OK;
if (InlineIsEqualUnknown(iid))
{
* ppvObject = ( void * )(IUnknown * ) this ;
AddRef();
}
else
hRes = m_contained._InternalQueryInterface(iid, ppvObject);
return hRes;
}
static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject < contained >** pp);
CComContainedObject < contained > m_contained;
};
CComAggObject有如下特征:
(1)在堆中分配内存
(2)支持被聚合聚合的对象
实现了两份IUnknown:CComAggObject实现了内部聚合类真正的IUnknown,它管理对象的生存期,并且完成接口查询(通过contained对象的_InternalQueryInterface);contained对象实现了具有转发功能的IUnknown,它将所有的调用转发给CComAggObject在构造函数中收到的外部IUnknown指针。
(3)产生时锁定服务器,销毁时解锁服务器
3. CComTearOffObject —— tear-off 对象
template
<
class
Base
>
class CComTearOffObject : public Base
{
public :
CComTearOffObject( void * pv)
{
m_pOwner = reinterpret_cast < Base::_OwnerClass *> (pv);
m_pOwner -> AddRef();
}
~ CComTearOffObject()
{
FinalRelease();
m_pOwner -> Release();
}
STDMETHOD_(ULONG, AddRef)() throw () { return InternalAddRef();}
STDMETHOD_(ULONG, Release)() throw ()
{
ULONG l = InternalRelease();
if (l == 0 )
delete this ;
return l;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw ()
{
return m_pOwner -> QueryInterface(iid, ppvObject);
}
};
class CComTearOffObject : public Base
{
public :
CComTearOffObject( void * pv)
{
m_pOwner = reinterpret_cast < Base::_OwnerClass *> (pv);
m_pOwner -> AddRef();
}
~ CComTearOffObject()
{
FinalRelease();
m_pOwner -> Release();
}
STDMETHOD_(ULONG, AddRef)() throw () { return InternalAddRef();}
STDMETHOD_(ULONG, Release)() throw ()
{
ULONG l = InternalRelease();
if (l == 0 )
delete this ;
return l;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw ()
{
return m_pOwner -> QueryInterface(iid, ppvObject);
}
};
tear-off对象有如下特征:
(1)在堆中分配内存
(2)支持在ATL组件内部使用的tear-off技术
(3)生成时锁定父对象,销毁时解锁父对象
(4)生命周期由自己管理,接口查询委托父对象
4. CComObjectStack —— 栈对象
template
<
class
Base
>
class CComObjectStackEx : public Base
{
public :
CComObjectStackEx( void * = NULL)
{
m_hResFinalConstruct = FinalConstruct();
}
virtual ~ CComObjectStackEx()
{
FinalRelease();
}
STDMETHOD_(ULONG, AddRef)()
{
return 0 ;
}
STDMETHOD_(ULONG, Release)()
{
return 0 ;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
return _InternalQueryInterface(iid, ppvObject);
}
HRESULT m_hResFinalConstruct;
};
class CComObjectStackEx : public Base
{
public :
CComObjectStackEx( void * = NULL)
{
m_hResFinalConstruct = FinalConstruct();
}
virtual ~ CComObjectStackEx()
{
FinalRelease();
}
STDMETHOD_(ULONG, AddRef)()
{
return 0 ;
}
STDMETHOD_(ULONG, Release)()
{
return 0 ;
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
return _InternalQueryInterface(iid, ppvObject);
}
HRESULT m_hResFinalConstruct;
};
栈对象有如下特征:
(1)内存分配于栈上 —— 不需要对象考虑释放问题
(2)无引用计数功能
(3)构造时初始化 —— 需要在构造函数调用后检查m_hResFinalConstruct,以判断对象是否构造成功
(4)不锁定服务器
5. CComObjectGlobal —— 全局对象
template
<
class
Base
>
class CComObjectGlobal : public Base
{
public :
CComObjectGlobal( void * = NULL)
{
m_hResFinalConstruct = FinalConstruct();
}
virtual ~ CComObjectGlobal()
{
FinalRelease();
}
STDMETHOD_(ULONG, AddRef)() throw ()
{
return _pAtlModule -> Lock();
}
STDMETHOD_(ULONG, Release)() throw ()
{
return _pAtlModule -> Unlock();
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw ()
{
return _InternalQueryInterface(iid, ppvObject);
}
HRESULT m_hResFinalConstruct;
};
class CComObjectGlobal : public Base
{
public :
CComObjectGlobal( void * = NULL)
{
m_hResFinalConstruct = FinalConstruct();
}
virtual ~ CComObjectGlobal()
{
FinalRelease();
}
STDMETHOD_(ULONG, AddRef)() throw ()
{
return _pAtlModule -> Lock();
}
STDMETHOD_(ULONG, Release)() throw ()
{
return _pAtlModule -> Unlock();
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw ()
{
return _InternalQueryInterface(iid, ppvObject);
}
HRESULT m_hResFinalConstruct;
};
全局对象有如下特征:
(1)在全局数据区分配内存
(2)初始化时不锁定服务器,引用计数变化时才锁定或者解锁服务器,这使得全局对象可以被用于全局类厂对象,以解决服务器和类厂之间的死锁问题
(3)构造方式同栈对象
还有一些其它种类的生存期管理类,如CComObjectNoLock、CComObjectCached、CComPolyObject等等,它们也都有自己独到的用处,我们也可以根据自己的需要编写自定义的类。总之CComObjectRootBase、CComObjectRootEx和线程模型特征类就像是积木一样,我们可以任意的把它们组合成想要的形状。