2

我是 .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?

4

1 回答 1

2

问题是您的 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。例如,智能设备框架代码至少有 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);
于 2012-05-18T13:05:46.223 回答