ATL对COM的基本支持可以分为:对象和服务器
3.1 回顾COM套间
COM支持两种对象:多线程对象和单线程对象。多线程对象是那些能够自己完成同步工作的对象,而单线程对象是COM来处理同步问题。
COM判断一个对象是单线程还是多线程取决于其生存套间。COM套间是一个或多个线程的组合。这些线程或是单线程或是多线程。
对于在单线程套间中创建的对象的调用必须完成之后,才能服务下一个请求。
多线程套间中创建对象必须随时准备接收到自任意数目线程的调用。
ATL把COM对象分成几个层次:
1, CComXXXThreadModel被CComObjectRootEx使用,用来提供线程安全定理对象生命周期和对象锁定的功能。
2, CComObjectRootBase 和CComObjectRootEx提供用于IUnknown实现辅助函数。
3, 我们的类从CComObjectRootEx派生,同时也实现我们自己接口的方法。
4, CComObject提供IUnknown方法的真正实现.
class CComSingleThreadModel
{
public:
static ULONG WINAPI Increment(LPLONG p) {return ++(*p);}
static ULONG WINAPI Decrement(LPLONG p) {return --(*p);}
};
class CComMultiThreadModel
{
public:
static ULONG WINAPI Increment(LPLONG p)
{return InterlockedIncrement(p);}
static ULONG WINAPI Decrement(LPLONG p)
{return InterlockedDecrement(p);}
};
用于数据同步
class CComCriticalSection
{
public:
void Lock() {EnterCriticalSection(&m_sec);}
void Unlock() {LeaveCriticalSection(&m_sec);}
void Init() {InitializeCriticalSection(&m_sec);}
void Term() {DeleteCriticalSection(&m_sec);}
CRITICAL_SECTION m_sec;
};
class CComAutoCriticalSection
{
public:
void Lock() {EnterCriticalSection(&m_sec);}
void Unlock() {LeaveCriticalSection(&m_sec);}
CComAutoCriticalSection() {InitializeCriticalSection(&m_sec);}
~CComAutoCriticalSection() {DeleteCriticalSection(&m_sec);}
CRITICAL_SECTION m_sec;
};
class CComFakeCriticalSection
{
public:
void Lock() {}
void Unlock() {}
void Init() {}
void Term() {}
};
IUnknown实现的核心
template <class ThreadModel>
class CComObjectLockT
{
public:
CComObjectLockT(CComObjectRootEx<ThreadModel>* p)
{
if (p)
p->Lock();
m_p = p;
}
~CComObjectLockT()
{
if (m_p)
m_p->Unlock();
}
CComObjectRootEx<ThreadModel>* m_p;
};
template <class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase
{
public:
typedef ThreadModel _ThreadModel;
typedef _ThreadModel::AutoCriticalSection _CritSec;
typedef CComObjectLockT<_ThreadModel> ObjectLock;
ULONG InternalAddRef()
{
ATLASSERT(m_dwRef != -1L);
return _ThreadModel::Increment(&m_dwRef);
}
ULONG InternalRelease()
{
ATLASSERT(m_dwRef > 0);
return _ThreadModel::Decrement(&m_dwRef);
}
void Lock() {m_critsec.Lock();}
void Unlock() {m_critsec.Unlock();}
private:
_CritSec m_critsec;
};
template <>
class CComObjectRootEx<CComSingleThreadModel> : public CComObjectRootBase
{
public:
typedef CComSingleThreadModel _ThreadModel;
typedef _ThreadModel::AutoCriticalSection _CritSec;
typedef CComObjectLockT<_ThreadModel> ObjectLock;
ULONG InternalAddRef()
{
ATLASSERT(m_dwRef != -1L);
return _ThreadModel::Increment(&m_dwRef);
}
ULONG InternalRelease()
{
return _ThreadModel::Decrement(&m_dwRef);
}
void Lock() {}
void Unlock() {}
};
CComObjectRootEx除了提供了线程安全,还能过基类CComObjectRootBase的QueryInerface提供静态表驱动实现
BEGIN_COM_MAP(CIXXX)
COM_INTERFACE_ENTRY(IIXXX)
END_COM_MAP()
展开为如下
IUnknown* _GetRawUnknown()
{ ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY);
return (IUnknown*)((int)this+_GetEntries()->dw); }
HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject)
{ return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); }
const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries()
{
static const _ATL_INTMAP_ENTRY _entries[] = { {&IID_IXX, 0, _ATL_SIMPLEMAPENTRY}, {0,0,0}};
return _entries;
}
到这里,开始讨论一下创建一个类对象,
CIXXX* pObj = new CIXXX; 显然不行,因为IUnknown的方法没有实现;
可以这样做,CComOject<CIXXX>* pObj = new CComObject<CIXXX>;
下面看看创建自己的一个静态函数
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;
}
typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void* pv, REFIID riid, LPVOID* ppv, DWORD dw);