2017-04-20 71 views
1

我熟悉通過引用將參數傳遞給過程。或者,ParamArray也允許我通過引用將0個或更多參數傳遞給過程的靈活性。但是,這種方法讓我懷疑是否有辦法保留對一個或多個超出程序範圍的變量的引用。我希望第一一線希望是VBA Array功能,當我看到它聲明如下:VBA - 安全地存儲可變引用

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 /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項目名稱。

有四個部分的代碼:

  1. Form_TEST_FORM - 表格模塊

    Private Sub Form_Open(Cancel As Integer) 
    
        FormHub.InitForm Me, Cancel 
    
    End Sub 
    
  2. 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 
    
  3. FormControl - 類模塊

    Public Ptr  As Variant ' Pointer to form control variable 
    Public acType As Access.AcControlType 
    
  4. 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

@ Mat'sMug舉例來說,如果我傳遞一個變量到一個程序'ByRef'我能夠通過修改過程參數修改源變量的值。但是,只要程序退出,我就會失去指向源變量的指針。我想安全地存儲指向source變量的指針,以便在單個過程的範圍之外更新它的值。請讓我知道這個解釋是否更有意義。 –

+0

這是「我失去了指向源變量」的一部分,它沒有任何意義了我。當程序退出時,你回到調用者,其中*您已經有*變量你路過'ByRef'。我只是沒有看到你想要解決什麼問題。 –

回答

0

如果您只需要在單一模塊中引用,聲明爲公共模塊頭。如果你想在任何模塊中引用,在通用模塊頭中聲明爲全局。即使數組和記錄集和連接對象也可以這樣聲明。請注意,如果代碼在運行時中斷,這些變量將丟失它們的值。

或可考慮TempVar的對象變量。如果代碼中斷,它們不會丟失值。但只能存儲數字或文本值,而不能存儲對象。