一起来讨论VB与COM......

Bardo 2002-03-15 08:10:05
说起COM我首先想起的是在《Inside Com》一书中所讲的,类实际上也是一种结构,用VB的语言来说,类即是Type的扩展。那么类扩展了什么?很简单,类是在结构中加上了函数(方法)和事件。再进一步,函数可以为虚函数,这样,就可以象定义结构那样定义类了。于是,这样的类即是一个空类,又称为父类。有了空类,在VC中通常是用构造函数来对类初始化,使其成为一个对象。而VB则用的是COM的接口委派继承而产生新的对象。于是这又回到了COM这个本质的问题。
我们现在难以想象,在COM以前究竟是什么方法能使应用程序实现二进制共享。但是,有些事实是记得的。早期的VB控件,其扩展名是VBX。其中的X是同时指16进制与扩展这两个含义,说穿了仍是二进制扩展。为何要扩展,目的是为了成为共享组件。到了VB4.0,那时还不是COM,但己有了OCX,据说原含义是OLE CONTROL EXTENTION。
而现在我们不妨再看看:VB能用的文件的扩展名有:OCX,DLL,TLB,OLB,EXE,而这些实际并不以扩展名而决定其是否为COM,但是如果我们只要在资源管理器中查看一下文件属性,即可以知道:
OCX:ActiveX DLL
DLL: ActiveX DLL
DLL: 应用程序扩展(当然前者在2000中说明也是这样)
TLB:Type Libaray
OLB: Object Libaray
EXE: ActiveX Exe
Exe: 应用程序(当然前者在2000中说明也是这样)
我们可以发现,只要是Libaray则VB即可以使用!!同样,只要带上ActiveX则VB即可以引用或添加为部件。
另一个很奇怪的是:通常VB中引用的ActiveX以后,常用的方法是:Set或CreateObject,如:
Dim oSome as fSome.oMenber
Set oSome = New fSome.oMenber
或者
Dim oSome as fSome.oMenber
Set oSome = CreateObject(fSome.oMenber)
如果你用过VC,那一定会想到,你可以用类向导新建类,选From Type Libaray, 然后即可选择一个VB的DLL。 这时最简单的则是用CreateObject创建对象后调用。在VBScript中同样也是用这一种方法。我想这三个CreateObject一定存在差别,差别在何处?
我还想到,一定有很多人不知,在Visual Studio 6.0的第三张安装盘上有这么两个工具:一个是在:
:\COMMON\TOOLS\VB\IDGEN\
说明是:
Both GUIDGEN and UUIDGEN are tools for generating globally unique identifiers known as GUIDs. GUIDS are commonly used in OLE to identify classes (CLSID) or interfaces (IID.) These utilities are included with VB for developers who want to generate IDL (Interface Description Language) or ODL (Object Description Language.) IDL and ODL are used with the MIDL.EXE and MKTYPLIB.EXE tools to generate type libraries that can be used with VB.
另一个是在:
:\COMMON\TOOLS\VB\UNSUPPRT\TYPLIB
这是一个将对象定义语言的文件编译成TLB扩展名的文件以使VB可用。
这两个工具是在COM之前的,也就是说,COM之前就有了某种模式。由此我在想,那个《Hardcore of Visual Basic 5.0》的作者是不是用这些工具为WIN32 API做了个对象库?好象不是,那么,可能就与MSDN中KB中的Make Type Libaray那个例子有关!
回过头来,再说COM与VB,一说起COM编程,一定是OCX或DLL,然而,OCX中却很难看出前述基本的COM,实际上应当与Visual FoxPro中的叫法一样——容器类,即控件是通过容器类来继承的。所以,如果你要自定义控件,则有两个途径:创建ActiveX控件工程,或者在你的工程中加上UserControl类。这是一个秘密,VB5界面上有此菜单,VB6.0界面上没有,实际上是可以加进去的。
那么通过什么才能看出前述基本的COM呢?以下即是一个最简单的例子:
新建一个ActiveX Dll 工程Project1,
在Class1中加入以下代码:
Option Explicit

Public Function doHello() As String
doHello = "Hello,world!"
End Function

编译,然后在另一工程Project2并引用Project1.dll,以下是调用代码:

Private Sub Form_Load()
Dim ctest As New class1
MsgBox ctest.doHello

End Sub

