我正在用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
);
我以前从未见过
object
和[MarshalAs(
UnmanagedType.AsAny
)]
,但MSDN documentation听起来很有希望:在运行时确定对象类型并将该对象封送为该类型的动态类型。此成员仅对平台调用方法有效。
我的问题是:使用此签名的“最佳”和/或“适当”方式是什么?
例如,
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);
当我调用它时,它至少没有抛出任何异常。那真是太难看了,不过屁股疼得厉害。不能像我希望的那样,将数据复制到本地结构中吗?
输出数据有时会很棘手,因为它们不是固定大小的结构。我知道马歇尔不可能自动处理这个问题,我可以做我需要的HGORD和复印业务。
附加:
This question起初看起来很有帮助,但最终只是一个不正确的常数。
我并不反对使用
unsafe
结构。(fixed
-sizestruct
成员需要此功能。) 最佳答案
设备控制非常不友好。但你可以让它不那么痛苦,你不必自己整理结构。你可以利用两件事:C.*支持方法重载,pPoECK封送器会相信你,即使你在声明中撒谎。这对于结构来说是完美的,它们已经被封送为一个字节块。正是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_属性的重载:
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
EIOControlCode IoControlCode,
ref STORAGE_PROPERTY_QUERY InBuffer,
int nInBufferSize,
out STORAGE_DEVICE_DESCRIPTOR OutBuffer,
int nOutBufferSize,
out int pBytesReturned,
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");
它应该看起来比你拥有的更漂亮,更容易诊断。未经测试,应该很接近。
关于c# - Pinvoke DeviceIoControl参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17268889/