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成员需要这个.)
解决方法
所以一般声明如下所示:
[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");
哪个应该比你所拥有的更漂亮,更可诊断.未经测试,应该很接近.