在开发一些Windows下的应用程序过程中,经常会手动加载一些DLL,使用的就是LoadLibrary这个函数,而这个函数一旦失败,返回的错误码基本都是126,126错误码的意思是找不到指定的模块,这不,我就遇到了这个问题,而且挺诡异的,就是Debug模式下一点问题没有,Release模式下就必出这个错误码。

先介绍下问题的环境,一个应用程序需要加载一个IoT模块的DLL,这个DLL又依赖了一些DLL。有经验的老司机或者对DLL加载这块很熟悉的人应该很快就知道问题所在了。不急,慢慢介绍。

-- core.exe
  |--module
    |--iot.dll
    |--mqtt.dll
1
2
3
4
目录是视图如上所示,core.exe会LoadLibrary目录module下iot.dll,而iot.dll又依赖mqtt.dll。

当时我都没有意识到IoT这个DLL还依赖了别的DLL这一个关键点,

所以我排查问题的第一步,既然找不到指定模块,那么就先看看对应位置下到底有没有iot.dll,很遗憾,有!

第二步,既然Debug和Release下表现地不一样,那么想会不会是是iot.dll的一些编译链接选项在这两种模式下不一样导致DLL有问题?于是就手动修改成Release模式下使用Debug来编译,还是不行,依然返回错误码126。

第三步,既然以自己现有的知识搞不定了,那么就只能求助Google了,搜索了一波"LoadLibrary error 126 Release",没看到别人在Release下出现过这种问题,反倒是查出来,出现126错误码一般是DLL所依赖的DLL没有找到,就会出现这种问题。这时候才意识到iot.dll还依赖了mqtt.dll,于是又去确认了下mqtt.dll,发现对应位置有这个DLL。这下完全懵了。

第四步,在stackoverflow上有一个大神https://stackoverflow.com/questions/14361992/dll-load-library-error-code-126 给出了一个分析的方法,大概意思我翻译下:

Windows dll 错误码126有很多原因,最有用的调试方案如下:

