# Background #

I am working on a VBA paradigm for modifying the Excel environment from a UDF.  I call this **"sudo mode"**, and I leverage [`Application.Run()`][1] to invoke a delegate procedure, like `RunSudo()` in my example.
> ```vba
> ' Delegate to sudo mode.
> ...
> Application.Run GetSudoCall()
> '               ^^^^^^^^^^^^^
> '               "...RunSudo()"
> ```

By passing the entire call `"RunSudo()"` rather than the name `"RunSudo"`, we "trick" VBA into "losing track" of the procedure, and we thus circumvent the ["ban"][4] on UDFs
> A user-defined function called by a formula in a worksheet cell cannot change the environment of Microsoft Excel.

which forbids them to modify the environment (beyond the cell [`Application.Caller`][2]). 
 The arguments for `RunSudo()` are cached in `Sudo_argList`
> ```vba
> ' Cache the arguments for sudo mode.
> Sudo_argList.Add rng, "rng"
> Sudo_argList.Add val, "val"
> ```

a [`Collection`][3] object at the modular level
> ```vba
> ' The parameteric cache for sudo mode.
> ...
> Private Sudo_argList As New Collection
> ```

such that `Application.Run()` need only invoke an empty call `"RunSudo()"`, without awkwardly splicing an arbitrary set of arguments as `String`s.

# Code #

I demonstrate this paradigm here, in the **`Demo`** module, with a UDF aptly named `Range_SetValue()`.  In an Excel formula
```swift
= Range_SetValue(X2:Z8, 5)
```
this UDF will overwrite the cells `X2:Z8` with the number `5`, whenever the formula is calculated.

## `Demo` ##

```vba
' #######################
' ## Modular Constants ##
' #######################

' The name of the module.
Private Const MOD_NAME As String = "Demo"

' The name of the sudo procedure.
Private Const SUDO_NAME As String = "RunSudo"


' ###############
' ## Sudo Mode ##
' ###############

' The parameteric cache for sudo mode.
Private Sudo_isActive As Boolean
Private Sudo_argList As New Collection

' Activate sudo mode.
Private Sub ActivateSudo()
    ' Record activation status.
    Sudo_isActive = True
End Sub

' Deactivate sudo mode (and clear cache).
Private Sub DeactivateSudo()
    ' Clear argument cache.
    Set Sudo_argList = Nothing
    
    ' Record deactivation status.
    Sudo_isActive = False
End Sub

' Generate the call to run sudo mode.
Private Function GetSudoCall() As String
    GetSudoCall = QualifyCall(SUDO_NAME, MOD_NAME, ThisWorkbook.Name)
End Function

' Modify the range value(s) in sudo mode.
Private Sub RunSudo()
    ' Catch any errors for housekeeping.
    On Error GoTo Catch
    
    ' Only perform task if sudo mode is properly activated.
    If Sudo_isActive Then
        ' Modify the range values.
        Sudo_argList("rng").Value = Sudo_argList("val")
        
        ' Deactivate sudo mode to prevent redundant calls.
        DeactivateSudo
    End If
    
    Exit Sub
    
' Housekeeping:
Catch:
    ' Prevent redundant calls...
    DeactivateSudo
    
    ' ...before passing on the error.
    Err_Raise
End Sub


' ##############
' ## User API ##
' ##############

' Set the value(s) for a range of cells, and report the outcome.
Public Function Range_SetValue( _
    ByRef rng As Range, _
    ByRef val As Variant _
) As Boolean
    On Error GoTo Fail
        ' Cache the arguments for sudo mode.
        Sudo_argList.Add rng, "rng"
        Sudo_argList.Add val, "val"
        
        ' Delegate to sudo mode.
        ActivateSudo
        Application.Run GetSudoCall()
        
        ' Report success.
        Range_SetValue = True
        Exit Function
        
Fail:
Debug.Print Err.Description
    ' Report failure.
    Range_SetValue = False
End Function


' #################
' ## Diagnostics ##
' #################

' Raise an (objective) error.
Private Sub Err_Raise(Optional ByRef e As ErrObject = Nothing)
    ' Default to the current error in VBA.
    If e Is Nothing Then
        Set e = VBA.Err
    End If
    
    ' Raise that error.
    VBA.Err.Raise _
        Number:=e.Number, _
        Source:=e.Source, _
        Description:=e.Description, _
        HelpFile:=e.HelpFile, _
        HelpContext:=e.HelpContext
End Sub


' #############
' ## Helpers ##
' #############

' Format a fully qualified call to a procedure.
Private Function QualifyCall( _
    ByRef procName As String, _
    Optional ByRef modName As String = Empty, _
    Optional ByRef wbName As String = Empty _
) As String
    QualifyCall = procName & "(" & ")"
    
    If modName <> Empty Then
        QualifyCall = modName & "." & QualifyCall
    Else
        Exit Function
    End If
    
    If wbName <> Empty Then
        QualifyCall = FormatWbRef(wbName) & "!" & QualifyCall
    End If
End Function

' Format a workbook reference.
Private Function FormatWbRef(ByRef wbName As String) As String
    FormatWbRef = "'" & VBA.Replace(wbName, "'", "''") & "'"
End Function
```

