原文地址:http://blog.csdn.net/my_business/article/details/8850151

某个桌面程序在win 8上运行异常的问题困扰了我有近一周,今天终于找到了根本原因,严重怀疑是win 8的一个Bug。
(所有程序都是desktop app,跟Metro模式无关)
情况是这样的,比如有个Main.exe会通过CreateProcess启动另外一个Sub.exe,而这个Sub.exe中会通过LoadLibrary动态加载多个动态链接库,Main.exe和Sub.exe以及相关dll都不在同一路径,所以在Sub.exe中会通过SetCurrentDirectory来设置dll的搜索路径以保证LoadLibrary可以正常找到dll并加载。这些程序在WinXP,Win7下都运行正常,但是到了Win8下运行时就报出某dll找不到(126)的错误。比较了代码以及一切相关设置都跟Win7完全相同,但dll就是不能正常加载。
 
第一层分析,检查了在Win8下SetCurrentDirectory是否正常工作,发现设置成功,一切正常。然后查了MSDN,windows下dll默认的搜索路径是:
1. 应用程序所在的路径
2. 当前目录(SetCurrentDirectory所设置的路径)
3. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
4. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
5. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
6. PATH环境变量指定的路径。
也就是说通过SetCurrentDirectory设置的第二项“当前目录”,在dll检索中没有起作用。那什么API会影响到dll搜索路径呢?
 
第二层分析,发现通过SetDllDirectory这个API可以直接设置dll搜索路径,而通过此API设置后搜索路径就变成:
1. 应用程序所在的路径
2. SetDllDirectory所设置的路径
3. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
4. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
5. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
6. PATH环境变量指定的路径。
也就是说如果你使用过SetDllDirectory来设置路径,那即使你再用SetCurrentDirectory来设置当前路径,它也不会属于dll搜索路径中。
 
第三层分析,难道是Sub.exe或者某个dll中调用了SetDllDirectory,搜索了下,一个没有。总不会是Main.exe中有调用从而会影响到Sub.exe吧?搜了下Main.exe的相关代码,确实发现有几处调用了SetDllDirectory。尝试在Sub.exe中通过GetDllDirectory打出该路径,发现不为空,确实是在Main.exe设置过的值。基本确定是原因。
 
第四层分析,那SetDllDirectory的设置怎么会从Main.exe传递到了Sub.exe,查看了调用CreateProcess的第五个参数(关于句柄继承的那项),确实设置成True了,难道这个改下就能解决?立马改成False,再试,还是失败。何况一样的处理在Win7下是正常的,说明肯定有什么特性在Win8下有差异。再回到SetDllDirectory,在Win7下尝试了下,不管CreateProcess的第五个参数设置True还是False,Main.exe中SetDllDirectory的设置都不会传递到Sub.exe,而Win8则相反会传递。
 
第五层分析,那怎么解决呢?尝试了在Main.exe调用CreateProcess启动Sub.exe前,或者在Sub.exe中通过SetDllDirectory(“”)来清除已有的设置,可以解决这个问题。另外比较推荐在所有通过调用SetDllDirectory来设置搜索路径并加载关联dll后马上通过SetDllDirectory(“”)来清除,防止影响到后续的其他处理。
 
目前为止仍旧想不通为什么会有这么恶心的区别。
 
结论:
  1. 这很可能是属于 Win8的一个 Bug
  2. 由于 Win7和 Win8下的这些差异,尽量保证 exe和所关联 dll在同一路径,或者尽量都用绝对路径去调用 LoadLibrary
  3. 如果使用 SetCurrentDirectory来配置 dll搜索路径时,当 exe由其他进程启动时,系统变量或句柄会可能受父进程的影响
  4. 网上还看到可以通过manifest文件来解决,目前还没有尝试。
 

