使用 P/Invoke 调用带有 char* 参数的 C DLL 函数

发布于 2024-11-10 03:01:07 字数 1025 浏览 0 评论 0原文

我读过其他类似的问题,但它们没有解决这个特定的问题。我有一个带有 touppercase 函数的旧 C 库(作为示例)。这需要一个 char* 并返回一个 char*。然而,返回的指针是指向同一个字符串的指针(别问我不是我写的)。

该函数如下所示:

__declspec(dllexport)
char * __cdecl touppercase(char *ps_source)
{
    char *ps_buffer = NULL;

    assert (ps_source != NULL);

    ps_buffer = ps_source;
    while (*ps_buffer != '\0')
    {
        *ps_buffer = toupper(*ps_buffer);
        ps_buffer++;
    }
*ps_buffer = '\0';
    return (ps_source);
}

声明此函数的 C# 代码如下所示:

    [DllImport("mydll.dll", EntryPoint = "touppercase",
               CharSet = CharSet.Ansi, ExactSpelling = true,
               CallingConvention = CallingConvention.Cdecl)]
    private static extern System.IntPtr touppercase(string postData);

在我的应用程序中对此的调用如下所示

     string sTest2 = Marshal.PtrToStringAnsi(to_uppercase(sTest));

但是 sTest2 最终只是一个随机字符串。

我向同一个 dll 添加了一个具有相同参数的测试函数,但这会在本地分配内存并复制字符串。这很好用。为什么原来的版本现在可以用了?

注意:更新 dll 库本身不是一个选项。

I've read other similar questions on this but they don't solve this particular problem. I have an old C-library with a touppercase function (as an example). This takes a char* and returns a char*. However, the pointer returned is a pointer to the same string (don't ask me I didn't write it).

The function looks like this:

__declspec(dllexport)
char * __cdecl touppercase(char *ps_source)
{
    char *ps_buffer = NULL;

    assert (ps_source != NULL);

    ps_buffer = ps_source;
    while (*ps_buffer != '\0')
    {
        *ps_buffer = toupper(*ps_buffer);
        ps_buffer++;
    }
*ps_buffer = '\0';
    return (ps_source);
}

The C# code to declare this looks like:

    [DllImport("mydll.dll", EntryPoint = "touppercase",
               CharSet = CharSet.Ansi, ExactSpelling = true,
               CallingConvention = CallingConvention.Cdecl)]
    private static extern System.IntPtr touppercase(string postData);

The call to this in my app looks like

     string sTest2 = Marshal.PtrToStringAnsi(to_uppercase(sTest));

However sTest2 just ends up being a random string.

I added a test function to the same dll with the same parameters but this allocates memory locally and copies the string. This works fine. Why does the original version now work?

Note: Updating the dll libraries themselves isn't an option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情何以堪。 2024-11-17 03:01:07

该函数正在修改引用,因此您应该使用字符串构建器:

[DllImport("dll.dll", EntryPoint="touppercase",
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr touppercase(StringBuilder postData);

将其称为这样的:

    StringBuilder sTest = new StringBuilder("abs");
    touppercase(sTest);
    string result = sTest.ToString();

对于返回指针的解释 ->本·沃伊特

The function is modifying the reference so you should use a stringbuilder:

[DllImport("dll.dll", EntryPoint="touppercase",
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern System.IntPtr touppercase(StringBuilder postData);

Call it something like this:

    StringBuilder sTest = new StringBuilder("abs");
    touppercase(sTest);
    string result = sTest.ToString();

For the explanation of the return pointer -> Ben Voigt

计㈡愣 2024-11-17 03:01:07

正如您所观察到的,返回类型是指向同一字符串的指针。提供给函数的字符串是 .NET 用于 Unicode->ANSI 转换的临时缓冲区,在 P/Invoke 返回之前释放。所以它是一个必须忽略的野指针(最好只使用 C# void 返回类型)。

我还建议使用 StringBuilder 作为参数而不是 String,这让 .NET 知道该函数将更改传递的参数。 StringBuilder 的内容将由该函数修改,这就是您在没有返回值的情况下获取结果的方式。

As you correctly observed, the return type is a pointer to the same string. And the string provided to the function is a temporary buffer used by .NET for Unicode->ANSI conversion, deallocated before P/Invoke returns. So it's a wild pointer which you must ignore (best to just use C# void return type).

I would also recommend using StringBuilder for the parameter instead of String, this lets .NET know that the function will change the parameter passed. The content of the StringBuilder will be modified by the function, that's how you get your results without a return value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文