C# · 12月 29, 2021

c# – Pinvoke DeviceIoControl参数

我正在使用 DeviceIoControl的C#项目工作.我已经咨询了相关的 Pinvoke.net page作为我的签名: [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 );

以前我从来没有看到对象和[MarshalAs(UnmanagedType.AsAny)],但MSDN documentation听起来很有希望:

A dynamic type that determines the type of an object at run time and marshals the object as that type. This member is valid for platform invoke methods only.

我的问题是:使用此签名的“最佳”和/或“适当”方式是什么?

例如,IOCTL_STORAGE_QUERY_PROPERTY希望InBuffer成为一个STORAGE_PROPERTY_QUERY的结构.似乎我应该能够定义该结构,创建一个新的实例,并将其传递给我的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并复制我需要的业务.

额外:

起初This question看起来很有帮助,但最终只是一个不正确的常数.

我不反对使用不安全的构造. (固定大小的struct成员需要这个.)

解决方法 DeviceIoControl是非常不友好的.但是你可以减少痛苦,你不必自己组织结构.你可以利用两件事情:C#支持方法重载,而pinvoke marshaller会相信你,即使你对这个声明说谎了.这对于结构是完美的,它们已经被封送成一串字节.什么DeviceIoControl()需要.

所以一般声明如下所示:

[DllImport(“Kernel32.dll”,SetLastError = true)]public static extern bool DeviceIoControl( SafeFileHandle hDevice,int IoControlCode,byte[] InBuffer,int nInBufferSize,byte[] OutBuffer,int nOutBufferSize,out int pBytesReturned,IntPtr Overlapped);

而且您会添加一个非常适合IOCTL_STORAGE_QUERY_PROPERTY的重载,假设您有兴趣返回STORAGE_DEVICE_DESCRIPTOR:

[DllImport(“Kernel32.dll”,ref STORAGE_PROPERTY_QUERY InBuffer,out STORAGE_DEVICE_DESCRIPTOR OutBuffer,IntPtr Overlapped);

你会这样称呼:

var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0,QueryType = 0 };var qsize = Marshal.SizeOf(query);STORAGE_DEVICE_DESCRIPTOR result;var rsize = Marshal.SizeOf(result);int written;bool ok = DeviceIoControl(handle,EIOControlCode.QueryProperty,ref query,qsize,out result,rsize,out written,IntPtr.Zero);if (!ok) throw new Win32Exception();if (written != rsize) throw new InvalidOperationException(“Bad structure declaration”);

哪个应该比你所拥有的更漂亮,更可诊断.未经测试,应该很接近.