使用Dependency Walker[http://www.dependencywalker.com/]查看你的dll依赖;
使用Process Monitor[https://docs.microsoft.com/zh-cn/sysinternals/downloads/procmon]去追踪dll加载时的所有文件操作。
第五步,先用第一个工具Dependency Walker分别看了下Debug和Release下的iot.dll,发现没用到的DLL在Release下被优化掉了,依然没看出来问题。但所有依赖的DLL在对应位置都存在,这依然没有解决问题。

第六步,没办法,只能使用Process Monitor了,这个我之前没用过,简单看了熟悉了下它,发现它和Linux下的strace命令很像,都是追踪程序运行过程中的系统调用和行为,终于我看到了以下的东西:

可以看到,iot.dll已经LoadImage了,但是它的依赖DLLmqtt.dll一直没找到,而且可以看出Windows在LoadLibrary时的查找路径,如下:

程序目录,也就是exe所在目录
系统目录
Windows目录
进程当前目录
环境变量PATH目录
而反观我的DLL所在位置,不在这上面的任意一个里面,因此,报出126错误码是很合理的。

解决的方法就很简单了,根据加载的第一顺序拷贝下依赖的DLLmqtt.dll到程序目录下就行了。

-- core.exe
  |--module
    |--iot.dll
    |--mqtt.dll
  |--mqtt.dll
1
2
3
4
5
当然,你可以通过SetCurrentDirectory改变当前进程目录来达到顺利加载DLL的目的,不过别忘了把通过GetCurrentDirectory把当前目录恢复回去;有一个函数SetDllDirectory是专门用来指定DLL的搜索路径的,这个更好,如果使用了这个函数,那么DLL的加载顺序会有点不同,如下:

进程当前目录
SetDllDirectory指定的目录
系统目录
Windows目录
进程当前目录
环境变量PATH目录
设置了这个之后,就会发现不会在程序所在目录下搜索DLL了,反而会把进程当前目录作为第一顺序。因此,如果你的应用程序下面有同名的DLL,这个DLL不是你想要的,那就一定要用SetDllDirectory这个函数了。

其实微软已经给我们提供了更好的方式,LoadLibrary有一个扩展函数LoadLibraryEx [https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw],里面有个参数LOAD_WITH_ALTERED_SEARCH_PATH,可以让DLL的搜索路径从DLL所在目录开始,这个同样可以使用Process Monitor去观察其行为。那么这个扩展函数和不扩展的有啥区别呢?下面是我摘抄的一段:

The LoadLibraryEx function is very similar to the LoadLibrary function. The differences consist of a set of optional behaviors that LoadLibraryEx provides:

LoadLibraryEx can load a DLL module without calling the DllMain function of the DLL.
LoadLibraryEx can load a module in a way that is optimized for the case where the module will never be executed, loading the module as if it were a data file.
LoadLibraryEx can find modules and their associated modules by using either of two search strategies or it can search a process-specific set of directories.
设置了SetDllDirectory,LoadLibrary和LoadLibraryEx使用的搜索算法是一样的,这个我通过Process Monitor已经看过了。

总结一下,这其实是一个很常识的问题,加载有依赖的DLL时要注意依赖DLL的位置,可是自己之前对这部分知识有盲区,导致思路打不开。如果我早知道DLL的查找路径,这个问题就不会排查这么久了,不过,在排查问题的过程中,学到了很多东西,包括新工具的使用,对一些东西理解也深刻了很多,同时也发现了知识盲区,知道自己不知道了。
————————————————
版权声明:本文为CSDN博主「FlushHip」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/FlushHip/article/details/96167157

LoadLibrary下错误返回126错误码排查过程相关推荐

  1. curl返回常见错误码

    关注公众号 风色年代(itfantasycc) 300G微服务资料等你拿! curl返回常见错误码 - 阿波伦 - 博客园 CURLE_OK(0) 成功. CURLE_UNSUPPORTED_PROT ...

  2. 使用百度地图定位功能第一次成功,第二次开始返回505错误码

    使用百度地图定位功能第一次成功,第二次开始返回505错误码 505错误码的意思是AK错误,申请AK的时候要严格按照官网的教程 http://lbsyun.baidu.com/index.php?tit ...

  3. libcurl中上传文件的坑-英文操作系统中文路径无法上传返回26错误码

    libcurl中上传文件的坑-英文操作系统中文路径无法上传返回26错误码 最近在使用libcurl使用表单形式上传本地文件,自己测试的时候都没有问题,但是在测试的电脑上无法上传,返回26错误码,在li ...

  4. linux udp 广播recvfrom 返回 -1 错误码是 11 EAGAIN Resource temporarily unavailable

    版本:银河麒麟桌面操作系统V10(SP1) 内核:Linux 5.4.18-28.23-bj-generic CPU:Loongson-3A5000 架构:loongarch64-linux-gnu ...

  5. 中文解释“GetLastError()返回值”---错误码大全

    GetLastError函数的定义形式为: DWORD GetLastError(VOID); SetLastError函数主要在对api函数进行模拟的dll函数中使用. (0)-操作成功完成. (1 ...

  6. VC中GetLastErro返回的错误码

    原文地址:http://www.cnblogs.com/braver/articles/2563157.html [0]-操作成功完成. [1]-功能错误. [2]-系统找不到指定的文件. [3]-系 ...

  7. Tars框架及Dcache返回的错误码一览

    简介 看到这篇文章的同学,应该都知道Tars和Dcache了. 但在使用时,有时会遇到冰冷的数字:错误码. 由于没有文字描述性信息,还要回去查看各种文档,甚至查看源码.这是笔者的经历. 经过查找,找到 ...

  8. CreateProcess返回740错误码

    该错误码的原因是权限问题,理论上认为是执行这代码的程序权限不够的问题,但有时却不是. 解决办法1:调用程序以管理员权限运行 解决办法2:即调用程序以管理员的权限运行时,还是会出现此错误,这时,可以修改 ...

  9. 【FFmpeg】ffmpeg中函数返回的错误码:AVERROR及AVERROR_*

    1.AVERROR FFmpeg的错误码大部分使用的PIOSIX标准中错误码的负值. AVERROR定义在文件 FFmpeg-n4.2.1/libavutil/error.h 中 #define AV ...

最新文章

  1. 2019年必须掌握的29个微服务面试问题(下)
  2. Web应用程序信息收集工具wig
  3. wp8.1 Study7: ListView 和GridView应用
  4. 《看聊天记录都学不会C语言?太菜了吧》(13)(9*9 乘法表)寻找电脑中的盲盒彩蛋
  5. 38 SD配置-销售凭证设置-定义拒绝原因
  6. 简洁大气好看的个人博客模板HTML源码
  7. python-temp-0626随堂
  8. LightOJ 1074 Extended Traffic(spfa+dfs标记负环上的点)
  9. java axis2 开发webservice_一、Axis2 WebService开发准备工作
  10. 更换pycharm主题
  11. 智慧校园视频监控管理系统平台建设的详情分析
  12. linux 繁体转简体,linux2 简体中文转繁体
  13. (五)可重入锁ReentrantLock的底层原理实现?
  14. java学习代码01 范围:基本测试、标识符、数据类型、运算符、控制语句
  15. acwing算法基础课
  16. SQL学习笔记(02)_别名
  17. mrtg流量图不更新了是怎么回事,谁有mrtg的安装及配置文档啊,求!!!
  18. 电脑只有一个c盘怎么办?看我怎么一招解决!
  19. 下载和安装MySQL(傻瓜)教程
  20. 微信开放平台之公众号第三方平台开发及全网发布验证

热门文章

  1. 《托尔斯泰的烦恼》纪录片笔记
  2. 安装 - LNMP一键安装包
  3. 上市即亏损?谈谈爱奇艺和拼多多上市后的艰难人生
  4. 波段选择方法综述:Hyperspectral Band Selection A review
  5. 模拟器左下方数字含义
  6. Cell | 深度突变学习预测SARS-CoV-2受体结合域组合突变对ACE2结合和抗体逃逸的影响...
  7. 7.23翻倍奖励——滴滴快车单(成交率≥60%,≥5指派单)
  8. 刚出的!2019中囯城市实力大排名!看完惊到了!
  9. esphome 在添加设备是出现错误
  10. 大话设计模式-第12章 牛市股票还会亏钱?--外观模式