我知道我不能使用 FFI 加载 C++ DLL(只有 C 可以工作),那么我该怎么做呢?如果我需要使用包装器,我该如何开始呢?
编辑:我无法以任何方式更改 DLL。
您可以使用 C++ DLL。您需要像这样导出函数(在 MSVC 中):
extern "C" __declspec(dllexport)
由于 C++ 名称修改(用于重载),您的函数签名将与 C 命名不同。例如,这个函数:
int foo(char* a, int b, double c)
可能会导出为foo@12abunchoflettershere
使用 C++ 命名之类的东西,而不是foo
像 C 命名那样。
请注意,extern "C"
这并不意味着您的代码是纯 C。您可以正常使用 C++。这仍然有效:
extern "C" __declspec(dllexport) void foo(char *a, int b, std::shared_ptr<Foo> ptr)
您可以尝试在 FFI cdefs 中手动修改名称,但不同的编译器使用不同的名称修改方案,更不用说引用函数会很尴尬。
我建议不要手动修改 cdef 中的名称,而是建议用 C 编写一些包装器。虽然很乏味,但并不难。它的要点是它的 C 端将类视为不透明的结构,以传递给包装函数。不过,请参阅此站点了解更多详细信息和一些问题。
这是我用于 Box2D 的包装器的示例片段:
#include <Box2D/Box2D.h>
#ifdef __linux__
#define CEXPORT extern "C"
#else
#define CEXPORT extern "C" __declspec(dllexport)
#endif
// ///////////////////////////////////////////////////////
// World
CEXPORT b2World* b2World_new(b2Vec2* gravity) {
return new b2World(*gravity);
}
CEXPORT void b2World_destroy(b2World* world) {
delete world;
}
CEXPORT b2Body* b2World_createBody(b2World* world, const b2BodyDef* def) {
return world->CreateBody(def);
}
CEXPORT void b2World_destroyBody(b2World* world, b2Body* body) {
world->DestroyBody(body);
}
CEXPORT void b2World_step(b2World* world, float32 timeStep, int32 velIters, int32 posIters) {
world->Step(timeStep, velIters, posIters);
}
CEXPORT b2Body* b2World_getBodyList(b2World* world) {
return world->GetBodyList();
}
以及对应的cdecl:
typedef struct b2World b2World;
b2World* b2World_new(b2Vec2*);
void b2World_destroy(b2World*);
b2Body* b2World_createBody(b2World*, const b2BodyDef*);
void b2World_destroyBody(b2World*, b2Body* body);
void b2World_step(b2World*, float, int32_t, int32_t);
b2Body* b2World_getBodyList(b2World*);