QT中的插件

QT提供了一种独特的插件管理方式,可以替代WIN32的动态库和静态库。QLibrary是QT中用于加载库的关键,它底层调用了LoadLibrary和GetProcAddress。本文介绍了QT插件的使用方法,包括定义接口、实现接口以及在主工程中使用QPluginLoader。通过Q_EXPORT_PLUGIN2和Q_DECLARE_INTERFACE宏定义,实现了QT插件的导出和多态性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

Qt插件的使用方法:

[1]project_main_1工程中定义接口

QT中的插件 - weyresearch - weyresearch的博客class interface__1
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客public:
QT中的插件 - weyresearch - weyresearch的博客    void __func1() = 0;
QT中的插件 - weyresearch - weyresearch的博客    void __func2() = 0;
QT中的插件 - weyresearch - weyresearch的博客    void __func3() = 0;
QT中的插件 - weyresearch - weyresearch的博客}
;
QT中的插件 - weyresearch - weyresearch的博客    class interface__2
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客public:
QT中的插件 - weyresearch - weyresearch的博客    void __func4() = 0;
QT中的插件 - weyresearch - weyresearch的博客    void __func5() = 0;
QT中的插件 - weyresearch - weyresearch的博客    void __func6() = 0;
QT中的插件 - weyresearch - weyresearch的博客}
;

[2]project_plugin_1工程中实现接口

QT中的插件 - weyresearch - weyresearch的博客class derive__1:public interface__1,interface__2
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客public:
QT中的插件 - weyresearch - weyresearch的博客    void __func1();
QT中的插件 - weyresearch - weyresearch的博客    void __func2();
QT中的插件 - weyresearch - weyresearch的博客    void __func3();
QT中的插件 - weyresearch - weyresearch的博客    void __func4();
QT中的插件 - weyresearch - weyresearch的博客    void __func5();
QT中的插件 - weyresearch - weyresearch的博客    void __func6();
QT中的插件 - weyresearch - weyresearch的博客}
;

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

用法1:

QT中的插件 - weyresearch - weyresearch的博客QobjectList objList = QpluginLoader::staticInstances();
QT中的插件 - weyresearch - weyresearch的博客for(int i = 0; i<objList.size(); i++)
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客    interface__1 *inter1 = qobject_cast< interface__1 *>(objList[i]);
QT中的插件 - weyresearch - weyresearch的博客    interface__2 *inter1 = qobject_cast< interface__2 *>(objList[i]);    
QT中的插件 - weyresearch - weyresearch的博客}

用法2:

QT中的插件 - weyresearch - weyresearch的博客QpluginLoader pl(“plugin path”);
QT中的插件 - weyresearch - weyresearch的博客Qobject* plugin = pl.instance();

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

看下面细节.

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

[1]如何加载

QT中的插件 - weyresearch - weyresearch的博客bool QLibraryPrivate::loadPlugin()
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客    if (instance) {
QT中的插件 - weyresearch - weyresearch的博客        libraryUnloadCount.ref();
QT中的插件 - weyresearch - weyresearch的博客        return true;
QT中的插件 - weyresearch - weyresearch的博客    }

QT中的插件 - weyresearch - weyresearch的博客    if (load()) {//这里最终调用load_sys()
QT中的插件 - weyresearch - weyresearch的博客
        instance =    (QtPluginInstanceFunction)resolve("qt_plugin_instance");//注意这里的 qt_plugin_instance,插件里面必然导出该函数名称
QT中的插件 - weyresearch - weyresearch的博客
        return instance;
QT中的插件 - weyresearch - weyresearch的博客    }

QT中的插件 - weyresearch - weyresearch的博客    return false;
QT中的插件 - weyresearch - weyresearch的博客}

QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客bool QLibraryPrivate::load_sys()
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客#ifdef Q_OS_WINCE
QT中的插件 - weyresearch - weyresearch的博客    QString attempt = QFileInfo(fileName).absoluteFilePath();
QT中的插件 - weyresearch - weyresearch的博客#else
QT中的插件 - weyresearch - weyresearch的博客    QString attempt = fileName;
QT中的插件 - weyresearch - weyresearch的博客#endif
QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客    //avoid 'Bad Image' message box
QT中的插件 - weyresearch - weyresearch的博客
    UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
QT中的插件 - weyresearch - weyresearch的博客    pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客    if (pluginState != IsAPlugin) {
QT中的插件 - weyresearch - weyresearch的博客        if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) {
QT中的插件 - weyresearch - weyresearch的博客            attempt += QLatin1String(".dll");
QT中的插件 - weyresearch - weyresearch的博客            pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16());
QT中的插件 - weyresearch - weyresearch的博客        }

QT中的插件 - weyresearch - weyresearch的博客    }

QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客    SetErrorMode(oldmode);
QT中的插件 - weyresearch - weyresearch的博客    if (!pHnd) {
QT中的插件 - weyresearch - weyresearch的博客        errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qt_error_string());
QT中的插件 - weyresearch - weyresearch的博客    }

QT中的插件 - weyresearch - weyresearch的博客    if (pHnd) {
QT中的插件 - weyresearch - weyresearch的博客        errorString.clear();
QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客        wchar_t buffer[MAX_PATH];
QT中的插件 - weyresearch - weyresearch的博客        ::GetModuleFileName(pHnd, buffer, MAX_PATH);
QT中的插件 - weyresearch - weyresearch的博客        attempt = QString::fromWCharArray(buffer);
QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客        const QDir dir =  QFileInfo(fileName).dir();
QT中的插件 - weyresearch - weyresearch的博客        const QString realfilename = attempt.mid(attempt.lastIndexOf(QLatin1Char('\\')) + 1);
QT中的插件 - weyresearch - weyresearch的博客        if (dir.path() == QLatin1String("."))
QT中的插件 - weyresearch - weyresearch的博客            qualifiedFileName = realfilename;
QT中的插件 - weyresearch - weyresearch的博客        else
QT中的插件 - weyresearch - weyresearch的博客            qualifiedFileName = dir.filePath(realfilename);
QT中的插件 - weyresearch - weyresearch的博客    }

QT中的插件 - weyresearch - weyresearch的博客    return (pHnd != 0);
QT中的插件 - weyresearch - weyresearch的博客}

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

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

宏定义:

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

QT中的插件 - weyresearch - weyresearch的博客
QT中的插件 - weyresearch - weyresearch的博客extern __declspec(dllexport) QObject* qt_plugin_instance()
QT中的插件 - weyresearch - weyresearch的博客{
QT中的插件 - weyresearch - weyresearch的博客    Qpoint<QOjbect> _instance;
QT中的插件 - weyresearch - weyresearch的博客    if (!_instance)
QT中的插件 - weyresearch - weyresearch的博客                _instance = new PLUGINCLASS;
QT中的插件 - weyresearch - weyresearch的博客            return _instance;
QT中的插件 - weyresearch - weyresearch的博客}

[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.

QT中的插件 - weyresearch - weyresearch的博客#  define Q_DECLARE_INTERFACE(IFace, IId) \
QT中的插件 - weyresearch - weyresearch的博客    template <> inline const char *qobject_interface_iid<IFace *>() \
QT中的插件 - weyresearch - weyresearch的博客    return IId; } \
QT中的插件 - weyresearch - weyresearch的博客    template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
QT中的插件 - weyresearch - weyresearch的博客    return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \
QT中的插件 - weyresearch - weyresearch的博客    template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
QT中的插件 - weyresearch - weyresearch的博客    return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); }
QT中的插件 - weyresearch - weyresearch的博客#endif // Q_MOC_RUN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值