由于VB不能直接支持IEnumVARIANT,
所以,我们不能编制自己的NewEnum方法,这样就失去了很多灵活性
(比如,反向的浏览集合)
偶尔看见一本VB5核心技术的东东,里面就说到用VB代码实现的IEnumVARIANT
但由于时间的关系,其具体代码EnumVar.Bas EnumVar.cls的链接已经失效了。
还请哪位有此代码的老大讲解一下如何实现本主题,谢谢!
(当然,请不要说用VC编一个什么Dll动态库的方法,偶问的是VB,偶只关心用VB的方法——例外:如果是tlb库,那到是可行的)
所以,我们不能编制自己的NewEnum方法,这样就失去了很多灵活性
(比如,反向的浏览集合)
偶尔看见一本VB5核心技术的东东,里面就说到用VB代码实现的IEnumVARIANT
但由于时间的关系,其具体代码EnumVar.Bas EnumVar.cls的链接已经失效了。
还请哪位有此代码的老大讲解一下如何实现本主题,谢谢!
(当然,请不要说用VC编一个什么Dll动态库的方法,偶问的是VB,偶只关心用VB的方法——例外:如果是tlb库,那到是可行的)
解决方案 »
- 请问下模块这么写
- inno setup 问题
- 关于动态数组控件的事件响应
- 用什么工具做asp.net最好
- 在窗体中添加背景图后,相关控件的显示问题
- 关于动态控件数组问题:能不能在动态生成的picturebox控件里动态添加一个image控件,请大家帮帮我
- 当在一个MDI的子窗体体FORM1上的TextBOX控件中按下了一个键盘上的F键后,之后产生了哪些消息,从哪儿产生,传到哪儿,又由哪儿最终处理掉了
- 如何使用INSTALL Shield 设置odbc的安装路径
- 救急呀“编译错误:找不到工程或库”(2)
- 怎么样用VB 得到硬盘的最后一个盘符
- 立华软件园上下载的图书离线用什么软件看啊?
- 请教在textbox控件中如何实现自动换行?
odl,
uuid(00020404-0000-0000-C000-000000000046)
]
interface IEnumVARIANT : IUnknown {
long _stdcall Next(
[in] long celt,
[in, out] VARIANT* rgvar,
[in, out, optional, defaultvalue(0)] long* pceltFetched);
HRESULT _stdcall Skip([in] long celt);
HRESULT _stdcall Reset();
HRESULT _stdcall Clone([out] IEnumVARIANT** ppenum);
};
http://www.mvps.org/vbvision/Super_Collections.htm
《Visual Basic 5.0 核心技术》(原名《Hardcore Visual Basic version 5.0》),Bruce McKinney著,希望图书创作室改编。北京希望电脑公司出版,1998
关于Visual Basic的Collection类工作方式没有什么神圣的东西。如果想把Collection设计成反向迭代,或是对每次迭代都产生一个随机数,这完全取决于你。问题是,Visual Basic没有为使你的Collection用For Each工作提供方便的方法。但假如理解了Collection迭代是如何工作的,就能办到不可能办到的事(或至少是不切实际的事)。你必得要理解有关IEnumVARIANT接口的一些事实。组件对象模型把IEnumVARIANT定义为在数据结构中迭代的标准方式。任何想允许客户遍历Variant数据的Collection类都应该提供一个实现IEnumVARIANT的迭代器。任何想迭代经过变量数据类(符合标准)的客户程序都可通过调用IEnumVARIANT方法来做到。
Visual Basic的For Each句法就是这样工作的。当写下一个For Each代码块时,Visual Basic为每个迭代调用IEnumVARIANT的Next方法。Collection类可用For Each操作,是因为它提供了一个实现IEnumVARIANT的方法的迭代器类。那么,你是如何实现IEnumVARIANT的呢?困难重重。
4.5.1 委派Collection
Collection类创建一个帮助器类来实现IEnumVARIANT接口。要创建自己的Collection,可把数据放进你的类内的一个真正的Collection中,并令其对公众适用,就如同它是你的一样。这项技术在Visual Basic 4中适用,但只是以一种间接的、不安全的方式,把封装性置之不理。第5版纠正了那些问题,但却是以一种……方式,好了,你自己判断是什么方式吧。CDrives集合,第1版
可使用第三章中的CDrives类来创建一个CDrives集合类。注意命名规则:类集合(collectionlike)类应该总是复数形式。图4.2显示了CDrives集合及其与CDrives类之间的关系。但在我们进入真正的CDrives类之前,来看一下我的第1个实现程序,我把它存在CDrivesO的名下。
下面的代码(摘自TCOLLECT.FRM)显示了CDrives和CDrivesObject几乎是多态的类,可使用同一代码调用:s=s& "Drive information for available drives:" & sCrLf
Dim drives As Object, drive As CDriveIf chkOld Then
Set drives= New CDrives0
Else
Set drives=New CDrives
EndIfFor Each drive In drives
With drives=s& "Drive" & .Root & "[" &.Label & ":" & _
.Serial & "](" & .KindStr & ") has " & _
Format$(.TotalBytes, sBFormat)& sCrLf
End With
Next代表内部Collection的类中的大部分工作是在Class_Initialize事件过程中完成的。它在CDrivesO中是这样工作的:Private drives As New CollectionPrivate Sub Class_Initialize( )
Refresh
End Sub'Argument handy for refreshing local and/or remote, but not floppies
Public Sub Refresh(Optional iFirst As Integer=1)
Dim i As Integer, af As Long, sRoot As String
Dim drive As CDrive' Remove old ones
Do While drives.Count> iFirst
drives.Remove iFirst
Loop
' Insert new
af = GetLogicalDrives( )
For i = iFirst To 26
If RShiftDWord(af, i-1) And 1 Then
Set drive = New CDrive
drive.Root = i
drives.Add drive, drive.Root
End If
Next
End SubClass_Initialize子程序只是调用Refresh来做真正的工作。在有时需要越过自动初始化的类中,从初始化事件中调用一个公共初始化方法是一项常用的技术,Refresh使用Win32 GetLogicalDrives函数和RshiftDWord函数(在第五章中讲述),来计算在系统中确实存在哪些驱动器。然后,这些驱动器被初始化,并加进内部Collection中。对老版本,Refresh方法非常重要且有用,但你不久就会看到,在现今按需要计算驱动器的真正的CDrives类中,那已成为历史。
有了适当的内部Collection,就可以简单地实现Collection的标准属性和方法了。通过按以下方法传输内部Collection的Count和Item揭示Count和Item属性:Public Property Get Count( ) As Integer
Count=drives.Count
End Property'Default property
Public Property Get Item(v As Variant) As CDrive
'Return default (Nothing) if error
On Error Resume Next
Set Item=drives(v)
End Property在类中嵌入Collection对象,并用相似的外部成员来传输其成员,是委派的另一种例子。在一般的面向对象语言中,你会用继承性来达到相同的目的。尤其是从Collection类中衍生出CDrivesO类。不必写任何代码即能取得Count和Item属性。不必为想要的任何附加成员(比如Refresh)编写代码,并且还可以解除或增强想要削弱或改变的任何成员(比如Add和Remove)的功能。挑战
乍看,你可能会认为实现Add和remove属性是不可能的。如果可以仅仅通过调用Add方法对系统添加新的驱动器,就永远不会用完磁盘空间,但即使是即插即用标准也不能保证这一点。另一方面,使用Add连接到网络驱动器和使用Remove方法断开都很容易。你可以查阅WNetAddConnection2和WNetCancelConnection2 API函数。我将增强CDrive集合来使之完全可适用于网络的任务留给了你。委派迭代器
只再需要一步就可使CDrivesO成为一个真正的Collection,这个步骤如此稀奇古怪,使我难以描述。但我将尽力而为。
如果是用其他语言编写集合,就必须创建一个名为NewEnum的方法。当某程序员使用你的集合类来编码一个For Each块时,Visual Basic调用这个_NewEnum方法来创建一个隐葳的、实现IEnumVARIANT接口的迭代器对象。这个对象实质上像我们早先用CListWalker类创建的迭代器。对于每一次循环,该迭代器对象的Next方法即取得Collection中的下一个条目。
为使你能让Visual Basic用For Each来使用你的集合,则要给你的集合一个_NewEnum,它会把其对列表对象的创建委派给内部集合。这说起来容易,做起来却不那么简单,且显示出来要比解释它更简单。' NewEnum must have the procedure ID -4 in Procedure Attributes dialog
Public Function NewEnum( ) As IEnumVARIANT
set NewEnum=drives.[_NewEnum]
End Function这个方法的第一个特色是它被命名为NewEnum,而不是_NewEnum,这是因为下划线做为Visual Basic符号名称的第一个字母是非法的。第二个特色是,无论是否合法,这个Collection类都有一个_NewEnum方法,并且,你必须要将它所做的一切委派给NewEnum属性。Visual Basic最含糊的特性之一是可以通过把非法名称放进方括号中来访问。第三个特色是NewEnum返回一个IEnumVARIANT类型。这是Collection类中迭代器的类型(其他书中有些例子使用IUnknown做为返回类型,但它们是一回事)。
最后一个也是最显著的特色是你如何告诉Visual Basic你的NewEnum方法实际上就是_NewEnum方法。这是一个简单的窍门,你把蝾螈的眼睛、青蛙的脚趾、蝙蝠的绒毛以及狗的舌头混在一起……不,等一等。那是一种不同的魔术。在这种情况下,给“来自地狱的对话框”(DBFH)中的过程ID指派一个魔数。图4.3显示了这种方法。
你可能记得,DBFH的过程ID复合框中有几个条目,包括(None)、(Default),AboutBox和一堆不相关的废话。但它对于NewEnum、_NewEnum,或任何与你想匹配的名称却没有条目。幸好,这个过程ID值是用一个普通的复合框设置的,它允许你或是从建议的条目中选出一个,或是敲入你自己的。这就是你要做的:敲入魔数ID号,请连击-4。评论
这个魔数起作用,虽然它违反了Visual Basic的所有标准,这是公式化的东西,没有创造性的余地。计算机比人类更善于按公式行事。Visual Basic努力想让事情更为简单。你应能够只是单击复选框就可表明你希望这个类成为一个集合。然后,可以选出想委派给哪个内部Collection变量(在不可能的事件中有一个以上的内部Collection)。Visual Basic会自动创建NewEnum属性。它不会像继承性那样简单,但至少它不是一个受嘲弄的对象。
作者介绍了很多COM底层细节
演示了很多原本被认为是VB办不到的功能此书书评:
http://dev.csdn.net/develop/article/13/13308.shtm
发表日期:2005-09-19 文件大小:9.7MB 下载次数:39
版权所有:
软件版本:
文件大小:9.7MB
操作系统:win9x/NT/2000/XP
下载说明: Visual Basic 5.0 核心技术
odl,
uuid(00020404-0000-0000-C000-000000000046)
]
interface IEnumVARIANT : IUnknown {
long _stdcall Next(
[in] long celt,
[in, out] VARIANT* rgvar,
[in, out, optional, defaultvalue(0)] long* pceltFetched);
HRESULT _stdcall Skip([in] long celt);
HRESULT _stdcall Reset();
HRESULT _stdcall Clone([out] IEnumVARIANT** ppenum);
};
interface IEnumVARIANT : IUnknown {消息是:
missing 'uuid' attribute
SuperCollection 的那个我看了,但我也想知道一下,自己来定义odl
(我才不要它那么多接口呢,偶只要简单点,像Collection 一样就行)