2016-05-30 7 views
3

私はC#に変換する必要があるIOCTL_VOLUME_GET_VOLUME_DISK_EXTENTSでDeviceIoControlを呼び出すC++コードを使用しました。
多くのDeviceIoControl p \ invokeサンプルが見つかりましたが、この特定のフラグはありませんでした。 私は次のようにextern使用して試してみた:常にあるDeviceIoControl with IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS - C#

int bytesReturned = 0; 
DiskExtents diskExtents = new DiskExtents(); 
bool res = DeviceIoControl(hVol, 5636096, IntPtr.Zero, 0, ref diskExtents, Marshal.SizeOf(diskExtents), ref bytesReturned, IntPtr.Zero); 

しかし、コール・リターン偽とデータ構造:

[DllImport("kernel32", SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool DeviceIoControl(SafeFileHandle hVol, int controlCode, IntPtr inBuffer, int inBufferSize, ref DiskExtents outBuffer, int outBufferSize, ref int bytesReturned, IntPtr overlapped); 

構造:

[StructLayout(LayoutKind.Sequential)] 
public struct DiskExtent 
{ 
    public uint DiskNumber; 
    public long StartingOffset; 
    public long ExtentLength; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct DiskExtents 
{ 
    public int numberOfExtents; 
    public DiskExtent[] first; 
} 

そして、次の呼び出しのコードを空の。 助けがあれば助かります!

+0

これはいくつのディスクで動作する必要がありますか? 1つのDiskExtent構造体に書き込むために呼び出すことは*かなり簡単*でしょう。あなたは複数をサポートする必要がありますか? –

答えて

2

コードの問題は、配列のサイズがわかっていなければマーシャリングできないことです。これは、DeviceIoControlコールを行うときに、DiskExtents構造体を適切にマーシャリングできないことを意味します。

次のコードは、私の作品(私は相互運用のために明示的にサイズの種類を好む、と私はすでに、彼らが何を意味するか知っていて、簡単にそれらをGoogleにすることができますので、Win32のヘッダからの名前に固執することを好む傾向にある):

もちろん
internal static class NativeMethods 
{ 
    internal const UInt32 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = 0x00560000; 

    [StructLayout(LayoutKind.Sequential)] 
    internal class DISK_EXTENT 
    { 
     public UInt32 DiskNumber; 
     public Int64 StartingOffset; 
     public Int64 ExtentLength; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal class VOLUME_DISK_EXTENTS 
    { 
     public UInt32  NumberOfDiskExtents; 
     public DISK_EXTENT Extents; 
    } 

    [DllImport("kernel32", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)]        
    internal static extern bool DeviceIoControl(SafeFileHandle hDevice, 
               UInt32   ioControlCode, 
               IntPtr   inBuffer, 
               UInt32   inBufferSize, 
               IntPtr   outBuffer, 
               UInt32   outBufferSize, 
               out UInt32  bytesReturned, 
               IntPtr   overlapped); 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     // Open the volume handle using CreateFile() 
     SafeFileHandle sfh = ... 

     // Prepare to obtain disk extents. 
     // NOTE: This code assumes you only have one disk! 
     NativeMethods.VOLUME_DISK_EXTENTS vde   = new NativeMethods.VOLUME_DISK_EXTENTS(); 
     UInt32       outBufferSize = (UInt32)Marshal.SizeOf(vde); 
     IntPtr       outBuffer  = Marshal.AllocHGlobal((int)outBufferSize); 
     UInt32       bytesReturned = 0; 
     if (NativeMethods.DeviceIoControl(sfh, 
             NativeMethods.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, 
             IntPtr.Zero, 
             0, 
             outBuffer, 
             outBufferSize, 
             out bytesReturned, 
             IntPtr.Zero)) 
     { 
      // The call succeeded, so marshal the data back to a 
      // form usable from managed code. 
      Marshal.PtrToStructure(outBuffer, vde); 

      // Do something with vde.Extents here...e.g. 
      Console.WriteLine("DiskNumber: {0}\nStartingOffset: {1}\nExtentLength: {2}", 
          vde.Extents.DiskNumber, 
          vde.Extents.StartingOffset, 
          vde.Extents.ExtentLength); 
     } 
     Marshal.FreeHGlobal(outBuffer); 
    } 
} 

、これはあなただけの単一のディスクに関する情報を取得する必要があることを前提としています。 VOLUME_DISK_EXTENTS構造体にディスクについての情報を記入するためにDeviceIoControl関数が必要な場合は、より厳しく作業する必要があります。

問題は、実行時まで正確にいくつのディスクがあるかわからないことです。 DeviceIoControlERROR_MORE_DATAを返して、テーブルに残っている情報が多く、大きなバッファで再度呼び出す必要があることを通知します。あなたは、上記と同じ行に沿って、余分な複雑さを伴ってそれを行います。追加のDISK_EXTENT構造に対応するために、バッファのサイズを拡張するには、Marshal.ReAllocHGlobalのようなものを使用する必要があります。必要な番号はDeviceIoControlへの最初の不成功の呼び出し後にVOLUME_DISK_EXTENTS.NumberOfDiskExtentsメンバーに返されます。 This C# codeも同様の実装を示しています。

このような厄介なコードを書くのに費やした時間が、私が主にC#でWindowsアプリケーションを開発することをあきらめた理由です。これは、C++がより洗練され、よりエレガントで、書きやすく、避けられないパラドックスを作り出します。は、エラーが発生しにくいです。 (上記のコードでハンドルが漏れていないことは確かですか?私はそうではありません)