Изменение порядка загрузки DLL Windows? (порядок загрузки, а не порядок поиска)
скажем, у меня есть один исполняемый файл: app.exe
в этом исполняемом файле я использую 2 разные сторонние библиотеки DLL:foo.dll
bar.dll
и приложение должно неявно ссылаться на эти библиотеки DLL, то есть я не могу использовать ::LoadLibrary
, чтобы загрузить их.
(Примечание: это не то, что я не могу позвонить LoadLibrary
, но эти библиотеки требуют статической компоновки (библиотеки C++ с __declspec(dllexport)
), так меня зовет LoadLibrary
не имеет никакого смысла, потому что excutable loader уже вызвал его.)
эти две библиотеки DLL do не имеют какие-либо зависимости друг от друга, то есть их порядок загрузки не определен, насколько я могу судить (и должны не имеет значения). (Зависимости обоих в основном только от стандартных DLL-библиотек windows (kernel32, msvcrt и т. д.)
теперь у меня есть проблема, что я хочу контролировать порядок загрузки этих библиотек DLL, то есть я хочу, чтобы foo.dll является всегда загружается (DLL_PROCESS_ATTACH
) до бар.файл DLL.
как-то можно сказать загрузчик DLL Windows для загрузки одной DLL перед другой?
Edit: To проверьте порядок загрузки DLL исполняемого файла, можно использовать DUMPBIN.exe
утилита: (просто запустите командную строку Visual Studio)
Edit: согласно ответ / эта запись в блоге, загрузчик NT тут последовательно пройдите раздел импорта. (Что приведет к независимая DLL загружаются в том порядке, в котором они появляются раздел импорт.)
C:pathtoprogram> dumpbin /IMPORTS app.exe | grep -i .dll
MSVCR80D.dll
KERNEL32.dll
OLEAUT32.dll
MSVCP80D.dll
foo.dll
bar.DLL
этот вывод означает, что MSVCR80D.dll (и его dependecies[a]) будет загружен первым и бар.DLL будет загружен последним. Выгрузка произойдет в обратном порядке.
Что Я не узнал еще как повлиять на этот порядок загрузки ...
(Примечания)
[a]: это означает, конечно, что, например, kernel32.dll будет загружен первым, потому что msvcr80d.dll будет зависеть от kernel32.файл DLL.
согласно некоторым запросам, я добавляю обоснование для этого:(а пожалуйста, я еще заинтересованы в этом в целом. я знаю, как обойти проблему MFC.)
DLL Microsoft MFC в отладочной версии имеет встроенное обнаружение утечки памяти. (Насколько я могу судить, это тот же механизм, который используется функции _crtsetdbgflag и связанных с инструменты.)
DLL отладки MFC сбросит всю несвободную память, когда она выгружается. Теперь, если у вас есть вторая DLL в вашем процессе, которая не зависит от MFC, и эта вторая DLL освобождает память на DLL_PROCESS_DETACH, механизм отчетности MFC сообщит о ложных утечках памяти, если DLL MFC выгружается перед другой dll.
если бы можно было убедиться, что библиотека DLL debug MFC загружается первой / выгружается последней из всех независимых библиотек DLL, то все остальные библиотеки уже убрали за собой, и MFC не сообщит о ложных утечках.
4 ответов
то, что я еще не выяснил, как повлиять на этот порядок загрузки ...
Я понятия не имею, почему я не пробовал это, но, похоже, порядок раздела импорта результирующего модуля зависит от порядка, в котором lib
файлы предоставляются компоновщику.
Configuration Properties -> Linker -> Additional Dependencies ...
файлы lib, перечисленные здесь первыми, также первыми в разделе импорта,смысл загрузчик импортирует их по порядку (по модулю зависимости.)
Итак, чтобы ответить на эту часть: просто предоставьте файлы lib в правильном порядке компоновщику.
Примечание: я пробовал это на VS2005, и, похоже, это работает. Я не знаю, задокументировано ли это где-то или изменилось в более новых версиях VC++.
обновление: пока он работал тогда, сегодня я попал в дело, что порядок загрузки был не влияние по порядку командной строки компоновщика на lib
файлы. Без понятия почему. (Еще VS2005)
мне, однако, удалось заставить его работать, добавив проблемные DLL в список загруженных DLL с задержкой (например, в ответ Макке).
вот идея: как насчет маркировки их как "задержка загруженных DLL" в параметрах компоновщика app.exe
?
Delay-loading позволит вам связать "статически" (т. е. без LoadLibrary () et.al), но не будет загружать DLL и делать ссылку, пока она не понадобится.
Если это опция, то (предполагая, что вы можете ждать так долго, т. е. не обращаться к функциям dll foo/bar перед main ()), вы можете в main () получить доступ к функции (просто получить функцию ptr или что-то) в foo.dll
во-первых, что загрузит его и свяжет все "статически" связанные функции?
(возможно, LoadLibrary () запускает ту же процедуру link-when-needed. Не уверенный. Хотя в вашем коде это выглядело бы чище.)
просто добавить foo.dll
в таблицу импорта из bar.dll
, загрузчик ОС будет обрабатывать остальные.
вы должны быть в состоянии сделать это без исходного кода bar.dll
Не уверен, что если editbin
инструмент имеет такую опцию, но это довольно тривиальное редактирование файла PE.
вместо этого вы можете использовать параметр реестра, который предварительно загружает DLL, но я бы этого не делал, вы не хотите foo.dll
загружается в другие процессы, которые в этом не нуждаются.
Если вы не свяжете библиотеку импорта (foo.lib & bar.lib), то загрузчик не будет автоматически загружать библиотеки DLL при запуске, и Вы можете вызвать LoadLibrary () когда захотите.
на боковой ноте я написал удобную небольшую библиотеку для инкапсуляции загрузки DLL на лету без необходимости иметь дело с LoadLibrary/GetProcAddress напрямую. Вы можете прочитать об этом здесь.