6

我目前正在使用 CallByName 来动态调用方法。我每天从服务器中的表格中获取几种方法以及参数。出于这个原因,我将参数数组发送给 CallByName 而不是参数数组,因为直到运行时我才知道参数的数量。鉴于 CallByName 需要一个参数数组,我使用私有声明函数来绕过 VBA 类型定义。

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

Public Function CallByNameMethod(Object As Object, ProcName As String, ByRef Args () As Variant)
  AssignResult CallByNameMethod, rtcCallByName(Object, StrPtr(ProcName), VbMethod, Args)
End Function 

 Private Sub AssignResult(target, Result)
  If VBA.IsObject(Result) Then Set target = Result Else target = Result
End Sub

当我传递一个方法更改其基础属性的对象时,这将起作用。但是,有一些方法我传递一个对象和一个改变传递参数值的方法。例如,我传递一个带有以下参数的数组

 Dim Name as String, Value1 as double, Value2 as double, Value3 as double
 Dim Array(3) as Variant

  String = "Name"
  Value1 = 0
  Value2 = 0
  Value3 = 0

  Array(0) = Name
  Array(1) = Value1
  Array(2) = Value2
  Array(3) = Value3

当我传递该数组时,该方法只返回具有相同值的数组,但我期望 Array(1)、Array(2)、Array(3) 的 double 类型值。有任何想法吗?

4

2 回答 2

2

答案的第一个线索在于 rtcCallByName 的函数声明(从 vbe7.dll 的导出表中提取):

function CallByName(Object: IDispatch; ProcName: BSTR; CallType: VbCallType; Args: ^SafeArray; out lcid: I4): Variant; stdcall;

请注意,Args它声明为指向 a 的指针SafeArray,但未声明out参数。这意味着该函数的 COM 合同基本上是说,如果您传递 aParamArray它所做的唯一保证是它不会更改指向ParamArray自身的指针。ByRefin Declare Functiononly 表示您正在传递一个指针。

至于 中的值ParamArray确实没有多少微软文档可以挖掘到特定于 VBA,但文档的 VB.NET 版本给出了第二条线索:

始终使用 ByVal (Visual Basic) 声明 ParamArray 参数。

在 的上下文中CallByName,这是完全合理的。rtcCallByName函数本身不(也不能)知道被调用方法的哪些参数本身声明的ByRefor ByVal,因此它必须假设它不能更改它们。

至于解决这个限制的实现,我建议要么重构以消除ByRef在调用的代码中传递的返回值,CallByName要么将所需的功能包装在一个类中。

于 2016-05-25T13:18:31.767 回答
1

事实证明这实际上是可能的,请参阅RunMacro这篇文章中的方法:

https://codereview.stackexchange.com/q/273741/146810

它将参数数组复制到变体数组中以传递给rtcCallByName ,同时保留变体的ByRef标志,使用此CloneParamArray方法:

https://github.com/cristianbuse/VBA-MemoryTools/blob/f01b0818930fb1708caaf5fc99812abdeaa9f1df/src/LibMemory.bas#L890

于 2022-03-03T09:25:30.443 回答