【问题标题】:Pass pointer to object to dll将指向对象的指针传递给 dll
【发布时间】:2018-09-03 10:18:40
【问题描述】:

我正在编写这个 Editor.exe 程序,它加载一个 game.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 方面,从传递的对象指针调用函数会导致 未解析的外部符号

game.dll 对给定对象指针的调用示例如下:

void gameInit(ldk::Core* core)
{
    _core->renderer.drawText("initializing...");
}

如何编译 dll 使其不会尝试在 dll 模块中查找例如 drawText() 实现?

1 - 请注意,这不是关于如何声明指向成员函数的指针的问题。

2 - 我知道如果我传递一个只有指向方法的指针的结构,它可以很容易地修复,但我真的对此很好奇。

3 - 我使用的是 Microsoft 的 cl 编译器 18.00,它是 Visual Studio 2013

附带的

【问题讨论】:

    标签: c++ c dll visual-studio-2013 unresolved-external


    【解决方案1】:

    在几乎相同的设置下,我遇到了与您类似的问题 - 游戏为 dll,引擎为 exe。以下是有关如何解决此问题的一些说明。

    仅调用虚拟方法。 正如您所指出的,如果您调用的方法未声明为虚拟方法,则链接器会尝试为其查找实现并失败(如果它不在标头中 -我们尽量避免的事情)。方法不需要抽象,虚拟就够了。另外,请注意,在您的结构 Renderer 中,您可以拥有非虚拟的方法,只要您不从 dll 调用它们(如果这样做,链接器会抱怨)。有这样的接口可能是不可取的,最好有某种 API 类,它只有虚拟公共方法,这样这个类的用户就不会出错。

    从 dll 中使用的所有类都需要共享或仅标头。 我的意思是,据我所知,没有什么神奇的方法可以在标头中声明类,在编译成exe的cpp中实现,然后从dll中使用这些类。例如,如果你有一个自定义字符串类,它需要在一个共享库中。如果它只是在 exe 中,您将无法在 dll 中实例化它(从函数等中返回它)。对此的解决方案是使用仅标头类。例如,您的字符串可能在 Editor 项目的标头中实现,并且此标头可能包含在您的 Game 项目中。这样,您基本上可以将相同的代码编译为 exe 和 dll。

    要查看小型工作示例,请查看我的带有 VS 2017 解决方案的存储库,它演示了这个确切的问题,仅此而已。 repo link.

    在 idTech4 引擎 - DOOM 3 版本here 中可以看到这个问题的更大工作示例。它还使用游戏作为 dll 和引擎作为 exe。并且还需要交换指向游戏中使用的引擎系统的指针。这个项目很大,但是如果你一直看项目Game-d3xpGame.h,他们有游戏的API 和一个函数GetGameAPI_t,它期望得到带有指向引擎系统的指针的gameImport_t 结构并返回gameExport_t 和游戏信息。然后加载发生在Common.cpp

    如您所见,他们在各自的项目中使用共享库idLib 来处理idString 等内容。 dll 中使用的所有引擎类通常都非常小,并且仅在标头中实现(它们主要是结构)。

    请注意,id 本身正在远离这种架构,甚至他们最新版本的 DOOM 3 - DOOM 3 BFG edition 编译为单个 exe,并且模块是静态库而不是 dll。

    【讨论】:

    • @downvoter 如果你能告诉我你不喜欢什么,我很乐意改进这个问题。
    【解决方案2】:

    看来我想多了。 文编译editor.exe的核心应该被声明只是链接任何类。

    struct Core
    {
        struct Renderer
        {
            void drawText(const char* text);
        }
        ...
    }
    

    但是,由于编辑器和game.dll共享同一个Core.h,所以我使用宏将Core.h成员函数的声明修改为纯虚,例如:

    struct Core
    {
        struct Renderer
        {
            virtual void drawText(const char* text) = 0;
        }
        ...
    }
    

    所以未解析的外部符号链接错误消失了

    但是:我在 RUNTIME 中没有按预期工作! :(

    【讨论】:

      【解决方案3】:

      不清楚你在哪里初始化_core。乍一看gameInit 应该这样做。

      声明接口类Core,即它应该是抽象的。在后继类中实现它,例如 exe 中的 CoreImpl。这将修复未解析的外部符号。

      【讨论】:

      • Core 由 Editor.exe 实例化并传递给在 game.dll 上实现的 gameInit(Core* core)。
      猜你喜欢
      • 2014-03-31
      • 2023-03-27
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多