如何使用其指针将未知长度的 C++ 字符串编组为 C#?

How to marshal an unknown length C++ string to C# using its pointer?

我正在尝试将结构中动态分配的 char 数组编组到 C#。该结构有一个指向数组的指针。问题是 char 数组包含多个以空字符结尾的字符串,最后一个字符串以两个连续的空字符结尾。

如果我尝试将其编组为 LPStr,我只会得到 "list" 中的第一个字符串。

我尝试使用 UnmanagedMemoryStream,但它需要知道数组的长度。

有没有办法在不知道数组长度的情况下将字节作为流读取? (除了使用 n 长度字节缓冲区并继续增加指针直到找到两个连续的空终止字符)。

正如Hans Passant所建议的那样,唯一的办法就是Marshal.ReadByte(),所以最后你必须多次读取内存(PtrToStringAnsi至少读取两次加上我们所做的一次找到下一个字符串的开始位置)。

public static string[] IntPtrToStringArrayAnsi(IntPtr ptr)
{
    var lst = new List<string>();

    do
    {
        lst.Add(Marshal.PtrToStringAnsi(ptr));

        while (Marshal.ReadByte(ptr) != 0)
        {
            ptr = IntPtr.Add(ptr, 1);
        }

        ptr = IntPtr.Add(ptr, 1);
    }
    while (Marshal.ReadByte(ptr) != 0);

    // See comment of @zneak
    if (lst.Count == 1 && lst[0] == string.Empty)
    {
        return new string[0];
    }

    return lst.ToArray();
}

替代版本,避免对数组进行第二次扫描

private static List<string> IntPtrToStringArrayAnsi(IntPtr ptr)
{
    var lst = new List<string>();
    while (true)
    {
        var str = Marshal.PtrToStringAnsi(ptr);
        if (!string.IsNullOrEmpty(str))
        {
            lst.Add(str);
            ptr += str.Length + 1;
        }
        else
            break;
    }

    return lst.ToArray();
}