将NON以null结尾的字符串传递给非托管代码

时间:2010-08-08 16:45:50

标签: .net string interop pinvoke marshalling

考虑通过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;
}

问题:marshaller假设foo是一个以空字符结尾的字符串,而非托管dll则没有 - 并且实际上使用了最后一个字符(它总是从编组器中返回null)。

有什么想法吗?

澄清:我不能只将SizeConst更改为43,因为我需要保持消息的总大小,以及结构中下一个字段的位置(根据现有的ICD)

3 个答案:

答案 0 :(得分: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...
}

TCP专家Stephen Cleary的similar解决方案

答案 1 :(得分:1)

您可以使用StructLayout(LayoutKind.Explicit ...)并使用[FieldOffset( n )]标记每个字段。这将允许您将SizeConst值增加到43,并仍然将下一个字段标记为从偏移量42开始。编组将编组42个字符串并忽略附加空终止符的第43个字节

答案 2 :(得分:0)

你有两个,只有两个选择:

  1. 让dll了解NUL终止的字符串;或
  2. 发送带有消息的字符计数,并让dll理解该计数。
  3. 其中一个,请选择。

    - b