64位VBA中VirtualProtect声明正确性及原保护值返回0故障排查
问题排查与解决方案
1. 声明错误点
你当前的VirtualProtect声明存在参数类型编组问题:虽然VBA的Enum默认底层是32位Long,理论上可以匹配DWORD类型,但自定义枚举类型作为ByRef参数传递给系统API时,VBA的运行时编组会出现异常,无法正确接收API写入的返回值,这就是你拿到的originalProtection始终为&H0的核心原因。
2. 修正后的声明
将参数类型替换为原生Long即可解决取值问题,修正后代码如下:
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" ( _ ByVal memAddress As LongPtr, _ ByVal lengthInBytes As LongPtr, _ ByVal newProtect As Long, _ ByRef outOldProtect As Long _ ) As Long ' 枚举定义可以保留,调用时直接传枚举成员即可,VBA会自动转为Long Public Enum protectFlags PAGE_NOACCESS = &H1 PAGE_READONLY = &H2 PAGE_READWRITE = &H4 PAGE_WRITECOPY = &H8 PAGE_EXECUTE = &H10 PAGE_EXECUTE_READ = &H20 PAGE_EXECUTE_READWRITE = &H40 PAGE_EXECUTE_WRITECOPY = &H80 PAGE_GUARD = &H100 PAGE_NOCACHE = &H200 PAGE_WRITECOMBINE = &H400 End Enum
3. 调用代码修正
- 存储原始保护属性的变量改为Long类型
- 恢复保护时的临时变量必须显式声明为Long类型,禁止使用未声明的隐式Variant变量
修正后的调用代码:
Dim memoryAddress As LongPtr memoryAddress = ... ' 你的受保护内存地址 Dim originalProtection As Long ' 不要用枚举类型存储返回值 If CBool(VirtualProtect(memoryAddress, 8, PAGE_EXECUTE_READWRITE, originalProtection)) Then Debug.Print "Previous protection cached: &H" & Hex(originalProtection) Else Err.Raise 5, Description:="Memory address cannot be unprotected with PAGE_EXECUTE_READWRITE" End If ' 恢复保护时的临时变量必须显式声明为Long Dim temp As Long VirtualProtect memoryAddress, 8, originalProtection, temp
4. 错误码87的原因
你恢复时触发错误87(参数无效)有两个明确原因:
- 传入的originalProtection是&H0,属于无效的内存保护标识
- 临时变量
temp没有显式声明为Long类型,默认是Variant,API无法识别Variant类型的指针参数,直接报错。
内容的提问来源于stack exchange,提问作者Greedo
相关产品推荐
相关产品推荐

