改变隐式加载dll路径的方法(不修改环境变量),该怎么解决

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

就在山穷水尽准备放弃之时,找到了一个并不完美的方法--因为需要重构部分代码,项目越庞大,需要的工作量也越多.

先定义明确一下概念(参见上述链接):
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

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



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

实例源代码下载地址(vs2005):
http://115.com/file/bhyqhjr8#TestLoadDll.zip


------解决方案--------------------

因为对于这些隐式加载的Dll,在你的代码即PE中的EP(EntryPoint)得到执行前,都已经被加载了,所以没法给你机会啊
------解决方案--------------------
隐式加载的DLL是在EXE主体模块之前加载进来的,执行顺序上是先通过PE文件的导入表加载隐式的DLL,然后再加载EXE本体,所以你的想法不行。