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