我熟悉通过参考将参数传递给程序。或者,ParamArray
也使我可以通过参考将0或更多参数传递给程序的灵活性。但是,这种方法使我怀疑是否有一种方法可以保留一个或多个变量超出程序范围的变量。当我看到这样的声明时,我的第一个希望是VBA Array
功能:
Array(ParamArray ArgList() As Variant)
所以,我整理了以下测试代码:
Private Sub Test()
Dim a As Object
Dim b() As Variant
ParamArrayTest a
Debug.Print TypeName(a) ' Output is 'Dictionary'
b = Array(a) ' b should be like ParamArray ArgList()
Set b(0) = Nothing ' This should clear a
Debug.Print TypeName(a) ' Output is still 'Dictionary'
End Sub
Private Sub ParamArrayTest(ParamArray ArgList() As Variant)
Set ArgList(0) = CreateObject("Scripting.Dictionary")
End Sub
不幸的是,这没有我预期的。尽管参数通过ParamArray
传递到Array
函数中,但似乎返回的数组是按值而不是参考。
进一步的研究使我进入了无证件的VBA VarPtr
/StrPtr
/ObjPtr
功能。我发现了许多与API RtlMoveMemory
函数一起使用它们的示例。但是,我读到的所有文章都强烈敦促使用该方法,因为它很容易崩溃。我的一些测试确实确实崩溃了。
我的另一个想法是看看我是否可以直接将一个变量的引用分配给另一个变量:
Private Sub Test()
Dim a As Object
Dim b As Variant
b = ByRef a ' Throws a compiler error
End Sub
可以说,编译器根本不允许这样做。然后,我的问题是,可以安全地存储/保存一个变量参考(最好是在另一个变量中(?
编辑
我认为,如果我阐明自己想构建的东西会更有帮助。
我目前正在创建一个包装类别的过程,该类别将将所有表单/控制事件传递给我的一个模块中的一个过程。它将与具有相同控制结构但连接到不同源表的两种形式一起使用。请记住,该代码不完整,但应该足以说明我要克服的问题。另外,Database
是我的VBA项目名称。
代码有四个部分:
Form_TEST_FORM
-表格模块Private Sub Form_Open(Cancel As Integer) FormHub.InitForm Me, Cancel End Sub
FormHub
-模块Public Sub InitForm( _ ByRef Form As Access.Form, _ ByRef Cancel As Integer _ ) Dim Evt As Database.EventHandler Set Evt = New Database.EventHandler Evt.InitFormObject Form, Cancel FormList.Add Evt, Form.Name End Sub Private Function FormList() As VBA.Collection Static Init As Boolean Static Coll As VBA.Collection If Not Init Then Set Coll = New VBA.Collection Init = True End If Set FormList = Coll End Function
FormControl
-类模块Public Ptr As Variant ' Pointer to form control variable Public acType As Access.AcControlType
EventHandler
-类模块Private WithEvents Form As Access.Form Private WithEvents SForm As Access.SubForm Private CtrlList As VBA.Collection Private Sub Class_Initialize() InitCtrlList End Sub Public Sub InitFormObject(FormObj As Access.Form, ByRef Cancel As Integer) Dim ErrFlag As Boolean Dim Ctrl As Access.Control Dim FCtrl As Database.FormControl On Error GoTo Proc_Err Set Form = FormObj If Form.Controls.Count <> CtrlList.Count Then Err.Raise 1, , _ "Form has incorrect number of controls" End If ' This is where I want to validate the form controls ' and also initialize my event variables. For Each Ctrl In Form.Controls If Not CtrlExists(FCtrl, Ctrl.Name) Then Err.Raise 2, , _ "Invalid control name" ElseIf FCtrl.acType <> Ctrl.ControlType Then Err.Raise 3, , _ "Invalid control type" Else ' Initialize the correct variable with it's ' pointer. This is the part I haven't been ' able to figure out yet. Set FCtrl.Ptr = Ctrl End If Next Proc_End: On Error Resume Next If ErrFlag Then ClearEventVariables End If Set Ctrl = Nothing Set FCtrl = Nothing Exit Sub Proc_Err: ErrFlag = True Debug.Print "InitFormObject " & _ "Error " & Err & ": " & Err.Description Resume Proc_End End Sub Private Function CtrlExists( _ ByRef FCtrl As Database.FormControl, _ ByRef CtrlName As String _ ) As Boolean On Error Resume Next Set FCtrl = CtrlList(CtrlName) CtrlExists = Err = 0 End Function Private Sub InitCtrlList() Set CtrlList = New VBA.Collection CtrlList.Add SetCtrlData(SForm, acSubform), "SForm" End Sub Private Function SetCtrlData( _ ByRef Ctrl As Access.Control, _ ByRef acType As Access.AcControlType _ ) As Database.FormControl Set SetCtrlData = New Database.FormControl With SetCtrlData ' This assignment is where I need to keep a reference ' to the variable in the class. However, it doesn't ' work. Set .Ptr = Ctrl .acType = acType End With End Function Private Sub ClearEventVariables() Dim FormCtrl As Database.FormControl Set Form = Nothing For Each FormCtrl In CtrlList ' Assuming I was able to retain a reference to the ' class variable, this would clear it. Set FormCtrl.Ptr = Nothing Next End Sub Private Sub Class_Terminate() ClearEventVariables Set CtrlList = Nothing End Sub
我在代码示例中仅使用1个控制,以简单起见。但是,这个想法是简化我需要修改多少代码,以便在形式的设计更改时添加/删除控件。或者,如果我必须在项目中添加更多表格。
如果您仅需要在单个模块中引用,请在模块标题中声明为公共。如果要在任何模块中引用,请在常规模块标头中声明为全局。甚至数组,记录集和连接对象也可以以这种方式声明。请注意,如果代码在运行时断开,这些变量将丢失其值。
或查看tempvar对象变量。如果代码断开,他们不会丢失价值。但是只能存储数字或文本值,而不是对象。