qt example plugandpaint 插件 动态库 pnp_extrafiltersd.dll无法加载问题

news2024/11/16 5:29:35

使用版本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);  //找到二进制文件中的QTMETADATA
    if (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 <qjsondocument.h>
#include <qjsonvalue.h>
#include <qjsonobject.h>
#include <qjsonarray.h>
#include <qcbormap.h>
#include <qcborvalue.h>
#include <qendian.h>
#include <qplugin.h>
#include <private/qplugin_p.h>
#include <qpluginloader.h>


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 CBOR
    int qt_metadataVersion = quint8(raw[0]);
    int qt_version = qFromBigEndian<quint16>(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 keys
    for (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_STRING

            case int(QtPluginMetaDataKeys::Requirements):
                // special case: recreate the debug key
                o.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<uint>(raw + 8);
        // but the maximum size of binary JSON is 128 MB
        size = 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 size
        size = qMin(sectionSize, qsizetype(size));

        QByteArray json(raw, size);
        return QJsonDocument::fromBinaryData(json);
    }
#endif

    return 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 supported
      systems, the read-only data/text segments are placed at the end
      of the file.  HOWEVER, when building with debugging enabled, all
      the debug symbols are placed AFTER the data/text segments.

      what does this mean?  when building in release mode, the search
      is fast because the data we are looking for is at the end of the
      file... when building in debug mode, the search is slower
      because 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 construction
        if (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<char *>(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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础深化和提高 ---- 网络编程

网络编程基本概念 计算机网络 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其 外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软 件及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计 算机系统。 …

Linux系统下文件的压缩与打包

压缩和解压缩 压缩数据或者解压数据&#xff1a; 为什么要移出数据信息前面的 / 目录 -P --absolute-paths 不要从文件名中去除 /1 compress和uncompress 格式 compress Options [file ...]常用选项 -d 解压缩&#xff0c;相当于uncompress-c 结果输出至标准输出…

Spring 事务失效的场景

1、private、final、static 方法 被 Transactional 注解标注的方法的访问权限必须是 public&#xff1b; 被 Transactional 注解标注的方法不能被 final、static 修饰&#xff0c;被标注的方法必须是可覆盖的。这是因为事务底层使用的是 aop&#xff0c;而 aop 使用的是代理模…

嵌入式为何钟爱SourceInsight,主要因为这个功能~

已剪辑自: https://mp.weixin.qq.com/s/F-gafwbZswpnY8EaCz8HxQ 不管是玩单片机还是嵌入式linux&#xff0c;只要是与硬件结合比较紧密的部分目前基本上还是C语言&#xff0c;当然了&#xff0c;不知道以后C语言会不会被取代&#xff0c;即便哪天被某种更加优秀的语言取代&…

m基于matlab的MIMO信道容量分析,对比了不同天线数量;非码本预编码SVD,GMD;码本预编码DFT,TxAA以及空间分集

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 MIMO信道容量 平均功率分配的MIMO信道容量&#xff1a;通过Matlab仿真在加性高斯白噪声情况下的SISO (1*1)、SIMO(1*6)、MISO(4*1)、MIMO(3*3)、MIMO&#xff08;4*4&#xff09;系统的…

VMware Explore 2022 China,赋能中国企业加速实现云智能

全球领先的企业软件创新者VMware&#xff08;NYSE: VMW&#xff09;的年度技术盛会—— VMware Explore 2022 China于11月8日正式举行。本届大会以“探索多云宇宙”为主题&#xff0c;汇聚云计算领域的顶尖技术专家和创新者&#xff0c;通过150多场解决方案演讲、围绕云基础架构…

[附源码]Python计算机毕业设计超市团购平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

JuiceFS 使用效果及注意事项

以某线上集群为例&#xff0c;数据规模&#xff1a;每天写入 5TB&#xff0c;数据储存 30 天&#xff0c;热数据储存一周&#xff0c;节点数量&#xff1a;5 个热节点&#xff0c;15 个冷节点。 采用 JuiceFS 后&#xff0c;热节点保持不变&#xff0c;冷节点从 15 个降到了 1…

[b01lers2020]Life on Mars (难发现的sql注入)

[b01lers2020]Life on Mars 打开界面以后&#xff0c;查看各种都没有提示&#xff0c;果断扫描目录&#xff0c;但也是没获得什么。 到这里只能burp抓个包看看 抓包两个界面发现了get传参&#xff0c;考虑是否存在sql注入 尝试额以后发现只返回了一个1&#xff0c;试一下别的引…

Nginx显示500错误原因和解决方法

文章目录1.背景2.Nginx 常见的几种报错3. 解决500错误1.背景 最近在操作nginx 的时候出现了 Nginx 500 内部错误&#xff0c;在此记录一下原因&#xff0c;项目采用的是前后端分离方式&#xff0c;后端SpringBoot &#xff0c;前端是Vue 部署到Nginx 下。 2.Nginx 常见的几种…

从水质监测运维工程师转行软件测试,武汉校区小哥哥除了收获10k高薪,还有...

从大学步入社会&#xff0c;每个人都会面临角色和身份的转变&#xff0c;大部分同学对此充满信心和期待&#xff0c;仿佛有用不完的精力、耗不尽的热情。可是社会中的磨砺也让心态慢慢变得成熟&#xff0c;生活、文化等方面的落差显现出来&#xff0c;想要做出改变&#xff0c;…

java项目-第151期ssm文物管理系统_java毕业设计_计算机毕业设计

java项目-第151期ssm文物管理系统_java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm文物管理系统》 该项目分为2个角色&#xff0c;管理员、用户。 用户可以浏览前台文物信息、论坛交流、文物资讯、留言反馈。 管理员负责登录后台系统&#xff0c…

[附源码]java毕业设计校医院病人跟踪治疗信息管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

产品质量模型

产品质量模型将系统/软件产品质量属性划分为8个特征&#xff1a;功能性、性能效率、兼容性、易用性、可靠性、安全性、可维护性、可移植性&#xff0c;每个特征由一组相关子特征组成。 衡量一个优秀软件的维度&#xff1a; 产品质量模型只应用于软件产品&#xff0c;或者包含软…

从零开始做一款Unity3D游戏<三>——编写游戏机制

添加跳跃 了解枚举 使用层遮罩 发射投射物 实例化对象 管理游戏对象的创建 游戏管理器 维护玩家属性 get和set属性 精益求精 图形用户界面 胜败条件 使用预编译指定和命令空间 总结 前面一章&#xff0c;我们专注于通过代码来移动玩家和相机&#xff0c;同时了解了…

深入理解计算机系统——Midterm Exam 2012

深入理解计算机系统——Midterm Exam 2012Problem 4 疑问Problem 6 疑问Problem 7 疑问Problem 8 疑问试卷&#xff1a;Midterm Exam 2012 答案&#xff1a;Exam Solutions Problem 4 疑问 第 4 题为第三章内容&#xff0c;这里觉得题目有一步骤写错了&#xff0c;<13> …

让Python可视化事半功倍!

分享一款不错的Matplotlib可视化查询手册&#xff0c;让Python Matplotlib事半功倍&#xff01; 当可视化时&#xff0c;记不清楚图形Marker名称、colormap名称、坐标轴刻度设置、图例设置等等时&#xff0c;稍微扫描一眼该手册&#xff0c;直接YYDS。 下面简单介绍一下这个手册…

SpringBoot SpringBoot 开发实用篇 5 整合第三方技术 5.5 变更缓存供应商 Ehcache

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇5 整合第三方技术5.5 变更缓存供应商 Ehcache5.5.1 缓存实现方案5.5.…

部署支持使用Redis哨兵模式,支持纳管ClickHouse数据库,JumpServer堡垒机v2.28.0发布

2022年11月21日&#xff0c;JumpServer开源堡垒机正式发布v2.28.0版本。在这一版本中&#xff0c;JumpServer的部署支持使用Redis哨兵集群作为后端缓存数据库&#xff0c;从而使系统更加健壮和高可用。操作日志审计方面&#xff0c;新增支持查看资源变更信息。当资源有新增、更…

今天给大家介绍一篇基基于SSM超市管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…