提问人:marciovmf 提问时间:3/25/2018 最后编辑:marciovmf 更新时间:7/20/2018 访问量:1388
将指向对象的指针传递给 dll
Pass pointer to object to dll
问:
我正在编写这个编辑器.exe程序,它加载游戏.dll,获取dll中函数的地址,并将指针传递给Core对象。
gameInitFuncPtr init =
(gameInitFuncPtr) GetProcAddress(LoadLibraryA("game.dll"),"gameInit");
init(&core); // core is already instanced somewhere, maybe on the stack
game.dll 包括定义 Core 类的 core.h。 Core 类已实现并编译为 Editor.exe。
在 dll 端,从传递的对象指针调用函数会导致 Unresolved 外部符号
game.dll 将对给定对象指针执行的调用示例如下:
void gameInit(ldk::Core* core)
{
_core->renderer.drawText("initializing...");
}
我怎样才能编译dll,使其不会尝试在dll模块中查找drawText()实现?
1 - 请注意,这不是关于如何声明指向成员函数的指针的问题。
2 - 我知道如果我传递一个只有指向方法指针的结构,它可以很容易地修复,但我对此真的很好奇。
3 - 我正在使用 Microsoft 的 cl 编译器 18.00,这是 Visual Studio 2013 附带的
答:
目前尚不清楚您在哪里初始化。乍一看应该这样做。_core
gameInit
声明接口类,即它应该是抽象的。在后继类中实现它,例如 exe 中的 CoreImpl。这将修复未解析的外部符号。Core
评论
看来我想多了。 温编译编辑器.exe,核心灵魂被声明,只需链接任何类。
struct Core
{
struct Renderer
{
void drawText(const char* text);
}
...
}
但是,由于编辑器和游戏.dll共享相同的Core.h,我使用宏将Core.h成员函数的声明修改为纯虚拟,例如:
struct Core
{
struct Renderer
{
virtual void drawText(const char* text) = 0;
}
...
}
因此,未解决的外部符号链接错误消失了
但是:我在 RUNTIME 中没有按预期工作!:(
我遇到了与您类似的问题,设置几乎相同 - 游戏作为 dll,引擎作为 exe。以下是有关如何解决此问题的一些说明。
仅调用虚拟方法。正如你所指出的,如果你调用的方法没有被声明为虚拟方法,链接器会尝试为它找到一个实现,但会失败(如果它不在标头中 - 我们试图避免这种情况)。方法不需要抽象,虚拟就足够了。另外,请注意,在您的结构中,您可以拥有非虚拟的方法,只要您不从 dll 调用它们(如果这样做,链接器会抱怨)。拥有这样的接口可能并不可取,最好有某种只有虚拟公共方法的 API 类,这样这个类的用户就不会犯错误。Renderer
dll 中使用的所有类只需要共享或仅标头。我的意思是,据我所知,没有神奇的方法可以在header中声明类,在cpp中实现,cpp被编译到exe,然后从dll中使用这些类。例如,如果您有一个自定义字符串类,它需要位于共享库中。如果它只是在 exe 中,您将无法在 dll 中实例化它(从函数等返回它)。解决此问题的方法是使用仅标头类。例如,您的字符串可能在 Editor 项目的标头中实现,并且此标头可能包含在您的游戏项目中。这样,您基本上可以将相同的代码编译为 exe 和 dll。
要查看一个小的工作示例,请参阅我的 VS 2017 解决方案存储库,该解决方案演示了这个确切的问题,仅此而已。回购链接。
这个问题的更大工作示例可以在idTech4引擎中看到 - DOOM 3版本在这里。它还使用游戏作为 dll,使用引擎作为 exe。并且还需要交换指向游戏中使用的引擎系统的指针。这个项目很大,但如果你一直看一下项目类 Game.h
,他们就会发现游戏的 API 只有一个函数,它期望通过指向引擎系统的指针获取结构,并返回游戏信息。然后加载发生在 Common.cpp
中Game-d3xp
GetGameAPI_t
gameImport_t
gameExport_t
如您所见,他们在各自的项目中使用共享库来执行诸如 .dll 中使用的所有引擎类通常都非常小,并且仅在标头中实现(它们大多是结构)。idLib
idString
请注意,id 本身正在远离这种架构,甚至他们最新版本的《DOOM 3 - DOOM 3 BFG edition》也编译为单个 exe,并且模块是静态库而不是 dll。
评论