VB动态调用类模块中的函数的方法
动态地调用函数是令广大VB程序员比较苦恼的一件事情。VB不同于C++,不同于Java,没有传递函数指针的概念。这么一说,肯定有很多的大神级别的VB高手要来喷我了,说"新手不懂就不要在这里胡说!"。的确,我承认,刚刚我说的不够严谨;老实说,VB中是有函数指针的概念的,不过这一概念显得很"隐晦",没有C++中使用的频率那么高,而以前我在一篇文章中也看到过,微软的官方也的确不推荐VB程序员在代码中使用指针,使用"AddressOf"运算符是可以获得一个函数的指针,用于WindowsAPI调用时做参数传递;然而,这个运算符是有很大局限性的,首先,这个运算符只能获得通用模块(Module)中定义的函数的指针,其次,大部分和我一样的新手级别的VB程序员对于WindowsAPI这一复杂高深的领域还普遍探索不深,对此没有什么经验可言。
今天在这里,是想向大家分享一下关于VB动态地调用类模块(Class Module)中的函数的一个方法。
要想调用类模块中的函数,我们需要借助一个类——"MSScriptControl.ScriptControl"。
一看这个类名,我想大家便也就大概了解了它的作用。没错,它的主要作用是"脚本控制",说白了呢,就是在VB中可以嵌入字符串形式的JavaScript脚本或VBScript脚本,并解析执行。关于它的一些基础用法,大家可以去问度娘,今天我只是想介绍一下利用它如何实现动态地调用类模块中的函数。以下介绍的方法在VBA中同样适用。
首先,如果想使用"MSScriptControl.ScriptControl"这个类,必须在工程中引用"Microsoft Script Control 1.0"这个Library,其实这个类的名字是"ScriptControl",但是我个人的习惯是加上Libiary的名字,也就是"MSScriptControl.ScriptControl",这样一来,就等于显式地告诉了VB使用哪一个Library下的类,个人认为,这是一个好的编码习惯,对于代码的可读性以及因为程序员自身的封装所导致的重名类使用时的暧昧降低到最小化。
另外,还有一点想要提及的,在VB中,这个类还可以被作为控件添加到窗体上,使用原理大同小异。但是在VBA中,如果机器中没有安装VB的开发环境的话,大概可能是不能够这么用的。
好的,下面进入到正题。如果想要执行一个类模块中的函数,以面向对象编程的原理来看,这个类模块必须有一个对象实例。单独的一个类,其概念是抽象化的。有了一个类后,我们便可以使用"MSScriptControl.ScriptControl"这个类来动态地调用函数了。具体实现过程请参考下面的代码。
Student.Cls
Option Explicit
' =========================================================
' 机 能 名:Student
' 机能说明:学生类
' 作 者:剑舞の地龙
' 作成时间:2016-01-24
' =========================================================
' --------------------------------------------------------------------------------------------- 私有成员
' 姓名
Private sName_ As String
' ---------------------------------------------------------------------------------------- Getter/Setter
' ========================================================================
' 方法说明:
' 取得姓名。
' 参数 :
' 无
' 返回值 :
' 姓名
' ========================================================================
Public Function GetName() As String
GetName = sName_
End Function
' ========================================================================
' 方法说明:
' 设置姓名。
' 参数 :
' psName:姓名
' 返回值 :
' 无
' ========================================================================
Public Sub SetName(ByVal psName As String)
sName_ = psName
End Sub
TestClass.Cls
Option Explicit
' =========================================================
' 机 能 名:TestClass
' 机能说明:测试类
' 作 者:剑舞の地龙
' 作成时间:2016-01-24
' =========================================================
' --------------------------------------------------------------------------------------------- 私有成员
' 学生类
Private oStudent_ As Student
' --------------------------------------------------------------------------------------------- 公有方法
' ========================================================================
' 方法说明:
' 将学生类实例化。
' ※ 没有参数,没有返回值的函数调用
' 参数 :
' 无
' 返回值 :
' 无
' ========================================================================
Public Sub InitStudent()
Set oStudent_ = New Student
End Sub
' ========================================================================
' 方法说明:
' 设置学生姓名
' ※ 有值类型参数,没有返回值的函数调用
' 参数 :
' psName:姓名
' 返回值 :
' 无
' ========================================================================
Public Sub SetStudentName(ByVal psName As String)
Select Case oStudent_ Is Nothing
Case False
oStudent_.SetName psName
End Select
End Sub
' ========================================================================
' 方法说明:
' 返回学生姓名
' ※ 没有参数,有值类型返回值的函数调用
' 参数 :
' 无
' 返回值 :
' 学生姓名
' ========================================================================
Public Function GetStudentName() As String
Select Case oStudent_ Is Nothing
Case True
GetStudentName = ""
Case Else
GetStudentName = oStudent_.GetName
End Select
End Function
' ========================================================================
' 方法说明:
' 设置学生类实例
' ※ 有对象类型参数,没有返回值的函数调用
' 参数 :
' poStudent:学生类实例
' 返回值 :
' 无
' ========================================================================
Public Sub SetStudent(ByRef poStudent As Variant)
Set oStudent_ = poStudent
End Sub
' ========================================================================
' 方法说明:
' 返回学生类实例
' ※ 没有参数,有对象类型返回值的函数调用
' 参数 :
' 无
' 返回值 :
' 学生类实例
' ========================================================================
Public Function GetStudent() As Variant
Set GetStudent = oStudent_
End Function
Main.Bas
Option Explicit
' =========================================================
' 机 能 名:Main
' 机能说明:主模块
' 作 者:剑舞の地龙
' 作成时间:2016-01-24
' =========================================================
' --------------------------------------------------------------------------------------------- 公有方法
' ========================================================================
' 方法说明:
' 没有参数,没有返回值的函数调用。
' 参数 :
' poTestClass:测试类实例
' 返回值 :
' 无
' ========================================================================
Public Sub Test01(ByRef poTestClass As TestClass)
' 实例化"脚本控制"对象,并指定脚本语言
Dim oScriptControl As MSScriptControl.ScriptControl: Set oScriptControl = New MSScriptControl.ScriptControl
oScriptControl.Language = "VBScript"
' 将要调用函数的类的实例传给"脚本控制"对象,并指定该实例在"脚本控制"对象中的别名
' 在后面的编辑脚本代码的过程中,便可以使用指定好的别名来操作这个对象了。
oScriptControl.AddObject "oTestClass", poTestClass
' 编辑脚本代码(字符串),并将代码传给"脚本控制"对象
Dim sCode As String
sCode = sCode & "Sub Test01()" & vbCrLf
sCode = sCode & " oTestClass.InitStudent" & vbCrLf
sCode = sCode & "End Sub"
oScriptControl.AddCode sCode
' 调用函数
oScriptControl.Run "Test01"
MsgBox "调用成功"
End Sub
' ========================================================================
' 方法说明:
' 有值类型参数,没有返回值的函数调用;
' 没有参数,有值类型返回值的函数调用。
' 参数 :
' poTestClass:测试类实例
' 返回值 :
' 无
' ========================================================================
Public Sub Test02(ByRef poTestClass As TestClass)
' 实例化"脚本控制"对象,并指定脚本语言
Dim oScriptControl As MSScriptControl.ScriptControl: Set oScriptControl = New MSScriptControl.ScriptControl
oScriptControl.Language = "VBScript"
' 将要调用函数的类的实例传给"脚本控制"对象,并指定该实例在"脚本控制"对象中的别名
' 在后面的编辑脚本代码的过程中,便可以使用指定好的别名来操作这个对象了。
oScriptControl.AddObject "oTestClass", poTestClass
' 编辑脚本代码(字符串),并将代码传给"脚本控制"对象
Dim sCode As String
sCode = sCode & "Function Test02(psName)" & vbCrLf
sCode = sCode & " oTestClass.InitStudent" & vbCrLf
sCode = sCode & " oTestClass.SetStudentName psName " & vbCrLf
sCode = sCode & " Test02 = oTestClass.GetStudentName" & vbCrLf
sCode = sCode & "End Function"
oScriptControl.AddCode sCode
' 调用函数,并传递值类型参数,以及接受值类型返回值
Dim sName As String: sName = oScriptControl.Run("Test02", "张三")
MsgBox sName
End Sub
' ========================================================================
' 方法说明:
' 有对象类型参数,没有返回值的函数调用;
' 没有参数,有对象类型返回值的函数调用。
' 参数 :
' poTestClass:测试类实例
' 返回值 :
' 无
' ========================================================================
Public Sub Test03(ByRef poTestClass As TestClass)
' 实例化"脚本控制"对象,并指定脚本语言
Dim oScriptControl As MSScriptControl.ScriptControl: Set oScriptControl = New MSScriptControl.ScriptControl
oScriptControl.Language = "VBScript"
' 将要调用函数的类的实例传给"脚本控制"对象,并指定该实例在"脚本控制"对象中的别名
' 在后面的编辑脚本代码的过程中,便可以使用指定好的别名来操作这个对象了。
oScriptControl.AddObject "oTestClass", poTestClass
' 编辑脚本代码(字符串),并将代码传给"脚本控制"对象
Dim sCode As String
sCode = sCode & "Function Test03(poStudent)" & vbCrLf
sCode = sCode & " oTestClass.SetStudent poStudent" & vbCrLf
sCode = sCode & " Set Test03 = oTestClass.GetStudent" & vbCrLf
sCode = sCode & "End Function"
oScriptControl.AddCode sCode
' 调用函数,并传递对象类型参数,以及接受对象类型返回值
Dim oPStudent As Student: Set oPStudent = New Student
oPStudent.SetName "张三"
Dim oRStudent As Student: Set oRStudent = oScriptControl.Run("Test03", oPStudent)
MsgBox oRStudent.GetName
End Sub
Form1.Frm
Private Sub Command1_Click()
Main.Test01 New TestClass
End Sub
Private Sub Command2_Click()
Main.Test02 New TestClass
End Sub
Private Sub Command3_Click()
Main.Test03 New TestClass
End Sub
代码运行效果