2008-09-16 9 views

Antwort

33

In einer Windows C++ - DLL werden alle globalen Objekte (einschließlich statischer Member von Klassen) kurz vor dem Aufruf von DllMain mit DLL_PROCESS_ATTACH erstellt, und sie werden direkt nach dem Aufruf von DllMain mit DLL_PROCESS_DETACH zerstört.

Jetzt

, müssen Sie drei Probleme berücksichtigen:

0 - Natürlich globale Nicht-const Objekte sind böse (aber Sie wissen bereits, dass, also werde ich mentionning Multithreading, Schlösser, Gott-Objekte vermeiden, usw. .)

1 - Die Reihenfolge der Konstruktion von Objekten oder verschiedenen Kompilierungseinheiten (dh CPP-Dateien) ist nicht garantiert, so dass Sie nicht hoffen können, dass das Objekt A vor B erstellt wird, wenn die zwei Objekte in zwei verschiedenen Instanzen vorliegen CPPs. Dies ist wichtig, wenn B von A abhängt. Die Lösung besteht darin, alle globalen Objekte in derselben CPP-Datei zu verschieben, da innerhalb derselben Kompilierungseinheit die Reihenfolge der Instanziierung der Objekte die Reihenfolge der Konstruktion (und die Umkehrung der Reihenfolge) ist der Zerstörung)

2 - Es gibt Dinge, die in der DllMain verboten sind. Diese Dinge sind wahrscheinlich auch in den Konstrukteuren verboten. Also vermeide es, etwas zu sperren. Siehe Raymond Chen ausgezeichneten Blog zum Thema:

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

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

In diesem Fall faul Initialisierung interessant sein könnte: Die Klassen bleiben in einem "nicht initialisierten" Zustand (interne Zeiger sind NULL, Booleans sind falsch, was auch immer), bis Sie eine ihrer Methoden aufrufen, an denen sie sich initialisieren. Wenn Sie diese Objekte innerhalb der Hauptfunktion (oder einer der Hauptfunktionen des Hauptprogramms) verwenden, sind Sie in Ordnung, da sie nach der Ausführung von DllMain aufgerufen werden.

3 - Natürlich, wenn einige globale Objekte in DLL A von globalen Objekten in DLL B abhängen, sollten Sie sehr sehr vorsichtig mit der DLL-Ladereihenfolge und damit Abhängigkeiten sein.In diesem Fall werden DLLs mit direkten oder indirekten zirkulären Abhängigkeiten Ihnen eine wahnsinnige Menge an Kopfschmerzen verursachen. Die beste Lösung besteht darin, die zirkulären Abhängigkeiten zu durchbrechen.

P.S .: Beachten Sie, dass Konstruktor in C++ werfen kann und Sie keine Ausnahme mitten in einem DLL-Laden möchten, also stellen Sie sicher, dass Ihre globalen Objekte keine Ausnahme ohne einen sehr guten Grund verwenden. Da korrekt geschriebene Destruktoren nicht zum Werfen berechtigt sind, sollte die DLL-Entladung in diesem Fall in Ordnung sein.

+2

ist Wenn ein Prozess einen globalen Wert ändert, ist die Veränderung in einem anderen Prozess beobachtet? –

+2

@ LB--: In der Regel nicht: Jeder Prozess seine eigene globale Variable hat *, es sei denn * Sie passieren sie im gemeinsam genutzten Speicher auf der Karte, oder einen OS-spezifischen Trick verwenden, um sie zwischen allen Prozessen gemeinsam zu machen mit, dass DLL (ich weiß nicht erinnere mich genau an den Trick auf Windows, aber es beteiligt #pragma Deklarationen, IIRC) – paercebal

3

Es sollte aufgerufen werden, wenn entweder die Anwendung beendet oder die DLL entladen wird, je nachdem, was zuerst eintritt. Beachten Sie, dass dies etwas von der tatsächlichen Laufzeit abhängig ist, für die Sie kompilieren.

Achten Sie auch auf nicht-triviale Destruktoren, da sowohl Timing- als auch Bestellprobleme auftreten. Ihre DLL wird möglicherweise entladen nach eine DLL, auf die Ihr Destruktor angewiesen ist, die offensichtlich Probleme verursachen würde.

1

Wenn DllMain mit FdwReason = DLL_PROCESS_DETACH Parameter aufgerufen wird, bedeutet dies, dass die DLL von der Anwendung entladen wird. Dies ist die Zeit bevor der Destruktor globaler/statischer Objekte aufgerufen wird.

4

Wenn Sie den eigentlichen Code sehen möchten, die ausgeführt wird, wenn eine DLL-Verknüpfung, bei %ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c einen Blick darauf werfen.

Von der Inspektion werden Destruktoren über _cexit() aufgerufen, wenn der interne Referenzzähler, der von der DLL-CRT gehalten wird, Null erreicht.

1

In Windows binäre Bilddateien mit der Erweiterung * .exe, * .dll sind in PE format Solche Dateien haben Einstiegspunkt. Sie können es mit dumpbin Tool wie

dumpbin anzuzeigen/headers

dllname.dll Wenn Sie C-Laufzeit von Microsoft verwenden, dann wird Ihr Einstiegspunkt wird so etwas wie * CRTStartup oder * DllMainCRTStartup

Solche Funktionen erfüllen Initialisierung von C und C++ Laufzeit und delegieren Ausführung (Haupt, WinMain) oder DllMain ist.

Wenn Sie Microsofts VC-Compiler, dann können Sie auf Quelltext dieser Funktionen in Ihr VC-Verzeichnis sehen:

  • crt0.c
  • dllcrt0.c

DllMainCRTStartup Prozess alle Dinge Sie müssen Ihre globalen Variablen von .data-Abschnitten im normalen Szenario initialisieren/detinieren, wenn sie die Benachrichtigung DLL_PROCESS_DETACH während des Dll-Entladens abrufen. Zum Beispiel:

  • Haupt- oder WinMain von Start Faden Programm kehrt Steuerfluss
  • Sie explictly Free aufrufen und verwenden-dll-Zähler Null
Verwandte Themen