从 C# Windows 应用程序调用 C dll 会导致 svchost.exe 崩溃
Calling a C dll from C# windows application causes the svchost.exe to crash
我创建了一个C DLL
,以便我可以在C#
应用程序中使用它。
我在C++
测试应用程序上测试了DLL
,它工作正常,但它在 C# 应用程序中不起作用。
由于某种原因,我无法构建DLL
的调试版本,因此我也无法在调试模式下运行C#
应用程序。DLL
调试配置找不到include directories
,就像在发布模式下一样,它工作得很好!
我需要说的是,我在下面给出了一个特定的方法,它会导致崩溃,从DLL
调用其他方法很好,并且可以按预期工作。 这是主要的实现:标头定义:
//use this function to classify an image
CDLL_API const char* Classify(const char* img_path, int N = 2);
.cpp实施
CDLL_API const char* Classify(const char * img_path, int N)
{
auto classifier = reinterpret_cast<Classifier*>(GetHandle());
std::vector<PredictionResults> result = classifier->Classify(std::string(img_path), N);
std::string str_info = "";
std::stringstream ss;
for (size_t i = 0; i <result.size(); ++i)
{
auto label = result[i].label;
auto acc = result[i].accuracy;
ss << "label=" << label << ",acc=" << acc << "|";
}
return ss.str().c_str();
}
C# 代码:
[DllImport(@"CDll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern string Classify([MarshalAs(UnmanagedType.LPStr)]string img_path,int N = 2);
//...
var s = Classify(txtFilePath.Text, 2);
MessageBox.Show(s);
所以我完全没有想到真正的原因是什么。
我看到您在 C# PInvoke 声明中指定了要Cdecl
(CallingConvention = CallingConvention.Cdecl
( 的调用约定;由于这也是C++代码中的默认调用约定,因此在这种情况下不应有任何调用约定不匹配。虽然,请注意,C 接口 DLL 的常见调用约定是__stdcall
。
我看到的问题是你从 C 接口 API 返回字符串的方式
CDLL_API const char* Classify(const char * img_path, int N) { ... return ss.str().c_str(); }
(顺便说一句,我认为ss
类似于std::ostringstream
对象。
使用输出字符串流(调用其str
方法(生成字符串,然后获得调用c_str
的原始 C 样式字符串指针。但是当函数退出时,字符串对象将被销毁,因此 C 样式的原始字符串指针不再有效。
若要将字符串从 C 接口 DLL API 返回到 C#,可以考虑以下选项之一:
-
从 C 接口 DLL返回
BSTR
字符串。使用SysAllocString
从原始 C 样式字符串指针创建BSTR
对象。请注意,BSTR
"自然"存储Unicode UTF-16编码的字符串,因此请确保将字符串转换为此编码。CLR 能够很好地管理BSTR
字符串,因此您不必注意释放字符串内存:这将是 CLR 的工作。 -
向 C 接口 DLL 函数添加几个参数:指向缓冲区的指针和缓冲区大小。这将是一个输出字符串缓冲区,由调用方(例如 C#(分配,从 DLL 导出的 C 接口 API 会将结果字符串写入该调用方提供的缓冲区。例如,这就是 Win32 API
GetWindowText
所做的(在 C# 端,输出字符串缓冲区可以由StringBuilder
对象表示(。
C# 中的string
类型与 C 中的const char *
不兼容。您必须使用StringBuilder
:
[DllImport("aCDLL.dll")]
public extern static void getabuilder(StringBuilder abuilder);
在 C dll 中:
extern "C" void __declspec(dllexport) __stdcall getabuilder(char *abuilder);
如果您不喜欢 StringBuilder,可以将字符串字符存储在用 C# 初始化并传递给 C 函数的byte
数组中:
[DllImport("aCDLL.dll")]
public extern static void getastring(byte[] data, ref int datalength);
在 C 中:
extern "C" void __declspec(dllexport) __stdcall getastring(const char *data, int *datalength);
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 终端不会为C++文件创建.exe文件吗
- 在Windows中以.exe的形式运行c++
- Visual Studio mkl_link_tool.exe链接错误
- PrintWindow函数在notepad.exe中出错
- VSCode C++ 编译的exe感染了Win32:TrojanX-gen[Trj]
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- 获取当前正在运行的 exe 名称(不是路径)
- 从 exe 文件 (Visual Studio ) 启动时调试断言失败
- 1d.exe找不到SFML文件?
- VI工作室代码错误无法打开输出文件主.exe
- 如何为每个客户生成自定义 exe
- 使用参数在 C# 的C++上运行.exe
- 在 ******.exe 中0x00000000772CA267 (ntdll.dll) 处未处理的异常:0xC0000
- 如何在Visual Studio Code中重命名我的a.exe文件?
- 解析引用 |exe/dll vs lib
- Q没有管理权限的 exe 无法启动维护工具
- 如何定义自定义生成配置类型,其中通常是.exe的目标改为 DLL
- Eclipse 没有在 Windows (C++) 中编译.exe
- 从 C# Windows 应用程序调用 C dll 会导致 svchost.exe 崩溃