Dynamic-Link Library Entry-Point-Funktion
Eine DLL kann optional eine Einstiegspunktfunktion angeben. Falls vorhanden, ruft das System die Einstiegspunktfunktion auf, wenn ein Prozess oder Thread die DLL lädt oder entlädt. Sie kann verwendet werden, um einfache Initialisierungs- und Bereinigungsaufgaben auszuführen. Beispielsweise kann er lokalen Threadspeicher einrichten, wenn ein neuer Thread erstellt wird, und ihn bereinigen, wenn der Thread beendet wird.
Wenn Sie Ihre DLL mit der C-Laufzeitbibliothek verknüpfen, stellt sie möglicherweise eine Einstiegspunktfunktion für Sie bereit, und Sie können eine separate Initialisierungsfunktion bereitstellen. Weitere Informationen finden Sie in der Dokumentation zu Ihrer Laufzeitbibliothek.
Wenn Sie Einen eigenen Einstiegspunkt bereitstellen, lesen Sie die DllMain-Funktion. Der Name DllMain ist ein Platzhalter für eine benutzerdefinierte Funktion. 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.
Aufrufen der Entry-Point-Funktion
Das System ruft die Einstiegspunktfunktion immer dann auf, wenn eines der folgenden Ereignisse auftritt:
- Ein Prozess lädt die DLL. Bei Prozessen, die die dynamische Verknüpfung zur Ladezeit verwenden, wird die DLL während der Prozessinitialisierung geladen. Bei Prozessen mit Laufzeitverknüpfung wird die DLL geladen, bevor LoadLibrary oder LoadLibraryEx zurückgegeben wird.
- Ein Prozess entlädt die DLL. Die DLL wird entladen, wenn der Prozess beendet wird oder die FreeLibrary-Funktion aufruft und der Verweiszähler 0 (null) wird. Wenn der Prozess als Ergebnis der TerminateProcess- oder TerminateThread-Funktion 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 DisableThreadLibraryCalls-Funktion verwenden, um die Benachrichtigung zu deaktivieren, wenn Threads erstellt werden.
- Ein Thread eines Prozesses, der die DLL geladen hat, wird normal beendet, ohne TerminateThread oder TerminateProcess zu verwenden. Wenn ein Prozess die DLL entlädt, wird die Einstiegspunktfunktion nur einmal für den gesamten Prozess und nicht einmal für jeden vorhandenen Thread des Prozesses aufgerufen. Sie können DisableThreadLibraryCalls verwenden, um die Benachrichtigung zu deaktivieren, wenn Threads beendet werden.
Nur jeweils ein Thread kann die Einstiegspunktfunktion aufrufen.
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 verwenden, um Speicher im virtuellen Adressraum des aufrufenden Prozesses zuzuweisen oder Handles zu öffnen, auf die der Prozess zugreifen kann. Die Einstiegspunktfunktion kann mithilfe von lokalem Threadspeicher (TLS) auch Speicher zuordnen, der für einen neuen Thread privat ist. Weitere Informationen zum lokalen Threadspeicher finden Sie unter ThreadLokale Storage.
Entry-Point Funktionsdefinition
Die DLL-Einstiegspunktfunktion muss mit der Aufrufkonvention für Standardaufrufe deklariert werden. Wenn der DLL-Einstiegspunkt nicht ordnungsgemäß deklariert ist, wird die DLL nicht geladen, und das System zeigt eine Meldung an, die angibt, dass der DLL-Einstiegspunkt mit WINAPI deklariert werden muss.
Im Text 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 entlädt 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 den Initialisierungscode ausgeführt hat. Ebenso darf die Einstiegspunktfunktion die FreeLibrary-Funktion (oder eine Funktion, die FreeLibrary aufruft) während der Beendigung des Prozesses nicht aufrufen, da dies dazu führen kann, dass eine DLL verwendet wird, nachdem das System den Beendigungscode ausgeführt hat.
Da Kernel32.dll beim Aufrufen der Einstiegspunktfunktion garantiert in den Prozessadressraum 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 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 der Aufruf von User-, 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 Zugriffsverletzungsfehlern 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 Rückgabewert der Funktion
Wenn eine DLL-Einstiegspunktfunktion aufgerufen wird, weil ein Prozess geladen wird, gibt die Funktion TRUE zurück, um den Erfolg anzugeben. Bei Prozessen, die die Ladezeitverknüpfung verwenden, führt der Rückgabewert FALSE dazu, dass die Prozessinitialisierung fehlschlägt und der Prozess beendet wird. Bei Prozessen, die Laufzeitverknüpfung verwenden, bewirkt der Rückgabewert FALSE, dass die LoadLibrary- oder LoadLibraryEx-Funktion NULL 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.