c ++中的字符串?

时间:2011-10-05 19:44:27

标签: c# c++ string pinvoke

我的问题是,我在DLL中有一些函数,例如:

#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
 return s;
}

每当我尝试从C#调用此函数时,以下是使用的代码:

[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);

我收到一个错误: 对PInvoke函数'Packer'的调用使堆栈失衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。

我猜我得到这个错误,因为我没有正确的功能声明 任何人都可以指导我如何解决这个问题,提前谢谢

4 个答案:

答案 0 :(得分:7)

std::string不能与PInvoke一起使用,因为C ++没有为其对象提供ABI,这对于正确清理堆栈,复制对象等是必需的。这是C ++最大的痛苦之一。

您必须使用char*指针和普通C API。简而言之,PInvoke不适用于C ++。

答案 1 :(得分:5)

我相信您已经知道,C ++ std::string实际上是一个模板。只有在实例化模板时(在这种情况下为std::basic_string<char>),该类型的对象的精确布局和方法的签名由C ++编译器确定。

不幸的是,有问题的C ++编译器可以访问所有相关信息(例如模板源代码)来做出这些决定。这就是为什么即使在不同的C ++编译器之间,模板之类的非C功能通常也不能“转移”,更不用说C ++和C#。

此外,C ++名称通常以特定于C ++编译器的方式“损坏”。

你必须改变你的原生方法的签名,所以它变成了一个“纯粹的”C函数:

  • 通过将函数声明为extern "C"(您已经在执行此操作),确保没有C ++名称损坏。
  • 使用char*参数代替std::string
  • 返回char*结果而不是std::string,但very careful如何执行此操作。
  • 确保您的DllImportAttribute.CallingConvention与C中的__cdecl__stdcall__fastcall相匹配。

答案 2 :(得分:4)

问题在于,您使用的是STL string类,C#不知道如何编组。你有两个选择:

  1. 重构您的C ++代码以使用char *个缓冲区。或者写一个包装器或重载或使用char *代替string的东西。
  2. 围绕使用System::String的C ++函数编写C ++ / CLI包装器,并在内部调用STL字符串版本。

答案 3 :(得分:2)

如果内存服务,如果你没有指定,P / Invoke假定调用约定是__stdcall。如果是这样,将__cdecl更改为__stdcall应该可以解决第一个问题。 正如@Adam Rosenfield指出的那样,您可能还需要传递并返回char const *,而不是string。 C#和C ++几乎肯定对构成字符串的内容有些不同。