Я подозреваю, что основная проблема с вашим кодом заключается в том, что вы запрашиваете перекрывающийся ввод-вывод, но предоставляете буфер, который перестает существовать, когда возвращается ReadFile
. Он работает в некоторых системах, а не в других, потому что система решает, выполнять ли операцию асинхронно или нет, и она может не выполнять асинхронную работу в одной системе и по-разному выбирать в другой.
Я уверен, что вы не хотите перекрывающихся операций ввода-вывода, поэтому вы должны просто передать 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
не возвращает дескриптор, он возвращает логическое значение, указывающее на успешность вызова функции.
- Использование перекрывающегося ввода-вывода, который вам не нужен и который не может работать с маршализованным буфером
byte[]
.
- Вы никогда не должны вызывать
GetLastError
из управляемого кода (вы сделали это в коде, указанном в комментарии). Вместо этого позвоните Marshal.GetLastWin32Error
. Причины объяснены в документации для этого метода.