分享
 
 
 

深入探索COM开发框架 之 MFC和ATL [三]

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

1. 事实上,组件类获得接口映射表是通过GetInterfaceMap()静态成员函数先

获得interfaceMap结构变量,此变量的第二个值便是接口映射表的入口.

InterfaceMap的第一个值保存了基类的_GetBaseInterfaceMap函数指针.

为在组件类中找不到接口的定义时,通过_GetBaseInterfaceMap

获得基类的interfaceMap,从而获得基类的接口映射表入口….

就这样不断上溯..

通过这些宏,我们实现了接口映射表,并为在类层次中辗转提供了

方法.这样,组件类就可以通过这张表实现接口的查询和地址定位了.

然而这里还有一个大问题

我们说,任何一个接口必须实现AddRef、Release、QueryInterface.

(注2:事实上,接口的定义在Idispatch出现后,有了一定的转变,你可将任何

实现了方法和数据的结合看作接口.)…可这里没见什么关于这方面的定义啊..

不错,这里还有一个”大阴谋”呢…. 关于这个还得从

#define INTERFACE_PART(theClass, iid, localClass)

{ &iid, offsetof(theClass, m_x##localClass) },

//填充接口影射表

说起….

在实际的工程中,默认的上面的localClass将会被Dispatch取代.

Dispatch又为何物 ? 事实上,在CDK1.0中,COM开发不用上面这些宏,

在那里你可以清楚的看到问题的实质,没办法,时代变了,就面前的情况来

探讨吧…

上面Dispatch的位置,规定置入实现接口的嵌套类的…

那么毫无疑问Dispatch就是嵌套类啦.可是你说,这是哪里来的 ?

事实上,在CCmdTarget中,有这么一片段:

struct XDispatch

{

DWORD m_vtbl; // place-holder for IDispatch vtable

#ifndef _AFX_NO_NESTED_DERIVATION

size_t m_nOffset;

#endif

} m_xDispatch;

它将成为实现接口的嵌套类.

这怎么可能成为嵌套类呢 . .它什么也没有啊…简简单单的结构而已啊….

事实在内部,存在一样的虚表vtable指派行为,正是这种行为使得m_xDispatch彻底的

变了,这种行为的引爆器就是组件类构造函数中的EnableAutomation();

代码如下:

void CCmdTarget::EnableAutomation()

{

ASSERT(GetDispatchMap() != NULL); // must have DECLARE_DISPATCH_MAP

// construct an COleDispatchImpl instance just to get to the vtable

COleDispatchImpl dispatch;

// vtable pointer should be already set to same or NULL

ASSERT(m_xDispatch.m_vtbl == NULL||

*(DWORD*)&dispatch == m_xDispatch.m_vtbl);

// sizeof(COleDispatchImpl) should be just a DWORD (vtable pointer)

ASSERT(sizeof(m_xDispatch) == sizeof(COleDispatchImpl));

// copy the vtable (and other data) to make sure it is initialized

m_xDispatch.m_vtbl = *(DWORD*)&dispatch;

*(COleDispatchImpl*)&m_xDispatch = dispatch;

}

PART2 深入CCmdTarget看一看COM三大元素的实现

我们之所以深入到CCmdTarget

不是想只是为了那简简单单的实现

我们想知道MFC对COM的一大美景:聚合

是怎么实现的.

二话不说,摆出架势先 :

public:

// data used when CCmdTarget is made OLE aware

long m_dwRef;

LPUNKNOWN m_pOuterUnknown; // external controlling unknown if != NULL

DWORD m_xInnerUnknown; // place-holder for inner controlling unknown

public:

// advanced operations

void EnableAggregation(); // call to enable aggregation

void ExternalDisconnect(); // forcibly disconnect

LPUNKNOWN GetControllingUnknown();

// get controlling IUnknown for aggregate creation

// these versions do not delegate to m_pOuterUnknown

DWORD InternalQueryInterface(const void*, LPVOID* ppvObj);

DWORD InternalAddRef();

DWORD InternalRelease();

// these versions delegate to m_pOuterUnknown

DWORD ExternalQueryInterface(const void*, LPVOID* ppvObj);

DWORD ExternalAddRef();

DWORD ExternalRelease();

// implementation helpers

LPUNKNOWN GetInterface(const void*);

LPUNKNOWN QueryAggregates(const void*);

// advanced overrideables for implementation

virtual BOOL OnCreateAggregates();

virtual LPUNKNOWN GetInterfaceHook(const void*);

从上面的声明中,你可发现:

这里声明了两套标准接口方法,

Externalxx对应于COM模型中的委托IUnknown

而Internalxx对应COM模型中的非委托Iunknown

有了这两套接口方法,聚合的实现就OK了…..

关于聚合的实现细节,欲知详情,请参阅相关专门

的书籍,这里不再赘述.

通过PART1和PART2关于接口的基础构造已经完成.

PART3------类厂的由来

不用说,COM对象的创建是需要类厂的.

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

DECLARE_OLECREATE(CSAM)宏剖析

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

#define DECLARE_OLECREATE(class_name)

public:

static AFX_DATA COleObjectFactory factory;

//定义类厂对象…

static AFX_DATA const GUID guid;

//组件类的GUID

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

IMPLEMENT_OLECREATE 宏剖析

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

#define IMPLEMENT_OLECREATE(class_name, external_name, l, w1, w2, b1,

b2, b3, b4, b5, b6, b7, b8)

AFX_DATADEF COleObjectFactory class_name::factory(class_name::guid,

RUNTIME_CLASS(class_name), FALSE, _T(external_name));

//这里要注意的是external_name:ProgID

AFX_COMDAT const AFX_DATADEF GUID class_name::guid =

{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } };

//将组件类的CLSID赋予组件类的成员变量guid.

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

IMPLEMENT_OLECREATE(CSAM, "MFCCOM.SAM",

0x43d242f9, 0x4f7e, 0x4cbb, 0xae, 0xda, 0x77, 0x8d, 0xa1, 0x16, 0xd0, 0xd9)

说明:我们知道,在创建组件类对象时,首先由App核心获得当前状态,

从中取出类厂表,依据CLSID获得相应的类厂对象指针.正是在这里

将类厂和CLSID、ProID等信息关联.

PART4-------自动化

事实上,自动化也是一个极大的主题.自动化技术增强了组件的环境适应性.

对于MFC中的自动化组件,由于默认的接口为dispinterface,所以它对方法的

访问一律采用分发的手段.不同于你意识中,一直牢记的通过vtable[_index]

来访问方法.在使用组件的过程中,首先获得Idispatch接口,然后调用Idispatch

的方法GetIDsOfNames获得programmers希望的方法的令牌(ID),最后通过

Idispatch的方法Invoke来执行.这种技术使得脚本和宏环境可以使用COM

对象,不过对于有预先编译能力的环境来说,会使得组件系统的性能大打

折扣.因为它多了一个反复调用的中间层.

关于Dispatch的支持,基本上构建思路原理同于

上述的Interface..

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

DECLARE_DISPATCH_MAP()

BEGIN_DISPATCH_MAP(CSAM, CCmdTarget)[.cpp]

DISP_PROPERTY_NOTIFY(CSAM, "Fook", m_Fook, OnFookChanged, VT_R4)

DISP_FUNCTION(CSAM, "Post", Post, VT_R4, VTS_NONE)

END_DISPATCH_MAP()

宏剖析

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

#ifdef _AFXDLL

#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;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有