插件编写及注意点(Qt为例子)

1.在编程的时候,启动程序常常会附带一些必须的dll文件和一些非必须的dll文件。非必须的dll文件作为该应用程序功能拓展使用,称为插件。所以插件和应用程序各为独立个体,但他们之间也应该有联系。

2.在编写能被应用程序使用的插件时,如果不仅仅是提供一些全局函(功能)给应用程序使用,一般还包含一些类。而这些类应当继承能被应用程序识别的类,一般为插件专门创建一个抽象类Base,而插件dll里面的类继承该base类。并在dll的代码里面提供一个创建dll里面实例的函数,以供在加载到dll后,利用该函数创建该实例,这样就能得到插件dll里面的实例的指针了,然后利用多态,完成插件功能的实现,比如:

//插件所需父类(抽象类)
class PluginBase
{
public:
virtual void DoFunction()=0;
virtual ~PluginBase(){}

};

//该类的.h文件应用程序和插件dll都应该包含,如果抽象类析构函数为虚函数,需要实现,否则其继承的子类无法创建,这是因为子类析构函数调用会调用父类析构,所以必须实现。

//插件实例声明

class TARGETDLL_EXPORT TargetDll:public QMainWindow ,public PluginBase
{
Q_OBJECT
public:
TargetDll();
~TargetDll();
virtual void DoFunction();
public slots:
void slot_Show();
private:
bool isStarting;
QTimer* m_timer;
QWidget* mCenWgt;
QLabel* mLabel;

};

//这里注意一下,如果是Qt类,使用到其Q_OBJECT相关功能,在多继承的时候,Qt相关的应放在前面,比如QMainWindow

//应该在插件父类PluginBase的前面。否则链接出错,这是Qt机制的特性。

//cpp实现

TargetDll::TargetDll()
{
m_timer=new QTimer(this);
mCenWgt=new QWidget(this);
mLabel=new QLabel(this);
mLabel->setText("JUSTTEST");
isStarting=false;
QVBoxLayout* vL=new QVBoxLayout(this);
vL->addWidget(mLabel);
mCenWgt->setLayout(vL);
this->setCentralWidget(mCenWgt);

connect(m_timer,SIGNAL(timeout()),this,SLOT(slot_Show()));

}


TargetDll::~TargetDll()
{


}


void TargetDll::DoFunction()
{
if(!isStarting)
{
m_timer->start();
isStarting=true;
this->show();
}
else
{
m_timer->stop();
isStarting=false;
this->hide();
}
}


void TargetDll::slot_Show()
{
QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间
QString str = time.toString("yyyy-MM-dd hh:mm:ss ddd"); //设置显示格式
QString strr= strr.fromLocal8Bit("当前时间:")+str;//调用中文显示
mLabel->setText(strr);

}

然后在插件的实现的cpp里面添加一个导出函数,用于dll解析时候使用,得到实例的指针:

extern "C" __declspec(dllexport) void * __cdecl CreateInstance()
{
//建立对象
PluginBase* pPlugin=NULL;
try
{
pPlugin=new TargetDll();
if (pPlugin==NULL) throw TEXT("创建失败");
return (void*)pPlugin;
}
catch (...) {}


//清理对象
if (pPlugin != NULL){
delete pPlugin;
}
return NULL;
}

将上诉文件生成的dll放在指定目录,接下来就是动态加载调用dll插件了,以Qt为例:

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyPluginTest w;
w.show();

PluginBase* m_plugin=NULL;

        //里面的路径自己安排

QLibrary* lib=new QLibrary("D:/code/MyPluginTest/Win32/Debug/TargetDll.dll");
PluginBase* entry=NULL;
if(lib->load())

{

//解析创建实例函数,得到函数地址

       typedef void* (*PLUGIN_LIB_ENTRY)();

PLUGIN_LIB_ENTRY func = (PLUGIN_LIB_ENTRY)lib->resolve("CreateInstance");

if(!func)
{
delete lib;
return false;
}
//call to get the entries.
try
{
entry = (PluginBase*)func();//调用解析到的函数,获取创建到的实例的指针
}
catch(...)
{

delete lib;
return false;
}
entry->DoFunction();//插件具体功能的实现(利用多态)
}

return a.exec();

}

效果如下:



小结:一般而言,插件会很多很多,应用程序会有一个插件管理器,插件管理器里面有一个容器,数据类型就是插件基础抽象类,首先应该判断某个目录下dll文件名,然后加载什么的:

QDir dir(“插件目录”);//只是示例,一般不用中文,中文可能出错

if(!dir.exists())
{
if(!dir.mkpath(this->_plugins_dir))
{
   throw new IOTP::IOTPException("can not make library directory %s!",
this->_plugins_dir.toLocal8Bit().data());
}
}


qDebug() << "Plugin home path:" << this->_plugins_dir;
foreach(QString file, QDir(this->_plugins_dir).entryList(QDir::Files))
{
file = file.toLower();
if(!file.endsWith(".dll"))
{//platform specific.
continue;
}


qDebug() << "Load library " << this->_plugins_dir + file;

QString errmsg;

//先判断是否dll,然后执行加载函数(这里理解意思就ok),主要就是获取实例或者等,然后放入定义的管理器里面等

if(!loadLibrary(this->_plugins_dir + file, &errmsg))
{
qCritical() << "Failed, error: " << errmsg;
continue;
}

}

Qt提供的接口浅显易懂,界面开发也相对容易。以上主要是了解下思路,相信简单的插件框架,都能写了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值