前两章把CTK插件库编译好了,这里篇编写一个插件试一下,共需要创建两个小工程,一个是插件库,一个是测试程序。
1. 插件库编写
1.1 创建工程
打开Qt creator,新建一个Emputy qmake Project,并给工程命名为ctk-plugin-first。Kits选择”Desktop Qt5.12.3 MSVC2017 64bit”。
更改ctk-plugin-first.pro文件,添加TARGET、CONFIG等参数,并添加头文件路径。需要注意的是,头文件路径需要添加两个位置,出了源码目录下,还要添加编译后生成文件的路径。这里以WIN64宏定义的方式区分MINGW编译器与MSVC编译器。
QT += core
QT -= gui
TARGET = ctk-plugin-first
TEMPLATE = lib
CONFIG += plugin
INCLUDEPATH += E:/lwks/CTK/Libs/Core \
+= E:/lwks/CTK/Libs/PluginFramework
if (contains(DEFINES,WIN64)){
# for msvc compiler
INCLUDEPATH += E:/lwks/ctk-vsbuild/CTK-build/Libs/PluginFramework
INCLUDEPATH += E:/lwks/ctk-vsbuild/CTK-build/Libs/Core
}else{
# for mingw compiler
INCLUDEPATH += E:/lwks/ctk-superbuild/CTK-build/Libs/PluginFramework
INCLUDEPATH += E:/lwks/ctk-superbuild/CTK-build/Libs/Core
}
1.2 创建插件类
在ctk-plugin-first工程中新建一个类,取名为
FirstPluginActivator
,程序源码如下。
firstpluginactivator.h
#ifndef FIRSTPLUGINACTIVATOR_H
#define FIRSTPLUGINACTIVATOR_H
#include <QObject>
#include "ctkPluginActivator.h"
#include "ctkPluginContext.h"
class FirstPluginActivator : public QObject, public ctkPluginActivator
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "FirstPlugin")
Q_INTERFACES(ctkPluginActivator)
public:
FirstPluginActivator();
void start(ctkPluginContext *context);
void stop(ctkPluginContext *context);
};
#endif // FIRSTPLUGINACTIVATOR_H
firstpluginactivator.cpp
#include "firstpluginactivator.h"
#include <QDebug>
FirstPluginActivator::FirstPluginActivator()
{
}
void FirstPluginActivator::start(ctkPluginContext *context)
{
qDebug() << "first plugin start: " << context;
}
void FirstPluginActivator::stop(ctkPluginContext *context)
{
qDebug() << "first plugin stop: " << context;
}
这个类的功能比较简单,仅仅实现了插件的start与stop服务。
1.3 创建资源文件
在工程中添加资源文件,名称可以随便取,我这里命名为resource。在资源文件中添加prefix,命名为
/ctk-plugin-first/META-INF
,注意这个prefix的命名,命名形式为”
/工程名/META-INF
“,这个不能随意更改。在该prefix下新建一个文件,命名为
MANIFEST.MF
,文件内容如下。
Plugin-SymbolicName:FirstPlugin
Plugin-Version:1.0.0
MANIFEST.MF
文件是插件库的清单文件,可以在里面设置插件库名称、版本号等属性,也可以添加一些自定义属性,后面测试程序中可以读取这些属性值。
整个插件库工程创建完毕,工程文件结构如下图所示。
编译工程,正常情况下,会在”build-ctk-plugin-first-Desktop_Qt_5_12_3_MSVC2017_64bit-Debug/debug”目录下生成
ctk-plugin-first.dll
文件,该文件是下面测试程序运行时需要加载的插件库文件。
2. 测试程序编写
2.1 创建工程
打开Qt Creator,新建一个
Qt Console Applciation
工程,工程名随便取,我这里设置的是MainTest,kits同样选用Qt5.12.3 MSVC2017 64bit”。新建的控制台应用,工程文件结构图应如下图所示,包含.pro文件与main.cpp文件。
修改.pro工程文件,添加CTK库的头文件路径以及库文件的路径。注意它与插件库工程的.pro文件配置不同的是,添加了LIBS的配置,-L指向了编译CTK工程的输出文件路径中,并指定链接CTKCore库以及CTKPluginFramework库。
QT -= gui
CONFIG += console
CONFIG -= app_bundle
INCLUDEPATH += E:/lwks/CTK/Libs/Core \
+= E:/lwks/CTK/Libs/PluginFramework
if (contains(DEFINES,WIN64)){
# for msvc compiler
INCLUDEPATH += E:/lwks/ctk-vsbuild/CTK-build/Libs/PluginFramework
INCLUDEPATH += E:/lwks/ctk-vsbuild/CTK-build/Libs/Core
LIBS += -LE:/lwks/ctk-vsbuild/CTK-build/bin/Debug -lCTKCore -lCTKPluginFramework
}else{
# for mingw compiler
INCLUDEPATH += E:/lwks/ctk-superbuild/CTK-build/Libs/PluginFramework
INCLUDEPATH += E:/lwks/ctk-superbuild/CTK-build/Libs/Core
LIBS += -LE:/lwks/ctk-superbuild/CTK-build/bin -lCTKCore -lCTKPluginFramework
}
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.2 编写测试程序
在main.cpp中,首先初始化插件框架,然后获取插件服务的context,用插件contex进行安装插件,并启动插件,代码如下。
#include <QCoreApplication>
#include <ctkPluginFrameworkFactory.h>
#include <ctkPluginFramework.h>
#include <ctkPluginException.h>
#include <ctkPluginContext.h>
#include <QtDebug>
#include <QUrl>
#ifdef __MINGW32__
// 使用mingw编译器时的定义
QString static firstPlugin_filePath = "E:/lwks/build-ctk-plugin-first-Desktop_Qt_5_12_3_MinGW_64_bit-Debug/debug/ctk-plugin-first.dll";
#else
// 使用msvc编译器时的定义
QString static firstPlugin_filePath = "E:/lwks/build-ctk-plugin-first-Desktop_Qt_5_12_3_MSVC2017_64bit-Debug/debug/ctk-plugin-first.dll";
#endif
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ctkPluginFrameworkFactory frameworkFactory;
QSharedPointer<ctkPluginFramework> framework = frameworkFactory.getFramework();
// 初始化并启动插件框架
try {
framework->init();
framework->start();
qDebug() << "CTK plugin framework start...";
} catch (const ctkPluginException &e) {
qDebug() << "CTK plugin framework init err: " << e.what();
return -1;
}
// 获取插件服务的contex
ctkPluginContext* pluginContext = framework->getPluginContext();
try {
// 安装插件
QSharedPointer<ctkPlugin> plugin = pluginContext->installPlugin(QUrl::fromLocalFile(firstPlugin_filePath));
qDebug() << QString("Plugin[%1_%2] installed...").arg(plugin->getSymbolicName()).arg(plugin->getVersion().toString());
// 启动插件
plugin->start(ctkPlugin::START_TRANSIENT);
qDebug() << "Plugin start...";
} catch (const ctkPluginException &e) {
qDebug() << QString("Failed install or run plugin: ") << e.what();
return -2;
}
return a.exec();
}
2.3 运行测试
编译并运行MainTest工程,程序运行结果如下。可以看出,在加载启动ctk-plugin-first插件后,该插件的start函数被调用执行。