每個COM組件需要實現這三個功能
1. 實現IUnknown接口 (通過 CComObjectRootEx 實現)
2. 實現一個類工廠,支持組件的創建 (通過 CComCoClass 實現)
3. 實現自注冊
ATL是如何實現IUnknown接口的?
組件通過派生CComObjectRootEx 獲得 IUnknown支持
CComObjectRootBase 提供集合的IUnknown方法支持 :OuterAddRef 和 OuterRelease
CComObjectRootEx 提供非集合的IUnknown方法支持 :InternalAddRef 和 InternalRelease
另外CComObjectRootBase還提供 IUnknown的QueryInterface方法支持 :InternalQueryInterface 和 OuterQueryInterface
IUnknown方法最終通過 CComObject 對用戶開放:
最終我們可以這樣聲明和使用ATL COM組件
-------------------------------------------------------------------------------------------------------------
其實共有9個類似 CComObject 的類用於處理對用戶開放的IUnknown接口,創建可實例化的COM組件。
CComObject : 不支持集合,不能處理引用計數
CComObjectNoLock : 同CComObject, 且該對象生命週期不影響組件宿主文件的鎖定計數。ATL在宿主類工廠實現中使用該類
CComAggObject : 支持集合
CComContainedObject : 類似一個集合對象
CComPolyObject 支持集合和標準實現,是一個佔位實現
CComObjectStack :完全不支持引用計數,結合棧創建COM對象一起使用
CComObjectGlobal : 生存期與組件宿主文件生存期相同,類似全局C++對象
CComObjectCached :存儲在對象的緩存裏,ATL用它實現組件的類工廠
CComTearOffObject :只在需要時創建類
-------------------------------------------------------------------------------------------------------------
總結一下 IUnknown 的實現
1. 類廠會這樣創建組件 CAtlMath
IAtlMath *pIMath = new CComObject <CAtlMath>; //非集合
2. CComObject 提供了IUnknown 接口的實現,它會調用 CAtlMath 的非集合內部IUnknown接口
3. 組件 CAtlMath 會派生於 CComObjectRootEx, CComObjectRootEx提供了部分非集合IUnknown接口
4. CComObjectRootEx 派生於 CComObjectRootBase,CComObjectRootBase提供了部分非集合IUnknown接口和全部集合IUnknown接口
ATL_NO_VTABLE : __declspec (novtable)
告訴編譯器不要爲類生成或初始化一個Vtable結構,可讓類的構造函數和析構函數更小,並減小內存使用