![](/img/trans.png)
[英]P/Invoke not returning expected result with StringBuilder parameter for call to GetUserDefaultLocaleName()
[英]P/Invoke a Function Passed a 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
。
你控制archive
功能的实现吗? 如果你这样做,你有几个选择。
1-让archive
功能分配缓冲区并将其返回给调用者。 缺点是调用者需要使用正确的函数来释放缓冲区,否则会冒内存泄漏甚至破坏堆的风险。
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);
}
您没有指定您的数据实际上是否为字符串,或者您是否使用stringbuffer来保存不透明的二进制数据。 如果响应数据是以null结尾的字符串,那么您可以轻松地使用PtrToStringUni
或PtrToStringAnsi
来获取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)
您无需为响应提供大小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.