2008-09-16 9 views

Répondre

33

Dans une DLL Windows C++, tous les objets globaux (y compris les membres statiques de classes) seront construits juste avant l'appel de DllMain avec DLL_PROCESS_ATTACH et seront détruits juste après l'appel de DllMain avec DLL_PROCESS_DETACH.

Maintenant, vous devez tenir compte de trois problèmes:

0 - Bien sûr, les objets globaux non-const sont mauvais (mais vous savez déjà que, donc je vais éviter multithreading, serrures mentionnant, dieu-objets, etc. 1 - L'ordre de construction des objets ou des différentes unités de compilation (fichiers CPP) n'est pas garanti, donc vous ne pouvez pas espérer que l'objet A sera construit avant B si les deux objets sont instanciés dans deux CPP. Ceci est important si B dépend de A. La solution est de déplacer tous les objets globaux dans le même fichier CPP, car dans la même unité de compilation, l'ordre d'instanciation des objets sera l'ordre de construction (et l'inverse de la commande de destruction)

2 - Il y a des choses qu'il est interdit de faire dans le DllMain. Ces choses sont probablement interdites, aussi, dans les constructeurs. Évitez donc de bloquer quelque chose. Voir excellent blog de Raymond Chen sur le sujet:

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

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

Dans ce cas, l'initialisation paresseuse pourrait être intéressant: Les classes restent dans un état "non initialisé" (pointeurs internes sont NULL, les booléens sont faux, peu importe) jusqu'à ce que vous appeliez une de leurs méthodes, à quel point ils s'initialisent. Si vous utilisez ces objets à l'intérieur de la fonction principale (ou de l'une des fonctions descendantes du principal), cela ne pose aucun problème, car ils seront appelés après l'exécution de DllMain.

3 - Bien sûr, si certains objets globaux dans la DLL A dépendent d'objets globaux dans la DLL B, vous devez faire très attention à l'ordre de chargement des DLL, et donc aux dépendances.Dans ce cas, les DLL avec des dépendances circulaires directes ou indirectes vous causeront une quantité folle de maux de tête. La meilleure solution est de casser les dépendances circulaires. Notez qu'en C++, le constructeur peut lancer, et vous ne voulez pas d'exception au milieu d'un chargement de DLL, alors assurez-vous que vos objets globaux n'utiliseront pas d'exception sans une très bonne raison. Comme les destructeurs correctement écrits ne sont pas autorisés à lancer, le déchargement de la DLL devrait être correct dans ce cas.

+2

Si un processus change une valeur globale, est le changement observé dans un autre processus? –

+2

@ LB--: Habituellement, non: Chaque processus a sa propre variable globale * à moins que * vous ne les ayez mappés en mémoire partagée, ou utilisez un truc spécifique à l'OS pour les partager entre tous les processus utilisant cette DLL (je ne sais pas rappelez-vous exactement l'astuce sur Windows, mais cela impliquait des déclarations #pragma, IIRC) – paercebal

3

Il doit être appelé lorsque l'application se termine ou que la DLL est déchargée, selon la première éventualité. Notez que cela dépend un peu du temps d'exécution réel que vous compilez.

Aussi, méfiez-vous des destructeurs non triviaux car il y a des problèmes de timing et de commande. Votre DLL peut être déchargé après une DLL sur laquelle votre destructeur s'appuie, ce qui causerait évidemment des problèmes.

1

Lorsque DllMain avec fdwReason = le paramètre DLL_PROCESS_DETACH est appelé, cela signifie que la DLL est déchargée par l'application. C'est le moment avant que le destructeur d'objets globaux/statiques soit appelé.

4

Si vous voulez voir le code réel qui est exécuté lors de la liaison d'un .dll, jetez un oeil à %ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c.

À partir de l'inspection, les destructeurs seront appelés via _cexit() lorsque le nombre de références internes maintenu par le CRT dll atteint zéro.

1

Dans les fichiers d'image binaires Windows avec l'extension * .exe, * .dll sont dans PE format Ces fichiers ont un point d'entrée. Vous pouvez le voir avec l'outil dumpbin comme

dumpbin/têtes dllname.dll

Si vous utilisez l'exécution C de Microsoft, votre point d'entrée sera quelque chose comme * ou * CRTStartup DllMainCRTStartup

De telles fonctions effectuent l'initialisation de l'exécution c et C++ et déléguent l'exécution à (main, WinMain) ou à DllMain respectivement.

Si vous utilisez le compilateur VC Microsofts alors vous pouvez regarder au code source de cette fonction dans le vôtre répertoire VC:

  • crt0.c
  • dllcrt0.c

processus DllMainCRTStartup toutes choses besoin d'init/deinit vos variables globales à partir de sections .data dans le scénario normal, quand il retrive notification DLL_PROCESS_DETACH au cours de la dll décharger. Par exemple:

  • main ou WinMain de fil de démarrage du programme retourne le contrôle du flux
  • vous appelez explictly FreeLibrary et utilisez-dll-compteur est zéro
Questions connexes