编组结构,嵌入指针从C#到非托管驱动程序

我正在尝试使用P / Invoked DeviceIoControl()调用将C#(.NET Compact Framework 3.5)与Windows CE 6 R2流驱动程序连接。 对于其中一个IOCTL代码,驱动程序需要一个DeviceIoControl输入缓冲区,该缓冲区是包含嵌入指针的以下非托管结构:

typedef struct { DWORD address; const void* pBuffer; DWORD size; // buffer size } IOCTL_TWL_WRITEREGS_IN; 

我在C#中定义了结构:

 [StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public byte[] Buffer; public uint Size; } 

和我的P / Invoke签名为:

 [DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, UInt32[] lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped); 

但是,每当我在C#中调用DeviceIoControl()时,它总是返回false,最后一次Win32错误为ERROR_INVALID_PARAMETER 。 这是驱动程序中IOCTL switch语句的源代码片段,它处理IOCTL代码并对输入缓冲区进行错误检查,其中inSize是nInBufferSize参数:

  case IOCTL_TWL_WRITEREGS: if ((pInBuffer == NULL) || (inSize address; pBuffer = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->pBuffer; size = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->size; if (inSize < (sizeof(IOCTL_TWL_WRITEREGS_IN) + size)) { SetLastError(ERROR_INVALID_PARAMETER); break; } rc = TWL_WriteRegs(context, address, pBuffer, size); 

我试过硬编码大小应该通过驱动程序的错误检查没有成功,这表明它是一个编组问题。 我可能没有正确定义C#struct中的嵌入指针或者我的P / Invoke签名错误。 有任何想法吗?

提前谢谢,本

作为参考,我可以从C ++与驱动程序通信,没有这样的问题:

 IOCTL_TWL_WRITEREGS_IN reg; reg.address = 0x004B0014; unsigned char data = 0xBE; reg.pBuffer = &data; reg.size = sizeof(char); BOOL writeSuccess = DeviceIoControl(driver, IOCTL_TWL_WRITEREGS, &reg, sizeof(IOCTL_TWL_WRITEREGS_IN) + 1, NULL, 0, NULL, NULL); 

更新:这是有效的! 使用JaredPar的IntPtr建议并通过SwDevMan81的建议清理我的P / Invoke签名:

  [StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public IntPtr Buffer; public uint Size; } // elided byte regData = 0xFF; GCHandle pin = GCHandle.Alloc(regData, GCHandleType.Pinned); IoctlWriteRegsIn writeInBuffer = new IoctlWriteRegsIn{Address = twlBackupRegA, Buffer = pin.AddrOfPinnedObject(), Size = 1}; bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, (uint) Marshal.SizeOf(writeInBuffer) + 1, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero); // P/Invoke signature [DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, IntPtr lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped); 

编组具有内联指针的结构时,需要将该值定义为IntPtr而不是数组

 [StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public IntPtr Buffer; public uint Size; } 

通过用IntPtr替换byte [] 数组来试一试。

您可能必须指定byte []的大小(将64替换为实际大小)

 [StructLayout(LayoutKind.Sequential, Pack=1)] public struct IoctlWriteRegsIn { public uint Address; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] Buffer; public uint Size; } 

然后你应该能够像这样设置大小:

 IoctlWriteRegsIn io_struct = new IoctlWriteRegsIn(); io_struct.Address = 5; io_struct.Buffer = new byte[1] { 0xBE }; // size of buffer, not struct io_struct.Size = 1;//Marshal.SizeOf(io_struct); 

我会将P / Invoke调用更改为:

 [DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, IntPtr lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped); 

并使用它来调用它:

 uint num_bytes = (uint)Marshal.SizeOf(writeInBuffer); bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, num_bytes, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero);