首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调用DeviceIoControl参数

调用DeviceIoControl参数
EN

Stack Overflow用户
提问于 2013-06-24 06:02:54
回答 1查看 9.1K关注 0票数 13

我正在使用C#进行一个DeviceIoControl项目。我已经查阅了相关的Pinvoke.net页面供我签名:

代码语言:javascript
复制
[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签名:

代码语言:javascript
复制
var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0, QueryType = 0 };
DeviceIoControl(..., query, Marshal.SizeOf(query), ...);

但是,我刚刚得到了一个System.ExecutionEngineException,因此我更改为如下所示:

代码语言:javascript
复制
int cb = Marshal.SizeOf(typeof(...));
IntPtr query = Marshal.AllocHGlobal(cb);
...
Marshal.PtrToStructure(...);
Marshal.FreeHGlobal(query);

我叫它的时候它至少没有抛出任何异常。这实在是太丑了,而且屁股也很疼。封送处理程序不能像我希望的那样处理到/从本地结构复制数据吗?

输出数据有时可能很棘手,因为它们不是固定大小的结构。我理解编组程序不可能自动处理这个问题,我可以在需要的地方执行HGlobal和复制业务。

补充:

起初,这个问题看起来很有帮助,但最终它只是一个不正确的常量。

我并不反对使用unsafe结构。( fixed-size struct成员要求这样做。)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-27 23:35:53

DeviceIoControl很不友好。但你可以减轻痛苦,你不需要自己组织结构。您可以利用两件事: C#支持方法重载,pinvoke封送处理程序会相信您,即使您在声明上撒谎了。这对于结构来说是完美的,它们已经被封送成一个字节块。这正是DeviceIoControl()所需要的。

所以一般的声明应该是这样的:

代码语言:javascript
复制
[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很完美的重载:

代码语言:javascript
复制
[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
);

你会这样称呼它:

代码语言:javascript
复制
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");

它应该看起来更漂亮,比你所拥有的更适合诊断。未经检验,应该是接近的。

票数 24
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17268889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档