深入探索MS COM開發框架 之 MFC和ATL(一)

文章索引:
一、概述和待剖析宏羅列
二、MFC、ATL COM支持原理概述
三、宏剖析
☆      ☆ MFC篇
PART1----接口基礎構造的由來
PART2 ----深入CCmdTarget看一看COM三大元素的實現
PART3------類廠的由來
PART4-------自動化支持
PART5-------組件得以使用的紐帶:幾個核心函數
☆      ☆ ATL篇
PART1----幾個核心模板類介紹
PART2----模板撐起的天空 : 接口的由來
PART3-------自動化支持
PART4------深入核心模板類
PART5-------組件得以使用的紐帶:幾個核心函數
---------------------------------------------------------------------------------------------------------------------------
 
COM是出了名的難纏.原因在於它本身的設計灌注了大量的細節處理,九曲十八彎,令人迷惑.
然而MS慣用的宏手法,也是令很多人迷惑、久久不得思路.那麼MFC、ATL用宏手法來提供對
COM開發的支持,就更加令人…了.下面我們就進程內組件開發探討一下MFC、ATL對COM開
發的基礎支持是怎樣實現的….
一、概述和待剖析宏羅列
 
首先給你一個關於COM結構大致的描述 : 在組件(dll,exe,ocx等)內,存在大量的組件類
(CoClass),每個組件類維護N多的接口(interface),接口背後維護N的方法.自然還有類廠
(ClassFactory),類廠是組件類的平行類.
不錯,那麼MFC、ATL是怎樣將上述的結構實現的呢 ?
針對MFC我們需要剖析的宏羅列於下:
存在組件類.h和.cpp文件中的宏:
    1. DECLARE_DYNCREATE(CSAM)
      IMPLEMENT_DYNCREATE(CSAM, CCmdTarget)[.cpp]
簡要說明:支持RTTI和動態創建類對象能力.
關於此,下面不會詳細講解.
欲瞭解更多細節者可參見
《深入淺出MFC》,原理相同
    2. DECLARE_MESSAGE_MAP()
      BEGIN_MESSAGE_MAP(CSAM, CCmdTarget)[.cpp]
END_MESSAGE_MAP()
簡要說明:維護消息處理系統,原因在於MFC仍然
以CwinApp對象爲核心.
          對於此,下面不會詳解,
          欲知詳情,參考《深入淺出MFC》.
3.DECLARE_OLECREATE(CSAM)
     IMPLEMENT_OLECREATE(CSAM, "MFCCOM.SAM",
0x43d242f9, 0x4f7e, 0x4cbb, 0xae, 0xda, 0x77, 0x8d, 0xa1, 0x16, 0xd0, 0xd9)
簡要說明:創建類廠對象,且將類廠和組件類關聯,
          爲通過CLSID創建類實例提供保證.
4.DECLARE_DISPATCH_MAP()
      BEGIN_DISPATCH_MAP(CSAM, CCmdTarget)[.cpp]
END_DISPATCH_MAP()
簡要說明:支持自動化分發,事實上,
          這裏體現MFC對COM支持的真正意圖,
          因爲MFC默認派生的接口爲dispinterface
          (純dispatch接口),具體細節下面會描述.
5.DECLARE_INTERFACE_MAP()
     BEGIN_INTERFACE_MAP(CSAM, CCmdTarget)[.cpp]
      INTERFACE_PART(CSAM, IID_ICOM, Dispatch)
     END_INTERFACE_MAP()
簡要說明:創建接口映射表,這裏的手法在MS的FrameWork中隨處可見
          雖然可能細節的實現不同.
    在dll主文件中的: [xxx.cpp]
1.AFX_MANAGE_STATE(AfxGetStaticModuleState())
簡要說明:這裏是模塊的狀態管理.
很重要,它維護關於程序的
大量信息,我們將討論其中的類廠表.
2. COleObjectFactory::RegisterAll()
簡要說明:在dll初始化時,註冊所有的類廠.
3. AfxDllGetClassObject(rclsid, riid, ppv);
簡要說明:根據rclsid獲取類廠指針.
  幾個重要的函數:
