有时候一个项目中需要在不改变源代码实现对原有系统功能上的扩展,这种情况就需要让原有系统猪支持插件以便日后随时可对该系统进行增强。
实现可扩展的插件系统有多种,本文采用动态链接库的方式实现。
我认为比较好的实现方法是,通过DLL导出一个类的实例,它就是插件系统的接口,供主程序获取并调用。实现它需要用到C++的虚函数或纯虚函数,通过子类继承基类并实现相关接口,然后导出该子类,这样在主程序中就可以用基类指针去调用子类实现的相关函数。需要注意的是,为了让插件扩展程度较高,最好把主程序的上下文传入插件中,以便插件进行扩展主程序功能。
本程序写了一个静态库,其实是一个类,需要用子类来实现该类中的部分功能,这样插件扩展只需要.h文件和.lib文件就可以制作出插件,而不必得知源程序的实现部分,因为这个静态库是基类,主程序也可以通过这个静态库的类指针指向子类的实例。
静态库头文件即Plugins.h代码#include
#include
struct PluginsInfo
{
QString title;
QString author;
QString version;
QString introduce;
QString imgPath;
};
class Plugins
{
public:
Plugins();
~Plugins();
virtual PluginsInfo GetPluginsInfo() = 0;
virtual void Load();
virtual void UnLoad();
virtual void Enable();
virtual void Disable();
virtual void OpenSettings();
virtual int EventMessage(QString title, QString content);
};
静态库实现部分Plugins.cpp#include "Plugins.h"
Plugins::Plugins()
{
}
Plugins::~Plugins()
{
}
void Plugins::Load()
{
QMessageBox::information(0, "提示", "加载...");
}
void Plugins::UnLoad()
{
QMessageBox::information(0, "提示", "卸载...");
}
void Plugins::Enable()
{
QMessageBox::information(0, "提示", "启用...");
}
void Plugins::Disable()
{
QMessageBox::information(0, "提示", "禁用...");
}
void Plugins::OpenSettings()
{
QMessageBox::information(0, "提示", "打开设置...");
}
int Plugins::EventMessage(QString title, QString content)
{
return -1;
}
然后在编写插件的时候引入该头文件以及编译生成出来的lib文件
插件的头文件PluginTest.h#pragma once
#include "Plugins.h"
class PluginTest : public Plugins
{
public:
PluginTest();
~PluginTest();
virtual PluginsInfo GetPluginsInfo();
virtual void Load();
virtual void UnLoad();
virtual void Enable();
virtual void Disable();
virtual void OpenSettings();
virtual int EventMessage(QString title, QString content);
};
// 导出子类实例
extern "C" __declspec(dllexport) PluginTest * GetInstance();
插件的实现PluginTest.cpp#include "PluginTest.h"
PluginTest::PluginTest()
{
}
PluginTest::~PluginTest()
{
}
PluginsInfo PluginTest::GetPluginsInfo()
{
PluginsInfo info = { u8"Plugin Test", u8"Zllf", u8"0.1 beta", u8"插件测试", u8"图片地址" };
return info;
}
void PluginTest::Load()
{
}
void PluginTest::UnLoad()
{
}
void PluginTest::Enable()
{
QMessageBox::information(0, u8"提示", u8"插件启用...");
}
void PluginTest::Disable()
{
QMessageBox::information(0, u8"提示", u8"插件禁用...");
}
void PluginTest::OpenSettings()
{
QMessageBox::information(0, u8"提示", u8"插件设置...");
}
int PluginTest::EventMessage(QString title, QString content)
{
return 0;
}
extern "C" __declspec(dllexport) PluginTest * GetInstance()
{
return new PluginTest();
}
然后将编译好的插件放入主程序的特定路径下,主程序遍历这个路径下的插件用Win32 API依次加载即可
效果如下