如何从 C++ 中的 dll 实例化 class?

How can I instantiate a class from a dll in C++?

我正在为插件开发者编写 API,这样他们就可以通过我的 API 访问应用程序的 SDK。我的 API 在 header 文件中提供了宏和抽象 class*,plugin-devs 必须包含该文件才能从抽象基础 class 继承并实现必要的功能( *见下面的代码)。

就手头问题的研究而言,我通读了许多 MSDN 和 Whosebug 文章,发现这些最相关:

这个问题是关于获取继承抽象 class/interface 的实例,您希望插件开发人员在创建 .dll 文件时实现该实例。

也许我的方法不正确,我陷入了困境,但是 Reflections and/or COM 之类的东西似乎是我应该做的......只有 COM 对于此操作似乎有点过分,因为应用程序将成为 运行ning 客户端。 C++/CLI Reflections 上的这篇文章看起来很有前途,但我正在使用 C++17 Visual Studio 工作。

在最高级别,预期行为是:

  1. API.dll 加载插件目录(例如 plugin/plugin1.dllplugin/plugin2.dll)
  2. API.dll 通过抽象创建插件的单例实例 class' getPlugin()
  3. 调用插件实现的其他方法,值得注意的是load()

所以这里有一些关于插件开发者使用 API 的背景设置信息。 API 为 interface/abstract class 的开发者提供了 header 以及在宏中创建单例的方法。

API的:baseplugin.hpp

#ifdef BUILDINGAPI
#define PLUGINIMPORT 
#define PLUGINEXPORT  __declspec(dllimport)
#else
#define PLUGINIMPORT  __declspec(dllimport)
#define PLUGINEXPORT  __declspec(dllexport)
#endif

// Long macro defined here for creating/deleting singleton
#define PLUGIN(classType)                                           \
static std::shared_ptr<classType> singleton;                        \
extern "C" {                                                        \
    PLUGINEXPORT uintptr_t getPlugin()                                  \
    {                                                               \
        if(!singleton) {                                            \
            singleton = std::shared_ptr<classType>(new classType());\
        }                                                           \
        return reinterpret_cast<std::uintptr_t>(&singleton);        \
    }                                                               \
    PLUGINEXPORT void erasePlugin() {                               \
        if(singleton)                                               \
            singleton = nullptr;                                    \
      }                                                             \
}

// Abstract class defined here:

class PLUGINEXPORT baseplugin
{
public:
    virtual void load() = 0;
    virtual void unload() = 0;
};

因此插件开发人员可以使用以下方法快速创建插件:

插件的:plugin1.hpp

class plugin1: public baseplugin
{
public:
    virtual void load();
    virtual void unload();
// other useful plugin methods/vars
}

插件的:plugin1.cpp

PLUGIN(plugin1) // This creates getPlugin() and erasePlugin()
void plugin1::load() {
// do stuff
}
void plugin1::unload() {
// do stuff
}
// other functions

现在我只剩下加载 coding/building 和 API.dll 来加载插件 .dll 的目录。这是我目前的代码,我意识到不知道 RTTI 是行不通的:

API的:dllmain.cpp

typedef uintptr_t(*pFunc)();
HINSTANCE hinstLib = LoadLibrary(TEXT("plugin1.dll"));
if (hinstLib != NULL) {
    FARPROC ProcAdd = GetProcAddress(hinstLib, "getPlugin"); // address to singeleton function
    // If the function address is valid, call the function.  
    if (NULL != ProcAdd) {
        pFunc pPluginSingleton = (pFunc) ProcAdd;
        baseplugin* plugin1Singleton = (baseplugin*) pPluginSingleton(); // THIS LINE WORKS, I GET A POINTER TO A SINGLETON
        plugin1Singleton->load(); // THIS CRASHES!!!! 

这里可能值得注意的是,使用 plugin1.dll 的代码构建 API.dll 可以按预期工作。我现在 testing/figuring 不知道如何在 运行 时加载插件类型。我已经验证我能够使用调试器获取指向单例的指针,但是在将其转换为抽象 class 之后尝试 运行 加载方法时我崩溃了: 0xC0000005: Access violation executing location 0x80B1CCDC

您的应用程序对插件中定义的具体类型一无所知。它唯一可以操作的是在您的应用程序中定义的 classes。每个插件都需要提供一个工厂方法来创建插件中定义的具体类型的实例,以及 return 指向应用程序中定义的抽象 class 的指针。 Plugin1.dll:

中定义的类似内容
baseplugin* PLUGINEXPORT create_plugin()
{
    return new plugin1;
}

在您的应用程序中,您动态加载 Plugin1.dll,获取 create_plugin 函数的地址并调用它以获取 plugin1 class 的实例作为指向 baseplugin摘要class.

实现插件 API 的一个好方法是借助 boost::dll. It provides some helpfull tools for implementing a plugin mechanism. There is, for example, the Factory method in plugin