为什么在调用C#DLL时不需要提供字符串缓冲区?

时间:2018-07-13 06:21:26

标签: c# c++ dll com

我了解到,当C ++调用者使用另一个C ++ DLL时,调用者必须分配具有一定最大大小的字符串,并将该指针和最大大小传递给C ++被调用者/ DLL。

因此C ++调用程序将执行以下操作:

MyCPPDllFunction(char *out, int maxOutSize);

现在我了解到,当C ++调用程序使用C#DLL时,它看起来可能像这样:

char *output = MyCSharpDllFunction();

我不明白C#被调用者如何分配内存,而C ++被调用者却无法分配内存?

3 个答案:

答案 0 :(得分:2)

我不了解C#被调用者如何分配内存,而C ++被调用者却无法分配内存?

您正在寻找错误的问题。问题不在于“ C#如何分配内存”。任何人都可以分配内存...并且有很多方式:-)问题总是总是“您将如何释放内存?”,因为释放内存与分配内存一样重要(不释放内存将导致内存泄漏,这将使您的程序内存占用迅速膨胀,而使用错误的分配器释放它至少不会释放 (请参见上一点),并且将崩溃该程序最糟糕的)。

现在,操作系统(例如Windows)为您提供了一些任何人都可以使用的分配器(例如CoTaskMemAlloc),但是问题是通常在C / C ++中,您将使用malloc / new。问题就在这里:两个dll之间的分配器可能是“不同的”(不同):两个C / C ++中编译的dll(但例如使用不同版本的Visual C ++,调试或发布模式,或者一个使用运行时)作为dll,另一个直接链接运行时,或使用不同的C编译器编译的dll将具有不同的malloc(和C ++中的不同new)。具有不同的malloc / new,它们将具有不同的free / delete,因此一个DLL的free无法释放另一个DLL的内存dll。

现在...使用此签名:

void MyCPPDllFunction(char *out, int maxOutSize);

调用方必须分配内存...因此,调用方知道如何释放内存...没有内存泄漏:-)

具有此签名:

char *MyCPPDllFunction();

被呼叫者必须分配内存...现在,呼叫者如何释放它?被调用者可以导出另一种方法:

void FreeMemoryAllocatedByMe(void *ptr)
{
    free(ptr);
}

然后,呼叫者将调用它,并且所有问题都将得到解决,因为free将成为被呼叫者 free

现在...通常,当C#封送对象(和字符串)时,它使用CoTaskMemAlloc分配内存,并且期望如果接收到内存,则必须使用{{1}释放它}。因此,在您的C ++-> C#示例中,C ++应该

CoTaskMemFree

答案 1 :(得分:1)

我想原因如下:

从c ++调用c#api时,将调用CLR虚拟机管理的代码,因此内存分配由虚拟机本身自动管理,从而使您不必为手动缓冲区分配而烦恼。

答案 2 :(得分:1)

如何返回值与所使用的语言无关。它仅由函数的调用签名定义。所以我可以用C ++编写以下DLL源:

#include <windows.h>

BOOL WINAPI DllMain(
  _In_ HINSTANCE hinstDLL,
  _In_ DWORD     fdwReason,
  _In_ LPVOID    lpvReserved
)
{
    return TRUE;
}

__declspec(dllexport) char *function1()
{
    char *foo = new char[100];
    // do stuff to fill in foo
    return foo;
}

__declspec(dllexport) void function2(char *out, int maxOutSize)
{
    // do stuff to fill in out
}

这是完全合法的,并定义具有与OP问题中列出的两个功能完全匹配的签名的C ++入口点。

请注意,这使用C ++ new[]function1()分配内存,因此有必要在某个时候使用delete[]释放它。

同样,如果在C#情况下由CLR分配内存,则您需要将其传递回C#DLL以正确释放,或者找到在C ++中销毁它的安全方法,甚至可以进行这种操作。

我会在这里100%诚实地说,如果C ++运行时和C#CLR与内存分配配合得很好,我一点都不知道。因此,可能唯一的选择是将其传递回C#进行释放。

-编辑-

我还将链接这个问题以供进一步参考,因为它处理同一问题的观点不同,尤其是被接受的答案中包含一些非常有用的信息。

Passing strings from C# to C++ DLL and back -- minimal example