2012-12-04 17 views
3

我有一個非託管的C++ Windows控制檯應用程序,工作正常。我想用C#。我曾經做過的DllImport語句進行必要的Kernel32.dll符號:爲什麼我的C#/ pinvoke DeviceIoControl調用返回0字節的垃圾數據讀取?

[StructLayout(LayoutKind.Sequential)] 
internal struct DiskGeometry 
{ 
    public long Cylinders; 
    public int MediaType; 
    public int TracksPerCylinder; 
    public int SectorsPerTrack; 
    public int BytesPerSector; 
} 

internal static class NativeMethods 
{ 
    internal const uint FileAccessGenericRead = 0x80000000; 
    internal const uint FileShareWrite = 0x2; 
    internal const uint FileShareRead = 0x1; 
    internal const uint CreationDispositionOpenExisting = 0x3; 
    internal const uint IoCtlDiskGetDriveGeometry = 0x70000; 

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern SafeFileHandle CreateFile(
     string fileName, 
     uint fileAccess, 
     uint fileShare, 
     IntPtr securityAttributes, 
     uint creationDisposition, 
     uint flags, 
     IntPtr template); 

    [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)] 
    public static extern int DeviceIoControl(
     SafeFileHandle device, 
     uint controlCode, 
     IntPtr inBuffer, 
     uint inBufferSize, 
     IntPtr outBuffer, 
     uint outBufferSize, 
     ref uint bytesReturned, 
     IntPtr overlapped); 
} 

然後我有以下應用程序代碼:

public static void Main() 
    { 
     SafeFileHandle diskHandle = NativeMethods.CreateFile(
      "\\\\.\\PhysicalDrive0", 
      NativeMethods.FileAccessGenericRead, 
      NativeMethods.FileShareWrite | NativeMethods.FileShareRead, 
      IntPtr.Zero, 
      NativeMethods.CreationDispositionOpenExisting, 
      0, 
      IntPtr.Zero); 
     if (diskHandle.IsInvalid) 
     { 
      Console.WriteLine("CreateFile failed with error: {0}", Marshal.GetLastWin32Error()); 
      return; 
     } 

     int geometrySize = Marshal.SizeOf(typeof(DiskGeometry)); 
     Console.WriteLine("geometry size = {0}", geometrySize); 

     IntPtr geometryBlob = Marshal.AllocHGlobal(geometrySize); 

     uint numBytesRead = 0; 
     if (0 == NativeMethods.DeviceIoControl(
      diskHandle, 
      NativeMethods.IoCtlDiskGetDriveGeometry, 
      IntPtr.Zero, 
      0, 
      geometryBlob, 
      (uint)geometrySize, 
      ref numBytesRead, 
      IntPtr.Zero)) 
     { 
      Console.WriteLine("DeviceIoControl failed with error: {0}", Marshal.GetLastWin32Error()); 
      return; 
     } 

     Console.WriteLine("Bytes read = {0}", numBytesRead); 

     DiskGeometry geometry = (DiskGeometry)Marshal.PtrToStructure(geometryBlob, typeof(DiskGeometry)); 
     Marshal.FreeHGlobal(geometryBlob); 

     long bytesPerCylinder = (long)geometry.TracksPerCylinder * (long)geometry.SectorsPerTrack * (long)geometry.BytesPerSector; 
     long totalSize = geometry.Cylinders * bytesPerCylinder; 

     Console.WriteLine("Media Type:   {0}", geometry.MediaType); 
     Console.WriteLine("Cylinders:   {0}", geometry.Cylinders); 
     Console.WriteLine("Tracks per Cylinder: {0}", geometry.TracksPerCylinder); 
     Console.WriteLine("Sectors per Track: {0}", geometry.SectorsPerTrack); 
     Console.WriteLine("Bytes per Sector:  {0}", geometry.BytesPerSector); 
     Console.WriteLine("Bytes per Cylinder: {0}", bytesPerCylinder); 
     Console.WriteLine("Total disk space:  {0}", totalSize); 
    } 

我的C#應用​​程序打印「讀取的字節= 0」和幾何形狀的構件值是垃圾。我當然不是DllImport和編組方面的專家。請幫我理解我做錯了什麼。如果我將第五個參數更改爲DeviceIoControl爲「ref DiskGeometry」,並且只傳入在調用之前創建的第一個參數(而不是IntPtr和alloc),則所有打印幾何成員值均爲0.

+0

看看這個問題:http://stackoverflow.com/questions/13192616/deviceiocontrol-does-not-set-output -buffer – vcsjones

+0

我在上面的代碼中解決了這兩個問題,現在它可以工作。 – Josh

+0

爲什麼用SetLastError = false註釋DeviceIoControl? – tm1

回答

1

你有錄入錯誤,試試這個:

internal const uint IoCtlDiskGetDriveGeometry = 0x70000; 
+0

謝謝!我從來沒有發現過。一旦我解決了這個問題,我發現我錯誤地檢查了DeviceIoControl()的返回值。失敗時返回0。一旦我確定它的效果很好。 – Josh