您必须使用全局的 C 风格方法。其原因在此处描述。
基本上可以归结为:C 函数很好地转换为 DLL 导出,因为 C 在语言特性方面“更接近地面”。C 更直接地翻译成机器代码。C++ 在编译器级别做了很多工作,为您提供了许多不能在 C++ 环境之外使用的功能。出于这个原因,您的导出函数应遵循 C 风格,以便跨 DLL 边界正常运行。这意味着没有模板、没有内联代码、没有非 POD 类或结构。
考虑这段代码:
extern "C"
{
__declspec(dllexport) int GlobalFunc(int n)
{
return n;
}
namespace SomeNamespace
{
__declspec(dllexport) int NamespaceFunction(int n)
{
return n;
}
}
class MyClass
{
__declspec(dllexport) int ClassNonStatic(int n)
{
return n;
}
__declspec(dllexport) static int ClassStatic(int n)
{
return n;
}
};
}
这将导致以下 DLL 导出函数名称:
?ClassNonStatic@MyClass@@AAEHH@Z
?ClassStatic@MyClass@@CAHH@Z
全球函数
命名空间函数
除了 Visual Studio 构建的 C++ 项目之外,具有有趣命名的项目基本上与任何其他项目都不兼容。这称为name mangling,将一些类型信息嵌入到名称本身中,以解决我正在谈论的导出函数的限制。从技术上讲,您可以在外部使用这些函数,但它很脆弱,并且依赖于编译器特定行为的细微差别。
在 DLL 中导出函数的经验法则是:你能在 C 中做到这一点吗?如果你不能,那么几乎可以肯定你会引起问题。
请注意,即使是静态类方法(本质上是全局的),即使使用extern "C"
. 但是命名空间导出中的独立函数没有名称修改(尽管它们失去了命名空间范围)。
你可以开始明白为什么这个经验法则是有意义的。
如果你想导出一个类,让我们按照经验法则,像在 C 中那样设计 DLL 接口。这里有一个例子。让我们来看看这个 C++ 类:
class Employee
{
private:
std::string firstName;
std::string lastName;
public:
void SetFirstName(std::string& s)
{
this->firstName = s;
}
void SetLastName(std::string& s)
{
this->lastName = s;
}
std::string GetFullName()
{
return this->firstName + " " + this->lastName;
}
};
你不能只坚持__declspec(dllexport)
这一点。您必须为其提供一个 C 接口,并将其导出。像这样:
extern "C"
{
__declspec(dllexport) Employee* employee_Construct()
{
return new Employee();
}
__declspec(dllexport) void employee_Free(Employee* e)
{
delete e;
}
__declspec(dllexport) void employee_SetFirstName(Employee* e, char* s)
{
e->SetFirstName(std::string(s));
}
__declspec(dllexport) void employee_SetLastName(Employee* e, char* s)
{
e->SetLastName(std::string(s));
}
__declspec(dllexport) int employee_GetFullName(Employee* e, char* buffer, int bufferLen)
{
std::string fullName = e->GetFullName();
if(buffer != 0)
strncpy(buffer, fullName.c_str(), bufferLen);
return fullName.length();
}
}
然后在 C# 端再写一个小包装器,你就成功地封送了这个类。
专门针对 C# 编组,另一种选择是为您的类提供 COM 接口而不是 C 接口。本质上是一样的,但是有很多帮助类和特殊的编译器支持直接将 COM 支持添加到 C++ 类,而无需编写单独的包装器。COM 对象可以被 C# 直接引用。
不过,这对您的ios没有帮助...