如何设置C ++函数以便p / invoke可以使用它?
希望这是一个无脑的简单问题,但它表明我缺乏C ++的专业知识。 我是一名C#程序员,过去我和其他人的C ++ / C dll一起完成了P / Invoke的大量工作。 但是,这次我决定自己编写一个包装器C ++ DLL(非托管),然后从C#调用我的包装器dll。
我遇到的问题是我无法定义可以通过p / invoke找到的C ++函数。 我不知道这是什么语法,但这是我到目前为止所做的:
extern bool __cdecl TestFunc() { return true; }
最初我只是有这个,但它也没有用:
bool TestFunc() { return true; }
然后在C#方面,我有:
public const string InterfaceLibrary = @"Plugins\TestDLL.dll"; [DllImport( InterfaceLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "TestFunc" ), SuppressUnmanagedCodeSecurity] internal static extern bool TestFunc();
所有东西都编译,但是当我执行这个C#p / invoke调用时,我得到一个System.EntryPointNotFoundException:无法在DLL’Clusins \ TestDLL.dll’中找到名为’TestFunc’的入口点。
当然,在C ++端,这一定非常简单,我只是不知道它的语法。
您将要使用extern "C"
以及__declspec(export)
,如下所示:
extern "C" _declspec(dllexport) bool TestFunc() { return true; }
有关完整详细信息,请参阅编组类型上的MSDN 。
扩展里德的正确答案。
通过PInvoke公开C ++函数时可能遇到的另一个问题是使用无效类型。 PInvoke实际上只支持原始类型和普通旧数据结构/类类型的编组。
例如,假设TestFunc具有以下签名
void TestFunc(std::string input);
即使添加extern“C”和__declspec(dllexport)
也不足以公开C ++函数。 相反,您需要创建一个辅助函数,它只暴露PInvoke兼容类型,然后调用main函数。 例如
void TestFunc(const std::string& input) { ... } extern "C" _declspec(dllexport) void TestFuncWrapper(char* pInput) { std::string input(pInput); TestFunc(input); }
您必须使用extern "C"
公开此函数,否则名称会被破坏。
C ++编译器修改函数的名称以包含有关参数和返回类型的信息。 这称为名称修改。 另一方面,C编译器不会破坏您的函数名称。
您可以告诉C ++编译器使用extern "C"
作为C编译器:
extern "C" __declspec(dllexport) bool TestFunc { return true; }
要使用P / Invoke从C#调用函数,不得破坏您的名称。 因此,您实际上可以将C函数导出到C#。 如果您希望在C ++中实现该function,您可以编写一个只调用实现该function的C ++函数的C函数。
做这样的事情:
#define EXPORT extern "C" __declspec(dllexport)
然后使用EXPORT关键字声明任何函数,例如c ++函数
BOOL getString(TCHAR* string, DWORD size);
会成为
EXPORT BOOL getString(TCHAR* string, DWORD size);
然后是有趣的部分:转到VS控制台并输入:
dumpbin /EXPORTS
并且你会看到所有易于导出的函数的错误名称和序数,那么它只是一个问题
使用Win32平台和适当的位(例如x86或x64)构建选项构建所有项目。