首页 > 编程知识 正文

loadlibrary失败信息193,loadlibrary错误193

时间:2023-05-04 03:17:15 阅读:246389 作者:2462

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

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

-- core.exe |--module |--iot.dll |--mqtt.dll

目录是视图如上所示,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

当然,你可以通过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的查找路径,这个问题就不会排查这么久了,不过,在排查问题的过程中,学到了很多东西,包括新工具的使用,对一些东西理解也深刻了很多,同时也发现了知识盲区,知道自己不知道了。

托管Hadoop集群 快速上手 UHadoop

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。