希望这是一个无脑的简单问题,但它表明我缺乏对C ++的专业知识。我是一名C#程序员,过去我和其他人的C ++ / C dll一起完成了P / Invoke的大量工作。但是,这次我决定自己编写一个包装器C ++ DLL(非托管),然后从C#调用我的包装器。
我遇到的问题是我无法定义可以通过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();
Everything编译,但是当我执行这个C#p / invoke调用时,我得到一个System.EntryPointNotFoundException:无法在DLL'Plugins \ TestDLL.dll'中找到名为'TestFunc'的入口点。
在C ++端,这肯定是非常简单的,我只是不知道它的语法。
答案 0 :(得分:13)
您需要使用extern "C"
以及__declspec(export)
,如下所示:
extern "C" _declspec(dllexport) bool TestFunc()
{
return true;
}
有关详细信息,请参阅MSDN on Marshalling Types。
答案 1 :(得分:7)
扩展里德的正确答案。
通过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);
}
答案 2 :(得分:1)
您必须使用extern "C"
公开此函数,否则名称会被破坏。
答案 3 :(得分:1)
C ++编译器修改函数的名称以包含有关参数和返回类型的信息。这称为名称修改。另一方面,C编译器不会破坏您的函数名称。
您可以使用extern "C"
:
extern "C" __declspec(dllexport) bool TestFunc { return true; }
要使用P / Invoke从C#调用函数,不得破坏您的名称。因此,您实际上可以将C函数导出到C#。如果您希望在C ++中实现该功能,您可以编写一个只调用实现该功能的C ++函数的C函数。
答案 4 :(得分:1)
做这样的事情:
#define EXPORT extern "C" __declspec(dllexport)
然后使用EXPORT关键字声明任何函数,例如c ++函数
BOOL getString(TCHAR* string, DWORD size);
会变成
EXPORT BOOL getString(TCHAR* string, DWORD size);
然后有趣的部分:转到VS控制台并输入:
dumpbin /EXPORTS <PATH_TO_GENERATED_DLL>
并且你会看到所有易于导出的函数的错误名称和序数,然后它只是一个问题或者是它们的推动
答案 5 :(得分:0)
使用Win32平台和适当的位(例如x86或x64)构建选项构建所有项目。