VBA RtlMoveMemory仅适用于ByVal

时间:2018-05-28 03:05:07

标签: vba memory

工作代码是:

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

我有两个问题:

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

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

1 个答案:

答案 0 :(得分:1)

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

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初始化它)。

调用ByValCopyMemory关键字:我假设对VarPtr的调用返回指针,并传递指针< / em>作为值 - 否则你将传递指针的地址