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

    技术2022-05-11  97

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


    最新回复(0)