【问题标题】:Passing NON null-terminated strings to unmanaged code将非空终止字符串传递给非托管代码
【发布时间】:2016-03-11 02:18:41
【问题描述】:

考虑通过 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 是一个以空值结尾的字符串,而非托管 dll 不是 - 并且实际上使用最后一个字符(从编组器中总是出现空值)。

有什么想法吗?

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

【问题讨论】:

  • 使用 char[] 确实是这样做的方法。

标签: .net string interop pinvoke marshalling


【解决方案1】:

由于没有发布其他答案,这里是我找到的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 解决方案

【讨论】:

  • 我觉得很奇怪,没有 Marshalling 属性可以帮助封送非空终止字符串...
  • 我们最终隐藏(私有)了 char[] 字段,并使用 getter 和 setter 在结构上定义了一个公共属性,将 char[] 转换为字符串,反之亦然。它还会根据需要应用 Trim 和 Pad。
  • public string Foo { get => new string(this.foo); set => this.foo = value.ToCharArray(); } 添加这样的属性以减少痛苦。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    1. 让 dll 了解 NUL 终止的字符串;或
    2. 随消息发送字符计数,让 dll 了解该计数。

    任你选。

    --b

    【讨论】:

    • 我无法控制 dll。我实际上找到了一种解决方法,请参阅 OP。只是想知道是否有更好的方法,尽管我对此表示怀疑。
    猜你喜欢
    • 2013-03-06
    • 2011-09-06
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    相关资源
    最近更新 更多