具有从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代码并在输入缓冲区上进行错误检查的驱动程序中IOCTL switch语句的源代码片段,其中inSize是nInBufferSize参数:
case IOCTL_TWL_WRITEREGS:
if ((pInBuffer == NULL) ||
(inSize < sizeof(IOCTL_TWL_WRITEREGS_IN)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
address = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->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#结构中正确定义嵌入式指针,或者我的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, ®, 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;
}
标签:struct,marshalling,c,pinvoke,pointers 来源: https://codeday.me/bug/20191210/2101624.html