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 mit den Funktionen LoadLibrary und FreeLibrary geladen oder entladen wird.

Warning

Es gibt erhebliche Einschränkungen bei den Aktionen, die Sie sicher in einem DLL-Einstiegspunkt durchführen können. Allgemeine bewährte Methoden für bestimmte Windows-APIs, die für den Aufruf in DllMain nicht sicher sind. 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 erfordern, dass Anwendungen die Initialisierungsfunktion aufrufen, nachdem DllMain ausgeführt wurde und bevor sie andere Funktionen in der DLL aufrufen.

Beispiel

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 Function.

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 Modulhandle erfordern.

fdwReason [in]

Der Grundcode, der angibt, warum die DLL-Einstiegspunktfunktion aufgerufen wird. Dieser Parameter kann einer der folgenden Werte sein:

Wert Bedeutung
DLL_PROCESS_ATTACH
1
Die DLL wird als Ergebnis des Startvorgangs oder infolge eines Aufrufs von LoadLibrary in den virtuellen Adressraum des aktuellen Prozesses geladen. DLLs können diese Gelegenheit verwenden, um Instanzdaten zu initialisieren oder die TlsAlloc-Funktion zu verwenden, um einen TLS-Index (Thread local storage) zuzuweisen.
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, da sie nicht erfolgreich geladen wurde oder die Verweisanzahl null erreicht hat (die Prozesse wurden entweder einmal beendet oder FreeLibrary für jedes Mal als LoadLibrary bezeichnet).
Der Parameter "lpvReserved " gibt an, ob die DLL aufgrund eines FreeLibrary-Aufrufs , eines Ladefehlers oder einer Beendigung des Prozesses entladen wird.
Die DLL kann diese Möglichkeit verwenden, um die TlsFree-Funktion aufzurufen, um alle TLS-Indizes freizurufen, die mithilfe von TlsAlloc zugewiesen wurden, und um alle threadlokalen Daten freizusprechen.
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 verwenden, um einen TLS-Steckplatz 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 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 zum zugewiesenen Speicher in einem TLS-Steckplatz gespeichert hat, sollte sie diese Gelegenheit verwenden, um den Speicher 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 lpvReservednull für dynamische Lasten und nicht NULL für statische Lasten.

Wenn fdwReasonDLL_PROCESS_DETACH ist, ist lpvReservedNULL , wenn FreeLibrary aufgerufen wurde oder die DLL-Ladefehler aufgetreten ist, und nicht NULL , wenn der Prozess beendet wird.

Zurückgegebener Wert

Wenn das System die DllMain-Funktion mit dem DLL_PROCESS_ATTACH Wert aufruft, gibt die Funktion WAHR 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 die Einstiegspunktfunktion sofort 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. Rufen Sie GetLastError auf, um erweiterte Fehlerinformationen abzurufen.

Wenn das System die DllMain-Funktion mit einem anderen Wert als DLL_PROCESS_ATTACH aufruft, wird der Rückgabewert ignoriert.

Bemerkungen

DllMain ist ein Platzhalter für den bibliotheksdefinierte Funktionsnamen. Sie müssen den tatsächlichen Namen angeben, den Sie beim Erstellen der 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 wird im Kontext des Threads ausgeführt, der dazu führte, dass der Prozessadressraum geändert wurde, z. B. den primären Thread des Prozesses oder den Thread, der LoadLibrary aufgerufen hat. Der Zugriff auf den Einstiegspunkt wird vom System prozessweit serialisiert. Threads in DllMain halten die Ladesperre, sodass keine zusätzlichen DLLs dynamisch geladen oder initialisiert werden können.

Wenn die Einstiegspunktfunktion der DLL FALSE nach einer DLL_PROCESS_ATTACH-Benachrichtigung 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 endenden 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, sodass das System die Einstiegspunktfunktion mit dem DLL_PROCESS_ATTACH Wert bezeichnete.
  • 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 Ergebnis einer nicht erfolgreichen Last der DLL, beendigung des Prozesses oder einem Aufruf von FreeLibrary entladen wird, ruft das System die Einstiegspunktfunktion der DLL nicht mit dem DLL_THREAD_DETACH Wert für die einzelnen Threads des Prozesses auf. Die DLL wird nur eine DLL_PROCESS_DETACH Benachrichtigung gesendet. DLLs können diese Gelegenheit nutzen, um alle Ressourcen für alle Threads zu bereinigen, die der DLL bekannt sind.

Beim Behandeln von DLL_PROCESS_DETACH sollte eine DLL Ressourcen wie Heapspeicher nur freigeben, wenn die DLL dynamisch entladen wird (der lpvReserved-Parameter ist NULL). Wenn der Prozess beendet wird (der lpvReserved-Parameter ist nicht NULL), haben alle Threads im Prozess außer dem aktuellen Thread entweder bereits beendet oder explizit durch einen Aufruf der ExitProcess-Funktion beendet, wodurch möglicherweise einige Prozessressourcen wie Heaps in einem inkonsistenten Zustand verlassen werden. In diesem Fall ist es nicht sicher, dass die DLL die Ressourcen bereinigt. Stattdessen sollte die DLL es dem Betriebssystem ermöglichen, den Arbeitsspeicher zurückzugeben.

Wenn Sie einen Prozess durch Aufrufen von TerminateProcess oder TerminateJobObject beenden, empfangen die DLLs dieses Prozesses nicht DLL_PROCESS_DETACH Benachrichtigungen. Wenn Sie einen Thread durch Aufrufen von TerminateThread beenden, empfangen die DLLs dieses Threads nicht DLL_THREAD_DETACH Benachrichtigungen.

Die Einstiegspunktfunktion sollte nur einfache Initialisierungs- oder Beendigungsaufgaben ausführen. Sie darf die LoadLibrary - oder LoadLibraryEx-Funktion (oder eine Funktion, die diese Funktionen aufruft) nicht aufrufen, 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 werden, wenn die Einstiegspunktfunktion aufgerufen wird, führt das Aufrufen von Funktionen in Kernel32.dll nicht dazu, dass die DLL verwendet wird, bevor der Initialisierungscode ausgeführt wurde. Daher kann die Einstiegspunktfunktion Funktionen in Kernel32.dll aufrufen, die keine anderen DLLs laden. DllMain kann z. B. Synchronisierungsobjekte wie kritische Abschnitte und Mutexes erstellen und TLS verwenden. Leider gibt es in Kernel32.dllkeine umfassende Liste sicherer Funktionen.

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 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. Deadlocks können als Ergebnis auftreten.

Informationen zu bewährten Methoden beim Schreiben einer DLL finden Sie unter Bewährte Methoden für die Dynamic Link Library.

Wenn Ihre DLL mit der C-Laufzeitbibliothek (C Run-Time Library, CRT) verknüpft ist, ruft der einstiegspunkt der CRT 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 code, der von ihnen aufgerufen wird.

Erwägen Sie das Aufrufen von DisableThreadLibraryCalls beim Empfang DLL_PROCESS_ATTACH, es sei denn, Ihre DLL ist mit statischer C-Laufzeitbibliothek (CRT) verknüpft.

Anforderungen

Anforderung Wert
Mindestens unterstützter Client
Windows XP [nur Desktop-Apps]
Unterstützter Server (Mindestversion)
Windows Server 2003 [Nur Desktop-Apps]
Header
Process.h

Siehe auch

Dynamic-Link Library Entry-Point-Funktion

Dynamic-Link Bibliotheksfunktionen

FreeLibrary

GetModuleFileName

LoadLibrary

Tlsalloc

TlsFree

DisableThreadLibraryCalls