com学习新体会(2)
在ATL中,类厂是计数的。
1. CComCoClass
template <class T, const CLSID* pclsid = &CLSID_NULL>
class CComCoClass
{
public:
DECLARE_CLASSFACTORY()
...
}
2.
#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
3. 类厂的_ClassFactoryCreatorClass
#if defined(_WINDLL) | defined(_USRDLL)
#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectCached< cf > > _ClassFactoryCreatorClass;
#else
// don't let class factory refcount influence lock count
#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
#endif
4.1 对于in-pro
template <class Base>
class CComObjectCached : public Base
{
public:
typedef Base _BaseClass;
CComObjectCached(void* = NULL){}
// Set refcount to -(LONG_MAX/2) to protect destruction and
// also catch mismatched Release in debug builds
~CComObjectCached()
{
m_dwRef = -(LONG_MAX/2);
FinalRelease();
#ifdef _ATL_DEBUG_INTERFACES
_AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
#endif
}
//If InternalAddRef or InternalRelease is undefined then your class
//doesn't derive from CComObjectRoot
STDMETHOD_(ULONG, AddRef)()
{
m_csCached.Lock();
ULONG l = InternalAddRef();
if (m_dwRef == 2)
_pAtlModule->Lock();
m_csCached.Unlock();
return l;
}
STDMETHOD_(ULONG, Release)()
{
m_csCached.Lock();
InternalRelease();
ULONG l = m_dwRef;
m_csCached.Unlock();
if (l == 0)
delete this;
else if (l == 1)
_pAtlModule->Unlock();
return l;
}
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{return _InternalQueryInterface(iid, ppvObject);}
CComGlobalsThreadModel::AutoCriticalSection m_csCached;
};
4.2 对于local server or service
template <class Base>
class CComObjectNoLock : public Base
{
public:
typedef Base _BaseClass;
CComObjectNoLock(void* = NULL){}
// Set refcount to -(LONG_MAX/2) to protect destruction and
// also catch mismatched Release in debug builds
~CComObjectNoLock()
{
m_dwRef = -(LONG_MAX/2);
FinalRelease();
#ifdef _ATL_DEBUG_INTERFACES
_AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
#endif
}
//If InternalAddRef or InternalRelease is undefined then your class
//doesn't derive from CComObjectRoot
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
//if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{return _InternalQueryInterface(iid, ppvObject);}
};
由此可见,在ATL中类厂是计数的。
只不过对于in-pro, 只有当m_dwRef由1->2时,才lock server;当m_dwRef由2->1时,就unlock server;通过这种手段来避免“自相矛盾”。
而对于local server or service, 计数但不lock/unlock server.