深入探索COM開發框架 之 MFC和ATL [四]

static const AFX_DISPMAP* PASCAL _GetBaseDispatchMap(); /<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

       virtual const AFX_DISPMAP* GetDispatchMap() const; /

 

#else

#define DECLARE_DISPATCH_MAP() /

private: /

       static const AFX_DISPMAP_ENTRY _dispatchEntries[]; /

       static UINT _dispatchEntryCount; /

       static DWORD _dwStockPropMask; /

protected: /

       static AFX_DATA const AFX_DISPMAP dispatchMap; /

       virtual const AFX_DISPMAP* GetDispatchMap() const; /

#endif

------------------------------------------------------

#ifdef _AFXDLL

#define BEGIN_DISPATCH_MAP(theClass, baseClass) /

       const AFX_DISPMAP* PASCAL theClass::_GetBaseDispatchMap() /

                { return &baseClass::dispatchMap; } /

       const AFX_DISPMAP* theClass::GetDispatchMap() const /

                { return &theClass::dispatchMap; } /

       AFX_COMDAT const AFX_DISPMAP theClass::dispatchMap = /

                { &theClass::_GetBaseDispatchMap, &theClass::_dispatchEntries[0], /

                         &theClass::_dispatchEntryCount, &theClass::_dwStockPropMask }; /

       AFX_COMDAT UINT theClass::_dispatchEntryCount = (UINT)-1; /

       AFX_COMDAT DWORD theClass::_dwStockPropMask = (DWORD)-1; /

       AFX_COMDAT const AFX_DISPMAP_ENTRY theClass::_dispatchEntries[] = /

       { /

#else

#define BEGIN_DISPATCH_MAP(theClass, baseClass) /

       const AFX_DISPMAP* theClass::GetDispatchMap() const /

                { return &theClass::dispatchMap; } /

       AFX_COMDAT const AFX_DISPMAP theClass::dispatchMap = /

                { &baseClass::dispatchMap, &theClass::_dispatchEntries[0], /

                         &theClass::_dispatchEntryCount, &theClass::_dwStockPropMask }; /

       AFX_COMDAT UINT theClass::_dispatchEntryCount = (UINT)-1; /

       AFX_COMDAT DWORD theClass::_dwStockPropMask = (DWORD)-1; /

       AFX_COMDAT const AFX_DISPMAP_ENTRY theClass::_dispatchEntries[] = /

{ /

#endif

#define END_DISPATCH_MAP() /

       { VTS_NONE, DISPID_UNKNOWN, VTS_NONE, VT_VOID, /

                (AFX_PMSG)NULL, (AFX_PMSG)NULL, (size_t)-1, afxDispCustom } }; /

 

思路跟上面的接口映射表的如出一轍.這裏不詳細敘述.

關於Automation問題,我想過兩天,專門寫一篇文章談談.

因爲Automation的確是一門範圍很廣的技術,不能說有多麼的

,不過細節很多,而且普遍的論述概念不清.

在上面幾個宏中出現的結構倒需要提一下:

struct AFX_DISPMAP_ENTRY

{

       LPCTSTR lpszName;       // 分發的方法或屬性名                        

       long lDispID;           // 接口分發ID (may be DISPID_UNKNOWN)

       LPCSTR lpszParams;      // 傳遞的參數

       WORD vt;                // 返回值類型或屬性類型

       AFX_PMSG pfn;           // normal member On<membercall> or, OnGet<property>

       AFX_PMSG pfnSet;        // special member for OnSet<property>

       size_t nPropOffset;     // 偏移量,這個地方是核心

       AFX_DISPMAP_FLAGS flags;// flags (e.g. stock/custom)

};

struct AFX_DISPMAP

{

#ifdef _AFXDLL

       const AFX_DISPMAP* (PASCAL* pfnGetBaseMap)();

#else

       const AFX_DISPMAP* pBaseMap;

#endif

       const AFX_DISPMAP_ENTRY* lpEntries;

       UINT* lpEntryCount;

       DWORD* lpStockPropMask;  //是否用備用的名稱

};

 

總之,即使在組件類尋到接口時,會按分發的方式來執行方法或更改屬性,不會直接執行.

 

 

PART5-------組件得以使用的紐帶:幾個核心函數

 

  自然,組件的使用不是一呼既來的,從調用接口查詢函數開始,

程序內部就開始了漫漫的尋找和創建過程 :

no1.

COleObjectFactory::RegisterAll();

在應用初始化時,調用.目的何在 ? 無非是註冊類廠.

(這個地方,本人認爲是加載了所有的類廠對象.

因爲下面可以直接使用類廠指針鏈中的類廠指針了)

no2.

AFX_MANAGE_STATE(AfxGetStaticModuleState());

MFC開發的以CwinApp對象爲核心的

組件中, AFX_MANAGE_STATE(AfxGetStaticModuleState());

必須在具體操作前調用,因爲它掌握着程序所有的信息.

而在ATL,CcomModel對象,內部進行了協調.

一切行爲由CcomModel對象來調度.

 

No3.

AfxDllGetClassObject(rclsid, riid, ppv);

你想得到希望的接口指針,獲得類廠指針這一步是必須的.

而獲得類廠指針是AfxDllGetClassObject(rclsid, riid, ppv);

完成的,它在使用前必須調用

AFX_MANAGE_STATE(AfxGetStaticModuleState());

來監視程序狀態,

代碼如下:

SCODE AFXAPI AfxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)

