2012-03-03 96 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_建議)? – 2012-03-03 03:10:24

+0

它實際上返回ERROR_SUCCESS或0 – jjjojjjooo 2012-03-03 03:30:57

+0

只是一個猜測,但文檔說'如果操作失敗*或正在等待*,返回值爲零。我猜這是後者。 – 2012-03-03 03:34:14

回答

2

IOCTL_DISK_GET_MEDIA_TYPES似乎是遺留的,不再支持。至少我的操作系統(Win7 x64)就是這種情況。試圖撥打DeviceIoControlIOCTL_DISK_GET_MEDIA_TYPES導致錯誤代碼1,ERROR_INVALID_FUNCTION

我相信你將需要使用IOCTL_STORAGE_GET_MEDIA_TYPES_EX來代替。

我在這種情況下的建議是先嚐試從C++調用API函數。這樣你就不必與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

您還應該從CreateFile返回一個SafeFileHandle。同樣,將一個SafeFileHandle傳遞給DeviceIoControl函數(用於hDevice參數)。 – Hans 2012-03-04 15:18:44