如果将前者看作是Type,则:
Type Class1
Option Explicit
Public Function doHello() As String
doHello = "Hello,world!"
End Function
End Type
当然,这样是不可执行的。
(未完持续)
**********************************************************************
很希望大家能帮助我解决以上诸多疑问,同时也希大家共同讨论,因为COM对于VB
还有:异步通知,多线程,网页文档,......
...全文
797 184 打赏 收藏 转发到动态 举报
写回复
用AI写文章
184 条回复
切换为时间正序
请发表友善的回复…
发表回复
LXFY 2002-05-30
  • 打赏
  • 举报
回复
up
missbo 2002-05-21
  • 打赏
  • 举报
回复
Bardo这个问题还没有写完成,ID就被封了,现在是在www.easthot.net
在那儿还有被这儿个别人气走的其他很多人,
你们想见他们吗?请点击“将贴子提前”,谢谢了
missbo 2002-05-21
  • 打赏
  • 举报
回复
Bardo这个问题还没有写完成,ID就被封了,现在是在www.easthot.net
在那儿还有被这儿个别人气走的其他很多人,
你们想见他吗?
dyugao 2002-05-16
  • 打赏
  • 举报
回复
标记+学习
wocan 2002-04-26
  • 打赏
  • 举报
回复
wocan95963-246@yeah.net
希望能得到电子书。
haisland 2002-04-26
  • 打赏
  • 举报
回复
加入收藏。
wbwb 2002-04-26
  • 打赏
  • 举报
回复
to bucher
与COM+,MSMQ的集成、使用MSAgent建立自己的帮助系统。使用流式对象来实现远程数据(文件)传输等等,这些东东都是很实用很先进的呀,欢迎写心得,大家一起来讨论吧
hollysky 2002-04-18
  • 打赏
  • 举报
回复
唉,这位老兄说了这么多
怎么不尝试回答我的问题呢
老熊宝宝 2002-04-08
  • 打赏
  • 举报
回复
上个星期从cnbook买到Matt的《Advanced VB》,真是太好太好太好了。
虽然翻译得极差,好在代码还在,这几天我都在看这本书。有好多好多感想,
过两天,我会来写的。
dsclub 2002-03-30
  • 打赏
  • 举报
回复
这里高高手很多:
叨扰一下,去看看http://www.csdn.net/expert/topic/564/564400.xml?temp=.3068659好吗?
老熊宝宝 2002-03-29
  • 打赏
  • 举报
回复
接着前上面的《用VB从头学COM》


先来熟悉一下"VB对象浏览器",它是VB里的一个重要工具。只有在对象浏览器

里能够看到东西,才能够在代码窗口里的代码输入自动提示和自动完成功能里显示

出来。它能够显示工程所引用的类型库里的常量和接口定义,还能够显示工程各模

块里变量、结构。
新建一个VB工程,名为"工程一"。打开"对象浏览器",可见到有五个库:

stdole、VB、VBA、VBRUN、工程一。实际上,"工程一"不是库,前面四个才是真正

的类型库。如前面所说,类型库里只有接口和常量定义,而"工程一"里却能有变量

和结构定义。
从某种意义上来说,"对象浏览器"其实名字上应该叫作"VB专用库型库和工程代

码定义浏览器"。之所以说它是VB专用的,是因为它隐藏了一些重要的东西。首先它

隐藏了类型库中有hidden属性的接口和函数,要看到这些接口和函数,可以在"对象

浏览器"的快捷菜单里钩选"显示隐藏成员"。
因为stdole这个类型库将IUnknown和IDispatch这两个接口标记为隐藏的,所以

只有显示了隐藏成员后,我们才能在stdole这个类型库里找到接口的定义。
看看IUnknown和IDispatch的接口定义吧!怎么回事?怎么接口里面什么都没有

?不是说IUnknown接口有三个函数吗?为什么什么都没有。这是因为stdole这个类

型库还将这两个接口的所有方法标记成"受限"的了。后面讲到IDL/ODL时,我们会自

己来做一个不受限的,看得到IUnknown接口的三个函数的类型库。

为什么要隐藏?为什么不让我们知道?不管为什么,我们都应该感谢VB的这种

处理。随后面对VB和COM了解的深入,我们就知道VB为我们做了多少默默无闻的工作

,不让我们知道这些,正是想让我们知道她是一个多么让人省心的语言。问问VC(

这是本文第一次提到VC)的程序员,他们会告诉你,处理IUnknown接口时要一定小

心,要记住处理AddRef和Release的规则,还会告诉你处理IDispatch接口的Variant

型参数数组时需要进行怎么复杂的工作。而这一切,在VB里我们省了,我们看不到

了,VB将它们隐藏了,甚至还限制我们使用它,但是我们应该多么感谢这种隐藏和

限制啊!
要知道,绝大多数时候,我们都感受不到这种限制,我们都应该接受VB对这两

