vba - VBA 中的自定义回调

标签 vba callback

注意标签: VBA ,不是 VB6,不是 VB.NET。

这是特定于 MS Access 中的 VBA。我在一个我称之为“可枚举”的模块中构建了一组方法。它做了很多让人想起 .NET 中的 Enumerable 类和接口(interface)的事情。我想要实现的一件事是 ForEach 方法,类似于 .NET Enumerable.Select method .

我构建了一个使用 Application.Run 的版本方法为每个元素调用一个函数,但 Application.Run 仅适用于用户定义的方法。例如,以下工作:

' User-defined wrapper function:
Public Function MyReplace( _
    Expression As String, Find As String, StrReplace As String, _
    Optional Start As Long = 1, _
    Optional Count As Long = 1, _
    Optional Compare As VbCompareMethod = vbBinaryCompare)
    MyReplace = Replace(Expression, Find, StrReplace, Start, Count, Compare)
End Function

' Using Application.Run to call a method by name
Public Sub RunTest()
    Debug.Print Run("MyReplace", "Input", "In", "Out")
End Sub

RunTest 按预期打印“输出”。以下不起作用:
Debug.Print Run("Replace", "Input", "In", "Out")

它抛出运行时错误 430:“类不支持自动化或不支持预期的接口(interface)”。这是意料之中的,因为文档指出 Application.Run 仅适用于用户定义的方法。

VBA 确实有一个 AddressOf 运算符,但仅在将函数指针传递给外部 API 函数时才有效;使用 AddressOf 创建的函数指针在 VBA 中不可使用。同样,这在文档中有所说明(或参见例如 VBA - CallBacks = Few Cents Less Than A Dollar? )。

那么有没有其他方法来识别和调用使用变量的方法呢?或者我的回调尝试是否会通过 Application.Run 方法仅限于用户定义的函数?

最佳答案

一周内没有其他答案......为了解决问题,这是我能想到的最好的:

  • 为了调用 CallByName,我构建了一个辅助模块,将 ParamArray 解析为单个参数。 .如果您将 ParamArray 传递给 CallByName它将所有参数混合成一个实际的 Array并将其传递给您尝试调用的方法中的第一个参数。
  • 我建了两个ForEach方法:调用 Application.Run 的方法, 另一个调用 CallByName .如问题所述,Application.Run仅适用于用户定义的全局(公共(public)模块)方法。反过来,CallByName仅适用于实例方法,并且需要对象参数。

  • 这仍然让我无法通过名称直接调用内置的全局方法(例如 Trim() )。我的解决方法是构建只调用内置全局方法的用户定义的包装器方法,例如:
    Public Function FLeft( _
       str As String, _
       Length As Long) As String
        FLeft = Left(str, Length)
    End Function
    
    Public Function FLTrim( _
       str As String) As String
        FLTrim = LTrim(str)
    End Function
    
    Public Function FRight( _
       str As String, _
       Length As Long) As String
        FRight = Right(str, Length)
    End Function
    
    ...etc...
    

    我现在可以使用这些来执行以下操作:
    ' Trim all the strings in an array of strings
    trimmedArray = ForEachRun(rawArray, "FTrim")
    
    ' Use RegExp to replace stuff in all the elements of an array
    ' --> Remove periods that aren't between numbers
    Dim rx As New RegExp
    rx.Pattern = "(^|\D)\.(\D|$)"
    rx.Global = True
    resultArray = ForEachCallByName(inputArray, rx, "Replace", VbMethod, "$1 $2")   
    

    关于vba - VBA 中的自定义回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9020481/

    相关文章:

    javascript - 如何进行需要其子函数信息的回调

    android - Android蓝牙低功耗回调(LeScanCallBack)在单独的线程上?

    c# - WCF 发布/订阅并使用回调向特定用户发送数据

    C++ Callback——如何解耦回调类型

    excel - 从晨星提取特定的表格单元格,然后循环到下一个晨星页面

    excel - #姓名?如何阅读公式栏以更改错误的公式 - 不要覆盖它

    excel - 如何显示一个系列的标记而不是另一个系列的标记

    Excel 损坏与 VBA 排序记录

    c++ - 从 C++11 中的回调函数终止线程

    excel - 将具有唯一值的所有行复制到新工作表,包括标题行