Marshal.PtrToStructure marshaled string is empty
I'm trying to marshal a struct from a byte[]. Each part works except marshaling a string. It looks to me like a BSTR:
06 00 00 00 48 00 65 00 6c 00 6c 00 6f 00 21 00 00 00
So, that's a 4-byte length then "Hello!" in unicode with a double null terminator. Here's the marshaling code I have toyed with:
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
Method 1 calls method 3 anyway, so this makes sense. However, I can't specify any type within the [MarshalAs(UnmanagedType.X)] attribute that will allow the structure to return anything meaningful whatsoever.
I have pared down the structure to this:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Schedule
{
[MarshalAs(UnmanagedType.BStr)]
public string Name;
}
I've literally tried all of the valid values for UnmanagedType.X and they either throw AccessViolationExceptions or return an empty string or return junk. None returns "Hello!". Am I not able to load this data into a struct?
Note: I cannot change the data, it is set in stone. I can, however, change my code. I have also pinned the byte[] so it is not being GC'ed.
The problem is that the Schedule
struct you are defining matches this kind of C struct:
struct Schedule {
BSTR *Name;
};
While the structure that exists in memory at the IntPtr
you are tinkering with has the layout:
struct Schedule {
BSTR Name;
};
If you use Marshal.StructureToPtr()
on an instance of Schedule
and then inspect the memory, you will see that only the first four bytes get set, because they are a pointer.
Unfortunately, there is no elegant workaround to this in .NET. You cannot use a non-pointer string in a struct because then the struct would be of variable length.
If it is an option, forgo the struct entirely and stick with Marshal.PtrToStringAuto()
.
精彩评论