来自C#代码的dll函数调用期间出错

时间:2011-03-19 20:55:19

标签: c# c++ pinvoke

我在c ++中创建了dll,并希望使用c#从中调用函数。我有一个错误,如果函数,程序调用,返回字符串。 Dll代码:

#include <string>
using namespace std;
#define EXPORT_API extern "C" __declspec(dllexport) 
EXPORT_API  void DllFunc()
{
    MessageBoxA(0,"DDL box", "Yeah!", 0);
}

EXPORT_API  string DllFuncStr()
{
    return "testStr";
}

C#应用程序代码:

[DllImport("dllka.dll")]
 static extern void DllFunc();
[DllImport("dllka.dll")]
static extern string DllFuncStr();

 private void btnStart_Click(object sender, RoutedEventArgs e)
 {
     DllFunc();
     string str = DllFuncStr();           
 }

“DllFunc();” - 效果不错,但在线“string str = DllFuncStr();”我有一个错误:

运行时遇到了致命错误。错误的地址是0x5e6dceca,在线程0x16b0上。错误代码是0xc0000005。此错误可能是CLR中的错误,也可能是用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括COM-interop或PInvoke的用户编组错误,这可能会损坏堆栈。

字符串类型有什么问题?如何解决这个问题?

2 个答案:

答案 0 :(得分:5)

您无法将std :: string从C ++封送到C#。而是使用以StringBuilder编组的以零结尾的字符串,或返回BSTR。

BSTR方法非常简单。如果您更喜欢以零结尾的字符串,那么请在Web上查找来自Win32 API的示例P / Invokes,例如: GetWindowText函数()。

您使用cdecl调用约定从C ++导出,但在C#代码中使用stdcall。在对数据类型进行排序后,您需要将这些匹配起来。你使用哪个都没关系,只要它在两端都是一样的。

您还需要了解您的C ++代码使用char(8位编码)而C#使用Windows本机UTF-16这一事实。

如果是我,我会用BSTR来做,因为我在this answer中概述了另一个问题。

答案 1 :(得分:3)

正如David所说,c ++ std :: string和c#string是不同的东西。我在我的应用程序中按照以下方式进行了操作:

c ++ DLL代码:

EXPORT_API void DllFuncStr(char* sRetText, int nCapacity)
{
  if(!sRetText)
    return;

  std::string sRetTextStr("testStr");

  strcpy_s(sRetText, nCapacity, sRetTextStr.c_str());
  return;
}

c#应用程序代码:

[DllImport("dllka.dll")]
static extern bool DllFuncStr(StringBuilder sStrBuilder, int nCapacity);

private void btnStart_Click(object sender, RoutedEventArgs e)
{
  StringBuilder strBuilder = new StringBuilder(50);
  DllFuncStr(strBuilder, strBuilder.Capacity);
  string str = strBuilder.ToString();
}

(谢谢汉斯的建议。我也会在我的应用程序中修复此内容)