PInvoke的DeviceIoControl的参数
我正在使用C#项目 的DeviceIoControl
。我已经咨询了相关 Pinvoke.net页面我的签名:
I'm working on a C# project using DeviceIoControl
. I've consulted the related Pinvoke.net page for my signature:
[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
);
我从来没有见过对象
和 [的MarshalAs( UnmanagedType.AsAny
)
之前,但是的MSDN文档听起来前途:
I'd never seen object
and [MarshalAs(
UnmanagedType.AsAny
)]
before, but the MSDN documentation sounded promising:
一个动态型在运行时确定的对象的类型和编组对象作为该类型。 ,该成员是有效的平台,只调用方法
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
结构。好像我应该能够定义结构,创建一个新
实例,并将其传递给我的PInvoke签名:
For example, IOCTL_STORAGE_QUERY_PROPERTY
expects InBuffer
to be a STORAGE_PROPERTY_QUERY
structure. It seems like I should be able to define that struct, create a new
instance, and pass it to my Pinvoke signature:
var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0, QueryType = 0 };
DeviceIoControl(..., query, Marshal.SizeOf(query), ...);
不过,我只是得到了 System.ExecutionEngineException
这样做,所以我改成这样的:
However, I just got a System.ExecutionEngineException
doing that, so I changed to something like:
int cb = Marshal.SizeOf(typeof(...));
IntPtr query = Marshal.AllocHGlobal(cb);
...
Marshal.PtrToStructure(...);
Marshal.FreeHGlobal(query);
和它至少没有抛出任何异常,当我把它叫做。这只是非常难看,而在屁股一个巨大的痛苦,但。不能编组柄复制数据到/从我的本地结构就像我一直希望?
and it at least didn't throw any exceptions when I called it. That is just very ugly, and a huge pain in the butt though. Can't the marshaller handle copying data to/from my local structs like I was hoping?
输出数据有时可能会非常棘手,因为他们没有固定大小结构。我明白编组不可能自动处理这一点,我好与做HGLOBAL和复印业务,我需要
The output data can sometimes be tricky, because they aren't fixed-size structures. I understand the marshaller can't possibly handle that automatically, and I'm okay with doing the HGlobal and copy business where I need to.
其他:
的这个问题起初看起来有用,但是它最终只是被不正确的常量。
This question looked helpful at first, but it ended up just being an incorrect constant.
我不反对使用不安全结构。 (在固定
-size 结构
成员需要这一点。)
I'm not against using unsafe
constructs. (The fixed
-size struct
members require this.)
DeviceIoControl的相当不友好。但是,你可以把它痛苦少,你不必自己名帅的结构。您可以利用两件事情:C#支持方法重载和PInvoke的编组会相信你,即使你撒谎通过你的牙齿有关的声明。这是完美的结构,他们已经编组为字节BLOB。 。究竟是什么的DeviceIoControl()需要
DeviceIoControl is quite unfriendly. But you can make it less painful, you don't have to marshal structures yourself. Two things you can take advantage of: C# supports method overloads and the pinvoke marshaller will believe you, even if you lie through you teeth about the declaration. Which is perfect for structures, they are already marshaled as a blob of bytes. Just what DeviceIoControl() needs.
所以,一般性声明是这样的:
So the general declaration would look like this:
[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:
And you'd add an overload that's perfect for IOCTL_STORAGE_QUERY_PROPERTY, assuming you're interested in it returning a 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");
这应该看起来比你有什么更漂亮和更大量可诊断。未测试,应该是接近。
Which ought to look prettier and a lot more diagnosable than what you've got. Untested, ought to be close.