Marshal.PtrToStructure封送字符串为空

时间:2010-11-17 22:35:06

标签: c# marshalling

我正在尝试从byte []编组结构。除了编组一个字符串外,每个部分都有效。它看起来像一个BSTR:

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

那么,这是一个4字节的长度,然后是“你好!”在unicode中使用双null终止符。这是我玩过的编组码:

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。

1 个答案:

答案 0 :(得分:2)

问题是你定义的Schedule结构符合这种C结构:

struct Schedule {
    BSTR *Name;
};

虽然您正在修改的IntPtr内存中存在的结构具有布局:

struct Schedule {
    BSTR Name;
};

如果在Marshal.StructureToPtr()的实例上使用Schedule然后检查内存,您将看到只有前四个字节被设置,因为它们是一个指针。

不幸的是,在.NET中没有优雅的解决方法。您不能在结构中使用非指针字符串,因为结构将具有可变长度。

如果是一个选项,请完全放弃结构并坚持使用Marshal.PtrToStringAuto()