我正在使用 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听起来很有希望:
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
结构体。看来我应该能够定义该结构,创建一个 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起初看起来很有用,但最终只是一个不正确的常量。
我不反对使用不安全
结构。 (fixed
-size struct
成员需要这个。)
最佳答案
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");
它应该比您现有的看起来更漂亮并且更易于诊断。未经测试,应该接近。
关于c# - Pinvoke DeviceIoControl 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17268889/