Writing Code with Code in VBA

In VBA, it's possible to write code that adds, deletes, or modifies other code, even within the same project.  This is possible via the VBA Extensibility library.  Chip Pearson has a great introductory article on the topic: Programming the VBA Editor.  Chip's site is focused on VBA within the context of Excel, but the concept is the same.

Words of warning

Generating code within the same project from which you are executing your code is dangerous and should be approached with caution.  Several things can go wrong:

  • Access could hard crash resulting in the loss of any unsaved work
  • Your Access application could get irrecoverably corrupted
  • You could accidentally delete or modify large portions of your code

Mitigating the risk

By following these recommendations, you can greatly reduce your risk from the above threats:

  • Keep your application under version control (you should be doing this anyway)
  • Save your project immediately before running any code like of this kind
  • Backup the .mdb/.accdb file after saving but before running the code

Why do this at all?

There are a variety of reasons you might want to do this sort of thing:

My contribution

The WriteModule procedure below creates or updates a Standard or Class Module named ModName.  The Contents parameter should contain the lines of code that will comprise the module.  ModuleType is a string instead of the vbext_ComponentType enum type.  That allows us to use late-binding of the VBIDE library and avoid adding the "Microsoft Visual Basic for Applications Extensibility 5.3" reference to our application.

WARNING: As noted in the comments above the procedure, this routine will OVERWRITE the contents of an existing code module.  I recommend you run this with a test module before changing any of your existing modules.

'Produces a code module named {ModName} with the Contents passed
'   - If the module exists, it is overwritten
'   - If the module does not exist, it is created and populated
'   - Contents should include *all* needed code, e.g. "Option Explicit"
Sub WriteModule(ModName As String, Contents As String, ModuleType As String)
    On Error GoTo Err_WriteModule

    Dim VBProj As Object ' VBIDE.VBProject
    Dim VBComp As Object ' VBIDE.VBComponent
        
    'Get the code module object
    Set VBProj = VBE.ActiveVBProject
    Set VBComp = VBProj.VBComponents(ModName)
    
    'Delete the contents of the module
    VBComp.CodeModule.DeleteLines 1, VBComp.CodeModule.CountOfLines
    
    'Update the contents of the module
    VBComp.CodeModule.AddFromString Contents


Exit_WriteModule:
    Exit Sub
Err_WriteModule:
    Select Case Err.Number
    Case 9  'Subscript out of range
        Select Case ModuleType
        Case "Standard"
            Set VBComp = VBProj.VBComponents.Add(1)  'vbext_ct_StdModule
        Case "Class"
            Set VBComp = VBProj.VBComponents.Add(2)  'vbext_ct_ClassModule
        Case Else
            'https://nolongerset.com/throwing-errors-in-vba/
            Throw "Unsupported ModuleType: {0}", ModuleType
        End Select
        VBComp.Name = ModName
        Resume
    Case Else
        LogErr Err, Errors, "DesignProcedures", "WriteModule"
    End Select
    Resume Exit_WriteModule
End Sub

Image by WikiImages from Pixabay