Marshal.PtrToStructure маршалированная строка пуста - PullRequest
1 голос
/ 18 ноября 2010

Я пытаюсь маршалировать структуру из байта [].Каждая часть работает, кроме маршалинга строки.Для меня это выглядит как BSTR:

06 00 00 00 48 00 65 00 6c 00 6c 00 6f 00 21 00 00 00

Итак, это 4-байтовая длина, а затем "Hello!"в юникоде с двойным нулевым терминатором.Вот код маршалинга, с которым я играл:

string auto = Marshal.PtrToStringAuto(nextSchedulePtr); // returns "Hello!"
string ansi = Marshal.PtrToStringAnsi(nextSchedulePtr); // returns "H"
string uni = Marshal.PtrToStringUni(nextSchedulePtr);   // returns "Hello!"
string bstr = Marshal.PtrToStringBSTR(nextSchedulePtr); // returns "Hel"
Schedule schedule = (Schedule)Marshal.PtrToStructure(nextSchedulePtr, typeof(Schedule)); // returns "" with UnmanagedType.BStr and UnmanagedType.LPWStr

Метод 1 в любом случае вызывает метод 3, так что это имеет смысл.Однако я не могу указать какой-либо тип в атрибуте [MarshalAs (UnmanagedType.X)], который позволит структуре возвращать что-либо значимое.

Я сократил структуру до следующего:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Schedule 
{
    [MarshalAs(UnmanagedType.BStr)]
    public string Name;
}

Я буквально перепробовал все допустимые значения для UnmanagedType.X, и они либо выдают AccessViolationExceptions, либо возвращают пустую строку, либо возвращаютмусор.Ни один не возвращает «Привет!».Разве я не могу загрузить эти данные в структуру?

Примечание: я не могу изменить данные, они в камне.Однако я могу изменить свой код.Я также закрепил байт [], чтобы он не был GC'ed.

1 Ответ

2 голосов
/ 18 ноября 2010

Проблема в том, что определяемая вами структура Schedule соответствует следующему виду структуры C:

struct Schedule {
    BSTR *Name;
};

В то время как структура, существующая в памяти в IntPtr, с которой вы работаете, имеет макет:

struct Schedule {
    BSTR Name;
};

Если вы используете Marshal.StructureToPtr() для экземпляра Schedule, а затем осмотрите память, вы увидите, что установлены только первые четыре байта, поскольку они являются указателем.

К сожалению, в .NET нет элегантного решения этой проблемы.Вы не можете использовать строку без указателя в структуре, потому что тогда структура будет иметь переменную длину.

Если это вариант, полностью отказаться от структуры и придерживаться Marshal.PtrToStringAuto().

...