如何在 C# 中编组指向一系列以 null 结尾的字符串的指针?
Posted
技术标签:
【中文标题】如何在 C# 中编组指向一系列以 null 结尾的字符串的指针?【英文标题】:How do I marshal a pointer to a series of null-terminated strings in C#? 【发布时间】:2013-04-17 11:31:25 【问题描述】:我需要以下方面的帮助。我有一个 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);
每次迭代都会正确显示列表中的每个项目。
【问题讨论】:
你应该至少给出你使用的 C++ API 的签名,也许还有一些调用这个 API 的 C# 代码。 请添加调用c++ api的c#代码 你仔细检查结果(长度)? 如果你了解 C/C++,你可以在Marshal
类中找到处理非托管内存所需的所有工具,查看方法:AllocHGlobal
、FreeHGlobal
、Copy
重载、StringToPtr*
、PtrToString*
等。 Marshal
class + IntPtr
结构允许在 C# 代码中重现任何 C/C++ 内存管理技巧。
嗨,我已经用我目前正在使用的一些代码更新了我的帖子。
【参考方案1】:
问题在于,当使用Marshal.PtrToStringAnsi
将 C++ char* 转换为 C# 字符串时,它会在第一个空字符处停止。
您不应将char*
直接转换为字符串。
您可以使用Marshal.Copy
将IntPtr
表示的char*
复制到byte[]
,然后根据需要提取尽可能多的字符串(请参阅Matthew Watson's answer 以从托管数组中提取字符串),但是您'首先需要获取多字符串大小。
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)
【讨论】:
当它停止时,为什么不用strlen + 1
增加指针?
是的,这是另一种可能性,但他必须在正确的时间小心地停下来,也许循环遍历托管数组对于 C# 程序员来说是最简单的。
zakinster...你就是那个人。感谢大家的帮助和快速响应。它正在 100% 工作。我真的很感激。【参考方案2】:
这种字符串称为Multi-String
,在 Windows API 中很常见。
编组它们很繁琐。您要做的是将其编组为char[]
数组,而不是字符串,然后将char[]
数组转换为一组字符串。
See here for an example solution。我已将相关代码复制到此答案中,但它是从我提供的链接中复制的:
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;
【讨论】:
以上是关于如何在 C# 中编组指向一系列以 null 结尾的字符串的指针?的主要内容,如果未能解决你的问题,请参考以下文章
使用 C# P/Invoke 方法在 Struct 内编组数组