Alternatives to Public Variables in VBA

前端 未结 5 960
萌比男神i
萌比男神i 2020-12-06 08:00

I have a number of public variables that are referenced across several modules. I know if you debug or hit stop the variable gets cleared out. I have been writing these vari

相关标签:
5条回答
  • 2020-12-06 08:15

    The TempVars Collection is a great alternative to Public Variables. It won't persist between sessions, but it will persist for the entirety of A session.

    You will need to add a reference to Microsoft Access 14.0 Object Library though. TempVars are only available from 2007 onward.

    0 讨论(0)
  • 2020-12-06 08:16

    Here is another solution that might be preferable to my first answer (using the registry) depending on the use case.

    You could store the values in a "Very Hidden" worksheet. This has the following advantages:

    1. Prevents the variables from accidentally being destroyed (they are completely invisible to the user)
    2. Allows multiple copies of the workbook to have their own versions of the variables instead of all instances accessing the same values from the registry
    3. Prevents multiples instances of the workbook from trying to edit the registry keys at the same time
    4. Allows the workbook to maintain the values after being used on multiple machines, emailed, etc etc
    0 讨论(0)
  • 2020-12-06 08:19

    Public variables don´t get erased from memory on debug (break) mode if there are still references that point to them further along in your code. In fact, in some cases if you move your mouse over the variable it will tell you the value at the break.

    If you want variables to persist I would use the same method as you are currently using (write them down on an excel worksheet) or a database.

    If you do write these variables down, I would recommend you never modify the variable directly, instead use setters and getters that suit your model. For example, if you write them down to a worksheet you might use the following:

    public sub setVariable(v as String)
         worksheets("Sheet1").Range("A1").value = v
    end sub
    
    public function getVariable() as String
        getVariable = worksheets("Sheet1").range("A1").value
    End Function
    
    0 讨论(0)
  • 2020-12-06 08:21

    Here is an example of the CustomDocumentProperties, which I recently started using to store some meta-information (easier than dealing with the CustomXMLParts).

    The examples below store only string data, but you can also use date, number and Yes/No (which with some finagling you could sub as a Boolean). You are limited to 255 characters for string data.

       Sub Test()
       '## Assign a CDP
       SetCustomProperty "myProperty", "some value I want to store"
    
       End Sub
    

    You can view the CPD's from the Backstage | Info | Properties | Advanced Properties | Custom:

    enter image description here

    In the event that you End run-time, you can restore the values from the CDP, you can query the property value by:

    myVar = ActiveWorkbook.CustomDocumentProperties("myProperty").Value

    You can use functions like these to set properties in the CustomDocumentProperties collection:

    Sub SetCustomProperty(property$, val$)
        Dim cdp As Variant
        Dim hasProperty As Boolean
        If HasCustomProperty(property) Then
            ActiveWorkbook.CustomDocumentProperties(property).Value = val
        Else
            ActiveWorkbook.CustomDocumentProperties.Add property, False, msoPropertyTypeString, val
    
        End If
    End Sub
    Private Function HasCustomProperty(property$) As Boolean
    Dim cdp As Variant
    Dim boo As Boolean
    For Each cdp In ActiveWorkbook.CustomDocumentProperties
        If cdp.name = property Then
            boo = True
            Exit For
        End If
    Next
    HasCustomProperty = boo
    End Function
    
    0 讨论(0)
  • 2020-12-06 08:26

    A simple solution would be to store your variables in the registry, and just read/write them as necessary. This has the added benefit of preserving values over multiple Excel sessions (and even after a computer reboot, or a crash - assuming your registry survived it!).

    EDIT: Also see John Walkenbach's book for more information on this.

    EDIT: See below comment by Ioannis for an important consideration.


    Boilerplate warning: Here be dragons, Twiddle with the Windows registry at your peril, etc etc.


    The above warning notwithstanding, realize that almost every program on your Windows computer does something with the registry, and it is not inherently dangerous to do so. Just make sure your code only changes/deletes registry keys which were created by your Excel application.


    Example procedures using Windows Scripting (I didn't write these; from a quick search):

    Reading from the Registry:

    'reads the value for the registry key i_RegKey
    'if the key cannot be found, the return value is ""
    Function RegKeyRead(i_RegKey As String) As String
    Dim myWS As Object
    
      On Error Resume Next
      'access Windows scripting
      Set myWS = CreateObject("WScript.Shell")
      'read key from registry
      RegKeyRead = myWS.RegRead(i_RegKey)
    End Function
    

    Checking if a Registry key exists:

    'returns True if the registry key i_RegKey was found
    'and False if not
    Function RegKeyExists(i_RegKey As String) As Boolean
    Dim myWS As Object
    
      On Error GoTo ErrorHandler
      'access Windows scripting
      Set myWS = CreateObject("WScript.Shell")
      'try to read the registry key
      myWS.RegRead i_RegKey
      'key was found
      RegKeyExists = True
      Exit Function
    
    ErrorHandler:
      'key was not found
      RegKeyExists = False
    End Function
    

    Saving a Registry key:

    'sets the registry key i_RegKey to the
    'value i_Value with type i_Type
    'if i_Type is omitted, the value will be saved as string
    'if i_RegKey wasn't found, a new registry key will be created
    Sub RegKeySave(i_RegKey As String, _
                   i_Value As String, _
          Optional i_Type As String = "REG_SZ")
    Dim myWS As Object
    
      'access Windows scripting
      Set myWS = CreateObject("WScript.Shell")
      'write registry key
      myWS.RegWrite i_RegKey, i_Value, i_Type
    
    End Sub
    

    Deleting a key from the Registry:

    'deletes i_RegKey from the registry
    'returns True if the deletion was successful,
    'and False if not (the key couldn't be found)
    Function RegKeyDelete(i_RegKey As String) As Boolean
    Dim myWS As Object
    
      On Error GoTo ErrorHandler
      'access Windows scripting
      Set myWS = CreateObject("WScript.Shell")
      'delete registry key
      myWS.RegDelete i_RegKey
      'deletion was successful
      RegKeyDelete = True
      Exit Function
    
    ErrorHandler:
      'deletion wasn't successful
      RegKeyDelete = False
    End Function
    
    0 讨论(0)
提交回复
热议问题