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;
}
代碼簡要說明:
在通過CLSID和IID調用組件導出函數DllGetClassObject時,首先
會監測程序環境,然後調用AfxDllGetClassObject,而AfxDllGetClassObject
內部的操作是這樣的,它會從程序維護的全局信息中(
還有進線程信息、資源句柄等)的註冊的類廠表中,根據CLSID搜索
相應的類廠,則從本dll引用的擴展dll中搜索.
OK !基本上,MFC對於COM的基礎支持,就是通過上面這些宏
來實現的…
------------------------------------------------------------------------------------
待續 ATL篇
------------------------------------------------------------------------------------
鄭重聲明:
允許複製、修改、傳遞或其它行爲
但不準用於任何商業用途.
寫於 1/4/2003
最後修改: 1/4/2003
By RedStar81
------------------------------------------------------------------------------------