我正在进行一个使用
我以前从未见过
它至少在我调用时没有抛出任何异常。但这实在是太丑陋了,而且非常麻烦。难道 marshaller 不能像我希望的那样处理将数据复制到/从我的本地结构体中吗?
输出数据有时可能很棘手,因为它们不是固定大小的结构。我理解 marshaller 不可能自动处理这个问题,我可以接受在需要的地方进行 HGlobal 和复制操作。
另外:
一开始看起来这个问题很有帮助,但最终只是一个错误的常量。
我不反对使用 unsafe 构造。(fixed-size 结构成员需要这样做。)
DeviceIoControl
的 C# 项目。我参考了相关的 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
和[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);
它至少在我调用时没有抛出任何异常。但这实在是太丑陋了,而且非常麻烦。难道 marshaller 不能像我希望的那样处理将数据复制到/从我的本地结构体中吗?
输出数据有时可能很棘手,因为它们不是固定大小的结构。我理解 marshaller 不可能自动处理这个问题,我可以接受在需要的地方进行 HGlobal 和复制操作。
另外:
一开始看起来这个问题很有帮助,但最终只是一个错误的常量。
我不反对使用 unsafe 构造。(fixed-size 结构成员需要这样做。)