【问题标题】:NETCF how do I pass a struct by ref to DeviceIoControlNETCF 如何通过 ref 将结构传递给 DeviceIoControl
【发布时间】:2012-05-18 08:49:00
【问题描述】:

我是 .NET 紧凑型框架的新手。我需要调用 DeviceIoControl 函数并将结构作为输入和输出参数传递给 IOControl 函数。

PInvoke/DeviceIoControl 中,我找到了如何访问函数本身。但是如何将结构指针作为InBufOutBuf 参数传递?

DeviceIoControl 被定义为 P/Invoke:

[DllImport("coredll", EntryPoint = "DeviceIoControl", SetLastError = true)]
  internal static extern int DeviceIoControlCE(
    int hDevice, int dwIoControlCode,
    byte[] lpInBuffer, int nInBufferSize,
    byte[] lpOutBuffer, int nOutBufferSize,
    ref int lpBytesReturned, IntPtr lpOverlapped);

有问题的结构具有以下布局:

struct Query
{
  int a;
  int b;
  char x[8];
}

struct Response
{
  int result;
  uint32 success;
}

void DoIoControl ()
{
  Query q = new Query();
  Response r = new Response();
  int inSize = System.Runtime.InteropServices.Marshal.SizeOf(q);
  int outSize = System.Runtime.InteropServices.Marshal.SizeOf(r);
  NativeMethods.DeviceIoControlCE((int)handle, (int)IOCTL_MY.CODE,
    ref q, inSize, ref r, outSize, ref bytesReturned, IntPtr.Zero);   
}

编辑: 当我尝试编译此代码时,出现错误:

cannot convert from 'ref MyNamespace.Response' to 'byte[]'

如何将结构的地址传递给 DeviceIoControl 函数,它需要一个指向字节的指针而不是 struct ref?

【问题讨论】:

    标签: c# windows-ce .net-cf-3.5


    【解决方案1】:

    问题是您的 P/Invoke 声明与您的调用不匹配。 DeviceIoControl 接收输入/输出参数的指针:

    BOOL DeviceIoControl(
      HANDLE hDevice, 
      DWORD dwIoControlCode, 
      LPVOID lpInBuffer, 
      DWORD nInBufferSize, 
      LPVOID lpOutBuffer, 
      DWORD nOutBufferSize, 
      LPDWORD lpBytesReturned, 
      LPOVERLAPPED lpOverlapped
    );
    

    因此,您可以通过多种方式“调整”您的声明。您提供的链接中的那个使用byte[] 可能是为了方便他们使用它。在您的情况下,由于您传递的是简单的结构(即没有指向其他数据的内部指针),那么最简单的“修复”就是更改您的 P/Invoke 声明:

    [DllImport("coredll", SetLastError = true)]    
    internal static extern int DeviceIoControl(    
        IntPtr hDevice, 
        IOCTL.MY dwIoControlCode,    
        ref Query lpInBuffer,
        int nInBufferSize,    
        ref Response lpOutBuffer, 
        int nOutBufferSize,    
        ref int lpBytesReturned, 
        IntPtr lpOverlapped);    
    

    你的代码应该可以工作。请注意,我还更改了前两个参数的类型,以使您的调用代码在没有强制转换的情况下更加清晰。

    编辑 2

    如果您发现需要不同的签名,只需重载 P/Invoke。例如,Smart Device Framework 代码至少有 11 个用于 DeviceIoControl 的重载。以下只是其中的一些,让您尝尝鲜:

        [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal static extern int DeviceIoControl<TInput, TOutput>(
            IntPtr hDevice,
            uint dwIoControlCode,
            ref TInput lpInBuffer,
            int nInBufferSize,
            ref TOutput lpOutBuffer,
            int nOutBufferSize,
            out int lpBytesReturned,
            IntPtr lpOverlapped)
            where TInput : struct
            where TOutput : struct;
    
        [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal unsafe static extern int DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            void* lpInBuffer,
            int nInBufferSize,
            void* lpOutBuffer,
            int nOutBufferSize,
            out int lpBytesReturned,
            IntPtr lpOverlapped);
    
        [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal static extern int DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            IntPtr lpInBuffer,
            uint nInBufferSize,
            IntPtr lpOutBuffer,
            uint nOutBufferSize,
            out int lpBytesReturned,
            IntPtr lpOverlapped);
    
        [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal static extern int DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            byte[] lpInBuffer,
            int nInBufferSize,
            IntPtr lpOutBuffer,
            int nOutBufferSize,
            out int lpBytesReturned,
            IntPtr lpOverlapped);
    

    【讨论】:

    • 克里斯,我包含了代码来说明我想要做什么,但错过了实际问题。现在很清楚我根本没有调用该函数,因为我得到了编译器错误。
    • 谢谢。我会检查这个,当我回来的时候。但是 ioctl 函数旨在根据代码执行许多不同的调用。对于每个代码,inBuf 和 outBuf 的结构可能会发生变化。所以我需要为下一个代码使用不同的类型。 C++ 将允许 C# 不允许的联合。如何处理这种不同类型的 in-/outBuf?
    • 使用不同的 P/Invoke 声明,本质上是很多重载。我将使用智能设备框架中的几个来更新我的答案。
    • 过载完成了这项工作。但是模板版本有问题,当 lpInBuffer 只是一个 UInt32 时。在那种情况下,当我通过“ref myUint32”时,我会得到一个 NotSupportedException。本例不调用服务中的iocontrol函数。
    • 因此限制它是一个结构。没有“一刀切”的声明来涵盖所有可能的用途——正如我所说,SDF 至少有 11 个重载(有 11 个聚集在一起,但我没有用 grep 找到所有的源)。
    猜你喜欢
    • 2012-07-29
    • 2019-11-09
    • 1970-01-01
    • 2013-11-15
    • 2020-12-20
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    相关资源
    最近更新 更多