前言
在最近几周的工作里,始终被一个头疼的问题所困扰,那就是VB6编写的ActiveX控件在Delphi环境下存在着诸多稀奇古怪的问题,几经周折,终于在搜索了几乎全部的论坛、资料后,找到了针对不同Delphi版本发生的问题的解决办法。
Delphi 5 莫名其妙的致命异常之一
首先,我们来看看VB写的ActiveX控件在Delphi 5下面的奇怪表现。
例如:我们用VB编写了一个控件UserTest(为简单起见,我们只导出一个类即用户控件),一个属性TestName,一个方法TestMethod。然后将其编译成一个ActiveX控件,注册并导入Delphi5的开发环境(以上步骤如有未清楚之处,请查阅各类参考资料,肯定有标准答案),到目前为止,看来一切正常。
然后,我们习惯的把控件拖放到窗体上,调整大小,在属性窗口中为属性赋值,或者在代码中也是一样,非常正常,好用的很。但是,下面问题来了,如果您兴致勃勃的去调用了那个TestMethod,那么您将得到一个古怪的异常 “Ole Error 800a01a9”,然后程序退出,而且非常不幸的是,您将无法跟踪到这个异常,在Delphi中或是VB中都是,当然如果您对汇编很在行的话,您可以跟着Delphi的调试窗口一步一步往下……
当我第一次碰到这个问题的时候,我几乎是愤怒的,因为无论是MicroSoft或是Borland,对该错误都没有任何解释,也没有任何可以查找的资料。我只好跑到常去的几个论坛,当然最主要的还是CSDN,在VB版和Delphi版中四处搜索类似的问题,然后非常遗憾的是,只有类似的问题,而没有答案,一个大客户就用的这个开发工具,我在测试了几乎所有Windows上的开发工具和开发环境(包括桌面和WEB)后,惟独将Delphi忘记了。
剩下的两天里,我几乎是满世界乱跑,给所有的朋友打电话,询问Delphi方面的高手是否知道这个情况,最后,我从Google上搜到了一个链接,可惜的是现在我忘记了那个链接的具体位置,但是我得到了一个近乎Magic的方法(发现者是这么称呼它的):
一个手工修改Delphi导入VB ActiveX控件后产生的代理类型库XXX_TLB.PAS(这里XXX指的是控件的类名)文件的方法可以解决这一问题。举例说明:
有一个VB 写的控件 UserControl1 ,在Delphi中导入后产生两个文件,其中一个UserControl1_TLB.PAS 就是我们所要修改的文件。
在文件中查找类似
FintF: _UserControl1;
Function GetControlInterface:_UserControl1;
和
property ControlInterface: _UserControl1 read GetControlInterface;
GetControlInterface;
以及
procedure TUserControl1.CreateControl;
procedure DoCreate;
begin
Finf:=IUnknown(OleObject) as _UserControl1;
End;
Begin
If Finf=nil then DoCreate;
End;
Function TUserControl1.GetControl1Interface: _UserControl1;
Begin
CreateControl;
Result:=Finfl;
End;
请注意:这里红色标出的_UserControl1要全部换成_ UserControl1Disp,如果编译不成功的话,请将编译警告中报出的_UserControl1 全部换成 _UserControl1Disp,编译即可,这样在调用控件的方法时便不会出现上述的致命错误。
感谢这个伟大的发现,我只能这么形容它,否则可能到现在我还要在这个圈子里套不出来,或者就是使用另外的工具重新开发这个控件(我难以想象这个工作量会有多大,又或者它可能还会存在其他的兼容性问题)。
Delphi 5 莫名其妙的致命异常之二
但是,Delphi并没有在我绕开这个限制之后而放过我,很快,客户那边发现另一个麻烦的问题,在开发环境下,每次运行时关闭载有控件的窗体都会跳出一个异常错误,但是在编译后的应用程序中则不会,虽然不会影响最终用户的使用,但是这对开发人员来说是个不小的困扰,然后我用了上述例子去试,发现并不会发生这个问题。(我当时就疯了,这很可能是代码中一些不兼容的用法所致,在一天时间里查找上万行代码是不是很正规是件极其恐怖的事情)我一气之下,屏蔽了我的控件中所有的代码,只留下用户界面本身,然后奇怪的事情发生了,我什么代码都没写,但是加载我的控件还是会发生这个错误,这使我又喜又惊,喜的是这个问题和我的代码无关,这样查找起来会方便的多;惊的是只是拖放几个VB中的标准控件居然也会造成这种恐怖的错误,Delphi5和VB6之间的矛盾还真不是一般的深。接下来的2个小时里,我不断地删除界面上的控件来测试到底是谁造成了这个致命的异常。
2个小时后,我舒了一口气,问题找到了,其根本问题是:
如果你在VB的用户控件中使用类似Frame和PictureBox这样的容器控件(其内部可以包含其他控件)时,那么您将不可以在这些控件中添加Label、Line、Image这样的windowLess控件(也就是无窗口控件,它们在运行时是VB实时画出来的),否则您就会得到上面这样的错误报告。
Delphi 6、7 隐蔽的ActiveX控件
正是因为有了Delphi5下面的恐怖经历,我发现还是很有必要在Delphi6和7下面测试是不是也存在同样的问题(之前的版本因为用户极少已无必要,Delphi8还没正式出,也暂不在考虑之列)。结果是:……无论我加载多少次,我在ActiveX栏上始终没有发现那个期待已久的小图标。这样的结果当然很滑稽,我连加载都做不到,更不要谈什么测试正常不正常了。
同样的,我搜索各类论坛和网站,CSDN里我也发现了更多的类似问题的提出者,但答案还是零,无奈之下,我只好对每个Delphi6、7中的选项进行调整……
历时3小时15分54秒后,我找到了这个该死的问题(请原谅我这么称呼它,我实在是忍无可忍)的原因,或者说是解决办法,说起来其实很简单。
现在请跟着我做:点击Tools菜单->Environment Options->Type Library页,我们应该发现一项:Ignore special CoClass Flags When Importing,选中它,然后再选中Can Create那一项,那么现在,我们再尝试去导入那个可怜的ActiveX控件吧(这里要注意,如果你已经导入过一次,那么请把产生的那两个文件 .dcr 和 .pas文件删除,否则将不会刷新)。这次如果还是不能在ActiveX栏中发现那个控件的话,那么只有致电Microsoft或是Borland,问问看什么时候它们能结成亲家,呵呵!
(另,在Delphi6和7中倒是没有发现Delphi5中出现的上述错误)
我的测试环境是:
Win2K
Delphi 5 Update1
Delphi 6 Update2
Delphi 7
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
相关推荐
Delphi使用SPComm控件实现单片机通信.pdf
delphi版 Raize控件 里面包含常用的Raize第三方控件。支持D7 D6 --D2012
delphi-modbus控件
Delphi7二维码控件ZIntQRCode
delphi RZ控件 主要用于Delphi7 到Delphi EX RZ控件包.
很简单的复合控件实例,初始化控件,加载属性,调用方法等
delphi自定义控件_treeview控件加强 Tmytreeview 对treeview控件加强 实现增删改及拖拽操作
delphi的透明属性控件,很好用,有很多透明的button、panel等等。
引用pas文件后,直接操作 sqlite3 数据库。 支持 delphi xe2
delphi如何安装控件,解释清楚,希望大家喜欢
Delphi使用TIdFtp控件实现FTP协议.doc
日期和时间一起选择的控件, 网络分享下载,需要先安装 TMS Component Pack v8.3.4.0 XE10.2 控件
Delphi VB 引用dll Delphi VB 引用dll Delphi VB 引用dll
delphi 条形码控件
Delphi_JSON控件及实例 Delphi_JSON控件及实例
delphi的打印控件,我自己使用的,有需要的可以下载安装
delphi7系列优秀控件-XPMenu for delphi 作用是图形具有xp效果
delphi tnt 控件,现在很难找到了的,分享给大家
VFW(delphi摄像头视频控件),VFW(delphi摄像头视频控件),VFW(delphi摄像头视频控件)
RsRuler4.0 一款Delphi上使用的标尺控件