CTK插件框架學習3-第一個插件編寫

前兩章把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函數被調用執行。
在這裏插入圖片描述

發佈了30 篇原創文章 · 獲贊 63 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章