Dynamic-Link Bibliothek Entry-Point-Funktion

Eine DLL kann optional eine Einstiegsfunktion angeben. Falls vorhanden, ruft das System die Einstiegspunktfunktion auf, wenn ein Prozess oder Thread die DLL lädt oder entlädt. Es kann verwendet werden, um einfache Initialisierungs- und Bereinigungsaufgaben auszuführen. Beispielsweise kann es den lokalen Threadspeicher einrichten, wenn ein neuer Thread erstellt wird, und sauber, wenn der Thread beendet wird.

Wenn Sie Ihre DLL mit der C-Laufzeitbibliothek verknüpfen, stellt sie möglicherweise eine Einstiegsfunktion für Sie bereit, und Sie können eine separate Initialisierungsfunktion bereitstellen. Weitere Informationen finden Sie in der Dokumentation für Ihre Laufzeitbibliothek.

Wenn Sie Einen eigenen Einstiegspunkt bereitstellen, sehen Sie sich die DllMain-Funktion an . Der Name DllMain ist ein Platzhalter für eine benutzerdefinierte Funktion. Sie müssen den tatsächlichen Namen angeben, den Sie beim Erstellen Ihrer DLL verwenden. Weitere Informationen finden Sie in der Dokumentation, die mit Ihren Entwicklungstools enthalten ist.

Aufrufen der Entry-Point-Funktion

Das System ruft die Einstiegspunktfunktion auf, wenn eines der folgenden Ereignisse auftritt:

  • Ein Prozess lädt die DLL. Bei Prozessen, die eine dynamische Verknüpfung mit Ladezeit verwenden, wird die DLL während der Prozessinitialisierung geladen. Bei Prozessen, die Laufzeitverknüpfung verwenden, wird die DLL geladen, bevor LoadLibrary oder LoadLibraryEx zurückgegeben wird.
  • Ein Prozess entladen die DLL. Die DLL wird entladen, wenn der Prozess beendet oder die FreeLibrary-Funktion aufruft, und die Verweisanzahl wird 0. Wenn der Prozess als Ergebnis der Funktion TerminateProcess oder TerminateThread beendet wird, ruft das System die DLL-Einstiegspunktfunktion nicht auf.
  • Ein neuer Thread wird in einem Prozess erstellt, der die DLL geladen hat. Sie können die Funktion DisableThreadLibraryCalls verwenden, um Benachrichtigungen beim Erstellen von Threads zu deaktivieren.
  • Ein Thread eines Prozesses, der die DLL geladen hat, wird normal beendet, ohne TerminateThread oder TerminateProcess zu verwenden. Wenn ein Prozess die DLL entladen, wird die Einstiegspunktfunktion nur einmal für den gesamten Prozess aufgerufen und nicht einmal für jeden vorhandenen Thread des Prozesses. Sie können DisableThreadLibraryCalls verwenden, um Benachrichtigungen zu deaktivieren, wenn Threads beendet werden.

Die Einstiegspunktfunktion kann jeweils nur von einem Thread aufgerufen werden.

Das System ruft die Einstiegspunktfunktion im Kontext des Prozesses oder Threads auf, der den Aufruf der Funktion verursacht hat. Dadurch kann eine DLL ihre Einstiegspunktfunktion zum Zuweisen von Arbeitsspeicher im virtuellen Adressraum des aufrufenden Prozesses oder zum Öffnen von Handles verwenden, die für den Prozess zugänglich sind. Die Einstiegspunktfunktion kann auch privaten Arbeitsspeicher einem neuen Thread zuordnen, indem sie den lokalen Threadspeicher (TLS) verwendet. Weitere Informationen zum lokalen Threadspeicher finden Sie unter Thread Local Storage.

Entry-Point Funktionsdefinition

Die DLL-Einstiegspunktfunktion muss mit der Standardaufrufkonvention deklariert werden. Wenn der DLL-Einstiegspunkt nicht ordnungsgemäß deklariert ist, wird die DLL nicht geladen, und das System zeigt eine Meldung an, dass der DLL-Einstiegspunkt mit WINAPI deklariert werden muss.

Im Textkörper der Funktion können Sie eine beliebige Kombination der folgenden Szenarien behandeln, in denen der DLL-Einstiegspunkt aufgerufen wurde:

  • Ein Prozess lädt die DLL (DLL_PROCESS_ATTACH).
  • Der aktuelle Prozess erstellt einen neuen Thread (DLL_THREAD_ATTACH).
  • Ein Thread wird normal beendet (DLL_THREAD_DETACH).
  • Ein Prozess entladen die DLL (DLL_PROCESS_DETACH).

Die Einstiegspunktfunktion sollte nur einfache Initialisierungsaufgaben 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 Einstiegsfunktion 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 Synchronisierungsobjekte wie kritische Abschnitte und Mutexe erstellen und TLS verwenden, da sich diese Funktionen in Kernel32.dll befinden. Es ist beispielsweise nicht sicher, die Registrierungsfunktionen aufzurufen, da sie sich in Advapi32.dll befinden.

Das Aufrufen anderer Funktionen 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 in ihren DLLs LoadLibrary aufrufen, um andere Systemkomponenten zu laden. Umgekehrt kann das Aufrufen dieser Funktionen während der Beendigung zu Zugriffsfehlern führen, da die entsprechende Komponente möglicherweise bereits entladen oder nicht initialisiert wurde.

Im folgenden Beispiel wird veranschaulicht, wie die DLL-Einstiegspunktfunktion strukturiert wird.

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

Entry-Point Funktionsrückgabewert

Wenn eine DLL-Einstiegspunktfunktion aufgerufen wird, weil ein Prozess geladen wird, gibt die Funktion TRUE zurück, um den Erfolg anzugeben. Bei Prozessen, die eine Ladezeitverknüpfung verwenden, führt ein Rückgabewert von FALSE dazu, dass die Prozessinitialisierung fehlschlägt und der Prozess beendet wird. Bei Prozessen, die Laufzeitverknüpfung verwenden, bewirkt ein Rückgabewert von FALSE, dass die LoadLibrary - oder LoadLibraryEx-FunktionNULL zurückgibt, was auf einen Fehler hinweist. (Das System ruft sofort Ihre Einstiegspunktfunktion mit DLL_PROCESS_DETACH auf und entlädt die DLL.) Der Rückgabewert der Einstiegspunktfunktion wird ignoriert, wenn die Funktion aus einem anderen Grund aufgerufen wird.