Как упорядочить неуправляемый буфер упакованных структур в c # - PullRequest
2 голосов
/ 03 февраля 2009

Я (успешно) вызываю функцию Windows FilterSendMessage в c #, используя следующую подпись pinvoke:

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

Параметр outBuffer заполняется произвольным числом структур (упакованных одна за другой), определенных в C как:

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

Полю name присваивается переменная длина строки Unicode с нулевым символом в конце. Поле len описывает общий размер структуры в байтах (включая строку имени). Я уверен, что нет ничего плохого в том, как обрабатываются структуры в неуправляемой стороне вещей.

Моя проблема возникает, когда я пытаюсь маршалировать outBuffer в экземпляр структуры BAH_RECORD, определенной в c # как:

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

Если я попытаюсь напечатать / просмотреть / отобразить bah.name, я получу мусор ...

Чтобы подтвердить, что outBuffer действительно содержит действительные данные, я сделал несколько грубых хакерских указателей в c #, чтобы пройти через него, дважды вызвав Marshal.ReadInt32 (чтобы покрыть первые 2 поля структуры), а затем несколько раз Marshal.ReadByte, чтобы заполнить byte [], который я затем использую в качестве аргумента для Encoding.Unicode.GetString () ... строка получается нормально, так что она определенно есть, я просто не могу заставить маршаллера правильно ее обработать ( если это вообще может?)

Любая помощь приветствуется

Steve

1 Ответ

1 голос
/ 03 февраля 2009

Проблема в том, что строка 'name' в вашей структуре C # BAH_RECORD маршалируется как указатель на строку (WCHAR *), но на стороне C это встроенный буфер WCHAR. Поэтому, когда вы упорядочиваете свою структуру, среда выполнения читает первые четыре байта буфера как указатель, а затем пытается прочитать строку, на которую она указывает.

К сожалению, во время выполнения нет способа автоматически маршалировать буферы переменного размера внутри структур, поэтому вам придется использовать маршалинг вручную (или, как вы говорите, «хакерство указателей»). Но когда вы перемещаете указатель, чтобы он указывал на буфер, вам не нужно отдельно читать байты, а затем преобразовывать их в строку - просто вызовите Marshal.PtrToStringUni.

...