static const AFX_DISPMAP* PASCAL _GetBaseDispatchMap(); \
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
------------------------------------------------------------------------------------
本文地址:http://com.8s8s.com/it/it1863.htm