《深入解析ATL》笔记(二)

来源:互联网 发布:锋芒网络剧百度云 编辑:程序博客网 时间:2024/05/19 12:17
 

ATLCOM的基本支持可以分为:对象和服务器 

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);