个接口的默认处理。但是,有时候,后面我们会看到,VB的处理也会有让人烦恼的

时候。深刻地了解VB处理这两个接口的方式,才能在享受VB带来的方便的同时,也

能解决VB带来的不便。

回到IUnknown上来,它定义在stdole这个类型库中。虽然我们看不到IUnknown

接口的三个重要的函数,不过我们应该知道它就在那儿。正是因为所有的接口都有

IUnknown的DNA,所以我们才能用一个接口引用来获得另一个接口引用,所以各个对

象各个接口之间才能互通有无。而且它也是控制对象生存期的关键,是维持内存生

态平衡的关键。

1.2 引用计数
当我们用New操作符新建一个对象时,VB运行时库会为这个对象分配内存,以存

储对象状态数据。我们通过对象的公有属性或方法访问来访问对象私有的状态数据

。当对象不再使用时,对象才会释放自己占用的内存,这样才能更加有效地利用内

存。
所谓对象已经不再使用就是指所有对这个对象的引用都不在了,也就是所有指

向这个对象的接口指针都不在了。这里再解说一下,在VB里不用区分指针和引用,

得到对象某一接口引用,其意思就是得到一个指向这个对象某一接口的指针。后面

讲到接口的二进制实现时,我们会看到接口到底是什么。在VB里,将一个接口引用

设为Nothing,就是说我们不再用这个接口指针了,当一个对象所有的接口指针都被

设为Nothing时,这个对象就会释放自己所使用的内存。
所以我们必须跟踪所有对对象的接口引用,这就有了引用计数的概念。当增加

一个引用时,必须调用IUnknown接口的AddRef函数通知对象增加引用计数,当减少

一个引用时,必须调用IUnknown接口的Release函数通知对象减少引用计数。用

Bruce所说的B--语言,或都说是伪VB语言来描述一下AddRef和Release的样子如下:
●伪代码1.1
Implements IUnknown
Private c As Long
private SomeData() As Variant

Sub IUnknown_AddRef()
c = c + 1
End Sub
Sub IUnknown_Release()
c = c - 1
If c = 0 Then
Call Class_Terminate
Erase SomeData
End If
End Sub

之所以说上面的代码是伪VB代码,是因为在VB里用上面的代码是不可能的。你

可以试试在一个类模块中加入上面的代码,VB会弹出一个错误:"函数或接口标记为

限制的,或函数使用了Visual Basic中不支持的自动类型"。一如VB里其它COM方面

的错误描述一样,如果你不理解,就会让你摸不着头绪。但是前面已经讲过,我们

所用的IUnknown是stdole类型库里的受限的接口,这样的接口是不能Implements的

。实际上,由于VB记为自己对IUnknown处理得很好,所以VB会限制我们自己来实现

IUnknown,因此即使我们能够做出不受限的IUnknonw,我们也不能够直接来实现它

。我想VB要这么做,是出于安全的考虑,如果我们一定要自己来处理IUnknown或

IDispatch接口,那么在了解了接口的二进制实现之后,我们可以用自己的函数指针

换掉VB已为我们提供函数指针。
虽然上面的程序不能够在VB里直接使用,但是它已经很好的描述了引用计数的

原理。当引用计数器c为0时,它会先调用对象的Terminate函数以通知对象所有对它

的引用已经结束,最后再将对象所分配的内存释放(Erase只能释放一个动态分配的

数组)。
看到出每增加或减少一个接口引用时,必须调用接口的AddRef或Release。正因

为所有的接口的第二个和第三个函数肯定AddRef或Release,所以我们能够很方便的

调用它们。在VC(第二次提到VC)里,我们必须自己来处理它们,每个AddRef就得

有对应的Release,如果少了一个Release还不要紧,只是存在内存泄露而已,但是

如果少了一个AddRef,就可能还有一个接口指针在引用已经被释放的对象了,使用

这个引用的结果就是非法内存访问的致命错误了。而在VB里,引用计数总是在后台

自动地来处理,其处理方式如下:
●代码1.2,引自Bruce Mckinney的《HardCore VB》
Dim toughluck As CHardway, toobad As CHardway
Set toughluck = New CHardway 'c = 1
Set toobad = toughluck 'c = 2
'使用 toobad...
Set toobad = Nothing 'c = 1
'使用toughluck...
Set toughluck = Nothing 'c = 0

可以看到,每次用Set,VB都在进行引用计数。但是实际上对toobad的引用计数

是多余的,因为它是套在toughluck引用里面的,只要toughluck引用还在,对

