gpt4 book ai didi

vba - 在 VBA 中复制数组引用

转载 作者:行者123 更新时间:2023-12-03 21:46:48 28 4
gpt4 key购买 nike

有没有办法在 VBA(或 VB6)中复制数组引用?

在 VBA 中,数组是值类型。将一个数组变量分配给另一个会复制整个数组。我想让两个数组变量指向同一个数组。有什么方法可以做到这一点,也许使用一些 API 内存函数和/或 VarPtr函数,它实际上返回 VBA 中变量的地址?

Dim arr1(), arr2(), ref1 As LongPtr
arr1 = Array("A", "B", "C")

' Now I want to make arr2 refer to the same array object as arr1
' If this was C#, simply assign, since in .NET arrays are reference types:
arr2 = arr1

' ...Or if arrays were COM objects:
Set arr2 = arr1

' VarPtr lets me get the address of arr1 like this:
ref1 = VarPtr(arr1)

' ... But I don't know of a way to *set* address of arr2.

顺便说一句,通过传递相同的数组变量 ByRef 可以获得对同一个数组的多个引用。一个方法的多个参数:

Sub DuplicateRefs(ByRef Arr1() As String, ByRef Arr2() As String)
Arr2(0) = "Hello"
Debug.Print Arr1(0)
End Sub

Dim arrSource(2) As String
arrSource(0) = "Blah"

' This will print 'Hello', because inside DuplicateRefs, both variables
' point to the same array. That is, VarPtr(Arr1) == VarPtr(Arr2)
Call DuplicateRefs(arrSource, arrSource)

但这仍然不允许人们在与现有引用相同的范围内简单地制造新引用。

最佳答案

是的,您可以 , 如果两个变量都是 Variant 类型。

原因如下: Variant 类型本身就是一个包装器。 Variant 的实际位内容是 16 个字节。第一个字节表示当前存储的实际数据类型。该值完全对应于 VbVarType 枚举。即如果 Variant 当前持有一个 Long 值,第一个字节将是 0x03vbLong的值.第二个字节包含一些位标志。例如,如果变体包含一个数组,则 0x20 处的位在这个字节中将被设置。

剩余 14 个字节的使用取决于存储的数据类型。对于任何数组类型,它都包含 数组地址 .

这意味着如果您使用 RtlMoveMemory 直接覆盖一个变体的值您实际上覆盖了对数组的引用。这确实有效!

有一个警告:当数组变量超出范围时,VB 运行时将回收实际数组元素包含的内存。当您通过我刚刚描述的 Variant CopyMemory 技术手动复制数组引用时,结果是当两个变体都超出范围时,运行时将尝试回收相同的内存两次,并且程序将崩溃。为避免这种情况,您需要在变量超出范围之前,通过再次覆盖变体(例如使用 0)手动“删除”除一个引用之外的所有引用。

示例 1:这有效,但是一旦两个变量都超出范围(子退出时)就会崩溃

Private Declare PtrSafe Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Sub CopyArrayRef_Bad()
Dim v1 As Variant, v2 As Variant
v1 = Array(1, 2, 3)
CopyMemory v2, v1, 16

' Proof:
v2(1) = "Hello"
Debug.Print Join(v1, ", ")

' ... and now the program will crash
End Sub

示例 2:通过仔细清理,您可以侥幸逃脱!
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Declare PtrSafe Sub FillMemory Lib "kernel32" _
Alias "RtlFillMemory" (Destination As Any, ByVal Length As Long, ByVal Fill As Byte)

Sub CopyArrayRef_Good()
Dim v1 As Variant, v2 As Variant
v1 = Array(1, 2, 3)
CopyMemory v2, v1, 16

' Proof:
v2(1) = "Hello"
Debug.Print Join(v1, ", ")

' Clean up:
FillMemory v2, 16, 0

' All good!
End Sub

关于vba - 在 VBA 中复制数组引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16323776/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com