2008-09-16 17 views

Respuesta

33

En una DLL de Windows C++, todos los objetos globales (incluidos los miembros estáticos de las clases) se construirán justo antes de la llamada de DllMain con DLL_PROCESS_ATTACH, y se destruirán justo después de la llamada de DllMain con DLL_PROCESS_DETACH.

Ahora, debe tener en cuenta tres problemas:

0 - Por supuesto, los objetos no const globales son malos (pero ya saben que, por lo que evitará mentionning multithreading, cerraduras, dios-objetos, etc. .)

1 - El orden de construcción de objetos o diferentes unidades de compilación (es decir, archivos CPP) no está garantizado, por lo que no se puede esperar que el objeto A se construya antes B si los dos objetos se instancian en dos diferentes CPPs. Esto es importante si B depende de A. La solución es mover todos los objetos globales en el mismo archivo CPP, ya que dentro de la misma unidad de compilación, el orden de instanciación de los objetos será el orden de construcción (y el inverso de la orden de destrucción)

2 - Hay cosas que están prohibidas en el DllMain. Esas cosas probablemente también están prohibidas en los constructores. Así que evita bloquear algo. Ver excelente blog de Raymond Chen sobre el tema:

http://blogs.msdn.com/oldnewthing/archive/2004/01/27/63401.aspx

http://blogs.msdn.com/oldnewthing/archive/2004/01/28/63880.aspx

En este caso, la inicialización perezosa podría ser interesante: Las clases se mantienen en un estado "no inicializada" (punteros internos son NULL, booleanos son falsos, lo que sea) hasta que llame a uno de sus métodos, en cuyo punto se inicializarán. Si usa esos objetos dentro de la principal (o una de las funciones descendientes de la principal), estará bien, ya que se invocarán después de la ejecución de DllMain.

3 - Por supuesto, si algunos objetos globales en DLL A dependen de objetos globales en DLL B, debe tener mucho cuidado con el orden de carga DLL y, por lo tanto, dependencias.En este caso, los archivos DLL con dependencias circulares directas o indirectas le causarán una enorme cantidad de dolores de cabeza. La mejor solución es romper las dependencias circulares.

P.S .: Tenga en cuenta que en C++, el constructor puede lanzar, y usted no quiere una excepción en el medio de una carga de DLL, así que asegúrese de que sus objetos globales no utilizarán la excepción sin una muy buena razón. Como los destructores correctamente escritos no están autorizados a lanzar, la descarga de DLL debería estar bien en este caso.

+2

Si uno proceso cambia un valor global, es el cambio observado en otro proceso? –

+2

@ LB--: por lo general, no: cada proceso tiene su propia variable global * a menos que * usted los asigne en la memoria compartida o use un truco específico del sistema operativo para compartirlos entre todos los procesos que usen esa DLL (no lo hago). recuerde exactamente el truco en Windows, pero implicó # declaraciones de pragma, IIRC) – paercebal

3

Se debe ejecutar cuando finaliza la aplicación o cuando se descarga la DLL, lo que ocurra primero. Tenga en cuenta que esto es algo dependiente del tiempo de ejecución real contra el que está compilando.

Además, tenga cuidado con los destructores no triviales, ya que hay problemas de tiempo y pedidos. Su DLL puede estar descargada después de una DLL en la que confíe su destructor, que obviamente causaría problemas.

1

Cuando se llama a DllMain con el parámetro fdwReason = DLL_PROCESS_DETACH, significa que la DLL descarga la DLL. Este es el tiempo antes de que se llame al destructor de objetos globales/estáticos.

4

Si desea ver el código real que se ejecuta cuando se enlaza un .dll, echar un vistazo a %ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c.

De la inspección, los destructores se llamarán a través de _cexit() cuando la cuenta de referencia interna mantenida por el dll CRT llega a cero.

1

En Windows, los archivos de imagen binarios con extensión * .exe, * .dll están en PE format Dichos archivos tienen Entry Point. También se puede ver con la herramienta dumpbin como

dumpbin/cabeceras dllname.dll

Si utiliza el tiempo de ejecución de Microsoft C, entonces su punto de entrada será algo así como * * CRTStartup o DllMainCRTStartup

Tales funciones realizan la inicialización del tiempo de ejecución c y C++ y delegan la ejecución en (main, WinMain) o en DllMain respectivamente.

Si utiliza Microsoft de VC compilador continuación se puede ver en el código fuente de estas funciones en la suya directorio VC:

  • crt0.c
  • dllcrt0.c

proceso DllMainCRTStartup todas las cosas necesita iniciar/definir sus variables globales desde secciones .data en el escenario normal, cuando recupera la notificación DLL_PROCESS_DETACH durante la descarga dll. Por ejemplo:

  • principal o WinMain de hilo de inicio de los rendimientos de los programas de control de flujo
  • que explícitamente se llama a FreeLibrary y utilizar DLL-contador es cero
Cuestiones relacionadas