如何封送未知长度的C++;使用指针将字符串转换为C#?

如何封送未知长度的C++;使用指针将字符串转换为C#?,c#,c++,pinvoke,marshalling,C#,C++,Pinvoke,Marshalling,我试图将结构中动态分配的字符数组封送到C#。结构有一个指向数组的指针。问题是char数组包含多个以null结尾的字符串,最后一个字符串由两个连续的null字符终止 如果我尝试将其封送为LPStr,我将只得到“列表”中的第一个字符串 我尝试使用UnmanagedMemoryStream,但它需要知道数组的长度 有没有一种方法可以在不知道数组长度的情况下以流的形式读取字节?(除了使用长度为n的字节缓冲区,并不断增加指针,直到找到两个连续的空终止字符)。正如Hans Passant所建议的,唯一的方法

我试图将结构中动态分配的字符数组封送到C#。结构有一个指向数组的指针。问题是char数组包含多个以null结尾的字符串,最后一个字符串由两个连续的null字符终止

如果我尝试将其封送为
LPStr
,我将只得到“列表”中的第一个字符串

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


有没有一种方法可以在不知道数组长度的情况下以流的形式读取字节?(除了使用长度为n的字节缓冲区,并不断增加指针,直到找到两个连续的空终止字符)。

正如Hans Passant所建议的,唯一的方法是
封送.ReadByte()
,因此最后必须多次读取内存(
PtrToStringAnsi
至少读取两次,再加上我们为查找下一个字符串的起始位置所做的读取)

公共静态字符串[]IntPtrToStringArrayAnsi(IntPtr ptr)
{
var lst=新列表();
做
{
第一次添加(封送员ptr(ptr));
while(封送处理读取字节(ptr)!=0)
{
ptr=IntPtr.Add(ptr,1);
}
ptr=IntPtr.Add(ptr,1);
}
while(Marshal.ReadByte(ptr)!=0);
//见@zneak的评论
if(lst.Count==1&&lst[0]==string.Empty)
{
返回新字符串[0];
}
返回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();
}
私有静态列表IntPtrToStringArrayAnsi(IntPtr ptr)
{
var lst=新列表();
while(true)
{
var str=Marshal.PtrToStringAnsi(ptr);
如果(!string.IsNullOrEmpty(str))
{
第一次添加(str);
ptr+=结构长度+1;
}
其他的
打破
}
返回lst.ToArray();
}

这听起来在计算字符串长度方面应该没有问题。您必须自己封送它。使用marshal.ReadByte()将结构成员声明为IntPtr.Loop,以0为单位复制到字节[]中。使用Encoding.Default.GetString()要转换子字符串。直到找到第二个0。注意第一个字符串可能是空的。第一个字符串可能是空的。至少要考虑一次。@ HANSPASANT必须反转< <代码> > < /Calp> /<代码> do;< /Cord> >我不是OP,但在我看来,如果“第一个字符串”是空的,那么就要做。(整个字符串是
\0\0
),那么它应该返回一个空列表。@zneak我正在使用的API声明,在这种情况下,将返回一个空指针。不过,这是一个通用算法的良好调用。@Cesarhnandez最终这种字符串数组格式不支持空字符串:
“a\0\B\0”
将被视为
“a\0\0”
,因此将
“\0\0”
裁剪为空数组与格式一致。
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();
}