c++ - ubicacion - ¿Cambiar el orden de carga de Windows DLL?(orden de carga, no orden de búsqueda)
pdb visual studio (4)
Digamos que tengo un ejecutable: app.exe
Utilizo 2 DLL de terceros diferentes en este archivo ejecutable: foo.dll
bar.dll
y la Aplicación debe vincular implícitamente a estos archivos DLL, es decir, no puedo usar ::LoadLibrary
para cargarlos.
(Nota: No es que no pueda llamar a LoadLibrary
, pero estas DLL requieren enlace estático (C ++ DLL con __declspec(dllexport)
), así que llamar a LoadLibrary
no tiene ningún sentido porque el cargador excutable ya lo ha llamado.
Estas dos DLL no tienen dependencias entre sí, es decir, su orden de carga no está definida hasta donde yo sé (y debería ser irrelevante). (Las dependencias de ambos son, básicamente, solo en las ventanas dlls estándar (kernel32, msvcrt, etc.)
Ahora tengo el problema de que deseo controlar el orden de carga de estos archivos DLL, es decir, deseo que foo.dll siempre se cargue ( DLL_PROCESS_ATTACH
) antes que bar.dll.
¿Es de alguna manera posible decirle al Windows DLL Loader que cargue una DLL antes que otra?
Editar: para verificar el orden de carga DLL de un archivo ejecutable, se puede usar la utilidad DUMPBIN.exe
: (Simplemente ejecute el símbolo del sistema de Visual Studio)
Editar: según esta respuesta / esta entrada de blog , NT Loader recorre la sección de importación secuencialmente. (Lo cual dará como resultado que se carguen archivos DLL independientes en el orden en que aparecen en la sección de importación).
C:/path/to/program> dumpbin /IMPORTS app.exe | grep -i /.dll
MSVCR80D.dll
KERNEL32.dll
OLEAUT32.dll
MSVCP80D.dll
foo.dll
bar.DLL
Esta salida significa que MSVCR80D.dll (y sus dependencias [a] ) se cargarán primero y que bar.DLL se cargará el último. La descarga ocurrirá en orden inverso.
Lo que aún no he descubierto es cómo influir en este orden de carga ...
(Notas)
[a]: Esto significa que, por supuesto, kernel32.dll se cargará primero, porque msvcr80d.dll dependerá de kernel32.dll.
Según algunas solicitudes, estoy agregando un fundamento para esto: (Pero, por favor , todavía estoy interesado en esto en general , sé cómo solucionar el problema de MFC ) .
La DLL de Microsoft MFC en su versión de depuración tiene integrada la detección de fuga de memoria. (Hasta donde puedo decir, es el mismo mecanismo utilizado por _CrtSetDbgFlag y las herramientas relacionadas.)
La DLL de depuración de MFC vaciará toda la memoria no actualizada cuando se descargue. Ahora, si tiene una segunda DLL en su proceso, que es independiente de MFC, y esta segunda DLL desasigna memoria en DLL_PROCESS_DETACH, el mecanismo de informes MFC informará fallas de memoria falsas, si la DLL de MFC se descarga antes que la otra DLL.
Si uno pudiera asegurarse de que la DLL de MFC de depuración se carga primero / descargó la última de todas las DLL independientes, todas las demás DLL ya se habrían limpiado después de ellas y MFC no informaría falsas filtraciones.
Lo que aún no he descubierto es cómo influir en este orden de carga ...
No tengo idea de por qué no lo he probado, pero parece que el orden de la sección de importación del módulo resultante depende del orden en que se lib
archivos lib
al enlazador.
Configuration Properties -> Linker -> Additional Dependencies ...
Los archivos lib listados aquí primero también son primeros en la sección de importación, lo que significa que el cargador los importará en orden (dependencias de módulo).
Entonces, para responder esa parte: Simplemente proporcione los archivos lib en el orden correcto al vinculador.
Nota : Lo he probado en VS2005 y parece funcionar. No sé si eso está documentado en alguna parte o si cambió en las versiones más recientes de VC ++.
Actualización: Mientras funcionaba en ese momento, hoy llegué al caso de que la orden de carga no debía verse influenciada por el orden de la línea de comando del vinculador de los archivos lib
. (Todavía) No hay idea de por qué. (Aún VS2005)
Sin embargo, he logrado hacer que funcione agregando los DLL problemáticos a la lista de archivos DLL cargados con retraso (como en la respuesta de Macke ).
Aquí hay una idea: ¿qué tal si los app.exe
" app.exe
de app.exe
retardada" en las opciones del enlazador de app.exe
?
La carga diferida le permitirá vincular "estáticamente" (es decir, sin LoadLibrary () et.al) pero no cargará el archivo DLL y realizará el enlace hasta que realmente se necesite.
Si eso es una opción, entonces (asumiendo que puede esperar tanto tiempo, es decir, no acceda a las funciones foo / bar dll antes de main ()), podría, en main (), acceder a una función (simplemente obtener una función ptr o algo) en foo.dll
primero, ¿cuál cargaría y vincularía todas las funciones vinculadas "estáticamente"?
(Tal vez LoadLibrary () desencadena el mismo procedimiento de enlace cuando es necesario. No estoy seguro. Sin embargo, se vería más limpio en tu código).
Si no vincula la biblioteca de importación (foo.lib & bar.lib), el cargador no cargará automáticamente los archivos DLL al inicio y podrá llamar a LoadLibrary () siempre que lo desee.
En una nota lateral, escribí una pequeña biblioteca práctica para encapsular DLL de carga sobre la marcha sin tener que lidiar con LoadLibrary / GetProcAddress directamente. Puedes leer sobre esto aquí .
Simplemente agregue foo.dll
a la tabla de importación de bar.dll
, el cargador del sistema operativo se encargará del resto.
Debería poder hacer esto sin el código fuente de bar.dll
, no estoy seguro si la herramienta editbin
tiene dicha opción, pero esta es una edición bastante trivial del archivo PE.
En su lugar, podría ser capaz de utilizar la configuración del registro que precarga los archivos DLL, pero yo no haría eso, no quiere que foo.dll
se cargue en otros procesos que no lo necesitan.