如何在 C++ 中从 dll 实例化类?

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

本文关键字:实例化 dll 中从 C++      更新时间:2023-10-16

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

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

  • COM/ATL 的东西
  • 一篇 C# 文章,类似于我在C++中使用反射尝试执行的操作
  • 这篇关于为什么C++没有反思的文章
  • 以及大量类似标题的文章,询问从DLL调用函数

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

也许我的方法不正确,我已经掉进了一个兔子洞,但是像反射和/或COM这样的东西似乎是我应该做的......只有 COM 对于此操作似乎矫枉过正,因为应用程序将运行客户端。这篇关于C++/CLI Reflections的文章看起来很有希望,但我正在使用Visual Studio C++17。

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

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

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

API's: 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;
};

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

插件的: 插件1.hpp

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

插件的:插件1.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's: 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

实现插件API的一个好方法是借助boost::d ll。它提供了一些有用的工具来实现插件机制。例如,插件中有工厂方法。

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

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

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