Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用嵌入指针将结构从C#编组到非托管驱动程序_C#_Struct_Pinvoke_Pointers_Marshalling - Fatal编程技术网

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

使用嵌入指针将结构从C#编组到非托管驱动程序,c#,struct,pinvoke,pointers,marshalling,C#,Struct,Pinvoke,Pointers,Marshalling,我正在尝试使用p/调用的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

我正在尝试使用p/调用的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#中的结构定义为:

我的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\u INVALID\u参数
。以下是驱动程序中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);
更新:这里是什么工作! 使用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替换字节[]数组来尝试一下。

您可能需要指定字节[]的大小(用实际大小替换64)

然后您应该能够如下设置大小:

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);
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);

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

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

确保你锁定IntPtr引用的内存,并在完成时取消锁定。向GC展示它是如何完成的:)也就是说,你将温和/不频繁且快速地返回/取消锁定:)我尝试了这个,但没有成功。我只需要传递一个字节就可以了——不需要整个缓冲区,因为我一次只需要写一个8位寄存器——所以我用SizeConst=1尝试了这个,但没有成功。同样的错误?您是否可以将LPEXBUFFER更改为IntPtr LPEXBUFFER,然后再试一次?您是否可以将您的呼叫发送到DeviceIoControl?我使用DeviceIoControl呼叫更新了问题。LPNBULL的大小看起来可疑,但它与我工作的C++代码(NIN BuffelStame= 13)中通过的一样,应该通过驱动程序的输入验证。我会尝试一下,但是注意在紧凑框架中不支持PACK。我按照您的建议定义了结构,然后进行了以下调用:ioctlwriteregsinwriteinbuffer=newioctlwriteregsin{Address=twlBackupRegA,Data=newintptr(0xFF),Size=1};bool writeSuccess=DeviceIoControlWrite(driverHandle,ioctltwriteregs,ref writeInBuffer,(uint)Marshal.SizeOf(ioctltwriteregs)+1,新uint[0],0,ref numbytes返回,IntPtr.Zero);大小和(Unt)元帅。SizeOf(IOCTLWTWRIGRIER)+ 1个东西匹配我的工作C++代码,所以我不认为这是原因。@本,你能把这个问题放到你的问题中吗?这真的很难在commetsI更新的问题,没有意识到评论将没有格式,抱歉!你能给我解释一下这行代码GCHandle pin=GCHandle.Alloc(regData,GCHandleType.pined);它到底在做什么?@FosterZ托管内存是流动的——对象可以并且将根据需要移动到不同的位置,而不是它们开始的位置。“固定”对象告诉垃圾收集器不要移动对象。封送对象时需要这样做,因为您在特定位置分配内存,然后将指向该内存位置的指针发送到本机代码。如果你没有固定内存,当本机代码查看它时,它可能是任何东西而不是你期望的对象。你把IntPtr放在内存中的一个随机值。你需要把指针分配给真正的内存操作,很好。现在可以了!非常感谢,我真的很感谢你的帮助。你能给我解释一下这行代码吗它到底在做什么?
uint num_bytes = (uint)Marshal.SizeOf(writeInBuffer);
bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, num_bytes, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero);
[StructLayout(LayoutKind.Sequential)]
public struct IoctlWriteRegsIn
{
    public uint Address;
    public IntPtr Buffer;
    public uint Size;
}