DLL的动态链接有两种方法。一种是加载时动态链接(Load_time dynamic linking)。Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径。

前天看到这几句,突然设计出一道自认绝妙的笔试题:
"如果采用加载时动态链接的方式,Windows搜索要装入的DLL采用怎样的顺序?"
这个是基础题,估计你很容易答出(答案就是上面的)。呵呵,我还有后着呢:
"你是如何证明Windows搜索要装入的DLL遵循这样的顺序呢,说出你的证明步骤"

你可以思考一下。下面是我设想的一个方案,但是自己测试了一下。结果却令人吃惊。

我的证明步骤是这样的:
1. 首先新建一个MFC 常规DLL工程OutputModulePath,在里面添加一个API函数,功能就是打印DLL所在路径,然后将其导出,代码如下:

  1. void PaintModulePath()
  2. {
  3. extern COutputModulePathApp theApp;
  4. TCHAR szModulePath[MAX_PATH];
  5. :: GetModuleFileName(theApp.m_hInstance,szModulePath, MAX_PATH);
  6. AfxMessageBox(szModulePath);
  7. }

2. 编译这个DLL工程,然后将生成的DLL文件OutputModulePath.dll复制到当前目录、Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径。这里要说明一下:如果调试运行的话,当前目录应该是当前目录的工程文件所在的路径,如果单击直接运行的话,当前目录应该是exe程序所在的路径,具体可以通过一下代码获取当前目录:

  1. TCHAR szBuf[MAX_PATH];
  2. ::ZeroMemory(szBuf,MAX_PATH);
  3. if (::GetCurrentDirectory(MAX_PATH,szBuf) > 0)
  4. {
  5. //获取进程目录成功。
  6. AfxMessageBox(szBuf);
  7. }

PATH环境变量指定的路径这里可能有多个路径,这里只须将OutputModulePath.dll拷贝到其中之一就行,例如我拷贝到的是:D:/Program Files/Lua/5.1。

3. 建一个测试工程(对话框程序或单文档程序都可以),在里面调用PaintModulePath函数。
我的测试步骤及结果是这样的,按F5调试运行测试程序,首先程序输出的是exe程序所在的路径,然后我将exe程序路径下的dll文件删除,但接着输出的是C:/WINDOWS/system/OutputModulePath.dll,我将C:/WINDOWS/system/OutputModulePath.dll删除,接着输出的是C:/WINDOWS/ OutputModulePath.dll,将C:/WINDOWS/ OutputModulePath.dll删除,输出的才是当前目录下的文件路径,最后输出的是PATH环境变量指定的路径。

这样的结果和书上的理论不符。难道我的测试方案有什么不对吗?

到论坛一问,得到一个答案是微软上的一篇文章:

Dynamic-Link Library Search Order

现在把它翻译一下:

动态链接库的搜索顺序

一个系统可以包含多个版本的同一个动态链接库(dll)。应用程序能够通过使用动态链接库重定向清单文件 指定要加载的DLL的全路径。如果没有使用这些方法,这篇文章将讲述在装入DLL时DLL的搜索顺序。

标准的搜索顺序

DLL的搜索顺序取决于是否安全DLL搜索模式是启用或禁用。
安全DLL搜索模式在默认状态下是启用的。通过创HKLM/System/CurrentControlSet/Control/Session Manager/SafeDllSearchMode注册表项并将它的值设为0可以关闭这个属性。通过调用SetDllDirectory函数可以有效禁用安全DLL搜索模式而在这篇文章中这个函数指定的路径将加入搜索范围并改变搜索顺序。

Windows XP and Windows 2000 with SP4: 安全DLL搜索模式在默认状态下是禁用的。通过创HKLM/System/CurrentControlSet/Control/Session Manager/SafeDllSearchMode注册表项并将它的值设为1可以启用这个属性。安全DLL搜索模式在默认状态下得到启用始于带sp2的Windows XP。

Windows 2000: 并不支持安全DLL搜索模式。在这种情况下DLL的搜索顺序和安全DLL搜索模式被禁用的情况下的顺序是一样的。安全DLL搜索模式得到支持始于带sp4的Windows 2000。

