更改Windows DLL加载顺序? (加载顺序,不是search顺序)

说我有一个可执行文件: app.exe

我在这个可执行文件中使用2个不同的第三方DLLfoo.dll bar.dll和应用程序必须隐式链接到这些DLL,也就是我不能使用::LoadLibrary来加载它们。

(注意:并不是我无法调用LoadLibrary ,但是这些DLL需要静态链接(C ++ DLL与__declspec(dllexport) ),所以我调用LoadLibrary没有任何意义,因为可改变的加载器已经调用它了。

这两个DLL 没有任何依赖关系,也就是说,他们的加载顺序是不确定的,据我所知( 应该是不相关的)。 (两者的依赖关系基本上只在标准的windows dll(kernel32,msvcrt等)

我现在有问题,我希望控制这些DLL的加载顺序,那就是我希望foo.dll 总是在bar.dll之前加载( DLL_PROCESS_ATTACH )。

是不是有可能告诉Windows DLL加载器加载一个DLL之前?

编辑:要检查可执行文件的DLL加载顺序 ,可以使用DUMPBIN.exe实用程序:(只需启动Visual Studio命令提示符)

编辑:根据这个答案 / 这个博客条目 ,NT加载程序确实按顺序走入导入部分。 (这将导致独立的 DLL以它们出现在导入部分的顺序加载。)

 C:\path\to\program> dumpbin /IMPORTS app.exe | grep -i \.dll MSVCR80D.dll KERNEL32.dll OLEAUT32.dll MSVCP80D.dll foo.dll bar.DLL 

这个输出意味着MSVCR80D.dll(及其依赖[a] )将首先被加载,并且bar.DLL将被最后加载。 卸载将以相反的顺序发生。

还没有发现的是如何影响这个加载顺序


(笔记)

[a]:当然,这意味着kernel32.dll将被加载,因为msvcr80d.dll将依赖于kernel32.dll。


根据一些要求,我为此添加了一个基本原理:( 但是 ,我仍然对此感兴趣, 我知道如何解决MFC问题。

在它的debugging版本中的Microsoft MFC DLL内置了内存泄漏检测。(据我所知,这是_CrtSetDbgFlag和相关工具所使用的机制)。

当它被卸载时,MFCdebuggingDLL将转储所有不确定的内存。 现在,如果您的进程中有第二个DLL,它独立于MFC,并且此第二个DLL在DLL_PROCESS_DETACH上取消分配内存,则MFC报告机制将报告错误的内存泄漏,如果MFC DLL在其他dll之前被卸载。

如果可以确保debugging的MFC DLL是首先加载/卸载所有独立DLL的最后一个,那么所有其他的DLL本身已经清理完毕,并且MFC不会报告错误的泄漏。

这里有一个想法:如何在app.exe的链接器选项app.exe它们标记为“Delay Loaded dlls”?

延迟加载将允许您链接“静态”(即没有LoadLibrary()et.al),但不会加载该DLL,并进行连接,直到实际需要。

如果这是一个选项,那么(假设你可以等待这么久,即在main()之前不要访问foo / bar dll函数),你可以在main()中访问一个函数(只需要获取一个函数ptr或其他东西)在foo.dll首先,这将加载它并绑定所有“静态”链接的功能?

(也许LoadLibrary()触发相同的链接时需要的过程。不知道,它会看起来更清洁,但你的代码。

只需将foo.dll添加到foo.dll的导入表中,操作系统加载程序将处理剩下的部分。

你应该可以在没有bar.dll源代码的情况下做到这bar.dll ,不知道editbin工具是否有这样的选项,但是这对PE文件来说是一个相当简单的编辑。

你也许可以使用预加载DLL的注册表设置,但是我不这么做,你不想让foo.dll加载到其他不需要它的进程中。

我还没有发现的是如何影响这个加载顺序…

我不知道为什么我没有尝试过,但看起来模块的导入部分的顺序依赖于lib文件提供给链接器的顺序。

 Configuration Properties -> Linker -> Additional Dependencies ... 

这里列出的lib文件也是第一个在导入部分, 这意味着加载器将按顺序导入这些文件(模依赖关系)。

所以,要回答这个部分: 只需要以正确的顺序提供lib文件给链接器。

注意 :我已经在VS2005上试过了,它似乎工作。 我不知道这是否记录在某处,或者如果它更新版本的VC ++中更改。


更新:当它回来的时候,今天我碰到加载顺序不受 lib文件的链接器命令行顺序影响的情况。 (仍)不知道为什么。 (还是VS2005)

然而,我已经设法通过将有问题的DLL添加到延迟加载的DLL列表(如在Macke的答案中 )来使其工作。


如果不链接导入库(foo.lib和bar.lib),那么加载程序不会在启动时自动加载DLL,您可以随时调用LoadLibrary()。

在一个侧面说明中,我写了一个方便的小型库,用于在运行中封装加载DLL,而不必直接处理LoadLibrary / GetProcAddress。 你可以在这里阅读。