【问题标题】:How can I instantiate a class from a dll in C++?如何从 C++ 中的 dll 实例化一个类?
【发布时间】:2026-01-15 03:05:01
【问题描述】:

我正在为插件开发人员编写一个 API,以便他们可以通过我的 API 访问应用程序的 SDK。我的 API 在头文件中提供了一个宏和抽象类*,plugin-devs 必须包含这些宏和抽象类*,才能从抽象基类继承并实现必要的功能(*参见下面的代码)。

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

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

也许我的方法不正确,我已经陷入了困境,但是反射和/或 COM 之类的东西似乎是我应该做的......对于这个操作,只有 COM 似乎有点矫枉过正,因为应用程序将在客户端运行. C++/CLI Reflections 上的这篇文章看起来很有希望,但我正在使用 C++17 在 Visual Studio 中工作。

在*别,预期的行为是:

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

这里有一些关于插件开发人员使用 API 的背景设置信息。 API 为开发人员提供了接口/抽象类的标头以及在宏中创建单例的方法。

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

现在我要加载编码/构建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 可以按预期工作。我现在正在测试/弄清楚如何在运行时加载插件类型。我已经验证我能够使用调试器获取指向单例的指针,但是在将 load 方法强制转换为抽象类后尝试运行它时崩溃: 0xC0000005: Access violation executing location 0x80B1CCDC

【问题讨论】:

    标签: c++ dll dllimport


    【解决方案1】:

    使用boost::dll 是实现插件API 的好方法。它提供了一些有用的工具来实现插件机制。例如,Factory method in plugin

    【讨论】:

    • 事实证明,我为 API 实现的插件架构是正确的。这确实是我对插件 1 的 load() 函数的调用,这才是问题所在。我接受这个答案,因为它提供了 boost::dll 作为参考,以表明我确实正确使用了接口并消除了任何疑问。不过我会说实际上并不需要 reinterpret_cast。
    【解决方案2】:

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

    baseplugin* PLUGINEXPORT create_plugin()
    {
        return new plugin1;
    }
    

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

    【讨论】:

    • 这不是我的宏在做什么吗?我意识到我在关于宏的原始问题中有一个错字,其中DLLIMPORT 应该是PLUGINEXPORT,我现在将对其进行编辑。在任何一种情况下,Plugin1.cpp 中的宏 PLUGIN(plugin1) 定义了 getPlugin(),它返回一个指向单例实例的指针 uintptr_t。在最终代码 sn-p 中,我尝试将其转换为 baseplugin* 并使用它——但这会使应用程序崩溃,请参阅:plugin1Singleton-&gt;load();