更改 Windows DLL 加载顺序?(加载顺序,不是搜索顺序)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6371779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Changing Windows DLL load order? (load order, not search order)
提问by Martin Ba
Say I have one executable: app.exe
假设我有一个可执行文件: app.exe
I use 2 different 3rd party DLLs in this executable: foo.dll
bar.dll
and the Application must link implicitly to these DLLs, that is I cannot use ::LoadLibrary
to load them.
我在这个可执行文件中使用了 2 个不同的 3rd 方 DLL:foo.dll
bar.dll
应用程序必须隐式链接到这些 DLL,也就是说我不能::LoadLibrary
用来加载它们。
(Note: It's not that I cannot call LoadLibrary
, but these DLLs require static linking (C++ DLLs with __declspec(dllexport)
), so me calling LoadLibrary
doesn't make any sense because the excutable loader has already called it.)
(注意:并不是我不能调用LoadLibrary
,而是这些 DLL 需要静态链接(C++ DLL 带有__declspec(dllexport)
),所以我调用LoadLibrary
没有任何意义,因为可执行加载器已经调用了它。)
These two DLLs do nothave any dependencies on each other, that is, their load order is undefined as far as I can tell (and shouldbe irrelevant). (Dependencies of both are basically only on the standard windows dlls (kernel32, msvcrt, etc.)
这两个 DLL彼此之间没有任何依赖关系,也就是说,据我所知,它们的加载顺序是未定义的(并且应该无关紧要)。(两者的依赖关系基本上只依赖于标准的 windows dll(kernel32、msvcrt 等)
I now have the problem that I wish to control the load order of these DLLs, that is I wish that foo.dll is alwaysloaded (DLL_PROCESS_ATTACH
) before bar.dll.
我现在有一个问题,我希望控制这些 DLL 的加载顺序,即我希望 foo.dll总是DLL_PROCESS_ATTACH
在 bar.dll 之前加载 ( )。
Is it somehow possible to tell the Windows DLL Loader to load one DLL before another?
是否有可能告诉 Windows DLL Loader 在另一个之前加载一个 DLL?
Edit: To check the DLL load orderof an executable, one can use the DUMPBIN.exe
utility: (Just launch the Visual Studio Command Prompt)
编辑:要检查可执行文件的 DLL 加载顺序,可以使用该DUMPBIN.exe
实用程序:(只需启动 Visual Studio 命令提示符)
Edit: As per this answer/ this blog entry, the NT Loader doeswalk the import section sequentially. (Which will result in independentDLLs being loaded in the order they appear in the import section.)
编辑:根据此答案/此博客条目,NT Loader确实按顺序执行导入部分。(这将导致按照它们在导入部分中出现的顺序加载独立的DLL。)
C:\path\to\program> dumpbin /IMPORTS app.exe | grep -i \.dll
MSVCR80D.dll
KERNEL32.dll
OLEAUT32.dll
MSVCP80D.dll
foo.dll
bar.DLL
This output means that MSVCR80D.dll (and its dependecies[a]) will be loaded first and that bar.DLL will be loaded last. Unload will happen in reverse order.
此输出意味着 MSVCR80D.dll(及其依赖项[a])将首先加载,而 bar.DLL 将最后加载。卸载将以相反的顺序发生。
What I haven'tfound out yet is how to influence this load order...
我还没有发现的是如何影响这个加载顺序......
(Notes)
(笔记)
[a] : This means of course that e.g. kernel32.dll will be loaded first, because msvcr80d.dll will depend on kernel32.dll.
[a] : 这当然意味着首先加载例如 kernel32.dll,因为 msvcr80d.dll 将依赖于 kernel32.dll。
As per some requests, I'm adding a rationale for this: (But please, I'm stillinterested in this generally. I know how to work around the MFC problem.)
根据某些要求,我为此添加了一个基本原理:(但是请注意,我通常仍然对此感兴趣。我知道如何解决 MFC 问题。)
The Microsoft MFC DLL in it's debug version has memory leak detection built in. (As far as I can tell, it's the same mechanism used by _CrtSetDbgFlagand related tools.)
调试版本中的 Microsoft MFC DLL 内置了内存泄漏检测。(据我所知,它与_CrtSetDbgFlag和相关工具使用的机制相同。)
The MFC debug DLL will dump all unfreed memory when it is unloaded. Now, if you have a second DLL in your process, that is independent of MFC, and this second DLL deallocates memory on DLL_PROCESS_DETACH, the MFC reporting mechanism will report false memory leaks, if the MFC DLL is unloaded before the other dll.
MFC 调试 DLL 将在卸载时转储所有未释放的内存。现在,如果您的进程中有第二个 DLL,它独立于 MFC,并且第二个 DLL 在 DLL_PROCESS_DETACH 上释放内存,如果 MFC DLL 在另一个 dll 之前卸载,则 MFC 报告机制将报告错误的内存泄漏。
If one could make sure that the debug MFC DLL is loaded first / unloaded last of all independent DLLs, then all other DLLs would already have cleaned up after themselves and MFC wouldn't report false leaks.
如果可以确保调试 MFC DLL 在所有独立 DLL 中首先加载/最后卸载,那么所有其他 DLL 将在它们自己之后已经清理干净,并且 MFC 不会报告错误泄漏。
采纳答案by Martin Ba
What I haven't found out yet is how to influence this load order ...
我还没有发现的是如何影响这个加载顺序......
I have no clue why I hadn't tried this, but it seems the import section order of the resulting module does depend on the order in which the lib
files are provided to the linker.
我不知道为什么我没有尝试过这个,但结果模块的导入部分顺序似乎取决于将lib
文件提供给链接器的顺序。
Configuration Properties -> Linker -> Additional Dependencies ...
The lib files listed here first are also first in the import section, meaningthe loader will import these in order (modulo dependencies).
此处首先列出的 lib 文件也是导入部分中的第一个,这意味着加载程序将按顺序导入这些文件(模依赖项)。
So, to answer that part: Just provide the lib files in the correct order to the linker.
因此,要回答该部分:只需以正确的顺序向链接器提供 lib 文件。
Note: I have tried that on VS2005 and it appears to work. I don't know whether that is documented somewhere or if it changed in newer versions of VC++.
注意:我已经在 VS2005 上尝试过,它似乎可以工作。我不知道这是否在某处有记录,或者它是否在较新版本的 VC++ 中发生了变化。
Update:While it worked back then, today I hit the case that the load order was notto be influenced by the linker command line orderof the lib
files. (Still) No clue why. (Still VS2005)
更新:虽然它当时有效,但今天我遇到了加载顺序不受lib
文件的链接器命令行顺序影响的情况。(仍然)不知道为什么。(还是VS2005)
I have however managed to make it work by adding the problematic DLLs to the list of delay loaded DLLs (like in Macke's answer).
然而,我设法通过将有问题的 DLL 添加到延迟加载的 DLL 列表中来使其工作(如Macke 的回答)。
回答by Ben Voigt
Just add foo.dll
to the import table of bar.dll
, the OS loader will handle the rest.
只需添加foo.dll
到 的导入表bar.dll
,OS 加载程序将处理其余部分。
You should be able to do this without the source code for bar.dll
, not sure if the editbin
tool has such an option, but this is a fairly trivial edit to the PE file.
您应该能够在没有源代码的情况下执行此操作bar.dll
,不确定该editbin
工具是否有这样的选项,但这是对 PE 文件的相当简单的编辑。
You might instead be able to use the registry setting that preloads DLLs, but I wouldn't do that, you don't want foo.dll
getting loaded into other processes that don't need it.
您也许可以使用预加载 DLL 的注册表设置,但我不会这样做,您不希望foo.dll
被加载到不需要它的其他进程中。
回答by Macke
Here's an idea: How about marking them as "Delay Loaded dlls" in the linker options of app.exe
?
这是一个想法:如何在 的链接器选项中将它们标记为“延迟加载的 dll” app.exe
?
Delay-loading will allow you to link "statically" (i.e. without LoadLibrary() et.al) but will not load the DLL and do the linking until it's actually needed.
延迟加载将允许您“静态”链接(即没有 LoadLibrary() 等),但不会加载 DLL 并在实际需要之前进行链接。
If that is an option, then (assuming you can wait so long, i.e. do not access foo/bar dll functions before main()), you could, in main(), access a function (just fetch a function ptr or something) in foo.dll
first, which would load it and bind all "statically" linked functions?
如果这是一个选项,那么(假设您可以等待这么长时间,即在 main() 之前不访问 foo/bar dll 函数),您可以在 main() 中访问一个函数(只需获取一个函数 ptr 或其他东西)在foo.dll
第一,这将加载它,并绑定所有的“静态”链接的功能呢?
(Maybe LoadLibrary() triggers the same link-when-needed procedure. Not sure. It would look cleaner in your code though.)
(也许 LoadLibrary() 会在需要时触发相同的链接过程。不确定。不过它在您的代码中看起来会更清晰。)
回答by Ferruccio
If you don't link the import library (foo.lib & bar.lib), then the loader will not automatically load the DLLs upon startup and you can call LoadLibrary() whenever you want.
如果您不链接导入库(foo.lib 和 bar.lib),则加载器不会在启动时自动加载 DLL,您可以随时调用 LoadLibrary()。
On a side note, I wrote a handy little library for encapsulating loading DLLs on the fly without having to deal with LoadLibrary/GetProcAddress directly. You can read about it here.
附带说明一下,我编写了一个方便的小库,用于即时封装加载 DLL,而无需直接处理 LoadLibrary/GetProcAddress。你可以在这里阅读它。