分享
 
 
 

MFC框架升级OCX时存在的向下兼容性问题

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

今天得闲,刚好又要处理OCX向下兼容性的问题,于是仔细查看了一下造成问题的原因,做了些简单测试,不打算从原理分析,我们暂且从表象上分析。

[问题描述]

在使用MFC框架制作OCX时,存在向下兼容性问题。

在旧控件的某个接口添加Property时,重新编译。你会发现原有的调用exe程序(VB编译所得)在调用该接口的Method时会出错。

Why?按理,添加属性,不应该出现兼容问题。

将旧有调用程序源码调出,采用新Ocx(tlb)关联,编译后,使用正常。

当然,上述做法显然有问题,实际上如果调用者并不需要新功能,他是没有义务来做此操作的。

所以,我们称之为向下兼容性问题。原因何在?

[查资料]

相关书藉并未能直接找到答案。

[分析ocx特性]

ActiveX Control是一个很特殊的COM,它使用了自动化技术。或者,更简单的说:它实现了IDispatch接口。属性以及方法也当然是由IDispath而来。我们当然应该从此接口的实现着手。IDispatch的具体略过(书上都有),看看最关键的Invoke,GetIDsOfName。它要求每个方法/属性编号都有一个id号,通过名称找到id,然后查找相应的函数。这是IDispatch的标准。好,我们暂时只需知道这一点。其它先不管。

[分析 mfc框架代码]

看看MFC框架做了些什么。

第1步:

用ClassWizard添加一个属性a(非Stock),

嗯,在实现文件的分发映射表里加了如下:(头文件的声明略)

BEGIN_DISPATCH_MAP(MyTest, CCmdTarget)

//{{AFX_DISPATCH_MAP(MyTest)

DISP_PROPERTY_EX(MyTest, "a", GetA, SetA, VT_I4)

//}}AFX_DISPATCH_MAP

END_DISPATCH_MAP()

在odl文件里添加了:

properties:

[id(1)] long a;

好了,?疑问来了:

在odl里面的id值1,而在分发映射表里没有id值,mfc如何对应?

第2步:

添加一个方法m,得到:

DISP_PROPERTY_EX(MyTest, "a", GetA, SetA, VT_I4)

DISP_FUNCTION(MyTest, "m", m, VT_EMPTY, VTS_NONE)

methods:

[id(2)] void m();

同样疑问,在old里有id值2,而在分发映射表里没有。

断定:

我们可以初步断定,MFC为了偷懒,将映射表的先后次序与id值进行了隐性关联,

第3步:

为了进一步证实这一点:我把odl中的m方法的id(2)改为id(3),发现调用失败,

将实现文件映射表中a与m调序,会出现类型调用错。

再次断定:

在Ocx内部的Dispatch id值是按映射表中的次序确定。

第4步:

接着,我们来验证再添加属性出错的问题:

再添加属性b 在实现文件中得到:

DISP_PROPERTY_EX(MyTest, "a", GetA, SetA, VT_I4)

DISP_PROPERTY_EX(MyTest, "b", GetB, SetB, VT_I4)

DISP_FUNCTION(MyTest, "m", m, VT_EMPTY, VTS_NONE)

我们可以先猜测一下在odl中的变更:

a的id应该是1,b的id应该是2,而m的id应该改为了3。

打开odl,果然:

properties:

[id(1)] long a;

[id(2)] long b;

methods:

[id(3)] void m();

再得到结论:

MFC的ClassWizard在添加ocx的属性或方法时,首先变更的是它的实现(映射表)及头文件,

顺序按属性或方法进行大排序,新属性加在原有属性的后面,新方法加在原有方法后面。然后,

它按照映射表中的位置关系,更新了odl中的内容以及id值。

利用MFC框架添加属性/方法时,会改变odl中方法的id值。

仔细试了一下:具体的次序应该是:

按Notify Property、Property、Function、StockFunc、StockProp顺序

第5步:

我们再看看Stock属性是如何处理的:

添加一个Stock TEXT属性。

映射表:

DISP_STOCKPROP_TEXT()

odl:

[id(DISPID_TEXT), bindable, requestedit] BSTR Text;

这似乎和上述结论有冲突,且慢,我们把DISP_STOCKPROP_TEXT展开:

#define DISP_STOCKPROP_TEXT() DISP_PROPERTY_STOCK(COleControl, "Text", DISPID_TEXT, COleControl::GetText, COleControl::SetText, VT_BSTR)

看到没有:DISPID_TEXT,它是有id值的,并且同odl里面的一样。

结论:

利用MFC框架添加Stock属性/方法时,映射表中将存在与odl相同的预定义id值。并且不影响原有odl中的id值。

第6步:

那么,改变id值为什么会造成原有代码无法正常使用呢。

这个书上是有的,VB代码在编译,对自动化的IDispatch接口显然采用了早绑定类型库的

方式,也就是在编译时将名称转换为ID值,也就是说执行文件里已认定m的调用的id值为2。而

在新ocx中,2已经不是m,而是指向新的属性,由于类型不匹配,当然会出错。

我们可以做个实例:

添加属性long a, 方法 void test1(), void test2()

(test1输出对话框"test1",test2输出对话框"test2").

编写VB例,调用 test2,编译为exe。

运行,得到"test2"输出。

再添加属性b,编译ocx。

运行先前的exe,得到 "test1"输出。

重新编译源程序,得到”test2”输出。

结论:

VB的早绑定,提早将id值纳入exe中,当ocx内的id发生变更时,会造成错位,即调用错误。

(其实,如果你用VC的COleDipatchDriver方式调用,会有同样问题,id已写入代码)

总结:

本来,按照COM、 Dispatch标准,只要名称不变,应该就能找到正确位置,id应该是个隐含值,不应成为关键。但MFC的实现显然为了偷懒,将id与映身表的次序挂上了钩,而其ClassWizard,在添加属性时,又错误的去变更了原有odl中的id值。所以造成已依赖于该id值编译的程序不兼容。

建议:

用MFC编写OCX时,添加用户属性/方法时,不要使用ClassWizard,而是手工在映射表中添加,然后根据其相对位置,在odl中填写id值。

添加Stock的属性和方法也要手工添加,因为它的变更,同样会触发ClassWiizard对映射表的排序和odl的同步,而造成你以往的手工编辑丢失。

最好是将odl文件变为受控(以利于备份),注意不接受添加属性/方法的ClassWizard的自动检出。减少误操作。如果经常需要变动属性/方法,或者也可以写一个简单的shell程序,来替代ClassWizard的相关功能,自动生成相关代码。

石头 于2005-07-12

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有