DeviceIoControl не устанавливает выходной буфер

У меня проблемы с DeviceIOControl. Я пытаюсь прочитать геометрию диска с физического диска, но выходной буфер никогда не устанавливается.

Вот пример моего кода, простая функция, которая должна получать геометрию диска и возвращать информацию о том, является ли диск съемным:

public static bool IsDeviceRemovable(int DriveNo) {
    string Filename=@"\\.\Physicaldrive"+DriveNo;

    SafeFileHandle drive=CreateFile(
        Filename,
        FileAccess_e.None,
        FileShare_e.Write|FileShare_e.Read,
        IntPtr.Zero,
        CreationDisposition_e.OpenExisting,
        FileAttributes_e.None,
        IntPtr.Zero
    );

    if(drive.IsInvalid) {
        throw new IOException("Unable to access drive. Win32 Error Code: "+Marshal.GetLastWin32Error());
    }

    uint bytesReturned=0;
    DISK_GEOMETRY dg=new DISK_GEOMETRY();

    if(!DeviceIoControl(
        drive,
        IOControlCode_e.DiskGetDriveGeometry,
        IntPtr.Zero,
        0,
        dg,
        (uint)Marshal.SizeOf(dg),
        ref bytesReturned,
        IntPtr.Zero
        )) {
        throw new Exception("Unable to get properties from device. Win32 Error Code: "+Marshal.GetLastWin32Error());
    }

    drive.Close();
    return dg.MediaType==MEDIA_TYPE.RemovableMedia;
}

И некоторые структуры данных:

[DllImport("Kernel32.dll", SetLastError=false, CharSet=CharSet.Auto)]
private static extern bool DeviceIoControl(
    SafeFileHandle hDevice,
    IOControlCode_e IoControlCode,
    [MarshalAs(UnmanagedType.AsAny)]
    [In] object InBuffer,
    uint nInBufferSize,
    [MarshalAs(UnmanagedType.AsAny)]
    [Out] object OutBuffer,
    uint nOutBufferSize,
    ref uint pBytesReturned,
    IntPtr Overlapped
    );

[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
    string lpFileName,
    FileAccess_e dwDesiredAccess,
    FileShare_e dwShareMode,
    IntPtr lpSecurityAttributes,
    CreationDisposition_e dwCreationDisposition,
    FileAttributes_e dwFlagsAndAttributes,
    IntPtr hTemplateFile
    );

private enum MEDIA_TYPE {
    Unknown=0x00,
    F5_1Pt2_512=0x01,
    F3_1Pt44_512=0x02,
    F3_2Pt88_512=0x03,
    F3_20Pt8_512=0x04,
    F3_720_512=0x05,
    F5_360_512=0x06,
    F5_320_512=0x07,
    F5_320_1024=0x08,
    F5_180_512=0x09,
    F5_160_512=0x0a,
    RemovableMedia=0x0b,
    FixedMedia=0x0c,
    F3_120M_512=0x0d,
    F3_640_512=0x0e,
    F5_640_512=0x0f,
    F5_720_512=0x10,
    F3_1Pt2_512=0x11,
    F3_1Pt23_1024=0x12,
    F5_1Pt23_1024=0x13,
    F3_128Mb_512=0x14,
    F3_230Mb_512=0x15,
    F8_256_128=0x16,
    F3_200Mb_512=0x17,
    F3_240M_512=0x18,
    F3_32M_512=0x19
}

[StructLayout(LayoutKind.Sequential)]
private struct DISK_GEOMETRY {
    public Int64 Cylinders;
    public MEDIA_TYPE MediaType;
    public Int32 TracksPerCylinder;
    public Int32 SectorsPerTrack;
    public Int32 BytesPerSector;
}

Используемые перечисления я получил от

Переменная bytesReturned устанавливается (в данном случае на 24), но переменная dg содержит все нули.

Я попробовал несколько других функций DeviceIoControl с тем же результатом: bytesReturned установлен, но выходной буфер - все нули.

Моя тестовая среда

  • ОС: Windows 7 Pro 64
  • IDE: Visual Studio 2010
  • Целевая платформа: .Net 4.0

person Johan    schedule 02.11.2012    source источник


Ответы (1)


Объявление DISK_GEOMETRY является проблемой. Он маршалируется как объект, но объявлен как структура. Это означает, что он будет упакован, только упакованная копия будет обновлена ​​вызовом pinvoke. Вы читаете исходное значение и, таким образом, получаете все нули.

Простое решение — объявить его как класс вместо структуры.

person Hans Passant    schedule 02.11.2012
comment
Действительно простое исправление! Большое спасибо за помощь. - person Johan; 02.11.2012