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

SetFilePointer异常:读取物理驱动器扇区遇保护内存错误

解决SetFilePointer在C# P/Invoke中HighPart非零时的保护内存异常问题

我在尝试从物理驱动器读取扇区时碰到了一个头疼的问题:当通过P/Invoke调用SetFilePointer,且传入的HighPart参数非零时,运行一段时间后就会抛出以下异常:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

奇怪的是,当HighPart传0时代码能正常工作,而且对应的C版本完全没有这个问题。

原问题代码

最初使用的P/Invoke签名和调用逻辑如下:

[DllImport("kernel32.dll", EntryPoint = "SetFilePointer", CallingConvention = CallingConvention.StdCall)]
static extern uint SetFilePointer(
    [In] IntPtr hFile,
    [In] int lDistanceToMove,
    [In,Out] int lpDistanceToMoveHigh,
    [In] EMoveMethod dwMoveMethod);

public void SetFilePointer(LARGE_INTEGER li)
{
    SetFilePointer((IntPtr)handle, li.LowPart, li.HighPart, EMoveMethod.Begin);
}
// 传入参数值:HighPart=381 int,LowPart=-1323466752 int

问题根源

问题出在lpDistanceToMoveHigh参数的传递方式上。原生Win32 API的SetFilePointer中,这个参数是一个指向int的指针(用来传递64位偏移量的高32位,支持输入和输出),但原签名里直接把它声明为int类型——这就导致C#会把传入的int值直接当作内存地址来传递,当HighPart非零时,这个值对应的内存区域通常是受系统保护的,自然就触发了内存访问异常。

修正后的解决方案

按照@mjwills的建议,我调整了P/Invoke签名,解决了这个问题:

[DllImport("kernel32.dll", EntryPoint = "SetFilePointer")]
static extern uint SetFilePointer(
    [In] Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
    [In] int lDistanceToMove,
    [In, Out] ref int lpDistanceToMoveHigh,
    [In] EMoveMethod dwMoveMethod);

public void SetFilePointer(LARGE_INTEGER li)
{
    SetFilePointer(shandle, li.LowPart, ref li.HighPart, EMoveMethod.Begin);
}

这里的关键修改有两点:

  • 将文件句柄替换为SafeFileHandle,这是更安全的托管句柄类型,能有效避免句柄泄漏等潜在问题;
  • 将lpDistanceToMoveHigh声明为ref int,这样C#会正确传递该变量的内存地址,完全符合原生API对指针参数的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:11:26