转自http://www.cppblog.com/codeart/archive/2010/08/28/125058.aspx
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是typedef 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