2010-11-17 91 views
1

我试图从字节[]中封送一个结构。除了封送字符串之外,每个部分都工作。它看起来像我一个BSTR:Marshal.PtrToStructure封送的字符串为空

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

所以,这是一个4字节的长度,然后“你好!”在unicode中使用双空终止符。下面是我玩过的编组代码:

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化。

回答

2

的问题是,要定义这样的C结构相匹配的Schedule结构:

struct Schedule { 
    BSTR *Name; 
}; 

虽然,在你摆弄的IntPtr存在于内存中的结构具有布局:

struct Schedule { 
    BSTR Name; 
}; 

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

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

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

+0

现在我认为它很完美。谢谢。讨厌,但至少有一个解决方法,我可以从客户端代码中抽象出来。 – Gary 2010-11-18 08:00:40

+0

叶,与非托管代码互操作可以吸。至少你正在处理P/Invoke而不是JNI ... – cdhowie 2010-11-18 08:01:49

+0

这怎么可能与一个固定大小的字符串工作? – Tsury 2015-03-18 18:11:28