DllMain-Einstiegspunkt
Ein optionaler Einstiegspunkt in eine Dll (Dynamic Link Library). 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 mit den Funktionen LoadLibrary und FreeLibrary geladen oder entladen wird.
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved ) // 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:
if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Dies ist ein Beispiel aus der Dynamic-Link Library Entry-Point-Funktion.
Warnung
Es gibt erhebliche Einschränkungen bei den Aktionen, die Sie sicher in einem DLL-Einstiegspunkt durchführen können. Weitere Informationen finden Sie unter Allgemeine bewährte Methoden für bestimmte Windows-APIs, die in DllMain nicht aufgerufen 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.
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
-
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 Modulhandle erfordern.
-
fdwReason [in]
-
Der Grundcode, der angibt, warum die DLL-Einstiegspunktfunktion aufgerufen wird. Dieser Parameter kann einen der folgenden Werte annehmen.
Wert Bedeutung - DLL_PROCESS_ATTACH
- 1
Die DLL wird als Ergebnis des Prozessstarts oder als Ergebnis eines Aufrufs von LoadLibrary in den virtuellen Adressraum des aktuellen Prozesses geladen. DLLs können diese Gelegenheit nutzen, um beliebige instance Daten zu initialisieren oder die TlsAlloc-Funktion zum Zuordnen eines TLS-Indexes (Thread Local Storage) zu verwenden.
Der Parameter lpvReserved 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, weil sie nicht erfolgreich geladen wurde oder die Verweisanzahl null erreicht hat (die Prozesse wurden entweder für jedes Mal FreeLibrary beendet oder aufgerufen, wenn sie LoadLibrary aufgerufen haben).
Der lpvReserved-Parameter gibt an, ob die DLL als Ergebnis eines FreeLibrary-Aufrufs , eines Ladefehlers oder einer Prozessbeendigung entladen wird.
Die DLL kann diese Gelegenheit nutzen, um die TlsFree-Funktion aufzurufen, um alle TLS-Indizes frei zu geben, die mithilfe von 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 unbedingt 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 LoadLibrary geladen 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 den zugeordneten Arbeitsspeicher in einem TLS-Slot gespeichert hat, sollte sie diese Gelegenheit nutzen, um den Arbeitsspeicher freizugeben. Das System ruft die Einstiegspunktfunktion aller derzeit geladenen DLLs mit diesem Wert auf. Der Aufruf erfolgt im Kontext des beendenden Threads. -
lpvReserved [in]
-
Wenn fdwReasonDLL_PROCESS_ATTACH ist, ist lpvReserved für dynamische Ladevorgänge NULL und nicht NULL für statische Ladevorgänge.
Wenn fdwReasonDLL_PROCESS_DETACH ist, ist lpvReservedNULL , wenn FreeLibrary aufgerufen wurde oder die DLL-Auslastung fehlgeschlagen ist, und nicht NULL , wenn der Prozess beendet wird.
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, weil 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 Prozessinitialisierung 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.
DllMain ist ein Platzhalter für den bibliotheksdefinierte Funktionsnamen. Sie müssen den tatsächlichen Namen angeben, den Sie beim Erstellen Ihrer DLL verwenden. Weitere Informationen finden Sie in der Dokumentation, die in Ihren Entwicklungstools enthalten ist.
Während des Startvorgangs oder nach einem Aufruf von LoadLibrary überprüft das System die Liste der geladenen DLLs für den Prozess. Für jede DLL, die noch nicht mit dem DLL_PROCESS_ATTACH-Wert aufgerufen wurde, ruft das System die Einstiegspunktfunktion der DLL auf. Dieser Aufruf erfolgt im Kontext des Threads, der dazu geführt hat, dass sich der Prozessadressraum geändert hat, z. B. der primäre Thread des Prozesses oder der Thread, der LoadLibrary aufgerufen hat. Der Zugriff auf den Einstiegspunkt wird prozessweit vom System serialisiert. Threads in DllMain enthalten die Ladesperre, 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, empfängt die Einstiegspunktfunktion die DLL_PROCESS_DETACH Benachrichtigung nicht.
Es gibt Fälle, in denen die Einstiegspunktfunktion für einen abschlussenden Thread aufgerufen wird, auch wenn die Einstiegspunktfunktion nie mit DLL_THREAD_ATTACH für den Thread aufgerufen wurde:
- Der Thread war der anfängliche Thread im Prozess, sodass das System die Einstiegspunktfunktion mit dem DLL_PROCESS_ATTACH Wert aufgerufen hat.
- Der Thread wurde bereits ausgeführt, als ein Aufruf der LoadLibrary-Funktion erfolgte, sodass das System nie die Einstiegspunktfunktion dafür aufgerufen hat.
Wenn eine DLL aufgrund eines nicht erfolgreichen Ladens der DLL, beendigung des Prozesses oder eines Aufrufs von FreeLibrary aus einem Prozess entladen wird, ruft das System die Einstiegspunktfunktion der DLL nicht mit dem DLL_THREAD_DETACH Wert für die einzelnen Threads des Prozesses auf. Der DLL wird nur eine DLL_PROCESS_DETACH Benachrichtigung gesendet. DLLs können diese Gelegenheit nutzen, um alle Ressourcen für alle Threads, die der DLL bekannt sind, zu sauber.
Bei der Verarbeitung DLL_PROCESS_DETACH sollte eine DLL Nur dann Ressourcen wie Heapspeicher freigeben, wenn die DLL dynamisch entladen wird (der lpvReserved-Parameter ist NULL). Wenn der Prozess beendet wird (der lpvReserved-Parameter ist ungleich NULL), wurden alle Threads im Prozess außer dem aktuellen Thread entweder bereits beendet oder explizit durch einen Aufruf der ExitProcess-Funktion beendet, wodurch einige Prozessressourcen wie Heaps möglicherweise in einem inkonsistenten Zustand bleiben. In diesem Fall ist es für die DLL nicht sicher, die Ressourcen zu sauber. Stattdessen sollte die DLL dem Betriebssystem erlauben, den Arbeitsspeicher zurückzugeben.
Wenn Sie einen Prozess durch Aufrufen von TerminateProcess oder TerminateJobObject beenden, erhalten die DLLs dieses Prozesses keine DLL_PROCESS_DETACH Benachrichtigungen. Wenn Sie einen Thread durch Aufrufen von TerminateThread beenden, erhalten die DLLs dieses Threads keine DLL_THREAD_DETACH Benachrichtigungen.
Die Einstiegspunktfunktion sollte nur einfache Initialisierungs- oder Beendigungsaufgaben ausführen. Die LoadLibrary - oder LoadLibraryEx-Funktion (oder eine Funktion, die diese Funktionen aufruft), darf nicht aufgerufen werden, da dadurch Abhängigkeitsschleifen in der DLL-Ladereihenfolge erstellt werden können. 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 garantiert in den Prozessadressraum geladen wird, wenn die Einstiegspunktfunktion aufgerufen 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 der sicheren 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 der Aufruf von Benutzer-, 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. Als Folge können Deadlocks auftreten.
Informationen zu bewährten Methoden beim Schreiben einer DLL finden Sie unter Bewährte Methoden für die Dynamic Link-Bibliothek.
Wenn Ihre DLL mit der C-Laufzeitbibliothek (CRT) verknüpft ist, ruft der vom 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 sowie alle Code, der von ihnen aufgerufen wird.
Erwägen Sie den Aufruf von DisableThreadLibraryCalls , wenn Sie DLL_PROCESS_ATTACH empfangen, es sei denn, Ihre DLL ist mit der statischen C-Laufzeitbibliothek (CRT) verknüpft.
Anforderung | Wert |
---|---|
Unterstützte Mindestversion (Client) |
Windows XP [nur Desktop-Apps] |
Unterstützte Mindestversion (Server) |
Windows Server 2003 [nur Desktop-Apps] |
Header |
|