QT中插件分析
发布日期:2021-10-03 22:59:34 浏览次数:32 分类:技术文章

本文共 4566 字,大约阅读时间需要 15 分钟。

QT有着独特的插件管理方法便于使用,调理清晰.完全可以替代WIN32下的动态库,静态库.不过,QT也支持动态库和静态库加载.QLibrary,最终,QLibrary调用WIN32下的LoadLibrary,GetProcAddress函数.

Qt插件的使用方法:

[1]project_main_1工程中定义接口

class interface__1
{
public:
    void __func1() = 0;
    void __func2() = 0;
    void __func3() = 0;
}
;
    
class interface__2
{
public:
    void __func4() = 0;
    void __func5() = 0;
    void __func6() = 0;
}
;

[2]project_plugin_1工程中实现接口

class derive__1:
public interface__1,interface__2
{
public:
    void __func1();
    void __func2();
    void __func3();
    void __func4();
    void __func5();
    void __func6();
}
;

[3]project_main_1中使用QPluginLoader,QPluginLoader内部实现也是使用LoadLibrary,GetProcAddress,稍后会有说明

用法1:

QobjectList objList = QpluginLoader::staticInstances();
for(
int i = 0; i<objList.size(); i++)
{
    interface__1 *inter1 = qobject_cast< interface__1 *>(objList[i]);
    interface__2 *inter1 = qobject_cast< interface__2 *>(objList[i]);    
}

用法2:

QpluginLoader pl(“plugin path”);
Qobject* plugin = pl.instance();

这里可以看出,充分的使用了对象对象的多态.那么,是 QpluginLoader是如何实现的呢?

看下面细节.

Qt的类几乎所有的都有一个QT_class+private的类,用来实现具体逻辑,暴露给我们的类定义通用的接口.QpluginLoader的内部类是QLibraryPrivate,QLibrary是同一个.

[1]如何加载

bool QLibraryPrivate::loadPlugin()
{
    if (instance) {
        libraryUnloadCount.ref();
        return true;
    }
    if (load()) {
//这里最终调用load_sys()
        instance =    (QtPluginInstanceFunction)resolve("qt_plugin_instance");//注意这里的 qt_plugin_instance,插件里面必然导出该函数名称
        return instance;
    }
    return false;
}
bool QLibraryPrivate::load_sys()
{
#ifdef Q_OS_WINCE
    QString attempt = QFileInfo(fileName).absoluteFilePath();
#else
    QString attempt = fileName;
#endif
    //avoid 'Bad Image' message box
    UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
    pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
    if (pluginState != IsAPlugin) {
        if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
            attempt += QLatin1String(".dll");
            pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
        }
    }
    SetErrorMode(oldmode);
    if (!pHnd) {
        errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qt_error_string());
    }
    if (pHnd) {
        errorString.clear();
        wchar_t buffer[MAX_PATH];
        ::GetModuleFileName(pHnd, buffer, MAX_PATH);
        attempt = QString::fromWCharArray(buffer);
        const QDir dir =  QFileInfo(fileName).dir();
        const QString realfilename = attempt.mid(attempt.lastIndexOf(QLatin1Char('\\')) + 1);
        if (dir.path() == QLatin1String("."))
            qualifiedFileName = realfilename;
        else
            qualifiedFileName = dir.filePath(realfilename);
    }
    return (pHnd != 0);
}

[2] qt_plugin_instance是定义导出的呢?

在实现接口时,必须加上Q_EXPORT_PLUGIN2,Q_EXPORT_PLUGIN2 ( PluginNameClassName )

宏定义:

#  define Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)      \
            Q_PLUGIN_VERIFICATION_DATA \
            Q_EXTERN_C Q_DECL_EXPORT \
            
const 
char * Q_STANDARD_CALL qt_plugin_query_verification_data() \
            
return qt_plugin_verification_data; } \
            Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) * Q_STANDARD_CALL qt_plugin_instance() \
            Q_PLUGIN_INSTANCE(PLUGINCLASS)
