百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

QLibrary 加载动态库(qlibrary加载动态库调用函数)

cac55 2024-10-07 06:43 65 浏览 0 评论

阅读本文大概需要 6.6分钟

一般情况下在没有头文件支持情况下,想要引入某个动态库,最好的办法就是使用「动态加载」的方法,在Qt中一般使用QLibyary来操作

常用 api

 QLibrary(const QString& fileName, QObject *parent = nullptr);
 QFunctionPointer resolve(const char *symbol);
 bool load();
 bool unload();
 bool isLoaded() const;

官方说明[1]

下面我们来看下详细的使用过程

创建动态库

我们创建一个「子工程」,用来编写我们的测试方法,该工程需要导出为动态库,完整的示例如下所示

├─App
│      App.pro
│      main.cpp
│
└─Libs
        Libs.pro
        SDKCore.cpp
        SDKCore.h
        SDKCoreImpl.cpp
        SDKCoreImpl.h
        SDKCore_global.h
        SDKStruct.h

我们创建一个函数,并且导出

SDKCore.h

extern "C" SDK_EXPORT int runFunction(const char * funName, const DS_Request &request, DS_Request& response);

SDKCore.cpp

int runFunction(const char *funName, const DS_Request &request, DS_Request &response)
{
    Internal::SDKCoreImpl m_pCoreImpl;
    int nRet = -1;
    QMetaObject::invokeMethod(&m_pCoreImpl, funName,
                              Qt::DirectConnection,
                              Q_RETURN_ARG(int, nRet),
                              Q_ARG(DS_Request, request),
                              Q_ARG(DS_Request&,response));
    return nRet;
}

这里为了访问方便,具体的函数都放在了SDKCoreImpl中实现,调用采用了反射,调用的时候直接传方法字符串即可

上面中入参和出参数据格式是自定义的,为了统一而自定义,具体如下所示

struct DS_Request{
    QString m_strData;
    QByteArray m_baStream;
};

这样就兼容所有的格式了,不管是传 字符串还是数据流都使用统一的格式

这里写一个简单的加法运算

int SDKCoreImpl::addNum(const DS_Request &request, DS_Request &response)
{
    QVariantMap map = QJsonDocument::fromJson(request.m_strData.toLatin1()).toVariant().toMap();
    int nValue1 = map.value("nValue1").toInt();
    int nValue2 = map.value("nValue2").toInt();
    int nResult = nValue1 + nValue2;
    QVariantMap mapResult;
    mapResult.insert("result", nResult);
    QJsonDocument doc = QJsonDocument::fromVariant(mapResult);
    response.m_strData = QString(doc.toJson());
    return SDKCODE_SUCCEED;
}

加载动态库

加载动态库就变的很简单了,只需要几行代码即可获取到对应的函数符号

 QLibrary library(strSDKName);
 bool bLoad = library.load();

只要动态库路径合法就会加载成功,一般加载失败可能就是路径后者导出符号有问题,遇到这些问题可以排查下

使用前先定义一个函数指针

typedef int (* pRunFunctionFun)(const char *, const DS_Request &, DS_Request&);

调用addNum函数

pRunFunctionFun pFun = (pRunFunctionFun) library.resolve("runFunction");
if ( pFun)
{
    int nRet = pFun("addNum", request, response);
    qDebug() << "add Resut:" << nRet << response.m_strData;
}

这样一个完整的调用流程就跑通了

优化代码

但是,如果你认为完了,那就错了,仔细看下就会发现上述代码有冗余,难道每调用不同的函数,都要重复上述过程么?肯定不会呀,程序员不会自己干重复的事情,要重复只能让机器去做

下面优化下,把重复的代码单独封装下,定义成宏

通过上述代码,我们可以看出来,首先这个方法可以封装成模板,每一次调用都是一样的

library.resolve("")

封装成模板调用

template <typename T>
T getFunction(QLibrary *lib, const char *symbol)
{
    T f = (T)lib->resolve(func);
    if (f == nullptr)
    {
        return nullptr;
    }
    return f;
}

然后接着优化,获取函数符号流程封装成宏

#define GET_SDK_FUNC(type, func, symbol)  GET_FUNC(sdk, type, func, symbol);
#define GET_FUNC(sdk, type, func, symbol) \
    type func = getFunction<type>(&sdk, symbol); \
    if (func == nullptr) \
{ \
    qDebug()<<"fun is null: "<< symbol; \
    return 0; \
}

优化完成后,我们看下调用过程会如何更简单

QLibrary library(strSDKName);
bool bLoad = library.load();
GET_FUNC(library, pRunFunctionFun, runFun, "runFunction");
int nRet = runFun("addNum", request, response);

完整代码已经上传到GitHub,感兴趣的可以自行去下载

demo 源码下载[2]

总结

在平时工作中,很多大型工程都是动态库调用,这样做的好处就是方便他人直接调用使用现有功能和业务,减少重复复杂的工作,提高我们的工作效率

上述代码中有没有发现一条迷惑之处,就是动态库的路径和名称没有看到呀,是怎么加载的?

这个其实用到了之前介绍的一种技术,qmake语法糖

阅读过源码你就会发现,我在pri文件中编写了字符串宏定义,这样在代码中就可以直接调用对应的字符串了,如果一天要修改,那么只修改pri文件即可,其它都不需要动

