将 Variant 数组中的元素作为参数传递给 ParamArray

Pass Elements in Variant Array as Arguments to ParamArray

提问人:Greg 提问时间:11/27/2022 最后编辑:Greg 更新时间:12/5/2022 访问量:448

问:

背景

我正在创建一个名为 的 VBA 函数 (UDF),它包装了 CallByName()。MyUDF()

我希望精确地模仿 CallByName() 的签名和参数行为。此外,MyUDF() 必须将其 Args() 参数复制到模块化变量 ArgsCopy(一个 Variant 数组)中,然后 MyUDF 将该变量的元素作为进一步的参数传递给 CallByName()。

不要问为什么——这是一个很长的故事。

参考

CallByName()在VBA编辑器中显示如下

2

文档中描述如下:

语法

CallByName对象procnamecalltype, [args()]_)

CallByName 函数语法具有以下命名参数

部分 描述
对象 必需:变体对象)。将在其上执行函数的对象的名称。
procname 必需:VariantString)。一个字符串表达式,包含对象的属性或方法的名称。
呼叫类型 必需:常量vbCallType 类型的常量,表示所调用过程的类型。
参数() 可选:变体数组)。

看起来 “” 实际上是一个 ParamArray,而不是一个简单的数组,但如果没有进一步的文档,我不能完全确定。args()Variant

格式

我的暂定设计形式如下:

' 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

显示的签名

与 相反,在 VBA 编辑器中显示如下,并以 :CallByName()MyUDF()ParamArray Args() As Variant

5

只有从 a 更改为数组 (),我们才能使它们显示相同:Args()ParamArrayVariantByRef Args() As Variant

6

但是,后者将与下面描述的功能行为发生冲突。CallByName()

参数化行为

不幸的是,不能按名称 () 传递,因为显然是 a,因此只接受未命名的参数:ArgsCopyArgsArgs := ArgsCopyArgsParamArray

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

注意

请忽略返回 的事实,该 可能(也可能不是)必须设置的 。我已经在我的实际代码中考虑到了这一点CallByName()VariantObject

问题

我如何构造,尤其是它的参数,使得MyUDF()Args()

  1. 它的签名在其参数的 和 ity 上都模仿了 的签名;CallByName()TypeOptional
  2. 它准确地传递给 ?CallByName()Args()

理想情况下,还将MyUDF()

  1. Mac 和 Windows 上都能正常工作;
  2. 像在VBA编辑器中一样显示:CallByName()

6

2

这第 3 和第 4 个标准是一个奖励,但我不需要它们。

建议

Visual Basic (VB) 建议可以如上所述将参数传递给它:参数是与 相同类型的数组中的元素,并且此数组作为单个参数提供。但是,我在 VBA 中既没有找到记录也没有实验等价物。ParamArrayMyUDF()ParamArray

我确实在 Stack Overflow 上找到了这三个 VBA 问题,但我缺乏在这里应用他们的课程的经验。

  1. 将参数数组传递给 CallByName VBA
  2. 将数组传递给 ParamArray
  3. 如何在 Mac OS 上从 Framework 文件中查看接口规范

更改方法签名

第一个问题有一个解决方案,它更改了 的方法签名,使得它是一个参数:一个数组。CallByName()Args()Any

但是,我不熟悉“任何”类型第三个问题(未回答)使我怀疑这种预处理器“魔术”是否可以在 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
VBA 参数传递 用户定义函数 包装器 ParamArray

评论

2赞 Cristian Buse 11/30/2022
请参阅我的存储库中的 rtcCallByName 声明。我一口气传递了整个数组。我实际上更进一步,确保保留任何标志(参见方法)。如果我有时间,明天会在这里写一个答案。ByRefRunObjMethod
1赞 Cristian Buse 11/30/2022
@Greg 很遗憾,不行。对于Mac,我已经建立了一个piramid :)
1赞 Greg 11/30/2022
@CristianBuse 啊,所以我注意到了。我们能否可靠地说,一个将总是有一个“合理”的大小限制,即元素(目前)?如果是这样,那么我可以编写一个脚本(在 R 中)来自动生成所有 VBA 的金字塔。我们甚至可以设计一个 VBA 模块,其中包含 和 的金字塔,其中代码是动态自动生成的。ParamArray255MAX_PARAMARRAY_SIZE <- 255CaseVBA.CallByName()Application.Run()
1赞 Cristian Buse 11/30/2022
限制不是 255 个参数。它适用于更多,超过 1000 个。限制是代码行的长度,即即使一行代码被拆分为带有 _ 字符的多个文本行,您也可以在一行代码中压缩多少个参数。piramid 根本不可行 - 它很快就会变得丑陋和巨大。如果能在Mac上运行就好了。rtcCallByName
1赞 Cristian Buse 12/4/2022
顺便说一句,我周四花了几个小时来弄清楚 Mac 上是否可用,但不幸的是,事实并非如此。rtcCallByName

答: 暂无答案