2010-11-17 26 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