2009-03-05 14 views
8

Tome una aplicación estándar de Windows. Carga una DLL usando LoadLibrary para llamar a una función (llamaremos a esto DLL_A). Esa función carga otra DLL (lo llamaremos DLL_B). La aplicación ahora descarga el DLL_A DLL usando FreeLibrary ya que ya no lo requiere.¿Se elimina una DLL si la DLL que la cargó está descargada?

La pregunta es: ¿La DLL_B todavía está en la memoria y cargada?

¿Es esto algo de lo que puedo depender, o no está documentado?

Respuesta

10

No. DLL_B no se descargarán. La llamada LoadLibrary() hecha por DLL_A incrementará el conteo de carga para DLL_B. Como no hay una llamada FreeLibrary() correspondiente para DLL_B, el recuento no pasará a cero.

A partir de los documentos LoadLibrary():

El sistema mantiene un recuento de referencia por proceso en todos los módulos cargados. Llamar a LoadLibrary incrementa el recuento de referencias . Si llama al FreeLibrary o al , la función FreeLibraryAndExitThread disminuye el recuento de referencias. El sistema descarga un módulo cuando su recuento de referencias llega a cero o cuando finaliza el proceso (independientemente de el recuento de referencias).

+0

Y el problema es que se supone que no debes llamar a FreeLibrary() en DLLMain en un proceso de separación, entonces, ¿cómo vas a limpiar DLL_B? –

+0

Un método común es tener llamadas init() y deinit() para el archivo DLL_A que carga/descarga DLL_B (y realiza otras funciones de inicio/limpieza). Es intrusivo, pero es directo. –

+0

En este caso, deseo * que * DLL_B se quede atrás hasta que se cierre la aplicación principal. De hecho, esto es ideal para mí. Mi intención es inyectar el archivo DLL y un hilo que creará en la aplicación. – mj2008

1

Lea la sección Observaciones para una explicación más detallada.

La clave para tener en cuenta es:

El sistema mantiene un recuento de referencia por proceso para cada módulo cargado

y más abajo

Cuando el contador de referencia de un módulo llega a cero o el proceso finaliza, el sistema descarga el módulo del espacio de direcciones del proceso

De MSDN:

libera al módulo cargado biblioteca de vínculos dinámicos (DLL) y, si es necesario, se decrementa el contador de referencia. Cuando el recuento de referencias llega a cero, el módulo se descarga del espacio de direcciones del proceso de llamada y el identificador ya no es válido.

1

Las DLL en ventanas son referencias contadas. Cuando A está descargado, usted está disminuyendo el recuento de referencia en A, si lo hace se descargará y (suponiendo que no haya errores en el código) disminuirá el recuento de referencias en B. Si el recuento en B pasa a cero, se descargará. . Es posible que DLL C tenga un refcount en B, y que la descarga A no descargue B.

3

Usted tendrá una pérdida de identificadores en el caso:

Program -Load> Dll A 
      -Load> Dll B 
     -Unload> Dll A 

Ningún código se ejecuta de forma implícita por un módulo que se descarga para descargar los módulos que este se abra.

Como no se ejecuta ningún código para disminuir el recuento de referencias, el módulo B nunca se descargará.

Estas son las reglas para la carga/descarga de archivos DLL:

  • Cada llamada a LoadLibrary y LoadLibraryEx incrementará el recuento de referencia para ese módulo. Esto está en el contexto del proceso de llamada solamente, no a través de los límites del proceso.
  • Cada llamada a FreeLibrary o FreeLibraryAndExitThread reducirá el recuento de referencias.
  • Cuando el recuento de referencias llega a 0, se descargará.
  • Cuando Windows ve que su programa es cerrado, los módulos descargados que se hayan descargado se descargarán.
  • Según lo que esté haciendo, DllCanUnloadNow podría serle útil.

Todavía en la memoria vs todavía cargado:

no hay ninguna garantía de que el módulo se libera de la memoria en un momento determinado, cuando la referencia llega a 0. Sin embargo, usted debe considerar el módulo como si se descarga cuando el recuento de referencias llega a 0.

Detener la DLL se descargue:

Para forzar la DLL se descargue podría intentar

  • El sistema llama a DllMain con el indicador DLL_PROCESS_DETACH. Podría tratar de no regresar de esto a través de algún tipo de operación de bloqueo.
  • Puede intentar llamar a LoadLibrary desde la DLL que no desea descargar. (Carga auto)

Editar:

Usted mencionó que su objetivo es INJET código en el programa en ejecución y que quería escaparse el mango a propósito.

Eso está bien, pero si ejecuta esta operación mucho, puede provocar un bloqueo en su programa de origen porque se usarán demasiados controladores o eventualmente se usará demasiada memoria.

Puede devolver FALSE desde su DllMain para evitar que se cargue y así no perder memoria. Haga esto cuando fdwReason es DLL_PROCESS_ATTACH. Puede read more about it here.

Si está tratando de emular una DLL y agregar su propia funcionalidad adicional, deberá implementar todas las funciones que la DLL de origen implementa y delegar cada llamada nuevamente a la DLL de origen.

+0

Estoy bastante feliz filtrando el control ya que el DLL_B en realidad estará realizando una función útil. Quiero "inyectarlo" en la aplicación. – mj2008

+0

Actualicé mi respuesta para incluir esto. –

+0

TVM: el tema de las cargas múltiples es algo que consideraré. – mj2008

Cuestiones relacionadas