我熟悉通过引用将参数传递给过程。或者,ParamArray
允许我灵活地通过引用将0或更多参数传递给过程。但是,这种方法让我想知道是否有办法保留对程序范围之外的一个或多个变量的引用。当我看到VBA Array
函数被声明为这样时,我的第一个希望就是:{/ p>
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
不幸的是,这并没有像我预期的那样奏效。尽管通过Array
将参数传递给ParamArray
函数,但看起来返回的数组是按值而不是通过引用。
进一步的研究使我了解了未记录的VBA VarPtr
/ StrPtr
/ ObjPtr
函数。我发现了许多将它们与API RtlMoveMemory
函数结合使用的示例。但是,我读到的所有文章都强烈反对使用该方法,因为它很容易使应用程序崩溃。我的一些测试确实让Access崩溃了。
我的另一个想法是看我是否可以直接将一个变量的引用分配给另一个变量:
Private Sub Test()
Dim a As Object
Dim b As Variant
b = ByRef a ' Throws a compiler error
End Sub
只需说,编译器根本不允许这样做。那么我的问题是,可以安全地存储/保存变量引用超出过程的范围(最好是在另一个变量中)吗?
如果我对我正在努力建立的内容有所了解,我认为会更有帮助。
我目前正在创建一个包装类,它将所有表单/控件事件传递给我的一个模块中的过程。它将与2个具有相同控制结构但连接到不同源表的表单一起使用。请记住,代码不完整,但应足以说明我想要克服的问题。此外,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个控件。但是,我的想法是简化我需要修改的代码,以便在表单设计更改时添加/删除控件。或者,如果我必须在项目中添加更多表单。
答案 0 :(得分:0)
如果只需要在单个模块中引用,请在模块头中声明为Public。如果要在任何模块中引用,请在通用模块头中声明为Global。甚至可以通过这种方式声明数组和记录集以及连接对象。请注意,如果代码在运行时中断,这些变量将丢失其值。
或者查看TempVar对象变量。如果代码中断,它们不会丢失值。但只能存储数字或文本值,而不能存储对象。