DEFINES += LIB_DIR_PATH=\"\\\"$LIB_DIR_PATH\\\"\"
DEFINES += FILE_DLL_EXT=\"\\\"$FILE_DLL_EXT\\\"\"
DEFINES += LIB_NAME=\"\\\"$LIB_NAME\\\"\"

参考资料

[1]官方api说明: https://doc.qt.io/qt-5/qlibrary.html

[2]示例源码下载地址: https://github.com/kevinlq/DynamicLibLoadDemo

相关推荐

14款健身APP蹿红 看看下载最多的是哪款?

Zombies,Run!($3.99,安卓,iOS)如果你的运动理念是:除非有人追,否则绝不跑起来,那么这款APP应该适合你。Zombies,Run!这款程序把单调的跑步过程变身为躲避僵尸的游戏...

微软官方彩蛋庆祝《回到未来》纪念日

2015年10月21日,是MartyMcFly和Brown博士回到未来的时间。现在,这一天真的到了,那么当时影片中展示的一些科技产品究竟有多少实现了呢?作为一家走在技术前沿的公司,日前,微软就在M...

时尚圈最潮同志情侣 帅到没朋友(同志情侣微信头像)

来源:MSN时尚综合|2015-03-0419:45:15男演员ZacharyQuinto(中)与男模MilesMcMillan(右)于纽约街头公开热吻。情人节这个拥有不同起源传说,最早可以...

IE浏览器阻止过期ActiveX控件或将影响网银的使用

IE浏览器网银IE浏览器网银如果经常使用IE浏览器浏览网页的用户,可能都有遇到过浏览器窗口提示安装ActiveX控件的情况,一般情况下用户也是会选择直接安装。ActiveX控件广义上是指微软公司的整...

如何使Microsoft Band连接到WP设备

如果你幸运地购买到了MicrosoftBand,那么恭喜你。现在我们(winbeta)推出了“帮助系列”,那些尚未买到MicrosoftBand的朋友可以了解设备的一些新功能,以及设备的其他关键特...

毕业生不得不看的五大骗局全揭秘(毕业生防骗)

目前,距离高校大学生毕业已不足100天,大部分毕业生都十分忙碌。论文定稿、答辩,参加招聘、面试等成了应届毕业生的头等大事。但随着毕业季的临近,不法分子专门针对毕业生的诈骗高发期也随之来临。360手机安...

菠萝觅生活是O2O应用流量入口最大的供应商

现在主流的传统O2O生活服务,他们其实都有一个共通点,那就是各行其道。打车有快的,滴滴,外卖有饿了么,买机票有去哪儿网…每个APP都有着自己的核心竞争力。而用户呢?既想拥有海量有趣应用,又担心占用过多...

WP8.1版MSN健康应用,现已支持锁屏计步

IT之家(www.ithome.com):WP8.1版MSN健康应用,现已支持锁屏计步@WP之家报道,微软今天已将必应系列应用品牌归为MSN,除此之外,WP8.1版MSN健康和天气应用也获得一些新的...

短信就能传播手机病毒?看完推理惊呆了!

很多人都收到过一种带网址的陌生短信,有的人会点击网址看看,有的还会在好奇心驱使下回复短信。近日《北京新发现》栏目报道了一起离奇的电信诈骗案,事主耿先生的银行卡从未离身,但是在收到一条带网址的陌生短信,...

微软OneClip:我承包了你的剪贴板(微软onedrive云空间)

不久前,Twitter用户WalkingCat曝光了微软一款名为OneClip的应用。这是一款剪贴板应用,根据描述这款应用将覆盖Windows10(包括桌面和移动)、iOS和Android平台,可以...

Windows 10手机应该是什么样?微博用户给出了概念图

随着Windows10发布的不断临近,WindowsPhone的用户对Windows10的旗舰手机的期望也越来越高,我们WP中文网也在微博上发出了同样的问题,搜集用户对Windows10的硬...

云管家出席武汉2015年支付宝O2O生态峰会

2月4日,蚂蚁金服O2O生态峰会在武汉启幕。此次峰会展现了2015年蚂蚁金服在O2O领域的开放思路和策略,以及合作伙伴对O2O的创新观念及思路分享,吸引了武汉近3000名企业大佬、众多创业者、第三方服...

微软将于下周开启Windows开发中心帐号迁移工作

自下周开始微软将启动Windows开发中心的帐号迁移工作。根据WindowsBuildingApps博客透露Windows开发中心帐号迁移工作将会分为几个阶段。首个阶段从下周开始持续到今年7月份...

如何解绑已经合并的MSN账户和Skype账户?

如果您绑定的账户已经充值,建议您把产品消耗完毕后,再进行解绑。当您需要解绑合并的账户时,可登入Skype点卡账户自助操作。输入Skype或MSN账号、密码登录账户:登录后,可在页面左下角选择语言"中文...

微博账号已显示所属MCN机构,成为目前第二个上线该功能的平台

7月25日,多位网友发现,部分微博大V的个人主页已经显示其所属的MCN机构名称,微博也成为目前第二个上线该功能的平台。【来源:中新经纬】声明:此文版权归原作者所有,若有来源错误或者侵犯您的合法权益,您...

取消回复欢迎 发表评论: