qt example plugandpaint 插件 动态库 pnp_extrafiltersd.dll无法加载问题
创始人
2024-02-05 09:24:15
0

使用版本windows qt5.12.0+vs2015编译器。

运行plugandpaint工程的时候发现pnp_extrafiltersd.dll在load的时候失败了,经过调试,发现qlibrary.cpp中的findPatternUnloaded()的qt_find_pattern()无法通过。(release 版的pnp_extrafilters.dll是可以通过的,也不存在下面的问题)

qt_find_pattern调用堆栈
//QtInstallDir\Qt5.12.0\5.12.0\Src\qtbase\src\corelib\plugin\qlibrary.cpp
.....
char pattern[] = "qTMETADATA ";pattern[0] = 'Q'; // Ensure the pattern "QTMETADATA" is not found in this library should QPluginLoader ever encounter it.const ulong plen = qstrlen(pattern);......pos = qt_find_pattern(filedata, fdlen, pattern, plen);  //找到二进制文件中的QTMETADATAif (pos > 0)hasMetaData = true;
.....if (pos >= 0 && hasMetaData) {const char *data = filedata + pos;QString errMsg;QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg);//直接将二进制文件中的QTMETADATA后面的内容转成json格式,此处在debug模式下会报错if (doc.isNull()) {qWarning("Found invalid metadata in lib %s: %s",qPrintable(library), qPrintable(errMsg));} else {lib->metaData = doc.object();if (qt_debug_component())qWarning("Found metadata in lib %s, metadata=\n%s\n",library.toLocal8Bit().constData(), doc.toJson().constData());ret = !doc.isNull();}}

qt moc生成的moc_*.cpp有一个metadata项,如下:

moc_extrafilters.cpp的metadata

 正常来讲,metadata中的内容应该会存放到dll中,但pnp_extrafiltersd.dll出现异常。对比如下:

正常的dll的metadata的内容(plugins/audio/qtaudio_wasapi.dll)
异常的dll的metadata的内容(pnp_extrafiltersd.dll)

对比发现,pnp_extrafiltersd.dll的qt_pluginMetaData在遇到qPluginArchRequirements()的时候就被截断了,可以看到pnp_extrafiltersd.dll中qt_pluginMetaData的内容没有紧凑的存放在一起。qJsonFromRawLibraryMetaData函数在pnp_extrafiltersd.dll中找到“QTMETADATA !”之后无法将其后的二进制内容成功转换出正确的metadata的json内容。然而在release版中却没有这个现象,qt_pluginMetaData的内容在dll中全部紧凑的存放在一起,qJsonFromRawLibraryMetaData能正确对其进行解析。

解决方法:
1、先右键清除,将之前生成的obj等内容先清除掉,一定要做清除操作,否则残留的文件会对生成结果有影响。
2、在extrafilters.pro中加入:QMAKE_CXXFLAGS_DEBUG += -O1  (对VS 编译器debug模式设置O1优化,O1优化会在编译时将inline函数结果计算出来,否则程序会做一次函数调用,上面的现象就是因为编译器没有直接将qPluginArchRequirements()直接计算结果,而是做了一次函数调用操作,才导致字符数组qt_pluginMetaData的值没有在dll中紧凑排列,而导致后续的问题。debug默认不开启优化也就是O0,release默认开启最优优化,也就是O2优化)

inline 函数G++ 优化_Ruifei_yu的博客-CSDN博客 
HMI-19-[Qt Release深度优化编译]开启-O优化编译_DreamLife.的博客-CSDN博客 

下面是从qt中特意拷贝出识别qtplugin 的 dll的代码,有兴趣可以看一看,可以放到main中调试

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include QJsonObject metaData;static inline int metaDataSignatureLength()
{return sizeof("QTMETADATA  ") - 1;
}static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QString *errMsg)
{// extract the keys not stored in CBORint qt_metadataVersion = quint8(raw[0]);int qt_version = qFromBigEndian(raw + 1);int qt_archRequirements = quint8(raw[3]);if (Q_UNLIKELY(raw[-1] != '!' || qt_metadataVersion != 0)) {*errMsg = QStringLiteral("Invalid metadata version");return QJsonDocument();}raw += 4;size -= 4;QByteArray ba = QByteArray::fromRawData(raw, int(size));QCborParserError err;QCborValue metadata = QCborValue::fromCbor(ba, &err);if (err.error != QCborError::NoError) {*errMsg = QLatin1String("Metadata parsing error: ") + err.error.toString();return QJsonDocument();}if (!metadata.isMap()) {*errMsg = QStringLiteral("Unexpected metadata contents");return QJsonDocument();}QJsonObject o;o.insert(QLatin1String("version"), qt_version << 8);o.insert(QLatin1String("debug"), bool(qt_archRequirements & 1));o.insert(QLatin1String("archreq"), qt_archRequirements);// convert the top-level map integer keysfor (auto it : metadata.toMap()) {QString key;if (it.first.isInteger()) {switch (it.first.toInteger()) {
#define CONVERT_TO_STRING(IntKey, StringKey, Description) \case int(IntKey): key = QStringLiteral(StringKey); break;QT_PLUGIN_FOREACH_METADATA(CONVERT_TO_STRING)
#undef CONVERT_TO_STRINGcase int(QtPluginMetaDataKeys::Requirements):// special case: recreate the debug keyo.insert(QLatin1String("debug"), bool(it.second.toInteger() & 1));key = QStringLiteral("archreq");break;}} else {key = it.first.toString();}if (!key.isEmpty())o.insert(key, it.second.toJsonValue());}return QJsonDocument(o);
}QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype sectionSize, QString *errMsg)
{raw += metaDataSignatureLength();sectionSize -= metaDataSignatureLength();#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)if (Q_UNLIKELY(raw[-1] == ' ')) {// the size of the embedded JSON object can be found 8 bytes into the data (see qjson_p.h)uint size = qFromLittleEndian(raw + 8);// but the maximum size of binary JSON is 128 MBsize = qMin(size, 128U * 1024 * 1024);// and it doesn't include the size of the header (8 bytes)size += 8;// finally, it can't be bigger than the file or section sizesize = qMin(sectionSize, qsizetype(size));QByteArray json(raw, size);return QJsonDocument::fromBinaryData(json);}
#endifreturn jsonFromCborMetaData(raw, sectionSize, errMsg);
}static qsizetype qt_find_pattern(const char *s, qsizetype s_len,const char *pattern, ulong p_len)
{/*we search from the end of the file because on the supportedsystems, the read-only data/text segments are placed at the endof the file.  HOWEVER, when building with debugging enabled, allthe debug symbols are placed AFTER the data/text segments.what does this mean?  when building in release mode, the searchis fast because the data we are looking for is at the end of thefile... when building in debug mode, the search is slowerbecause we have to skip over all the debugging symbols first*/if (!s || !pattern || qsizetype(p_len) > s_len)return -1;size_t i, hs = 0, hp = 0, delta = s_len - p_len;for (i = 0; i < p_len; ++i) {hs += s[delta + i];hp += pattern[i];}i = delta;for (;;) {if (hs == hp && qstrncmp(s + i, pattern, p_len) == 0)return i;   // can't overflow, by constructionif (i == 0)break;--i;hs -= s[i + p_len];hs += s[i];}return -1;
}static bool findPatternUnloaded(const QString &library)
{QFile file(library);if (!file.open(QIODevice::ReadOnly)) {return false;}// Files can be bigger than the virtual memory size on 32-bit systems, so// we limit to 512 MB there. For 64-bit, we allow up to 2^40 bytes.constexpr qint64 MaxMemoryMapSize =Q_INT64_C(1) << (sizeof(qsizetype) > 4 ? 40 : 29);QByteArray data;qsizetype fdlen = qMin(file.size(), MaxMemoryMapSize);const char *filedata = reinterpret_cast(file.map(0, fdlen));if (filedata == 0) {// Try reading the data into memory instead (up to 64 MB).data = file.read(64 * 1024 * 1024);filedata = data.constData();fdlen = data.size();}/*ELF and Mach-O binaries with GCC have .qplugin sections.*/bool hasMetaData = false;qsizetype pos = 0;char pattern[] = "qTMETADATA ";pattern[0] = 'T'; // Ensure the pattern "QTMETADATA" is not found in this library should QPluginLoader ever encounter it.const ulong plen = qstrlen(pattern);pos = qt_find_pattern(filedata, fdlen, pattern, plen);if (pos > 0)hasMetaData = true;bool ret = false;if (pos >= 0 && hasMetaData) {const char *data = filedata + pos;QString errMsg;QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg);if (doc.isNull()) {qWarning("Found invalid metadata in lib %s: %s",qPrintable(library), qPrintable(errMsg));} else {metaData = doc.object();ret = !doc.isNull();}}
}int main()
{findPatternUnloaded("E:/workspace/QtWork/build-plugandpaint-Desktop_Qt_5_12_0_MSVC2015_64bit-Debug/plugins/pnp_extrafiltersd.dll");return 0;
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...