P /调用函数传递StringBuilder

在C#文件中我有一个

class Archiver { [DllImport("Archiver.dll")] public static extern void archive(string data, StringBuilder response); } 

字符串数据是一个输入,StringBuilder响应是函数写入的东西

归档函数原型(用C编写)如下所示:

 void archive(char * dataChr, char * outChr); 

它在dataChr中接收一个字符串,然后执行a

 strcpy(outChr,"some big text"); 

从C#我称之为:

 string message = "some text here"; StringBuilder response = new StringBuilder(10000); Archiver.archive(message,response); 

这是有效的,但问题是,你可能会看到我给StringBuilder大小一个值,但是归档函数可能会返回一个(方式)更大的文本,而不是我给我的StringBuilder的大小。 有任何解决这个问题的方法吗?

您需要编写一个函数来告诉您StringBuilder需要多大,然后调用该函数来初始化StringBuilder

你是否控制了archivefunction的实现? 如果你这样做,你有几个选择。

1-让archivefunction分配缓冲区并将其返回给调用者。 缺点是调用者需要使用正确的函数来释放缓冲区,否则会冒内存泄漏甚至破坏堆的风险。

2-将您拥有的缓冲区大小传递给archive函数,以便在填充缓冲区时不会超过缓冲区长度。

3-如果你有一个可以返回所需缓冲区大小的函数,那么你可以使用它。 这是Windows API中的常用方法,将null作为缓冲区和指向DWORD的指针传递,该DWORD接收所需的缓冲区大小,然后您可以分配并进行第二次调用以传递分配的缓冲区。

我会让非托管代码分配内存,然后让托管端通过IntPtr将其复制到托管数组并释放分配。

您需要首先使您的非托管函数返回其输出数组的大小:

 void archive(char * dataChr, char * outChr, int length); 

然后管理方需要将其作为IntPtr:

 class Archiver { public static byte[] Archive(string data) { IntPtr responsePtr = IntPtr.Zero; int length = 0; // Call the unmanaged function with our output params archive(data, responsePtr, length); byte[] responseArray; try { // Create an array for the response responseArray = new byte[length]; // Copy from unmanaged into managed Marshal.Copy(responsePtr, responseArray, 0, length); } finally { // Free the unmanaged memory once copied Marshal.FreeHGlobal(responsePtr); } return responseArray; } [DllImport("Archiver.dll")] private static extern void archive(string data, [Out]IntPtr encoded, [Out]int length); } 

您没有指定您的数据实际上是否为字符串,或者您是否使用字符串缓冲区来保存不透明的二进制数据。 如果响应数据是以null结尾的字符串,那么您可以轻松地使用PtrToStringUniPtrToStringAnsi来获取string而不是简单数组:

在非管理方面:

 void archive(char * dataChr, char * outChr); 

在管理方面:

 class Archiver { public static string Archive(string data) { IntPtr responsePtr = IntPtr.Zero; // Call the unmanaged function with our output params archive(data, responsePtr); string responseString; try { // Marshal the string from unmanaged SZ String responseString = Marshal.PtrToStringAnsi(responsePtr); } finally { // Free the unmanaged memory once copied Marshal.FreeHGlobal(responsePtr); } return responseString; } [DllImport("Archiver.dll")] private static extern void archive(string data, [Out]IntPtr encoded); } 

注意:我没有测试任何代码,所以可能会有一些小的遗漏或错误……

我有一个非常类似的问题,但我有dll的源代码,所以我添加了一个转储文件的函数,新的调用看起来像这样:

 cr012062(query,filename) 

然后我会读取文件内容

 File.ReadAllText(filename) 

您无需为响应提供大小。