您的位置:首页 > 编程语言 > Qt开发

Qt 插件篇

2015-08-22 23:25 411 查看
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]instance是typedefQObject *(*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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: