############# A Easy Problem ################

Jover 2002-01-18 10:05:51
在DLL工程中有N个类模块
主类模块中申明了xlapp对象
Public WithEvents xlapp As EXCEL.Application
在其他类模块中如何引用带有事件的xlapp对象???
...全文
122 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Jneu 2002-01-18
  • 打赏
  • 举报
回复
人呢???
查考:创建和实现接口

如上面“Visual Basic 是如何提供多态的”中所解释的,所谓接口,就是一组属性和方法。在下面的代码示例中,将创建一个 Animal 接口,并在两个类— Flea 和 Tyrannosaur 中实现它。

创建该 Animal 接口的方法是:将一个类模块添加到工程中,将它命名为 Animal,并插入到下面的代码中:

Public Sub Move(ByVal Distance As Double)

End Sub

Public Sub Bite(ByVal What As Object)

End Sub

注意,在这些方法中并没有任何代码。Animal 是一个抽象类,不包含实现的任何代码。抽象类不是用来创建对象的—其用途是为添加其它类中的接口提供模板。(尽管,已经证明,有些时候实现一个非抽象类的接口是有用的;这将在本节主题的后面进行讨论。)

注意 确切地说,一个抽象的类是不能从中创建对象的类。从 Visual Basic 的类中总是可以创建对象的,即使它们不含有代码,它们也不是真正抽象的。

现在,就可以添加另外两个类模块了,这两个类模块一个叫 Flea,另一个叫 Tyrannosaur。为了在 Flea 类中实现 Animal 接口,要用到 Implements 语句:

Option Explicit
Implements Animal

一旦将这行代码添加进去,就可以单击代码窗口中左边(“对象”)下拉菜单。其中一个登录项将是 Animal。当选择了它时,右边(“过程”)下拉菜单上将显示 Animal 接口的方法。

依次选择每种方法,可为所有的方法创建空白过程模板。这些模板将具有正确的参数和数据类型,就象在 Animal 类中所定义的那样。每个过程名都将以 Animal_ 前缀来标识该接口。

重点 一个接口就象一个契约。实现接口后,当调用该接口的任何属性或者方法时,一个类已经约定好要作出反应。因此,必须实现接口的所有属性和方法。

现在,就可以将下面的代码添加到 Flea 类中了:

Private Sub Animal_Move(ByVal Distance As Double)
'(跳过多少英寸的代码,略。)
Debug.Print "Flea moved"
End Sub

Private Sub Animal_Bite(ByVal What As Object)
'(吃了多少生命的代码,略。)
Debug.Print "Flea bit a " & TypeName(What)
End Sub

可能想知道为什么这些过程被声明为 Private。如果它们是 Public,那么 Animal_Jump 和 Animal_Bite 过程将成为 Flea 界面的一部分,这样将被困在跟原先所在的同样的圈子中,将 Critter 参数声明为 As Object,这样它就可能包含一个 Flea 或者一个 Tyrannosaur。

多重接口
现在,Flea 类有了两个接口:刚刚实现的 Animal 接口—它有两个成员,以及缺省的 Flea 接口—它没有任何成员。该示例的后面,将把一个成员添加到缺省接口的其中一个。

类似地,可以为 Tyrannosaur 类实现 Animal 接口:

Option Explicit
Implements Animal

Private Sub Animal_Move(ByVal Distance As Double)
'(跳起多少码的代码,略。)
Debug.Print "Tyrannosaur moved"
End Sub

Private Sub Animal_Bite(ByVal What As Object)
' (拿起一磅肉的代码,略。)
Debug.Print "Tyrannosaur bit a " & TypeName(What)
End Sub

练习 Tyrannosaur 和 Flea
将下列代码添加到“Form1”的 Load 事件中:

Private Sub Form_Load()
Dim fl As Flea
Dim ty As Tyrannosaur
Dim anim As Animal

Set fl = New Flea
Set ty = New Tyrannosaur
'首先看一下 Flea。
Set anim = fl
Call anim.Bite(ty) 'Flea 叮咬 dinosaur。
'现在轮到 Tyrannosaur。
Set anim = ty
Call anim.Bite(fl) 'Dinosaur 咬 flea。
End Sub

按 F8 键,单步执行代码。注意“立即”窗口中的信息。当 变量 anim 包含对 Flea 的引用时,就调用该 Flea 的 Bite 实现,同样的,对于 Tyrannosaur 来说,情况也是如此。

变量 anim 可以包含对实现 Animal 接口的任何对象的引用。事实上,它只能包含对这种类型对象的引用。如果试图将一个 Form 或者一个 PictureBox 对象赋给 anim 的话,那么将会产生错误。

当通过 anim 来调用 Bite 方法时,该方法是前期绑定的,因为 Visual Basic 在编译时知道,不论将什么对象赋给 anim,该对象都将有一个 Bite 方法。

将 Tyrannosaurs 和 Fleas 传递给过程
回忆一下“Visual Basic 如何提供多态?”("How Visual Basic Provides polymorphism?")中的 GetFood 过程。可以将 GetFood 过程的第 2 个版本—演示多态的版本—添加到“Form1”中,并用下面的代码来取代 Load 事件中的代码:

Private Sub Form_Load()
Dim fl As Flea
Dim ty As Tyrannosaur

Set fl = New Flea
Set ty = New Tyrannosaur
'Flea 在恐龙上吃饭。
Call GetFood(fl, ty)
'相反的情况。
Call GetFood(ty, fl)
End Sub

单步执行上述代码,显示作为传递给另一接口类型参数的对象引用,是怎样转换为对第二个接口(在这里是 Animal)的引用的。所发生的情况是: Visual Basic 查询该对象,看看该对象是否支持第二个接口。如果该对象支持的话,它将返回对该接口的引用,于是 Visual Basic 将返回的引用放置到参数变量中。如果该对象不支持第二个接口,将会出现错误。

