Qt 插件篇

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 (PluginName,ClassName)

宏定义:

#  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]instancetypedefQObject *(*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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值