在VBA中,ByRef是否可以实现?

在VBA中,ByRef是否可以实现?,vba,pass-by-reference,Vba,Pass By Reference,在最近使用PDF打印机进行测试后,我发现VBA的ByRef并没有像预期的那样真正地将引用传递给变量:当通过引用传递时,异步更改的变量的值永远不会更新 在下面的简化示例中,ByRef变量参数永远不会更改其值: '--- definition --- Private Sub WaitUntilEqual(ByRef Variable As Variant, ByVal Value As Variant) Dim PollingInterval as Integer = 200 Do

在最近使用PDF打印机进行测试后,我发现VBA的
ByRef
并没有像预期的那样真正地将引用传递给变量:当通过引用传递时,异步更改的变量的值永远不会更新

在下面的简化示例中,
ByRef变量
参数永远不会更改其值

'--- definition ---

Private Sub WaitUntilEqual(ByRef Variable As Variant, ByVal Value As Variant)
    Dim PollingInterval as Integer = 200
    Do While Variable <> Value 
        TimeSpent = TimeSpent + PollingInterval
        Sleep PollingInterval
    Loop
End Sub

'--- usage (initializations omitted) ---

PdfCreator.cPrint "filename1"
PdfCreator.cPrint "filename2"
PdfCreator.cPrint "filename3"
'at this point, PdfCreator.cCountOfPrintjobs is 0 and needs few seconds to raise to 3
WaitUntilEqual PdfCreator.cCountOfPrintjobs, 3  'this will stick forever - it shouldn't
”---定义---
私有子WaitUntilEqual(ByRef变量作为变量,ByVal值作为变量)
Dim PollingInterval为整数=200
当变量值
TimePent=TimePent+PollingInterval
睡眠污染间期
环
端接头
'---用法(省略初始化)---
PdfCreator.cPrint“filename1”
PdfCreator.cPrint“文件名2”
PdfCreator.cPrint“filename3”
'此时,PdfCreator.ccontofprintjobs为0,需要几秒钟时间提升到3
WaitUntilEqual PdfCreator.cCountOfPrintjobs,3'这将永远保持不变-不应该
这是VBA限制吗?这可以避免吗


我需要此方法3-4次(它还包括超时等额外功能),因此我不想通过复制粘贴重复整个等待循环。

不确定这在多大程度上适用于VBA,但MSDN表示,如果输出值没有“地址”,即不是变量,则调用代码可以强制调用
ByVal
,但是求值、函数调用或立即常数等的结果

假设
cCountOfPrintjobs
是对象
PdfCreator
属性Get
。这意味着实际上有一个函数可以检查对象的内部结构,计算出有多少打印作业,并返回该值。该值是“在堆栈上”返回的,它没有固定的“地址”供代码轮询。为了避免读取无效/未设置的内存区域,VBA会将调用更改为
ByVal
,因此代码会挂起,因为没有什么可以更改参数值

后期编辑


已经在评论部分给出了答案…

PdfCreator.cCountOfPrintjobs返回什么?它需要是一个具有返回当前计数的默认属性的对象,以便执行您必须执行的操作。如果它返回一个类似整数的数值基元,那么您只需将一个包含
ccuntofprintjobs
值副本的新整数(在调用时)传递给子对象,这将永远不会更改,因为它与对象解除绑定。您可以传入
PdfCreator
,然后修改循环以实时检查属性
while Variable.ccuntofprintjobs Value
PdfCreator.ccuntofprintjobs
可能是一个
Get属性
方法,因此实际上您所做的是比较此方法返回的值的副本。我不相信您可以在VBA中引用属性本身。但是,您可以使用
CallByName
函数来避免多个循环基于您的见解,我通过创建等待循环的两个通用部分来解决问题:初始化(从配置读取超时,初始化计数器)和循环体(等待一段时间,测试和处理超时)。每个应用的等待循环都使用这两个子例程,但主条件的检查直接在循环中,而不是在这些子例程中。如果值不是
左值,VBA将复制该值,您将获得该值的引用。左值只是一个表达式,可以是byref。。。。属性get实际上是一个伪装的函数调用,而不是一个变量,所以它不能是byref。@Ben:没错。我怀疑将在函数/子参数列表中创建副本。:-)以下是我在帖子中提到的链接:(检查“传递机制的确定”)——它是针对VB而不是VBA的。@CST链接VBA规范:
如果[…]参数是ByRef,并且映射参数的表达式被分类为值、函数、属性或未绑定成员,使用与参数相同的名称值和声明类型在调用的过程中使用过程范围定义局部变量,并按如下方式分配其值:[……]
@z̫͋:感谢您费尽心机找到有关此问题的正确文档。:-)