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

C# ReadProcessMemory在WinForms/WPF报AccessViolationException控制台正常

核心原因

异常完全是错误的P/Invoke函数签名导致的,控制台运行正常只是栈内存布局的巧合,问题从控制台测试阶段就已存在:

  • ReadProcessMemory第二个参数lpBaseAddress是平台相关的指针类型,固定长度的long(8字节)在32位环境下会打乱整个函数调用的栈参数排布。控制台启动时栈初始状态刚好让错位的参数指向合法内存,没有触发报错;WinForms/WPF加载的UI模块更多,栈对应位置的内存值为非法地址,调用时直接触发访问违例。
  • 签名最后一个参数lpNumberOfBytesRead是指向int的输出指针,你定义为传值int且默认值为0,相当于把空指针传给内核,内核写入读取字节数时本身就会触发内存访问错误,之前没报错纯粹是栈错位歪打正着。
  • 签名返回值定义为int也不符合Windows API的BOOL类型规范,虽然不会直接触发异常,但会导致返回值判断逻辑出错。
可行解决方案

1. 修正P/Invoke签名

替换成适配32/64位环境的正确签名,开启错误码捕获方便排查:

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadProcessMemory(
    IntPtr hProcess,
    IntPtr lpBaseAddress,
    [Out] byte[] lpBuffer,
    int nSize,
    out int lpNumberOfBytesRead
);

2. 调整调用逻辑

  • 所有内存地址统一用IntPtr类型存储,不要用long直接传参。如果是数值形式的地址,32位进程下转int后转IntPtr,64位进程下转long后转IntPtr,避免地址截断或长度不匹配
  • 调用时必须传入接收读取字节数的输出变量,不要传空值
  • 调用失败时通过Win32错误码定位问题,常见错误码:5代表句柄权限不足(需要PROCESS_VM_READ权限),87代表参数非法,299代表仅读取到部分内存
    正确调用示例:
int bytesRead = 0;
bool callSuccess = ReadProcessMemory(
    GetProcessHandle(),
    targetAddress, // 此处targetAddress必须为IntPtr类型
    Buffer,
    Buffer.Length,
    out bytesRead
);

if (!callSuccess)
{
    int errCode = Marshal.GetLastWin32Error();
    // 按错误码处理对应问题
}

3. 额外配置检查

  • 项目目标平台不要用默认AnyCPU,和目标读写进程保持位数一致:目标是32位程序就开Prefer 32-bit,目标是64位程序就固定编译为x64,避免地址长度不匹配
  • 拿进程句柄时确认申请了PROCESS_VM_READ权限,不要仅申请查询类权限

内容的提问来源于stack exchange,提问作者eentweedrie123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:12:33