假如安全DLL搜索模式启用,搜索顺序如下:
1. 应用程序所在的路径
2. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
3. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
4. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
5. 当前目录
6. PATH环境变量指定的路径。请注意,这并不包括每个应用程序的应用程序路径注册表项中指定。在应用程序路径注册表项的键值并不作为DLL的搜索路径。

假如安全DLL搜索模式禁用,搜索顺序如下:
1. 应用程序所在的路径
2. 当前目录
3. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
4. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
5. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
6. PATH环境变量指定的路径。请注意,这并不包括每个应用程序的应用程序路径注册表项中指定。在应用程序路径注册表项的键值并不作为DLL的搜索路径。

预备的搜索顺序

由系统指定的标准搜索顺序可以通过调用LoadLibraryEx函数加上LOAD_WITH_ALTERED_SEARCH_PATH参数值得到改变。标准搜索顺序也可以通过调用SetDllDirectory函数得到改变。

Windows XP: 通过调用SetDllDirectory函数来改变标准搜索顺序并不支持直到Windows XP sp1出现。
Windows 2000: 不支持通过调用SetDllDirectory函数来改变标准搜索顺序。

如果您指定一个备用的搜索顺序,程序将按备用的搜索顺序进行搜索,直到所有相关的可执行模块被找到。系统启动后,DLL初始化例程处理,该系统将恢复为标准的搜索顺序。

LoadLibraryEx函数通过指定LOAD_WITH_ALTERED_SEARCH_PATH属性和lpFileName参数指定一个绝对路径支持一个预备的搜索顺序。

请注意:标准搜索顺序和通过调用指定LOAD_WITH_ALTERED_SEARCH_PATH属性的LoadLibraryEx函数来设置的预备搜索顺序只是有一点不同:标准搜索顺序开始于搜索1. 应用程序所在的路径而预备搜索顺序开始于LoadLibraryEx函数所要加载的可执行模块的所在目录。

假如安全DLL搜索模式启用,搜索顺序如下:

1. lpFileName参数值所指定的目录
2. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
3. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
4. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
5. 当前目录
6. PATH环境变量指定的路径。请注意,这并不包括每个应用程序的应用程序路径注册表项中指定。在应用程序路径注册表项的键值并不作为DLL的搜索路径。

假如安全DLL搜索模式禁用,搜索顺序如下:

1. lpFileName参数值所指定的目录
2. 当前目录
3. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
4. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
5. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
6. PATH环境变量指定的路径。请注意,这并不包括每个应用程序的应用程序路径注册表项中指定。在应用程序路径注册表项的键值并不作为DLL的搜索路径。

假如lpPathName参数指定了一个路径,SetDllDirectory函数支持一个预备的搜索顺序。这个预备的搜索顺序如下:

1. 应用程序所在的路径
2. lpPathName参数指定的目录
3. Windows SYSTEM目录。通过调用GetSystemDirectory函数可以获取这个目录的路径。
4. 16位系统的目录。并没有函数可以获取这个目录的路径,但是它会被查找。
5. Windows目录。通过调用GetWindowsDirectory函数可以获取这个目录的路径。
6. PATH环境变量指定的路径。请注意,这并不包括每个应用程序的应用程序路径注册表项中指定。在应用程序路径注册表项的键值并不作为DLL的搜索路径。

如果lpPathName参数为一个空字符串,当前目录将会从搜索顺序中删除。
SetDllDirectory 有效地禁用安全DLL搜索模式,而在搜索指定的目录路径。要恢复安全 DLL搜索模式的SafeDllSearchMode注册表值的基础和恢复当前目录到搜索顺序,调用 lpPathName的参数值为NULL的SetDllDirectory函数。

看完这篇文章,我大致知道了我的测试为何会出现那个结果,因为我的操作系统环境是Win XP + sp3。

参考文献:

1. MFC深入浅出

