を使用して C# プロジェクトに取り組んでいDeviceIoControl
ます。関連するPinvoke.net ページで署名を調べました。
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
EIOControlCode IoControlCode,
[MarshalAs(UnmanagedType.AsAny)]
[In] object InBuffer,
uint nInBufferSize,
[MarshalAs(UnmanagedType.AsAny)]
[Out] object OutBuffer,
uint nOutBufferSize,
out uint pBytesReturned,
[In] IntPtr Overlapped
);
私は見たことがありませんでしobject
たが、MSDNのドキュメントは有望に聞こえました:[MarshalAs(
UnmanagedType.AsAny
)]
実行時にオブジェクトの型を決定し、オブジェクトをその型としてマーシャリングする動的な型。このメンバーは、プラットフォーム呼び出しメソッドに対してのみ有効です。
私の質問は次のとおりです。この署名を使用する「最良の」および/または「適切な」方法は何ですか?
たとえば、構造体であることがIOCTL_STORAGE_QUERY_PROPERTY
期待InBuffer
されますSTORAGE_PROPERTY_QUERY
。new
その構造体を定義し、インスタンスを作成して、それを Pinvoke 署名に渡すことができるように思えます。
var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0, QueryType = 0 };
DeviceIoControl(..., query, Marshal.SizeOf(query), ...);
しかし、私はSystem.ExecutionEngineException
それをやったばかりなので、次のように変更しました:
int cb = Marshal.SizeOf(typeof(...));
IntPtr query = Marshal.AllocHGlobal(cb);
...
Marshal.PtrToStructure(...);
Marshal.FreeHGlobal(query);
少なくとも、呼び出したときに例外はスローされませんでした。それは非常に醜く、お尻に大きな痛みがあります。私が望んでいたように、マーシャラーはローカル構造体との間のデータのコピーを処理できませんか?
出力データは固定サイズの構造体ではないため、扱いにくい場合があります。マーシャラーがそれを自動的に処理できない可能性があることは理解しており、必要に応じて HGlobal とコピー ビジネスを実行しても問題ありません。
追加:
この質問は最初は役に立ちましたが、最終的には定数が正しくありませんでした。
私はunsafe
コンストラクトの使用に反対しているわけではありません。( fixed
-sizestruct
メンバーにはこれが必要です。)