toobad的引用计数就是多余的。要是在VB里有一种Set2关键字,用Set2时不去调用

接口里的AddRef和Release函数,上面的代码就得被优化成下面的代码:

●代码1.3
Dim toughluck As CHardway, toobad As CHardway
Set toughluck = New CHardway 'c = 1
Set2 toobad = toughluck 'c = 1
'使用 toobad...
Set2 toobad = Nothing 'c = 1
'使用toughluck...
Set toughluck = Nothing 'c = 0

当然调用AddRef和Release的开销并不大,和VB直接处理所带来的方便性而言,

这点额外开销根本就不算什么。但是VB总是进行引用计数这种简单的处理在大部分

时候是可行的,但也会在不少地方带来问题。
VB里有很多问题和引用计数相关,在VB文档的《部件设计的一般准则》和《

ActiveX部件的标准及指南》谈到的部件的毁坏或关闭(一个意思)的本质就是对引

用计数的处理。
这其中最有名的最重要的VB程序员最反感的问题就是循环引用的问题。一个对

象引用了他的父对象,那么他们都无法被销毁,结果是程序不能被正确的终止,你

可能要自己来Kill掉这个进程。
不仅是循环引用,在部件设计的很多地方,都要注意引用的问题,比如把一个

Private的私有对象引用传递给一个外部客户后,对象自己要保证它的客户总能引用

到它,如果它先于客户被销毁,那么客户就会有一个非法的对象接口引用,使用这

个引用又是一个致命错误。
解决这些问题的方法就是Bruce所提出的偷引用的技术,后面我会详细的讲解这

项有用的技术,它是我们在VB里玩接口游戏时的基本功。

IUnknown的本质已经讲完了,我们应该已经了解了这位老祖宗的优秀血统。在

接口的世界里,它是如此的重要,它的原理讲起来很简单,但要在VB里真正的用起

它来,还需要我们深入地理解接口的本质。
而接口的本质实际上还没讲。了解接口的本质是下面演示实用技术的基础。所

以下一章我会来谈谈接口的本质。

未完待继……

老熊宝宝 2002-03-29
  • 打赏
  • 举报
回复
对不起,由于我的一点失误,我说的那篇《Call Function Pointer》的
翻译文章,一直没能够发出来,我想CSDN应该能够很快发布它了。
还有我最近两篇文章的配套代码,也由于我的失误,没有能够发布出来,
我刚更正的名字,应该也会很快出来。
Bye,下线了,明天也不知有没有时间写东西,呵呵。
lenrry 2002-03-28
  • 打赏
  • 举报
回复
AdamBear(学习再学习)
挺佩服你的,希望你能找到好工作。但是个人总觉得你钻研的方向有点偏,实用意义不大,毕竟无论VB还是COM都不是未来主流的技术方向,还有更多更值得花精力的地方,比如.net,钻研是必不可少的,但是看清方向也是很重要的地。
祝你好运吧
visualbaby 2002-03-28
  • 打赏
  • 举报
回复
几家公司都说我表达能力还不错,形象还可以,
我也是呀,而且我们的名字挺象嘛,
说起找工作,我觉得vb就不好用了,不知道各位仁兄的别的方面如何???
visualbaby 2002-03-28
  • 打赏
  • 举报
回复
AdamBear(学习再学习)
老兄,惊悉你还没有过六级,真是感到万分意外,因为小弟我已经过了,
另外,我还以为你年龄很大了呢,看来你和我差不多少呀,
但是你可比我厉害多了,佩服佩服!!!
caozuodong 2002-03-28
  • 打赏
  • 举报
回复
关注!
期待!
学习!
szxzwang 2002-03-28
  • 打赏
  • 举报
回复
很好!
bucher 2002-03-28
  • 打赏
  • 举报
回复
很喜欢你写的文章,继续努力

我也一直很想写一些自己在VB6方面的是用心得。比如与COM+,MSMQ的集成、使用MSAgent建立自己的帮助系统。使用流式对象来实现远程数据(文件)传输等等。只是不知道是否有人感兴趣。
Quady515 2002-03-28
  • 打赏
  • 举报
回复
看看。
老熊宝宝 2002-03-27
  • 打赏
  • 举报
回复
对不起,这两天找工作花了不少时间。不提了,找工作真认人伤心。
今天刚把指针专题写完了,我会接下去写COM的东西。
下个月我可能就要去深圳闯闯,也不知还有没有时间写。
还有,我还想翻译一下《VB Design Patterns》,这是搞VB软件开发的
一本好书。
就算要去深圳,一旦有时间我肯定会写下去。
加载更多回复(164)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