Marshalling-Struktur mit eingebettetem Zeiger von C # auf nicht verwalteten Treiber

Ich versuche, C # (.NET Compact Framework 3.5) mit einem Windows CE 6 R2-Stream-Treiber zu verbinden, indem ich P / Invoked DeviceIoControl () -Aufrufe verwende. Für einen der IOCTL-Codes benötigt der Treiber einen DeviceIoControl-Eingabepuffer, bei dem es sich um die folgende nicht verwaltete Struktur handelt, die einen eingebetteten Zeiger enthält:

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

Ich habe die Struktur in C # wie folgt definiert:

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

und meine P / Invoke-Signatur als:

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

Wenn ich jedoch DeviceIoControl () in C # aufrufe, wird immer false zurückgegeben, mit dem letzten Win32-Fehler vonERROR_INVALID_PARAMETER. Hier ist ein Quellcode-Snippet aus der IOCTL-switch-Anweisung im Treiber, der den IOCTL-Code verarbeitet und den Eingabepuffer auf Fehler überprüft, wobei inSize der Parameter nInBufferSize ist:

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

Ich habe hartnäckige Codierungsgrößen ausprobiert, die die Fehlerprüfung des Treibers ohne Erfolg bestehen sollten, was darauf hindeutet, dass es sich um ein Marshalling-Problem handelt. Wahrscheinlich habe ich den eingebetteten Zeiger in der C # -Struktur nicht richtig definiert oder meine P / Invoke-Signatur ist falsch. Irgendwelche Ideen?

Danke im Voraus, Ben

Als Referenz kann ich ohne Probleme mit dem Treiber von C ++ sprechen:

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

Update: Hier ist was funktioniert! Verwendete JaredPars IntPtr-Vorschlag und bereinigte meine P / Invoke-Signatur durch SwDevMan81-Vorschlag:

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

Antworten auf die Frage(3)

Ihre Antwort auf die Frage