说到DLL调用,大家都不会陌生,静态加载或动态加载就可以,但是如果出现多个调用多个DLL,同时还存在嵌套调用的情况,还会不会这就么简单呢?
当然,如果把所有的DLL和EXE都放在同一个目录下,绝对没问题;但若不在同一个目录下,能够运行正常吗?
这里做个试验,假设:EXE调用DLL1,而DLL1又调用DLL2;DLL1和DLL2放在子目录lib下,EXE放在根目录下。EXE调用DLL1采用绝对路径。
执行结果:
1. EXE调用DLL1 (成功)
2. DLL1调用DLL2 (失败)
分析:
第1个好理解,绝对路径都给了,哪能找不到啊;
第2个容易误解,有的人会想DLL2和DLL1在同一个目录下,怎么可能找不到DLL2呢。
这里需要明确一下,DLL是不能独立运行的,必须由主程序EXE将其加载到内存空间中才能运行,所以DLL2的路径不是以DLL1为参考,而是以EXE为参考的,而EXE是不知道DLL2在哪里的。如果把DLL2放在EXE的同一目录下,运行就正确了。
这里就引出了DLL的搜索路径,可以参考官方解释:Dynamic-Link Library Search Order
简单来说,基本的搜索顺序是:当前目录->system目录->windows目录->环境变量Path指定的目录。
(小提示:可以写个测试程序验证,或者使用Process Monitor来监测。)
那么,上面问题的解决方法是什么呢?
SetCurrentDirectory设置当前目录为子目录lib。
(注:msdn中也提到过用SetDllDirectory,但提示不是线程安全的,不推荐使用。)
最近做的一个项目也遇到了类似的问题,但比上面要复杂一些,上面例子中所说的DLL都是C/C++的DLL,而这个项目是C++调用C#编写的DLL,为了实现目的,在中间层增加了C++/CLR的DLL,上面的方法不适用,这里直接给出解决方法:在xxx.exe目录下增加配置文件xxx.exe.config,指定程序集目录,内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="lib"/>
</assemblyBinding>
</runtime>
</configuration>
问题是解决了,不过发连续运行两次,又会出现像找不到路径问题,最后是通过结合SetCurrentDirectory和xxx.exe.config两种方法一起使用才解决,其中的原因现在还不明确,因为它不是任何情况都出现,在单独的测试程序就没有问题,有知道的朋友,还请赐教,或者再深入研究研究。