其中
#  define Q_PLUGIN_VERIFICATION_DATA \
    
static 
const 
char *qt_plugin_verification_data = \
      "pattern=""QT_PLUGIN_VERIFICATION_DATA""\n" \
      "version="QT_VERSION_STR"\n" \
      "debug="QPLUGIN_DEBUG_STR"\n" \
      "buildkey="QT_BUILD_KEY;
#define  Q_EXTERN_C extern
#define  Q_DECL_EXPORT __declspec(dllexport)
#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \
        
{ \
            static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \
            if (!_instance)      \
                _instance = new IMPLEMENTATION; \
            return _instance; \
        }
去掉宏之后,是2个函数.
static 
const 
char *qt_plugin_verification_data =           "pattern=""QT_PLUGIN_VERIFICATION_DATA""\n"     "version="QT_VERSION_STR"\n" 
    "debug="QPLUGIN_DEBUG_STR"\n"
          "buildkey="QT_BUILD_KEY;
extern __declspec(dllexport) qt_plugin_query_verification_data()
{
    return  qt_plugin_verification_data;
}
extern __declspec(dllexport) QObject* qt_plugin_instance()
{
    Qpoint<QOjbect> _instance;
    if (!_instance)
                _instance = new PLUGINCLASS;
            return _instance;
}

[3] instancetypedef QObject *(*QtPluginInstanceFunction)();

这样就实现了QT的插件.但是还没完.

在定义接口时,还应加上Q_DECLARE_INTERFACE,This macro associates the given Identifier (a string literal) to the interface class called ClassName. The Identifier must be unique.

#  define Q_DECLARE_INTERFACE(IFace, IId) \
    template <> inline 
const 
char *qobject_interface_iid<IFace *>() \
    
return IId; } \
    template <> inline IFace *qobject_cast<IFace *>(QObject *
object) \
    
return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \
    template <> inline IFace *qobject_cast<IFace *>(
const QObject *
object) \
    
return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); }
#endif 
//
 Q_MOC_RUN

转载地址:https://blog.csdn.net/lclflash/article/details/8856751 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Qt 插件学习(一)
下一篇:qt 实现单例

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年03月24日 19时45分15秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

ab753变频器参数怎么拷贝到面板_变频器不知道如何上手,厂家教你如何三点搞定设置变频器参数... 2019-04-21
keepalived mysql双主架构图_华为CRM资深架构师:MySQL数据库架构和同步复制流程,看完就懂... 2019-04-21
gradle 本地maven仓库_Gradle的使用教程 2019-04-21
python制作表格处理软件_震惊!当Python遇到Excel后,将开启你的认知虫洞 2019-04-21
手写一个promise用法_手写系列之实现一个Promise 2019-04-21
数字拆分问题算法回溯_学会了回溯算法,我终于会做数独了 2019-04-21
广州刷脸支付骗局_刷脸支付是骗局?那可能你还不了解刷脸支付 2019-04-21
卸载源码安装的mysql_源码安装与卸载mysql 2019-04-21
mysql查询当天记录_sql查询当天记录 2019-04-21
java 远程调试 端口_JAVA远程调试 2019-04-21
java 获取 html 图片路径_JAVA-替换html中图片的路径-从html代码中提取图片路径并下载(完整版)... 2019-04-21
java redis 面试题_Java面试题(Redis篇) 2019-04-21
java 正则表达式分类功能_JAVA正则表达式4种常用功能 2019-04-21
java3d立方体_3d立方体贴图 2019-04-21
java ajax教程_(转)JAVA AJAX教程第三章—AJAX详细讲解 2019-04-21
java operators_A guide to Java Operators 2019-04-21
java socket调试_JAVA实现SOCKET多客户端通信的案例 2019-04-21
java 使用或覆盖了已过时的api_JAVA使用或覆盖了已过时的 API 2019-04-21
java 图片旋转保存_Java 对图片90度旋转 2019-04-21
用java实现文学研究助手_数据结构文学研究助手 C语言代码实现(带源码+解析)... 2019-04-21