【发布时间】:2013-06-24 06:02:54
【问题描述】:
我正在使用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);
至少在我调用它时它没有抛出任何异常。那只是非常丑陋,而且是一个巨大的痛苦。编组器不能像我希望的那样处理向/从我的本地结构复制数据吗?
输出数据有时可能很棘手,因为它们不是固定大小的结构。我知道编组器不可能自动处理这个问题,我可以在需要的地方进行 HGlobal 和复制业务。
补充:
This question 起初看起来很有帮助,但最终它只是一个不正确的常量。
我不反对使用unsafe 构造。 (fixed-size struct 成员需要这个。)
【问题讨论】:
-
我知道@HansPassant 会知道这个问题的答案:-)
-
是的,我也希望是这样。
标签: c# pinvoke deviceiocontrol