改变隐式加载dll路径的方法(不修改环境变量)

问题:

今天我遇到了这样一个需求:随着代码的累计,dll越来越多了,想将exe所有依赖的dll放到子目录中,保持软件顶级目录的整洁.
但有个一限制条件--不能修改环境变量PATH.对于使用LoadLibrary加载的dll还好办,只需要修改dll所在的路径即可.但对于那些隐式加载的dll却无法分离(有些dll要么导出了大量的函数,如果使用LoadLibrary+GetProcAddess的方式工作量很大,还有些dll导出的是cpp的类,我就不知道怎么用Load的方式使用了).找了很多资料都没有答案,似乎这种需求无解了.

 

答案:

先定义明确一下概念(参见上述链接):
Windows下(Linux也是),加载动态链接库,有两种方式:
① 显式加载,或称“Run-Time Dynamic Linking”,即使用LoadLibrary、GetProcAddress等函数
② 隐式加载,或称“Load-Time Dynamic Linking”,即不使用以上那些函数,而是在编译选项里指定需要用到哪些dll,或在程序里使用“#pragma comment(lib,"xx.lib")
extern "C" void __declspec(dllimport) Func();” 等。


由此,图1的3的模块间的关系可以描述为:
TestLoadDll.exe 间接依赖(RunTime linking) wrapper.dll
wrapper.dll 直接依赖(LoadTime linking) core.dll

用一个简单的列子来说明.exe本来直接依赖于core.dll,可以使用以下方法来解除这种依赖,之后就可以将core.dll放到任意位置:
1.重构exe的代码,将所有exe直接依赖的dll用一个中间dll(wrapper.dll)封装起来.这一步的工作量可能比较大,但也是我能想到的唯一办法.再使用LoadLibrary调用这些封装好的函数.在这一步之后,用dependency walker查看exe就会发现,exe只依赖于一些系统的dll了.
现在把所有的dll放到某个子目录下,如bin下,启动exe,仍然报加载core.dll失败.这是因为在LoadLibrary("bin\\wrapper.dll")时,系统会自动加载wrapper.dll所有直接依赖的dll,其中就包含core.dll,但在指定的目录下都无法找到core.dll(对于dll搜素路径的讨论还是参见上述链接).

2.使用SetDllDirectory.msdn解释如下:
The SetDllDirectory function affects all subsequent calls to the LoadLibrary and LoadLibraryEx functions. After calling SetDllDirectory, the DLL search path is:
The directory from which the application loaded. 
The directory specified by the lpPathName parameter.
......
在第一次调用LoadLibrary之前就设置所有附加的dll搜索路径即可:

C/C++ code?

1

2

SetDllDirectory(L"bin\\");

HMODULE h = LoadLibrary(L"Wrapper.dll");



疑问:既然windows提供了SetDllDirectory,那么为什么不给一次机会在加载dll之前回调SetDllDirectory的机会呢?

 

疑问答案:

隐式加载的DLL是在EXE主体模块之前加载进来的,执行顺序上是先通过PE文件的导入表加载隐式的DLL,然后再加载EXE本体,所以你的想法不行。   需要使用延迟加载。

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值