# Concern #

My biggest challenge in using `Application.Run()` is in avoiding any nomenclatural clashes with synonyms: procedures from other modules, and defined [`Name`][5]s throughout Excel.  I have tried many approaches, but all have their weaknesses:

## Renaming as `A1()` ##

Like anything that resembles a cell address, the name `A1` is [illegal][6] for defined `Name`s. In renaming `RunSudo()` as `A1()`, we ensure that
```vba
Application.Run "A1()"
```

will not conflict with any such `Name`s.  However, it might plausibly clash with some `A1()` procedure from some other module.


## Prefixing with `Demo.` ##

Since the `.` character is [illegal][7] in names for VBA objects, the qualifying call `Demo.RunSudo()` or `Demo.A1()` will be unambiguous among synonyms like `Mod2.RunSudo()` and `Mod2.A1()` from other modules.  However, names like `Demo.RunSudo()` — and even `Demo.A1()` — actually _are_ legal as `Name`s, so we expose ourselves once again to _those_ clashes.


## Randomizing a Suffix ##

We could play the odds and suffix `RunSudo()` with a random sequence of alphanumerics
```vba
  RunSudo_2398hrfj092389h2434...jf9ge980h5675h6e()
'         |------------------...---------------|
'                     240 characters
```

such that the total length of the `String`
```vba
"Demo.RunSudo_2398hrfj092389h2434...jf9ge980h5675h6e()"
```

meets the [limit of `255`][8] characters on the `Macro` argument to `Application.Run()`.  While this essentially rules out a _coincidental_ clash, malicious interference is easily possible via a simple copy-paste, since `Name`s [may also][6] have `255` characters.  Furthermore, the length heavily encumbers normal usage, and it essentially rules out many practical applications (like hyperlinks, etc.).


## Recursion on `Range_SetValue()` ##

It is possible to have `Range_SetValue()` perform recursion, and call _itself_ via `Application.Run()`:
```vba
' ...

If Sudo_isActive Then
    ' ...
    RunSudo
    ' ...
Else
    ' ...
    ActivateSudo
    Application.Run "Range_SetValue()"
    ' ...
End If

' ...
```

But this would require that all arguments to `Range_SetValue()` be `Optional`, to preserve the syntactic validity of the call `"Range_SetValue()"`.  Furthermore, it impacts security in a number of unpleasant ways, since the user may now access `RunSudo()` far more directly; the specifics are complex in my use case, so please take my word for it.


## Full Qualification ##

My heart nearly leapt for joy when I realized one may qualify `RunSudo()` like so:
```vba
'Workbook''s Name.ext'!Demo.RunSudo()
```

Since the `!` character is [illegal][6] in `Name`s, this call would never clash with them, and the qualification automatically disambiguates it from synonyms in other modules and workbooks.

Then I realized with despair that a workbook may have a rather long name, and that every `'` must be escaped by another `'`.  Thus, the entire call may exceed `255` characters when the workbook's name is long or riddled with `'`s, a fact I confirmed (miserably) by testing.


# Question #

How might I rigorously stabilize this approach against clashes on the name `RunSudo`, or more generally on any `Sub` like `Foo()` in one of several modules within one of several workbooks?


  [1]: https://learn.microsoft.com/en-us/office/vba/api/excel.application.run
  [2]: https://learn.microsoft.com/en-us/office/vba/api/excel.application.caller
  [3]: https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/collection-object
  [4]: https://support.microsoft.com/en-us/topic/description-of-limitations-of-custom-functions-in-excel-f2f0ce5d-8ea5-6ce7-fddc-79d36192b7a1
  [5]: https://learn.microsoft.com/en-us/office/vba/api/excel.name
  [6]: https://support.microsoft.com/en-us/office/use-names-in-formulas-9cd0e25e-88b9-46e4-956c-cc395b74582a
  [7]: https://learn.microsoft.com/en-us/office/vba/language/concepts/getting-started/visual-basic-naming-rules
  [8]: https://github.com/rubberduck-vba/Rubberduck/issues/3074#issuecomment-309723538