VBA实现指针时MoveMemory返回异常值,结果不符预期求助
问题根源分析
你的代码核心问题出在AL_Address函数的参数传递逻辑上:
- 当把
Integer类型变量a传递给ByVal Variant类型的参数Variable时,VBA会自动将a装箱为一个临时Variant对象。 VarPtr(Variable)获取的是这个临时Variant对象的内存地址,而非原变量a的真实地址。- 解引用临时Variant的地址时,读取的是Variant结构的类型标识(VT)部分,而非原变量的实际值,因此得到错误的
16387。
修正方案
1. 为特定类型编写地址函数
由于VBA不支持函数重载,我们可以为每种需要支持的数据类型编写单独的地址函数,通过ByRef参数确保获取原变量的真实地址:
Private Declare PtrSafe Sub MoveMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _ (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As Long) ' Integer类型的地址获取函数 Public Function AL_Address_Integer(ByRef var As Integer) As LongPtr AL_Address_Integer = VarPtr(var) End Function ' Integer类型的解引用函数 Private Function AL_DeRef_Integer(Pointer As LongPtr) As Integer MoveMemory VarPtr(AL_DeRef_Integer), Pointer, Len(AL_DeRef_Integer) End Function Sub Test() Dim a As Integer, b As Integer, c As Integer a = 1: b = 2: c = 0 ' 直接调用对应类型的地址和解引用函数 c = AL_DeRef_Integer(AL_Address_Integer(a)) Debug.Print a Debug.Print b Debug.Print c End Sub
2. 通用地址函数优化(可选)
如果需要支持多种数据类型,可以通过ByRef Variant参数结合Variant内部结构获取原变量地址,需区分32/64位系统的结构差异:
Public Function AL_Address(ByRef var As Variant) As LongPtr Dim vt As Integer ' 读取Variant的类型标识 MoveMemory VarPtr(vt), VarPtr(var), Len(vt) Select Case vt Case vbInteger, vbByte, vbBoolean ' 值类型直接存储在Variant的偏移位置(32位偏移4字节,64位偏移8字节) #If Win64 Then AL_Address = VarPtr(var) + 8 #Else AL_Address = VarPtr(var) + 4 #End If ' 其他数据类型可按需扩展 End Select End Function
验证结果
运行修正后的Test过程,输出将符合预期:
1 2 1
内容的提问来源于stack exchange,提问作者Almesi
相关产品推荐
相关产品推荐

