2012-03-03 2 views
1

Мне нужно получить информацию о геометрии диска, но что-то не так, и 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 об этом.

+0

Вы сказали, что вы читаете документацию MSDN по этому вопросу, если это так, что сделал [GetLastError] (http://msdn.microsoft.com/en-us/library/windows/ desktop/ms679360 (v = vs.85) .aspx) return (_s, предложенный MSDN docs_)? –

+0

На самом деле это возвращает ERROR_SUCCESS или 0 – jjjojjjooo

+0

Просто догадайтесь, но в документации говорится: 'Если операция не завершена * или находится в ожидании *, возвращаемое значение равно нулю. Думаю, это последнее. –

ответ

2

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/invokes. Позаботьтесь о том, чтобы использовать 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); 
+0

Вы также должны вернуть SafeFileHandle из CreateFile. Точно так же передайте SafeFileHandle в функцию DeviceIoControl (для параметра hDevice). – Hans

Смежные вопросы