Custom callbacks in VBA Custom callbacks in VBA vba vba

Custom callbacks in VBA


No other answers in a week...for resolution's sake here's the best I could come up with:

  1. I built a helper module that resolves a ParamArray to individual arguments for the sake of calling CallByName. If you pass a ParamArray through to CallByName it will mash all the arguments into a single, actual Array and pass that to the first argument in the method you attempt to invoke.
  2. I built two ForEach methods: one that invokes Application.Run, and another that invokes CallByName. As noted in the question, Application.Run only works for user-defined global (public module) methods. In turn, CallByName only works on instance methods, and requires an object argument.

That still leaves me without a way to directly invoke built-in global methods (such as Trim()) by name. My workaround for that is to build user-defined wrapper methods that just call the built-in global method, for example:

Public Function FLeft( _   str As String, _   Length As Long) As String    FLeft = Left(str, Length)End FunctionPublic Function FLTrim( _   str As String) As String    FLTrim = LTrim(str)End FunctionPublic Function FRight( _   str As String, _   Length As Long) As String    FRight = Right(str, Length)End Function...etc...

I can now use these to do things like:

' Trim all the strings in an array of stringstrimmedArray = ForEachRun(rawArray, "FTrim")' Use RegExp to replace stuff in all the elements of an array' --> Remove periods that aren't between numbersDim rx As New RegExprx.Pattern = "(^|\D)\.(\D|$)"rx.Global = TrueresultArray = ForEachCallByName(inputArray, rx, "Replace", VbMethod, "$1 $2")   


Very old question but for those looking for a more general approach please use stdCallback and stdLambda alongside stdICallable. These can be found as part of the stdVBA library.

sub Main()  'Create an array  Dim arr as stdArray  set arr = stdArray.Create(1,2,3,4,5,6,7,8,9,10) 'Can also call CreateFromArray  'Demonstrating join, join will be used in most of the below functions  Debug.Print arr.join()                                                 '1,2,3,4,5,6,7,8,9,10  Debug.Print arr.join("|")                                              '1|2|3|4|5|6|7|8|9|10  'Basic operations  arr.push 3  Debug.Print arr.join()                                                 '1,2,3,4,5,6,7,8,9,10,3  Debug.Print arr.pop()                                                  '3  Debug.Print arr.join()                                                 '1,2,3,4,5,6,7,8,9,10  Debug.Print arr.concat(stdArray.Create(11,12,13)).join                 '1,2,3,4,5,6,7,8,9,10,11,12,13  Debug.Print arr.join()                                                 '1,2,3,4,5,6,7,8,9,10 'concat doesn't mutate object  Debug.Print arr.includes(3)                                            'True  Debug.Print arr.includes(34)                                           'False  'More advanced behaviour when including callbacks! And VBA Lamdas!!  Debug.Print arr.Map(stdLambda.Create("$1+1")).join          '2,3,4,5,6,7,8,9,10,11  Debug.Print arr.Reduce(stdLambda.Create("$1+$2"))           '55 ' I.E. Calculate the sum  Debug.Print arr.Reduce(stdLambda.Create("Max($1,$2)"))      '10 ' I.E. Calculate the maximum  Debug.Print arr.Filter(stdLambda.Create("$1>=5")).join      '5,6,7,8,9,10    'Execute property accessors with Lambda syntax  Debug.Print arr.Map(stdLambda.Create("ThisWorkbook.Sheets($1)")) _                 .Map(stdLambda.Create("$1.Name")).join(",")            'Sheet1,Sheet2,Sheet3,...,Sheet10    'Execute methods with lambdas and enumerate over enumeratable collections:  Call stdEnumerator.Create(Application.Workbooks).forEach(stdLambda.Create("$1#Save")    'We even have if statement!  With stdLambda.Create("if $1 then ""lisa"" else ""bart""")    Debug.Print .Run(true)                                              'lisa    Debug.Print .Run(false)                                             'bart  End With    'Execute custom functions  Debug.Print arr.Map(stdCallback.CreateFromModule("ModuleMain","CalcArea")).join  '3.14159,12.56636,28.274309999999996,50.26544,78.53975,113.09723999999999,153.93791,201.06176,254.46879,314.159    'Creating from an object property  Debug.Print arr.Map(stdCallback.CreateFromObjectProperty(arr,"item", vbGet))  '1,2,3,4,5,6,7,8,9,10  'Creating from an object method  Debug.Print arr.Map(stdCallback.CreateFromObjectMethod(someObj,"getStuff"))End SubPublic Function CalcArea(ByVal radius as Double) as Double  CalcArea = 3.14159*radius*radiusEnd Function