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

标签 c# c++

我目前正在探索 DLL 导出函数和 C# 中的 P/invoke。 我创建了非常简单的 .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);

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

相关文章:

c++ - 我必须使用什么 Uxtheme 函数来获取最小化、最大化和关闭按钮的默认大小?

c++ - 不使用OpenCV函数在C++中旋转图像

c++ - 在我关闭开始的子对话框并进入父对话框后,我的 qt 桌面应用程序一直崩溃

C# 从 C++ DLL 捕获输出

C# - 如何计算当前日期?

c# - 为什么应用程序会抛出多个 "Operation is not valid due to the current state of the object"错误?

c# - Asp.Net MVC 4 - 绑定(bind)到在 POST 中不起作用的复杂对象

c# - 如何在 EF6 中刷新上下文?

c# - Unity C# 中的泛型

C++ If 语句,从 else 开始重复