Domanda

Sono (con successo) chiamando la funzione Windows FilterSendMessage in C # utilizzando la seguente firma PInvoke:

[DllImport("fltlib.dll")]
    public static extern IntPtr FilterSendMessage(
        IntPtr hPort,
        IntPtr inBuffer,
        UInt32 inBufferSize,
        IntPtr outBuffer,
        UInt32 outBufferSize,
        out UInt32 bytesReturned);

OutBuffer parametro viene compilata con un numero arbitrario di strutture (confezionati uno dopo l'altro), definito come C:

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

nome viene assegnata una lunghezza variabile, stringa unicode terminazione Null. Il len campo descrive la dimensione totale del struct in byte (inclusa la stringa nome). Sono fiducioso c'è niente di sbagliato con il modo le struct vengono gestiti nel lato non gestito delle cose.

Il mio problema si pone quando provo e il maresciallo della OutBuffer a un'istanza del struct BAH_RECORD, definito in c # come:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct BAH_RECORD
{
    public UInt32 evt;
    public UInt32 len;
    public string name;
}

IntPtr outBuffer = Marshal.AllocHGlobal(OUT_BUFFER_SIZE);

hResult = Win32.FilterSendMessage(hPortHandle, inBuffer, IN_BUFFER_SIZE, outBuffer, OUT_BUFFER_SIZE, out bytesReturned);

BAH_RECORD bah = (BAH_RECORD)Marshal.PtrToStructure(outBuffer, typeof(BAH_RECORD));

<snip>

Se provo e stampare / view / visualizzazione bah.name, ottengo spazzatura ...

Per confermare che OutBuffer realtà non contiene dati validi, ho fatto un po 'grezzo puntatore hackery in C # con il passo anche se, chiamando Marshal.ReadInt32 due volte (per coprire i primi 2 struct campi), e poi Marshal.ReadByte un paio di volte a popolano un byte [] che ho poi usato come argomento per Encoding.Unicode.GetString () ... la stringa viene fuori bene, quindi è sicuramente lì dentro, io proprio non riesco a ottenere il marshaller di gestirlo correttamente ( se ancora può?)

Qualsiasi aiuto apprezzato

Steve

È stato utile?

Soluzione

Il problema è che la stringa 'nome' nel vostro C # BAH_RECORD struct è marshalling come un puntatore a una stringa (WCHAR *), ma sul lato C è un buffer di linea WCHAR. Così, quando si effettua il marshalling tua struct il runtime legge i primi quattro byte del buffer come un puntatore e quindi tenta di leggere la stringa a cui punta.

Purtroppo, non v'è alcun modo per il runtime per marshal automaticamente i buffer variabili dimensioni dentro le strutture per cui sarà necessario utilizzare marshalling manuale (o, come si dice "puntatore aggiustamenti"). Ma quando si avanza il puntatore per puntare al buffer non è necessario leggere nel byte individualmente e poi convertirli in una stringa -. Basta chiamare Marshal.PtrToStringUni

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top