我目前正在使用CallByName来动态调用方法。我每天从服务器中的表中提取几种方法以及参数。出于这个原因,我将一个参数数组发送到CallByName而不是一个param数组,因为我不知道运行时的参数数量。鉴于CallByName需要一个paramarray,我使用私有声明函数来绕过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)的双重类型值。有什么想法吗?
答案 0 :(得分:1)
答案的第一个线索在于rtcCallByName的函数声明(从vbe7.dll的exports表中拉出):
function CallByName(Object: IDispatch; ProcName: BSTR; CallType: VbCallType; Args: ^SafeArray; out lcid: I4): Variant; stdcall;
请注意,Args
被声明为指向SafeArray
的指针,但不被声明为out
参数。这意味着该函数的COM契约基本上是说如果你传递ParamArray
它唯一的保证是它不会改变指向ParamArray
本身的指针。 ByRef
中的Declare Function
仅表示您正在传递指针。
对于里面的值 ParamArray
,我真的没有太多的微软文档我可以专门针对VBA,但VB.NET version of the documentation给出了第二个线索:
ParamArray参数始终使用ByVal(Visual Basic)声明。
在CallByName
的背景下,这是完全合理的。 rtcCallByName
函数本身不会(也不能)知道被调用方法的哪些参数是自己声明为ByRef
或ByVal
,所以它必须假设它无法改变它们。
就解决此限制的实现而言,我建议重构以消除在ByRef
调用的代码中传递CallByName
的返回值,或者在类中包含所需的功能。