PInvoke的DeviceIoControl的参数

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.