3

我需要以下帮助。我有一个 c++ API(无法访问源代码),我正在努力处理返回 char* 属性或返回包含 char* 属性的结构的方法。根据 API 的文档,返回值如下:

返回值
如果函数成功,则返回值是指向一系列以空字符结尾的字符串的指针,主机系统上的每个项目都有一个,以第二个空字符结尾。以下示例显示了缓冲区内容,<null>表示终止空字符:

project1<null>project2<null>project3<null><null>

如果函数失败,返回值为NULL

我遇到的问题是 C# 中返回的指针仅包含第一个值... project1 在这种情况下。如何获得完整列表以便能够在托管端循环访问它们?

这是c#代码:

    [DllImport("vmdsapi.dll", EntryPoint = "DSGetProjectList", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr DSGetProjectList();

调用方法:

   IntPtr ptrProjectList = DSAPI.DSGetProjectList();
   string strProjectList = Marshal.PtrToStringAnsi(ptrProjectList).ToString();

strProjectList 仅包含第一项。
这是API头文件中的信息......

   DllImport char *DSGetProjectList dsproto((void));

这是我用于测试目的的 c++ 控制台应用程序的一些示例代码...

   char *a;
   a = DSGetProjectList( );
   while( *a ) { 
    printf("a=%s\n", a); 
    a += 1 + strlen(a); 
   } 

每次迭代都会正确显示列表中的每个项目。

4

2 回答 2

2

问题是,当使用 将 C++ char* 转换为 C# 字符串Marshal.PtrToStringAnsi时,它会在第一个空字符处停止。

您不应该直接将其转换char*为字符串。

char*您可以将由 an 表示的复制IntPtr到 a byte[]using Marshal.Copy,然后根据需要提取尽可能多的字符串(请参阅Matthew Watson的从托管数组中提取字符串的答案),但您需要先获取多字符串大小。

正如leppie建议的那样,您还可以使用提取第一个字符串,Marshal.PtrToStringAnsi然后将指针增加该字符串大小并提取下一个字符串,依此类推。当 is 提取空字符串(从最后一个 NULL 字符开始)时,您会停止。

就像是 :

IntPtr ptrProjectList = DSAPI.DSGetProjectList();
List<string> data;
string buffer;
do {
    buffer = Marshal.PtrToStringAnsi(ptrProjectList);
    ptrProjectList += buffer.size() + 1;
    data.Add(buffer);
}while(buffer.size() > 0)
于 2013-04-17T11:44:42.213 回答
0

这种字符串称为 a Multi-String,在 Windows API 中很常见。

编组它们很繁琐。您要做的是将其编组为char[]数组,而不是字符串,然后将char[]数组转换为一组字符串。

有关示例解决方案,请参见此处。我已将相关代码复制到此答案中,但它是从我提供的链接中复制的:

static List<string> MultiStringToList(char[] multistring)
{
    var stringList = new List<string>();
    int i = 0;

    while (i < multistring.Length)
    {
        int j = i;

        if (multistring[j++] == '\0') 
            break;

        while (j < multistring.Length)
        {
            if (multistring[j++] == '\0')
            {
                stringList.Add(new string(multistring, i, j - i - 1));
                i = j;
                break;
            }
        }
    }

    return stringList;
}
于 2013-04-17T11:56:13.910 回答