{

        *ppv = NULL;

        DWORD lData1 = rclsid.Data1;

 

        // search factories defined in the application

        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

        AfxLockGlobals(CRIT_OBJECTFACTORYLIST);

        for (COleObjectFactory* pFactory = pModuleState->m_factoryList;

          pFactory != NULL; pFactory = pFactory->m_pNextFactory)

        {

                 if (pFactory->m_bRegistered != 0 &&

                   lData1 == pFactory->m_clsid.Data1 &&

                   ((DWORD*)&rclsid)[1] == ((DWORD*)&pFactory->m_clsid)[1] &&

                   ((DWORD*)&rclsid)[2] == ((DWORD*)&pFactory->m_clsid)[2] &&

                   ((DWORD*)&rclsid)[3] == ((DWORD*)&pFactory->m_clsid)[3])

                 {

                   // found suitable class factory -- query for correct interface

                   SCODE sc = pFactory->InternalQueryInterface(&riid, ppv);

                   AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);

                   return sc;

                 }

        }

        AfxUnlockGlobals(CRIT_OBJECTFACTORYLIST);

#ifdef _AFXDLL

        AfxLockGlobals(CRIT_DYNLINKLIST);

        // search factories defined in extension DLLs

        for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL;

          pDLL = pDLL->m_pNextDLL)

        {

          for (pFactory = pDLL->m_factoryList;

                   pFactory != NULL; pFactory = pFactory->m_pNextFactory)

                 {

                   if (pFactory->m_bRegistered != 0 &&

                             lData1 == pFactory->m_clsid.Data1 &&

                     ((DWORD*)&rclsid)[1] == ((DWORD*)&pFactory->m_clsid)[1] &&

                     ((DWORD*)&rclsid)[2] == ((DWORD*)&pFactory->m_clsid)[2] &&

                     ((DWORD*)&rclsid)[3] == ((DWORD*)&pFactory->m_clsid)[3])

                   {

                             // found suitable class factory -- query for correct interface

                             SCODE sc = pFactory->InternalQueryInterface(&riid, ppv);

                     AfxUnlockGlobals(CRIT_DYNLINKLIST);

                             return sc;

                   }

                 }

        }

        AfxUnlockGlobals(CRIT_DYNLINKLIST);

#endif

 

        // factory not registered -- return error

        return CLASS_E_CLASSNOTAVAILABLE;

}

 

代碼簡要說明:

在通過CLSIDIID調用組件導出函數DllGetClassObject,首先

會監測程序環境,然後調用AfxDllGetClassObject,AfxDllGetClassObject

內部的操作是這樣的,它會從程序維護的全局信息中(

還有進線程信息、資源句柄等)的註冊的類廠表中,根據CLSID搜索

相應的類廠,則從本dll引用的擴展dll中搜索.

 

OK !基本上,MFC對於COM的基礎支持,就是通過上面這些宏

來實現的

 

------------------------------------------------------------------------------------

待續                      ATL

------------------------------------------------------------------------------------

                          鄭重聲明:

                 允許複製、修改、傳遞或其它行爲

                 但不準用於任何商業用途.

                      寫於  1/4/2003

                      最後修改: 1/4/2003

                         By RedStar81

                      [email protected]

------------------------------------------------------------------------------------

 

發佈了46 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章