You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:45:00