VBA RtlMoveMemory 仅适用于 ByVal



工作代码是:

Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
Sub Test()
Dim Long1 As Long
Dim Long2 As Long
Long1 = 1000
CopyMemory ByVal VarPtr(Long2), ByVal VarPtr(Long1), 4
Debug.Print VarPtr(Long1)
Debug.Print Long2
End Sub

我有两个问题:

我的理解是,当 Long1 和 Long2 超出范围时,VB 运行时会释放它们的内存。为什么Debug.Print VarPtr(Long1)在每次运行程序时都返回相同的地址?VB运行时是否为变量保留了内存的某一部分?我相信是的,因为即使我做了一些事情(例如关闭Chrome标签(来从它保持显示相同地址的堆中释放内存。

为什么我需要使用ByVal才能获得正确的结果?我确实理解CopyMemory只是将多个字节从整数VarPtr(Long1)指向的地址移动到整数VarPtr(Long2)指向的地址,但我不知道为什么我必须使用关键字ByVal,否则它只会返回0。我认为也许 VBA 默认ByRef,并且ByRef意味着将字节从存储Long1地址的地址(基本上是对 VarPtr 返回值的引用,它只是一个整数(,这没什么,到存储Long2地址的地址, 这也算不了什么。但是如果我故意使用ByRef,VBA 只会给我错误消息。

原始局部变量存储在堆栈上,因此地址取决于您调用例程的顺序,您可以通过一个简单的示例看到这一点:

Sub showAdresses()
myTest
callTest
callTest
myTest
End Sub
Sub callTest()
myTest
End Sub
Sub myTest()
Dim x As Long
Debug.Print VarPtr(x)
End Sub

您将看到第一次和最后一次调用的相同地址,以及中间调用的另一个地址 - 仅仅是因为堆栈上需要空间用于中间例程。当子例程完成时,堆栈上消耗的空间被释放,并且(这是堆栈的性质(立即重用,因此,如果您再次调用相同的例程,相同的变量将获得相同的地址(但 VBA 会初始化它(。

对于调用CopyMemory时的ByVal关键字:我假设对VarPtr的调用返回一个指针,并且您将指针作为值传递 - 否则您将传递指针的地址

最新更新