1.        EnableAutomation()
簡要說明:存在於各組件類的構造函數中
          使得CcmdTarget內含的xDiapatch首先獲得
另一個內含的實現Idispatch的對象的vtable,
從而使得programmers自建的接口類成爲真正的
實用品.
          這裏有點複雜,詳細的下面說明.
2.        AfxOleLockApp()
簡要說明:存在於各組件類的構造函數中
          自然這個組件類須是Creatable By ID的
          纔會顯式.
          創建組件對象時,鎖定App,進入臨界區.
3.        AfxOleUnlockApp()
簡要說明: 存在於各組件類的構析函數中
           自然這個組件必須是Creatable By ID 的,
            纔會顯式.
            退出臨界區.
           是否OLE 自動化創建的所有對象銷燬,
是則終止應用程序,在析構函數中調用.
4.        CCmdTarget::OnFinalRelease()
組件類對象的最後引用釋放後,進行的收尾工作.
 
針對ATL我們需要剖析的宏羅列如下:
  在組件類.h文件中的宏:
  在.h文件中:
  1. DECLARE_REGISTRY_RESOURCEID(IDR_SIM)
    簡要說明:支持用註冊表腳本註冊組件,腳本
在ATL中作爲資源的一種.
2.DECLARE_PROTECT_FINAL_CONSTRUCT()
    簡要說明:防止組件類對象被刪除.
3.BEGIN_COM_MAP(CSim)
COM_INTERFACE_ENTRY(ISim)
           COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
簡要說明:生成COM映射表,其作用與MFC的接口映射表作用是一樣的.
  在.cpp文件中:[xxx.cpp]
5. BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_Sim, CSim)
END_OBJECT_MAP()
簡要說明:生成組件類表,保存所有組件類的大量信息,包括
              CLSID、組件類的類工廠、更新註冊成員函數的指針、
          獲得描述成員函數的指針、創建組件類實例成員函數的指針等.
          這裏也是一個關鍵之所在.
我們發現上面的MFC和ATL宏大有不同.是吧,事實上它們實現的手法也是大不相同的.

二、MFC、ATL COM支持原理概述
 首先我們必須清楚:MFC、ATL支持COM的手法是不一樣的.
       MFC是通過嵌套類,而ATL是通過多繼承.
        MFC支持手法概述:在一般的嵌套類解決方案中,嵌套類對象中需要維護一個指向
包裹類對象的指針,這樣才能在接口(其實是嵌套類對象)之間轉移,並實現與包裹類
的本身的通信.然而由於Programmers並不需要自己處理在QueryInterface時保證
接口指針指向正確的地址.事實上,ATL手法也不需要.所以MFC在具體實現上,
採用了MS的慣用手法:建偏移量表.表中記錄IID和接口vtable與包裹類對象地
址this之間的偏移量.這樣,在得到組件類的地址時,就可以得到接口的地址,從而
調用方法.自然,這裏還有一個你感覺不到的問題:不採取特殊的手段
在接口指針級回到包裹類會又是一問題,然而MFC在這個問題上的解決方案是:
早就將嵌套類的AddRef、Release、QueryInterface,轉移到包裹類的調用.
這樣還怕進去了回不來嗎 ? 這是在xDispatch中實現的.
沒辦法MS就鍾情與data-driven,而且它產品中,這種手法的確玩的爐火純青.
我實驗了通過在嵌套類中維護包裹類指針,事實上的確比這裏的
方法不好控制.
這裏的一切手段的由來,都是針對解決類嵌套的特徵的.
值得講一下的是,這裏使用的手法有組件的聚合之風範.你就帶着這份感覺來
透徹的理解聚合和這裏對嵌套的處理吧…
ATL支持手法概述:ATL的支持手法,可能很貼近你的思維.組件類從任意的接口繼承,
        這樣就可以利用接口在C++中的虛特徵實現方法,自然同於MFC,接口必須共享
一套AddRef、Release、QueryInterface實現.這也是由C++的虛機制保證的.
 
發佈了26 篇原創文章 · 獲贊 13 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章