Pass Elements in Variant Array as Arguments to ParamArray

491 Views Asked by At

Background

I am creating a VBA function (UDF) called MyUDF(), which wraps CallByName().

I wish to mimic precisely the signature and parametric behavior of CallByName(). Furthermore, MyUDF() must copy its Args() argument to a modular variable ArgsCopy — a Variant array — whose elements are then passed by MyUDF() as further arguments to CallByName().

Don't ask why — it's a long story.

Reference

CallByName() displays in the VBA editor like so

2

and it is described in the documentation like so:

Syntax

CallByName (object, procname, calltype, [args()]_)

The CallByName function syntax has these named arguments:

Part Description
object Required: Variant (Object). The name of the object on which the function will be executed.
procname Required: Variant (String). A string expression containing the name of a property or method of the object.
calltype Required: Constant. A constant of type vbCallType representing the type of procedure being called.
args() Optional: Variant (Array).

It appears that "args()" is actually a ParamArray, rather than a simple Variant array, but without further documentation, I can't be perfectly sure.

Format

My tentative design is of the following form:

' Modular variable.
Private ArgsCopy() As Variant


' Wrapper function.
Public Function MyUDF( _
    ByRef Object As Object, _
    ByRef ProcName As String, _
    CallType As VbCallType, _
    ParamArray Args() As Variant _
)
    ' ...
    
    ' Copy the argument list to the modular variable.
    ArgsCopy = Args
    
    ' ...
    
    ' Pass the arguments (and modular variable) to 'CallByName()'.
    MyUDF = VBA.CallByName( _
        Object := Object, _
        ProcName := ProcName, _
        CallType := CallType, _
        Args := ArgsCopy _
    )
End Function

Displayed Signature

In contrast to CallByName(), MyUDF() displays in the VBA editor like so, and concludes with ParamArray Args() As Variant:

5

Only by changing Args() from a ParamArray to a Variant array (ByRef Args() As Variant) can we make them display identically:

6

However, the latter would clash with the functional behavior described below for CallByName().

Parametric Behavior

Unfortunately, one cannot pass ArgsCopy to Args by name (Args := ArgsCopy), since Args is apparently a ParamArray and would thus accept only the unnamed arguments:

VBA.CallByName( _
    Object, ProcName, CallType, _
    ArgsCopy(0), ArgsCopy(1), ..., ArgsCopy(n) _
)

Note

Please disregard the fact that CallByName() returns a Variant, which may (or may not) be an Object that must be Set. I have already accounted for this in my actual code.

Question

How do I construct MyUDF(), and especially its Args() argument, such that

  1. its signature mimics that of CallByName(), in both the Type and Optionality of its parameters; and
  2. it accurately passes to CallByName() any arbitrary set of arguments listed in Args()?

Ideally, MyUDF() will also

  1. work properly on both Mac and Windows; and
  2. display like CallByName() in the VBA editor:

6

2

This 3rd and 4th criteria are a bonus, but I don't require them.

Suggestions

Visual Basic (VB) suggests that one may pass arguments to its ParamArray as in MyUDF() above: the arguments are elements in an array of the same type as the ParamArray, and this array is supplied as a single argument. However, I have found neither a documented nor an experimental equivalent in VBA.

I did find these three VBA questions on Stack Overflow, but I lack the experience to apply their lessons here.

  1. Passing an array of Arguments to CallByName VBA
  2. Pass array to ParamArray
  3. How to view interface spec from Framework files on Mac OS

Change Method Signature

That first question has a solution, which changes the method signature for CallByName(), such that Args() is a single argument: an Any array.

However, I am unfamiliar with the "Any" type, and the third question (unanswered) makes me doubt this preprocessor "magic" could work on a Mac:

#If VBA7 Or Win64 Then
  Private Declare PtrSafe Function rtcCallByName Lib "VBE7.DLL" ( _
    ByVal Object As Object, _
    ByVal ProcName As LongPtr, _
    ByVal CallType As VbCallType, _
    ByRef args() As Any, _
    Optional ByVal lcid As Long) As Variant
#Else
  Private Declare Function rtcCallByName Lib "VBE6.DLL" ( _
    ByVal Object As Object, _
    ByVal ProcName As Long, _
    ByVal CallType As VbCallType, _
    ByRef args() As Any, _
    Optional ByVal lcid As Long) As Variant
#End If
Public Function CallWithArgs( _
    ByRef Object As Object, _
    ByRef ProcName As String, _
    CallType As VbCallType, _
    ByRef Args() As Variant _
)
   CallWithArgs = rtcCallByName(Object, ProcName, CallType, Args)
End Function
0

There are 0 best solutions below