c# - 在单元测试中使用 StringBuilder 进行 PInvoking

标签 c# .net c unit-testing pinvoke

我有一个 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/

相关文章:

c# - 使用VS2019创建WebService

c# - 检查输入是否为数字且仅包含数字 0-9

.net - dotnet build 未编译 .NET Framework 4.6.1 应用程序

C# - 追加文本文件

c - 如果我使用 GPA 指针,为什么在使用 scanf ("%lf", GPA) 时会出现段错误,如果不是指针,则在使用 scanf ("%lf", &GPA) 时会出现段错误?

c# - Windows 窗体应用程序 : Displaying rows of content

c# - UWP 径向进度条图像填充

c# - 设置 Azure 跟踪日志记录开关 - 为什么在 2 个位置而不是 1 个位置?

c - 写入文件时,fputs() 不会更改行

c++ - 更新数组中给定单元格范围的值的有效方法?