我有一个 C DLL,我正在 PInvoking。主要目标是获取 39 个字符的 GUID 字符串,例如 abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd
。
我首先调用一个方法来获取该字符串的大小,我预计该字符串为 39 个字符,然后调用另一个函数,向其传递一个容量为 39 的 StringBuilder
:
[DllImport("test.dll")]
public static extern int get_size();
[DllImport("test.dll")]
public static extern void get_string(StringBuilder result);
我的代码看起来像这样:
int size = get_size(); // Returns 40, because it includes the null terminating character.
var result = new StringBuilder(size - 1); // Gives it a capacity of 39. Subtracting 1 here because this does not fancy that null terminator over the marshaling layer.
get_string(result);
Console.WriteLine(result.ToString());
当我在控制台应用程序中调用它时,我得到以下结果:abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd
当我使用完全相同的代码从单元测试中调用它时,我得到以下结果:abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcdq
请注意末尾的 q
,这是添加的额外字符,并且通过调试单元测试,我可以验证 StringBuilder
对象的容量已增加尽管初始化时容量为 39,但在调用 get_string
后显着增加到 42。为什么会发生这种情况?这是正常的吗?难道我做错了什么?为什么只在单元测试中?
C 实现是这样的:
static char *_result = NULL; // At some point result is initialized and set.
int get_size() {
if (_result != NULL)
return strlen(_result) + 1;
return 1;
}
void get_string(char *result) {
if (result != NULL && _result != NULL)
strncpy(result, _result, strlen(_result));
}
最佳答案
这需要一些修复。
需要更改的函数签名:
[DllImport("test.dll")]
public static extern int get_size();
[DllImport("test.dll")]
public static extern void get_string(int resultSize, StringBuilder result);
C 实现需要更改:
static char *_result = NULL; // At some point result is initialized and set.
int get_size() {
if (_result != NULL)
return strlen(_result) + 1;
return 1;
}
void get_string(int resultSize, char *result) {
memset(result, 0, resultSize);
if (_result != NULL)
strncpy(result, _result, resultSize);
}
需要更改的 C# 调用:
int resultSize = get_size();
var result = new StringBuilder(resultSize); // Needed to also include the null Terminator ("I'LL BE BACK" - ARNOLD).
get_string(resultSize, result);
Console.WriteLine(result.ToString());
给 C 新手的注意事项...如果您不使用 char
,并且您使用的是 wchar_t
或其他内容以及字符串长度计算方法中,在执行诸如 memset
之类的操作时,您需要将缓冲区大小乘以 sizeof(wchar_t)
,因为字符串中的字符数之间存在很大差异以及字符串中的字节数。我只是碰巧知道 sizeof(char)
是 1,所以我在实现中省略了它以保存代码。
关于c# - 在单元测试中使用 StringBuilder 进行 PInvoking,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45103396/