【转】Windows 8 desktop app中dll搜索路径设置的诡异现象,Bug?的更多相关文章

  1. DLL搜索路径和DLL劫持

    DLL搜索路径和DLL劫持 环境:XP SP3 VS2005 作者:magictong 为什么要把DLL搜索路径(DLL ORDER)和DLL劫持(DLL Hajack)拿到一起讲呢?呵呵,其实没啥深 ...

  2. 关于DLL搜索路径顺序的一个问题

    DLL的动态链接有两种方法.一种是加载时动态链接(Load_time dynamic linking).Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SY ...

  3. 关于指定dll搜索路径

    原文:关于指定dll搜索路径 问题现象 当部分DLL放在子文件夹下,需要指定DLL搜索路径,否则系统将找不到文件 产生原因 系统默认搜索只会在前程序目录并不包括子目录 解决方法 1,使用App.con ...

  4. 关于DLL搜索路径的顺序问题

    DLL的动态链接有两种方法.一种是加载时动态链接(Load_time dynamic linking).Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SY ...

  5. C和C++中include 搜索路径的一般形式以及gcc搜索头文件的路径

    C和C++中include 搜索路径的一般形式 对于include 搜索的路径: C中可以通过 #include <stdio.h> 和 #include "stidio.h&q ...

  6. .NET 6学习笔记(4)——如何在.NET 6的Desktop App中使用Windows Runtime API

    Windows Runtime API是当初某软为了区别Win32 API,力挺UWP而创建的另一套Windows 10专用的API集合.后来因为一些原因,UWP没火.为了不埋没很有价值的Window ...

  7. Linux 静态库与动态库搜索路径设置详解【转】

    原文地址:http://blog.chinaunix.net/uid-29025972-id-3855495.html 1. 连接和运行时库文件搜索路径的设置 库文件在连接(静态库和共享库)和运行(仅 ...

  8. linux动态库默认搜索路径设置的三种方法

    众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/lib .动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两 ...

  9. LaTeX自定义宏包、类文件的默认搜索路径设置方法

      对于自定义的LaTeX宏包与类,在调用时可以通过在命令\documentclass{}与\usepackage{}命令中指定完整路径或者相对路径,这样确实可以调用,但是编译时总是有烦人的警告信息, ...

随机推荐

  1. classmethod,staticmethod

    '''1 绑定方法: 在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法 绑定对象的方法特殊之处: 应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入 绑定到类 ...

  2. android上的i-jetty (1)环境搭建

    介绍下如果把android设备作为一个web服务器使用, 编译i-jetty 1. 将源码download下来,http://code.google.com/p/i-jetty/downloads/l ...

  3. 差值的再议-Hermite差值

    1. 插值法 插值法又称“内插法”,是利用函数f (x)在某区间中已知的若干点的函数值,作出适当的特定函数,在区间的其他点上用这特定函数的值作为函数f (x)的近似值,这种方法称为插值法. 如果这特定 ...

  4. adb push 和 adb pull命令

    adb push命令 :从电脑上传送文件到手机: adb pull命令 :从手机传送文件到电脑上             @Cocos 下次需要权限的目录可以执行chmod 777 目录名      ...

  5. DXP常用有效的快捷操作记录

    1.在PCB中快速选中一个器件 1)  M+C+Enter将弹出元件对话框,移动一个元件后,在十字架光标 状态时按[Enter]键 2)M(Move)+M(Move)按下时,鼠标光标变成“+”后,点击 ...

  6. JVM中的新生代、老年代和永生代

    1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...

  7. Python 中的深拷贝和浅拷贝

    一.浅拷贝python中 对象赋值时 默认是浅拷贝,满足如下规律:1. 对于 不可变对象(字符串,元组 等),赋值 实际上是创建一个新的对象:例如: >>> person=['nam ...

  8. jquery基于form-data文件上传

    1.html代码 <input type="file" name="myupdate" id="myupdate"> 2.jav ...

  9. Ubuntu修改apt-get源

    1.背景 服务器上安装了最新的Ubuntu Server 17.04,代号为zesty.使用apt-get命令安装软件时,有时候速度比较慢,有时候会失败.因此考虑用国内的镜像源更换下apt-get的默 ...

  10. 【洛谷4238】 多项式求逆(NTT,分治)

    前言 多项式求逆还是爽的一批 Solution 考虑分治求解这个问题. 直接每一次NTT一下就好了. 代码实现 #include<stdio.h> #include<stdlib.h ...