I am using Excel VBA. Does anyone know about a way to overcome the argument length limit of Application.Run()
? (Or please suggest other function that can do the same job.)
Specific to my situation some of my constraints are:
- I need to specify the called function as a string
- The function is within a standard module
- It is a function, the return value is needed, so
Call()
will not work.
In any case, I do not want the parameter list of the called function to be changed (e.g. to variant array or ParamArray
) since I have written some other functionalities which depend on the function declaration.
EDIT: In response to some of the comments below I can provide a simplified version of my project here (could be off the original question though). In fact the whole design is established and running smooth except for the 30-arg constrain.
The very ultimate goal is to enable the following spreadsheet function which can be called like =mySpreadSheetFn("calledFn", "para1=abc", "para2=2002", ...)
. This will invoke the function calledFn()
whose declaration may be:
Function calledFn(Optional para1 As String = "P1", _
Optional para2 As Integer = 202, _
Optional para3 As Boolean = True)
and the default argument will be replaced accordingly as specified in the ParamArray
in the mySpreadSheetFn()
call. Similarly there will be calledFn2()
etc which an end user can use. So, there has to be an Application.Run()
inside mySpreadSheetFn()
.
And here are the function definitions:
Type paramInfo
Val As Variant
dataType As String 'can be Enum but let's forget it for this purpose
End Type
Function mySpreadSheetFunction(fnName As String, ParamArray otherParams())
Dim fnParams As Scripting.Dictionary
' getFnDefaultParams(fn): return the defaults and data types of fn's params
' as a Dictionary. Each item is of type paramInfo (see above)
Set fnParams = getFnParams(fnName)
' For each specified arg check whether it exists for the function.
' If so, replaces the default value with the input value.
' If not exist, then just ignore it
' The problem is really not with this part so just know
' we have all the parameters resolved after the for-loop
For i = LBound(otherParams) To UBound(otherParams)
Dim myKey As String
myKey = Split(otherParams(i), "=")(0)
If fnParams.Exists(myKey) Then
' parseParam() converts the input string into required data type
fnParams(myKey).Val = parseParam(Split(otherParams(i), "=", 2)(1), _
fnParams(myKey).DataType _
)
End If
Next
' Here is the issue since the call cannot go beyond 30 args
Dim lb As Integer: lb = LBound(fnParams)
Select Case UBound(fnParams) - LBound(fnParams) + 1
Case 1: Application.Run fnName, fnParams(lb).Val
Case 2: Application.Run fnName, fnParams(lb).Val, fnParams(lb + 1).Val
' Omitted, goes until Case 30
' What to do with Case 31??
End Select
' Some other operations for each call
End Function
' An example of function that can be called by the above mySpreadSheetFn()
Function calledFn(Optional para1 As String = "P1", _
Optional para2 As Integer = 202, _
Optional para3 As Boolean = True)
' needs to return value
calledFn = para1 & para2 * 1000
End Function
There is hardly any room to change the front-end since this is how the user interface is desired.
Any thoughts?