我正在使用C#进行一个DeviceIoControl项目。我已经查阅了相关的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文档听起来很有前途:
一种动态类型,它在运行时确定对象的类型,并将对象作为该类型封送。此成员仅对平台调用方法有效。
我的问题是:使用此签名的“最佳”和/或“正确”方式是什么?
例如,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和复制业务。
补充:
起初,这个问题看起来很有帮助,但最终它只是一个不正确的常量。
我并不反对使用unsafe结构。( fixed-size struct成员要求这样做。)
发布于 2013-06-27 23:35:53
DeviceIoControl很不友好。但你可以减轻痛苦,你不需要自己组织结构。您可以利用两件事: C#支持方法重载,pinvoke封送处理程序会相信您,即使您在声明上撒谎了。这对于结构来说是完美的,它们已经被封送成一个字节块。这正是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", 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");它应该看起来更漂亮,比你所拥有的更适合诊断。未经检验,应该是接近的。
https://stackoverflow.com/questions/17268889
复制相似问题