如何设置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)构建选项构建所有项目。