使用FileRead API时AccessViolationException

时间:2011-12-04 08:53:13

标签: c# .net windows winapi pinvoke

我正在使用FileRead API。 我使用的是Windows 7 x64,我的代码运行良好且正确。 现在我安装了一个新的Windows 7 x86和VS2008 teamuit以及.NET 2,3 + SP1 + SP2,3.5,3.5.1。 我以管理员身份运行我的代码,但仍然遇到以下错误:

  

AccessViolationException(尝试读取或写入受保护的内存。这通常表示其他内存已损坏。)

 int nread = 0;
 uint handle;
 byte[] buff = new byte[1024];
 string driveRoot = string.Concat("\\\\.\\", driveLetter);
 uint hRoot = CreateFile(driveRoot,
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                IntPtr.Zero,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                IntPtr.Zero);
 if (hRoot != -1)
      handle = ReadFile(hRoot, buff, 1024, nread, new System.Threading.NativeOverlapped());

2 个答案:

答案 0 :(得分:1)

虽然我不是C#guru,但在我看来,您正在使用错误的参数调用ReadFile()

第4个参数必须是指向将接收读取的字节数的整数的指针。您提供整数本身(nread),而不是其地址(&nread)。

除非你想要异步文件I / O,否则ReadFile()的最后一个参数必须是一个NULL指针(或者只是0)。

请参阅this example on MSDN

答案 1 :(得分:0)

我怀疑您的代码的主要问题是您正在请求重叠的I / O,但提供的缓冲区在ReadFile返回时不再存在。它适用于某些系统而不是其他系统,因为系统决定是否异步执行操作,并且可以选择不在一个系统上执行异步并在另一个系统上选择不同的方式。

我确定您不希望重叠I / O,因此您只需将NULL传递给ReadFile的最终参数。

另一方面,也许您的代码在x64系统上根本不起作用,并且永远不会像AV一样远。您的句柄类型被误称为32位整数。

您的代码还有许多其他小问题。这是修改这些错误的代码的编辑版本。 P / invoke签名来自pinvoke.net。

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr SecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile
);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(
    IntPtr hFile, 
    [Out] byte[] lpBuffer,
    uint nNumberOfBytesToRead, 
    out uint lpNumberOfBytesRead, 
    IntPtr lpOverlapped
);

static void Main(string[] args)
{
    string physicalDrive = @"\\.\PhysicalDrive0";
    IntPtr hFile = CreateFile(
        physicalDrive, 
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        IntPtr.Zero,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        IntPtr.Zero
    );
    if (hFile.ToInt64() != INVALID_HANDLE_VALUE)
    {
        byte[] buff = new byte[1024];
        uint nread;
        if (ReadFile(hFile, buff, (uint)buff.Length, out nread, IntPtr.Zero))
            Console.WriteLine("Read successful");
    }
}

总结代码中的错误:

  • 错误地使用32位整数来存储句柄。
  • 您的P / invoke声明ReadFile声明lpNumberOfBytesRead错误。
  • ReadFile不返回句柄,它返回一个布尔值,表示函数调用成功。
  • 使用您不想要的重叠I / O,但不能使用已编组的byte[]缓冲区。
  • 您绝不能从托管代码中调用GetLastError(您在注释中显示的代码中这样做了)。而是致电Marshal.GetLastWin32Error。原因在该方法的documentation中进行了解释。