我正在尝试使用 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 < 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);