实现返回值的方法
假设 Move 方法返回一个值。不管怎么说,自己知道想让 Animal 移动多远的距离,但是,各个实例不可能都移动那么远。它可能又老又弱,或者在路上可能恰好有一堵墙。可以用 Move 方法的返回值来说明该 Animal 实际移动了多远的距离。

Public Function Move(ByVal Distance As Double) _
As Double

End Function

在 Tyrannosaur 类中实现该方法时,把返回值赋给过程名,这跟处理任何其它 Function 过程一样:

Private Function Animal_Move(ByVal Distance _
As Double) As Double
Dim dblDistanceMoved As Double
'计算能弹跳多远(基于对年龄、健康状态和障碍物的
'考虑)的代码,略。
'该示例假设已经将结果放置到变量 dblDistanceMoved 中。
Debug.Print "Tyrannosaur moved"; dblDistanceMoved
Animal_Move = dblDistanceMoved
End Function

为了返回值的赋值,使用全过程名,包括接口前缀。

详细信息 所实现的接口,除方法外还可以有属性。下面“实现属性”讨论了属性实现的方式上的一些不同之处。
Jneu 2002-01-18
  • 打赏
  • 举报
回复
Implements 语句

指定要在包含该语句的类模块中实现的接口或类
Jneu 2002-01-18
  • 打赏
  • 举报
回复
循环引用和部件的关闭

下面说明 Visual Basic 是如何卸载进程内部件的。当客户应用程序释放了对一个进程内部件的对象的所有引用后,该部件将被卸载。另外,还说明循环引用将如何妨碍这种卸载,强调指出公有和私有对象的重要区别。

因为Visual Basic从不会卸载一个在开发环境中运行的进程内部件工程,所以,上述过程只能使用编译过的部件和编译过的测试工程来进行。

注意 创建一个 ActiveX DLL 示例需要分为几步,这个帮助主题只是其中一步。要访问该帮助主题,选择帮助主题“创建 ActiveX DLL”即可。

要观察 DLL 的卸载,请按照以下步骤执行:

向 ThingDemo 中添加新的类模块。将其命名为 TellTale,并把它的 Instancing 属性设为 Private。向它的 Terminate 事件中添加下列代码:
Private Sub Class_Terminate()
MsgBox "Private object destroyed"
End Sub

私有的对象不能由客户应用程序创建,并且永远不会传递给它们。可以看到,私有的对象并不阻止进程内部件的卸载。在部件卸载后,如果客户应用程序仍然使用对一个私有对象的引用,那么将会导致严重的程序错误。

向 ThingDemo 中的模块 Module1 添加下列代码:
Option Explicit
Private mtt As TellTale '新代码。

Sub Main
Debug.Print "E xecuting Sub Main"
Set mtt = New TellTale '新代码。
End Sub

一旦编译了工程之后,就不能再使用 Debug 语句来显示内部发生的情况。就象一个告密者一样,TellTale 对象的作用是显示编译的部件内发生了什么情况。

在“文件”菜单中,单击“生成工程组”编译 ThingDemo 和 ThingTest。在“启动”菜单中,单击“运行”打开“运行”对话框,通过浏览找到并运行 ThingTest,也可以使用 Windows 资源管理器。


关闭模式对话框,并单击“Create Temporary Thing”。在输入框中随意输入一个名字,然后单击“确定”。
正如前面看到的,临时的 Thing 并不会存在很长时间。现在创建它的原因只是为了加载 ThingDemo.dll 并执行 Sub Main。对于目前的步骤,一个很有意思的问题是:如果 Thing 全部没有了的话,那么情况会是什么样?

等一会儿,喝杯咖啡或是干点别的什么。等过几分钟后再回来看时,就会看见一个消息框,上面的消息是“Private object destroyed”。
究竟是怎么回事?由于没有对公共对象的引用,在一段时间后(通常是两分钟左右,不过也依赖于程序进入空闲状态的时间间隔),Visual Basic 将试图卸载进程内部件。

在卸载 DLL 时,Visual Basic 将释放它使用的内存,其中也包含了含有私有对象引用的变量。结果 TellTale 对象就被破坏了,这个线索可以告诉我们 DLL 被卸载。

如果此时创建新的 Thing 对象,那么在 DLL 被重新载入时可以发现一小段的暂停。

现在来演示循环引用。选中“Stuck on itself”框,然后单击“Create Temporary Thing”,创建一个自己引用自己的 Thing 对象。


等一会儿,再喝杯咖啡或干点别的什么。不过无论等多长时间,DLL 都不会被卸载,因为对 Thing 对象的引用阻止了 Visual Basic 卸载它。
Visual Basic 不能区分对公共变量的内部引用和对公共对象的外部(客户应用程序)引用,因此它不会卸载 DLL。

关闭 ThingTest 的主窗体。私有变量再次被破坏,因为在卸载客户应用程序的同时要卸载用到的所有进程内部件。
详细信息 关于关闭部件的规则,请参阅“部件设计的一般准则”的“启动和结束部件”的列表,附录 A“ActiveX 部件标准及指南”中有更详细的讨论。

循序渐进
创建 ActiveX DLL 示例需要好几步,该帮助主题只是其中一步。

目的 请参阅
到下一步 创建 ActiveX DLL 的总结
从头开始 创建一个 ActiveX DLL

5,173

社区成员

发帖
与我相关
我的任务
社区描述
其他开发语言 Office开发/ VBA
社区管理员
  • Office开发/ VBA社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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