如何封送一个指向一系列以空结束的字符串的指针
本文关键字:一系列 结束 字符串 指针 何封送 一个 | 更新日期: 2023-09-27 18:09:33
我需要一些帮助。我有一个c++ API(无法访问源代码),我正在努力使用返回char*属性的方法,或者返回包含char*属性的结构。根据API的文档,返回值如下:
返回值如果函数成功,返回值是一个指针,指向一系列以空结束的字符串,每个字符串对应主机系统上的一个项目,以第二个空字符结束。下面的示例显示了缓冲区内容,其中<null>
表示终止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); }
每次迭代都正确地显示列表中的每个项目。
问题是,当使用Marshal.PtrToStringAnsi
将c++字符*转换为c#字符串时,它在第一个空字符处停止。
你不应该直接把char*
转换成字符串
您可以使用Marshal.Copy
将IntPtr
表示的char*
复制到byte[]
,然后根据需要提取尽可能多的字符串(参见Matthew Watson对于从托管数组中提取字符串的回答),但是您需要首先获得多字符串大小。
正如leppie建议的那样,您也可以使用Marshal.PtrToStringAnsi
提取第一个字符串,然后将指针增加该字符串的大小并提取下一个字符串,以此类推。当它提取一个空字符串(从最后一个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)
这种字符串称为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;
}