【发布时间】:2026-01-15 03:05:01
【问题描述】:
我正在为插件开发人员编写一个 API,以便他们可以通过我的 API 访问应用程序的 SDK。我的 API 在头文件中提供了一个宏和抽象类*,plugin-devs 必须包含这些宏和抽象类*,才能从抽象基类继承并实现必要的功能(*参见下面的代码)。
就手头问题的研究而言,我已经阅读了许多 MSDN 和 * 文章,发现这些最相关:
- COM/ATL stuff
- An article in C# similar to what I'm trying to do in C++ using reflections
- This article on why C++ doesn't have reflections
- 以及大量类似标题的文章询问如何从 DLL 调用函数
这个问题是关于获取一个继承的抽象类/接口的实例,您希望插件开发人员在创建 .dll 文件时实现该实例。
也许我的方法不正确,我已经陷入了困境,但是反射和/或 COM 之类的东西似乎是我应该做的......对于这个操作,只有 COM 似乎有点矫枉过正,因为应用程序将在客户端运行. C++/CLI Reflections 上的这篇文章看起来很有希望,但我正在使用 C++17 在 Visual Studio 中工作。
在*别,预期的行为是:
-
API.dll加载插件目录(例如plugin/plugin1.dll和plugin/plugin2.dll) -
API.dll通过抽象类'getPlugin()创建插件的单例实例 - 调用插件实现的其他方法,值得注意的是
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
【问题讨论】: