DllMain-Einstiegspunkt
Ein optionaler Einstiegspunkt in eine Dynamic Link Library (DLL). Wenn das System einen Prozess oder Thread startet oder beendet, ruft es die Einstiegspunktfunktion für jede geladene DLL mithilfe des ersten Threads des Prozesses auf. Das System ruft auch die Einstiegspunktfunktion für eine DLL auf, wenn sie mithilfe der Funktionen LoadLibrary und FreeLibrary geladen oder entladen wird.
Beispiel
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Dies ist ein Beispiel aus der Dynamic Link Library Entry-Point Function.
Warnung
Es gibt erhebliche Einschränkungen bei den Aktionen, die Sie sicher in einem DLL-Einstiegspunkt durchführen können. Unter Allgemeine bewährte Methoden finden Sie Windows APIs, die in DllMain nicht sicher auf aufruft werden können. Wenn Sie mehr als nur die einfachste Initialisierung durchführen müssen, führen Sie dies in einer Initialisierungsfunktion für die DLL durch. Sie können verlangen, dass Anwendungen die Initialisierungsfunktion aufrufen, nachdem DllMain ausgeführt wurde und bevor sie andere Funktionen in der DLL aufrufen.
Syntax
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
Parameter
-
hinstDLL [ In]
-
Ein Handle für das DLL-Modul. Der Wert ist die Basisadresse der DLL. Die HINSTANCE einer DLL ist identisch mit dem HMODULE der DLL, sodass hinstDLL in Aufrufen von Funktionen verwendet werden kann, die ein Modulhandl erfordern.
-
fdwReason [ In]
-
Der Grundcode, der angibt, warum die DLL-Einstiegspunktfunktion aufgerufen wird. Dieser Parameter kann einen der folgenden Werte annehmen.
Wert Bedeutung - DLL _ PROZESS _ ANFÜGEN
- 1
Die DLL wird als Ergebnis des Prozessstarts oder als Ergebnis eines Aufrufs von LoadLibraryin den virtuellen Adressraum des aktuellen Prozesses geladen. DLLs können diese Gelegenheit nutzen, um Instanzdaten zu initialisieren oder die TlsAlloc-Funktion zu verwenden, um einen TLS-Index (Thread Local Storage) zu zuordnen.
Der lpReserved-Parameter gibt an, ob die DLL statisch oder dynamisch geladen wird.- DLL _ PROCESS _ DETACH
- 0
Die DLL wird aus dem virtuellen Adressraum des aufrufenden Prozesses entladen, da sie nicht erfolgreich geladen wurde oder die Verweisanzahl 0 (null) erreicht hat (die Prozesse wurden entweder einmal beendet oder freeLibrary aufgerufen, wenn sie LoadLibraryaufgerufen hat).
Der lpReserved-Parameter gibt an, ob die DLL als Folge eines FreeLibrary-Aufrufs, eines Ladefehlers oder einer Prozessbeendigung entladen wird.
Die DLL kann diese Gelegenheit zum Aufrufen der TlsFree-Funktion nutzen, um alle TLS-Indizes frei zu geben, die mit tlsAlloc zugeordnet wurden, und um alle lokalen Threaddaten frei zu geben.
Beachten Sie, dass der Thread, der die DLL _ PROCESS _ DETACH-Benachrichtigung empfängt, nicht notwendigerweise derselbe Thread ist, der die DLL PROCESS _ _ ATTACH-Benachrichtigung empfangen hat.- DLL _ THREAD _ ATTACH
- 2
Der aktuelle Prozess erstellt einen neuen Thread. In diesem Fall ruft das System die Einstiegspunktfunktion aller DLLs auf, die derzeit an den Prozess angefügt sind. Der Aufruf erfolgt im Kontext des neuen Threads. DLLs können diese Gelegenheit nutzen, um einen TLS-Slot für den Thread zu initialisieren. Ein Thread, der die DLL-Einstiegspunktfunktion mit DLL _ PROCESS _ ATTACH aufruft, ruft die DLL-Einstiegspunktfunktion nicht mit DLL THREAD ATTACH _ _ auf.
Beachten Sie, dass die Einstiegspunktfunktion einer DLL mit diesem Wert nur von Threads aufgerufen wird, die nach dem Laden der DLL durch den Prozess erstellt wurden. Wenn eine DLL mit LoadLibrarygeladen wird, rufen vorhandene Threads die Einstiegspunktfunktion der neu geladenen DLL nicht auf.- DLL _ THREAD _ DETACH
- 3
Ein Thread wird sauber beendet. Wenn die DLL einen Zeiger auf zugeordneten Arbeitsspeicher in einem TLS-Slot gespeichert hat, sollte sie diese Gelegenheit nutzen, um den Arbeitsspeicher frei zu geben. Das System ruft die Einstiegspunktfunktion aller derzeit geladenen DLLs mit diesem Wert auf. Der Aufruf erfolgt im Kontext des beendenden Threads. -
lpvReserved [ In]
-
Wenn fdwReason DLL PROCESS _ _ ATTACH ist, ist lpvReserved für dynamische Auslastungen NULL und bei statischen Auslastungen nicht NULL.
Wenn fdwReason DLL PROCESS _ _ DETACH ist, ist lpvReserved NULL, wenn FreeLibrary aufgerufen wurde oder beim Laden der DLL ein Fehler auftrat, und nicht NULL, wenn der Prozess beendet wird.
Rückgabewert
Wenn das System die DllMain-Funktion mit dem DLL PROCESS _ _ ATTACH-Wert aufruft, gibt die Funktion TRUE zurück, wenn sie erfolgreich ist, oder FALSE, wenn die Initialisierung fehlschlägt. Wenn der Rückgabewert FALSE ist, wenn DllMain aufgerufen wird, da der Prozess die LoadLibrary-Funktion verwendet, gibt LoadLibrary NULL zurück. (Das System ruft sofort ihre Einstiegspunktfunktion mit DLL _ PROCESS _ DETACH auf und entlädt die DLL.) Wenn der Rückgabewert FALSE ist, wenn DllMain während der Prozessin initialisierung aufgerufen wird, wird der Prozess mit einem Fehler beendet. Um erweiterte Fehlerinformationen zu erhalten, rufen Sie GetLastError auf.
Wenn das System die DllMain-Funktion mit einem anderen Wert als DLL PROCESS _ _ ATTACH aufruft, wird der Rückgabewert ignoriert.
Hinweise
DllMain ist ein Platzhalter für den bibliotheksdefinierten Funktionsnamen. Sie müssen den tatsächlichen Namen angeben, den Sie beim Erstellen der DLL verwenden. Weitere Informationen finden Sie in der Dokumentation zu Ihren Entwicklungstools.
Beim Start des ersten Prozesses oder nach einem Aufruf von LoadLibrarydurchsucht das System die Liste der geladenen DLLs für den Prozess. Für jede DLL, die noch nicht mit dem WERT DLL _ PROCESS _ ATTACH aufgerufen wurde, ruft das System die Einstiegspunktfunktion der DLL auf. Dieser Aufruf erfolgt im Kontext des Threads, der die Änderung des Prozessadressenbereichs verursacht hat, z. B. der primäre Thread des Prozesses oder der Thread, der LoadLibrary aufgerufen hat. Der Zugriff auf den Einstiegspunkt wird vom System prozessweit serialisiert. Threads in DllMain halten die Loadersperre, sodass keine zusätzlichen DLLs dynamisch geladen oder initialisiert werden können.
Wenn die Einstiegspunktfunktion der DLL nach einer DLL _ PROCESS _ ATTACH-Benachrichtigung FALSE zurückgibt, empfängt sie eine DLL PROCESS _ DETACH-Benachrichtigung, _ und die DLL wird sofort entladen. Wenn der DLL _ PROCESS _ ATTACH-Code jedoch eine Ausnahme auslöst, erhält die Einstiegspunktfunktion nicht die DLL PROCESS _ _ DETACH-Benachrichtigung.
Es gibt Fälle, in denen die Einstiegspunktfunktion für einen beendenden Thread aufgerufen wird, auch wenn die Einstiegspunktfunktion nie mit DLL _ THREAD _ ATTACH für den Thread aufgerufen wurde:
- Der Thread war der erste Thread im Prozess, daher hat das System die Einstiegspunktfunktion mit dem WERT DLL _ PROCESS _ ATTACH aufgerufen.
- Der Thread wurde bereits ausgeführt, als ein Aufruf der LoadLibrary-Funktion erfolgt ist, sodass das System nie die Einstiegspunktfunktion dafür aufgerufen hat.
Wenn eine DLL aus einem Prozess als Folge eines nicht erfolgreichen Ladens der DLL, der Beendigung des Prozesses oder eines Aufrufs von FreeLibraryentladen wird, wird die Einstiegspunktfunktion der DLL nicht vom System mit dem _ DLL-THREAD _ DETACH-Wert für die einzelnen Threads des Prozesses aufgerufen. Die DLL wird nur mit einer DLL _ PROCESS _ DETACH-Benachrichtigung gesendet. DLLs können diese Gelegenheit nutzen, um alle Ressourcen für alle Threads zu bereinigt, die der DLL bekannt sind.
Bei der Verarbeitung von DLL PROCESS _ _ DETACH sollte eine DLL Ressourcen wie Heapspeicher nur dann frei geben, wenn die DLL dynamisch entladen wird (der lpReserved-Parameter ist NULL). Wenn der Prozess beendet wird (der lpvReserved-Parameter ist nicht NULL), wurden alle Threads im Prozess mit Ausnahme des aktuellen Threads entweder bereits beendet oder explizit durch einen Aufruf der ExitProcess-Funktion beendet, wodurch einige Prozessressourcen wie Heaps möglicherweise inkonsistent sind. In diesem Fall ist es nicht sicher, dass die DLL die Ressourcen bereinigt. Stattdessen sollte die DLL dem Betriebssystem das Wiederverlangen des Arbeitsspeichers ermöglichen.
Wenn Sie einen Prozess beenden, indem Sie TerminateProcess oder TerminateJobObjectaufrufen, empfangen die DLLs dieses Prozesses keine DLL PROCESS _ _ DETACH-Benachrichtigungen. Wenn Sie einen Thread beenden, indem Sie TerminateThread aufrufen,empfangen die DLLs dieses Threads keine DLL THREAD _ _ DETACH-Benachrichtigungen.
Die Einstiegspunktfunktion sollte nur einfache Initialisierungs- oder Beendigungsaufgaben ausführen. Es darf nicht die LoadLibrary- oder LoadLibraryEx-Funktion (oder eine Funktion, die diese Funktionen aufruft) aufrufen, da dies Abhängigkeitsschleifen in der DLL-Lade reihenfolge erstellen kann. Dies kann dazu führen, dass eine DLL verwendet wird, bevor das System seinen Initialisierungscode ausgeführt hat. Ebenso darf die Einstiegspunktfunktion die FreeLibrary-Funktion (oder eine Funktion, die FreeLibrary aufruft) während der Prozessbeendigung nicht aufrufen, da dies dazu führen kann, dass eine DLL verwendet wird, nachdem das System seinen Beendigungscode ausgeführt hat.
Da Kernel32.dll beim Aufruf der Einstiegspunktfunktion garantiert in den Prozessadressenbereich geladen wird, führt das Aufrufen von Funktionen in Kernel32.dll nicht dazu, dass die DLL verwendet wird, bevor ihr Initialisierungscode ausgeführt wurde. Daher kann die Einstiegspunktfunktion Funktionen in Kernel32.dll aufrufen, die keine anderen DLLs laden. DllMain kann beispielsweise Synchronisierungsobjekte wie kritische Abschnitte und Mutexe erstellen und TLS verwenden. Leider gibt es keine umfassende Liste sicherer Funktionen in Kernel32.dll.
Das Aufrufen von Funktionen, die andere DLLs als Kernel32.dll erfordern, kann zu Problemen führen, die schwer zu diagnostizieren sind. Beispielsweise kann das Aufrufen von User-, Shell- und COM-Funktionen zu Zugriffsverletzungsfehlern führen, da einige Funktionen andere Systemkomponenten laden. Umgekehrt kann das Aufrufen von Funktionen wie diesen während der Beendigung zu Zugriffsverletzungsfehlern führen, da die entsprechende Komponente möglicherweise bereits entladen oder nicht initialisiert wurde.
Da DLL-Benachrichtigungen serialisiert werden, sollten Einstiegspunktfunktionen nicht versuchen, mit anderen Threads oder Prozessen zu kommunizieren. Dies kann zu Deadlocks führen.
Informationen zu bewährten Methoden beim Schreiben einer DLL finden Sie unter https://docs.microsoft.com/windows/win32/dlls/dynamic-link-library-best-practices .
Wenn Ihre DLL mit der C-Laufzeitbibliothek (CRT) verknüpft ist, ruft der von der CRT bereitgestellte Einstiegspunkt die Konstruktoren und Destruktoren für globale und statische C++-Objekte auf. Daher gelten diese Einschränkungen für DllMain auch für Konstruktoren und Destruktoren und jeglichen Code, der von ihnen aufgerufen wird.
Erwägen Sie den Aufruf von DisableThreadLibraryCalls beim Empfangen von DLL PROCESS _ _ ATTACH, es sei denn, Ihre DLL ist mit der statischen C-Laufzeitbibliothek (STATIC C Run-Time Library, CRT) verknüpft.
Anforderungen
| Anforderung | Wert |
|---|---|
| Unterstützte Mindestversion (Client) |
Windows Nur [ XP-Desktop-Apps] |
| Unterstützte Mindestversion (Server) |
Windows Nur Server [ 2003-Desktop-Apps] |
| Header |
|