Получение информации о геометрии диска - PullRequest
1 голос
/ 03 марта 2012

Мне нужно получить информацию о геометрии диска, но что-то не так и DeviceIoControl возвращает false. Есть идеи как это исправить? Или другие примеры использования C # и kernel32 приветствуются.

 [DllImport("kernel32.dll")]
            public static extern IntPtr CreateFile(
            string lpFileName, int dwDesiredAccess, int dwShareMode,
            IntPtr lpSecurityAttributes, int dwCreationDisposition,
            int dwFlagsAndAttributes, IntPtr hTemplateFile);

            private const int FILE_SHARE_READ = 1;
            private const int OPEN_ALWAYS = 4;
            private const int INVALID_HANDLE_VALUE = -1;

            [DllImport("kernel32.dll", ExactSpelling = true)]
            internal static extern bool DeviceIoControl(
            IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize,
            IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped);

            private const int IOCTL_DISK_GET_MEDIA_TYPES = 0x00070c00;

            static void Main(string[] args)
            {
                IntPtr hflp = CreateFile(@""\\.\C:", 0, FILE_SHARE_READ, IntPtr.Zero, OPEN_ALWAYS, 0, IntPtr.Zero);
                if ((int)hflp == INVALID_HANDLE_VALUE)
                { Console.WriteLine("CreateFile failed"); return; }

                Type ts = typeof(DISK_GEOMETRY);
                int ss = Marshal.SizeOf(ts);
                int ssa = ss * 20;
                IntPtr mptr = Marshal.AllocHGlobal(ssa);
                int byret = 0;
                bool ok = DeviceIoControl(hflp, IOCTL_DISK_GET_MEDIA_TYPES, IntPtr.Zero, 0,
                mptr, ssa, ref byret, IntPtr.Zero);
                if (!ok)
                { Console.WriteLine("DeviceIoControl failed"); return; }
                int count = byret / ss;
                int run = (int)mptr;
                DISK_GEOMETRY gem;
                for (int i = 0; i < count; i++)
                {
                    gem = (DISK_GEOMETRY)Marshal.PtrToStructure((IntPtr)run, ts);
                    Console.WriteLine("MediaType={0} SectorsPerTrack={1}", gem.MediaType, gem.SectorsPerTrack);
                    run += ss;
                }
                Marshal.FreeHGlobal(mptr);
            }

P.S Я уже прочитал справку по MSDN.

1 Ответ

2 голосов
/ 04 марта 2012

IOCTL_DISK_GET_MEDIA_TYPES представляется устаревшим и больше не поддерживается. По крайней мере, так на моей ОС (Win7 x64). Попытка вызова DeviceIoControl с IOCTL_DISK_GET_MEDIA_TYPES приводит к коду ошибки 1, ERROR_INVALID_FUNCTION.

Я считаю, что вам нужно будет использовать IOCTL_STORAGE_GET_MEDIA_TYPES_EX.

Мой совет в этой ситуации - сначала попытаться вызвать функции API из C ++. Таким образом, вам не нужно бороться с p / invoke, и вы знаете, что все структуры и прототипы функций верны. Как только вы разобрались, как вызывать определенную функцию API, переведите ее в p / invoke.

Кроме того, вам следует быть немного более осторожным в отношении ваших вызовов p /. Будьте внимательны, чтобы использовать uint для соответствия DWORD, и убедитесь, что вы используете SetLastError=true, чтобы вы могли запросить код ошибки с помощью Marshal.GetLastWin32Error().

Примерно так:

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

[DllImport("kernel32.dll", SetLastError=true)]
internal static extern bool DeviceIoControl(
    IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer,
    uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, 
    ref uint lpBytesReturned, IntPtr lpOverlapped);
...