关于DLL搜索路径顺序的一个问题的更多相关文章

  1. DLL搜索路径和DLL劫持

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

  2. 【转】Windows 8 desktop app中dll搜索路径设置的诡异现象,Bug?

    原文地址:http://blog.csdn.net/my_business/article/details/8850151 某个桌面程序在win 8上运行异常的问题困扰了我有近一周,今天终于找到了根本 ...

  3. 关于指定dll搜索路径

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

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

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

  5. python 搜索路径顺序查找

    但我们通过 import 或者frome .. import...查找模块的时候,当你导入一个模块,Python 解析器对模块位置的搜索顺序是 1.当前目录 2, 如果不在当前目录,Python 则搜 ...

  6. 同一个dll 不同路径下注册 一个失败 一个成功

    一个路径下用regsvr32注册成功,一个注册失败,提示平台不兼容. 最后用depends查看依赖的dll,发现依赖的dll有问题,从注册成功的路径下复制一个过来,重新注册就成功了

  7. python的搜索路径与包(package)

    python的搜索路径其实是一个列表,它是指导入模块时,python会自动去找搜索这个列表当中的路径,如果路径中存在要导入的模块文件则导入成功,否则导入失败: >>> import ...

  8. exe加载DLL的时候会有一系列的搜索路径

    假如安全DLL搜索模式启用,搜索顺序如下: 1. 应用程序所在的路径 2. Windows SYSTEM目录.通过调用GetSystemDirectory函数可以获取这个目录的路径. 3. 16位系统 ...

  9. Windows平台LoadLibrary加载动态库搜索路径的问题

    一.背景 在给Adobe Premiere/After Effects等后期制作软件开发第三方插件的时候,我们总希望插件依赖的动态库能够脱离插件的位置,单独存储到另外一个地方.这样一方面可以与其他程序 ...

随机推荐

  1. iOS keyChain(钥匙串)的简单使用

    通常在开发中我们需要长久的保存某些值比如用户的账号密码等,对于隐私度很高的数据来说保证数据的安全性是尤为重要的.ios中的keyChain是一种很好的选择. 首先去开发者网站(https://deve ...

  2. [非技术参考]C#基础:使用Thread创建线程(1)

    Thread类可以创建和控制线程,Thread类的构造函数重载为接受ThreadStart和ParameterizedThreadStart类型的委托参数.下面我们用一个例子来解释怎样用Thread类 ...

  3. mysql alter example

    alter table `user_movement_log` AFTER `Regionid` (在哪个字段后面添加) ) default null; //主键 ) unsigned not nul ...

  4. Labview中引用,属性节点,局部变量之间的区别

    Labview中引用,属性节点,局部变量之间的区别        在Labview中我们经常会碰到这样几个概念,那就是控件的引用,属性节点以及局部变量,他们之间到底有哪些区别呢?        首先谈 ...

  5. 眼花缭乱的UI,蓝牙位于何方

    我们在前面已经分析了Android启动中涉及蓝牙的各个方面,今天我们着重来看看,在蓝牙打开之前,我们能看到的蓝牙UI有哪些,这些UI又是如何实现的. 1,settings中UI的分析 首先,最常见的也 ...

  6. javascript笔记—面向对象

    什么是对象: 对象是一个整体,对外提供一些操作. 什么是面向对象: 使用对象时,只关注对象提供的功能,不关注其内部细节,例如jquery 面向对象是一种通用思想,并非只有编程中能用,任何事情都可以用. ...

  7. 【转】Eclipse自动补全的设置方法

    转自:http://blog.csdn.net/xiadasong007/archive/2009/11/11/4799715.aspx 打开 Eclipse -> Window -> P ...

  8. ortoiseSVN无法编辑日志信息的解决方法

    提交时忘记编写日志,想重新编辑日志信息,弹出错误提示: DAV 请求失败:可能是版本库的 pre-revprop-change 钩子执行失败或者不存在 至少有一个属性变更失败:版本库未改变 设置属性  ...

  9. ElasticSearch D3

    http://www.elasticsearch.org/blog/data-visualization-elasticsearch-aggregations/

  10. OP(Over-provisioning)预留空间

    SSD上的OP指的是用户不可操作的容量,大小为实际容量减去用户可用容量,OP区域一般被用于优化操作如:WL,GC和坏块映射等.       OP一般分三层(见下图).第一层容量固定为SSD标称容量的7 ...