gpt4 book ai didi

从 dll 调用方法时 C# 应用程序阻塞

转载 作者:搜寻专家 更新时间:2023-10-31 01:53:17 24 4
gpt4 key购买 nike

我目前正在探索 C# 中的 DLL 导出函数和 P/调用。我创建了非常简单的 .dll:

测试.h

#ifndef TEST_DLL_H
#define TEST_DLL_H
extern "C" __declspec(dllexport) const char * __cdecl hello ();
extern "C" __declspec(dllexport) const char * __cdecl test ();
#endif // TEST_DLL_H

测试.cpp

#include <stdlib.h>
#include "test.h"
#include <string.h>

const char* hello()
{
char *novi = (char *)malloc(51);
strcpy(novi, "Test.");

return novi;
}

const char * test()
{
return "Test.";
}

我已经编译它并在 C# 项目中使用,如下所示:

    [DllImport("test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr hello();

[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern string test();

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(test());
IntPtr a = hello();
MessageBox.Show(Marshal.PtrToStringAnsi(a));
}

但它不起作用。 test() 被成功调用,我得到了正确的字符串。但是hello()只是挂掉了程序。如果我从 hello() 定义中删除 malloc 行并返回常量,一切正常,所以我想我现在知道 malloc 有问题。

此外,我在某处看到当返回类型为 char* 时不应使用字符串。如果这是真的,我们为什么要使用 IntPtr?

最佳答案

跨越 DLL 边界返回字符串的函数很难从 C 或 C++ 中可靠地调用,当您从 C# 中执行时它也不会变得更好。问题在于调用者将如何释放字符串缓冲区。这需要为 hello() 而不是为 test() 完成。很难猜测的事情。 hello() 函数需要使用 free() 函数,使用用于调用 malloc() 的完全相同的分配器。这只有在 DLL 和调用者共享相同的 CRT 实现时才有效。可能性很小。

pinvoke 编码器还必须释放字符串缓冲区。并通过唯一合理的选择 CoTaskMemFree() 来做到这一点。它使用 COM 使用的默认分配器。这不会有好结果,您的 C 代码没有使用 CoTaskMemAlloc()。可能的结果取决于操作系统。在 Vista 及更高版本上,您的程序将因 AccessViolation 而死,这些 Windows 版本使用严格的堆分配器,旨在使行为不当的程序崩溃。在 XP 上,您会遇到内存泄漏和堆损坏之间的问题,听起来您选择了第二个选项。

将返回值声明为 IntPtr 就圆满结束了。好吧,你的程序不会崩溃,你仍然有无法堵塞的内存泄漏。无法可靠地调用 free()。或者在您的 C 代码中使用 CoTaskMemAlloc(),这样 pinvoke 编码器的释放调用就会起作用。

但实际上,不要像这样编写 C 代码。始终使用调用者分配的内存,因此永远不会猜测谁拥有内存。这需要类似于这样的函数签名:

extern "C" __declspec(dllexport) 
int hello(char* buffer, int bufferSize);

关于从 dll 调用方法时 C# 应用程序阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11386011/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com