我的问题是,我在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签名的调用约定和参数是否与目标非托管签名匹配。
我猜我得到这个错误,因为我没有正确的功能声明 任何人都可以指导我如何解决这个问题,提前谢谢
答案 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#不知道如何编组。你有两个选择:
char *
个缓冲区。或者写一个包装器或重载或使用char *
代替string
的东西。System::String
的C ++函数编写C ++ / CLI包装器,并在内部调用STL字符串版本。答案 3 :(得分:2)
如果内存服务,如果你没有指定,P / Invoke假定调用约定是__stdcall
。如果是这样,将__cdecl
更改为__stdcall
应该可以解决第一个问题。
正如@Adam Rosenfield指出的那样,您可能还需要传递并返回char const *
,而不是string
。 C#和C ++几乎肯定对构成字符串的内容有些不同。