2010-08-08 101 views
3

考慮通過TCP發送到非託管的dll傳遞非空值終止字符串非託管代碼

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct FooMessage 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)] 
    public string foo; 

    //More fields... 
} 

下面的結構使用下面的函數(信貸Cheeso):

public byte[] RawSerialize(T item) 
{ 
    int rawSize = Marshal.SizeOf(typeof(T)); 
    IntPtr buffer = Marshal.AllocHGlobal(rawSize); 
    Marshal.StructureToPtr(item, buffer, false); 
    byte[] rawData = new byte[ rawSize ]; 
    Marshal.Copy(buffer, rawData, 0, rawSize); 
    Marshal.FreeHGlobal(buffer); 
    return rawData; 
} 

問題:編組人員假設foo是一個以null結尾的字符串,而非託管dll則不會 - 並且實際上使用最後一個char(它總是從編組器中變爲null)。

任何想法?

澄清:我不能只是將SizeConst更改爲43,因爲我需要保留消息的總大小以及結構中下一個字段的位置(根據現有的ICD)

+0

使用char []確實是這樣做的方法。 – 2010-08-17 11:41:04

回答

2

由於沒有其他的答案已經發布,這裏是workaround我發現

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct FooMessage 
{ 
    // use this for non-null-terminated strings 
    // use default encoder to convert to and from string 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=42)] 
    public char[] foo; 

    //More fields... 
} 

另外一個similar解決方案通過TCP專家斯蒂芬·克利

+0

對我來說,似乎真的很奇怪,沒有編組屬性可以幫助封送非空終止的字符串... – pauloya 2010-08-25 13:18:41

+0

我們最終隱藏了(私有)char []字段並使用getter和setter在結構上定義了一個公共屬性將char []轉換爲字符串,反之亦然。它也適用於修剪和墊。 – pauloya 2010-08-25 13:22:24

0

你有兩個,只有兩個選擇:

  1. 使DLL都懂NUL結尾的字符串;或
  2. 發送一條字符數與消息,並讓dll明白數量。

一個或另一個,請選擇。

- B

+0

該DLL不在我的控制之下。實際上我發現了一個解決方法,請參閱OP。只是想知道是否有更好的方法,但我懷疑它。 – 2010-08-08 17:07:04

1

你可以使用StructLayout(LayoutKind.Explicit ...)並用[FieldOffset(n)]標記每個字段。這將允許您將SizeConst值增加到43,,而仍然將下一個字段標記爲從偏移量42開始。編組器將編組42個字符的字符串,並忽略附加空終止符的第43個字節。