Hvordan Marshal uovervåkede buffer av pakket structs i C #

stemmer
2

Jeg (hell) å kalle Windows FilterSendMessage funksjon i C # ved hjelp av følgende pinvoke signatur:

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

Den outBuffer parameter er befolket med et vilkårlig antall structs (pakket ene etter den andre), definert i C som:

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

Den navn feltet er tilordnet en variabel lengde, null-terminert unicodeverdien streng. Den len feltet beskriver den totale størrelsen på struct i byte (inkludert navnstrengen). Jeg er sikker på det ikke er noe galt med hvordan structs blir håndtert i uovervåkede siden av ting.

Mitt problem oppstår når jeg prøver og Marshal den outBuffer til en forekomst av BAH_RECORD struct, definert i C # som:

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

Hvis jeg prøver og print / visning / display bah.name, får jeg søppel ...

For å bekrefte at outBuffer betyr faktisk inneholder gyldige data, gjorde jeg noen råolje pekeren hackery i C # for å gå om det, ringer Marshal.ReadInt32 to ganger (for å dekke de første 2 struct felt), og deretter Marshal.ReadByte et par ganger for å fylle en byte [] som jeg da bruke som argument for å Encoding.Unicode.GetString () ... strengen kommer ut fine, så det er definitivt der, jeg bare ikke kan synes å få marshaller å håndtere det på riktig måte (hvis det enda kan?)

Alle hjelpe verdsatt

Steve

Publisert på 03/02/2009 klokken 07:14
kilden bruker
På andre språk...                            


1 svar

stemmer
1

Problemet er at 'navnet' strengen i C # BAH_RECORD struct er formidlet som en peker til en streng (WCHAR *), men på C siden det er en inline WCHAR buffer. Så når du marskalk din struct runtime leser de fire første byte av bufferen som en peker og deretter forsøker å lese strengen at den peker til.

Dessverre er det ingen måte for kjøretids automatisk Marshal variable størrelse buffere inne structs så du må bruke manuell marshaling (eller som du sier "pekeren hackery"). Men når du avanserer pekeren å peke på buffer trenger du ikke å lese i byte individuelt og deretter konvertere dem til en streng - bare ringe Marshal.PtrToStringUni.

Svarte 03/02/2009 kl. 10:29
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more