Was ist eine DLL

Der vorliegende Artikel erläutert, was eine DLL (Dynamic Link Library) ist, und beschreibt die verschiedenen Probleme, die bei der Verwendung von DLLs auftreten können. Es werden auch einige weiterführende Aspekte beschrieben, die Sie bei der Entwicklung Ihrer eigenen DLLs berücksichtigen sollten.

Gilt für:   Windows 10 – alle Editionen
Ursprüngliche KB-Nummer:   815065

Zusammenfassung

Neben der Definition des Begriffs DLL werden Methoden für dynamisches Verknüpfen, DLL-Abhängigkeiten und DLL-Einstiegspunkte sowie das Exportieren von DLL-Funktionen und DLL-Problembehandlungstools näher erläutert.

Außerdem finden Sie am Ende des Artikels einen allgemeinen Vergleich der Funktionen von Microsoft .NET Framework-Assemblys und DLLs.

Für die Windows-Betriebssysteme wird ein Großteil der Funktionalität des Betriebssystems von DLLs bereitgestellt. Die Funktionalität von Programmen, die Sie auf einem dieser Windows-Betriebssysteme ausführen, wird eventuell ebenfalls über DLLs bereitgestellt. Programme können viele verschiedene Module beinhalten. Die einzelnen Module sind in DLLs enthalten und werden über diese verteilt.

Die Verwendung von DLLs trägt zur Modularisierung und Wiederverwendung des Codes bei, ermöglicht eine effizientere Nutzung des Speichers und sorgt so dafür, dass weniger Speicherplatz belegt wird. Betriebssystem und Programme können so schneller geladen und ausgeführt werden und nehmen weniger Festplattenspeicherplatz auf dem Computer ein.

Wenn ein Programm eine DLL verwendet, können so genannte „Abhängigkeiten“ dazu führen, dass das Programm nicht ausgeführt wird. Eine Abhängigkeit wird hergestellt, wenn ein Programm eine DLL verwendet. Überschreibt ein anderes Programm diese DLL und hebt damit die Abhängigkeit auf, kann das ursprüngliche Programm nicht mehr erfolgreich ausgeführt werden.

Mit der Einführung von Microsoft .NET Framework konnten durch die Verwendung von Assemblys die meisten Abhängigkeitsprobleme behoben werden.

Weitere Informationen

Eine DLL ist eine Bibliothek, die Code und Daten enthält. Sie kann von mehreren Programmen gleichzeitig verwendet werden. In Windows-Betriebssystemen führt die DLL „Comdlg32“ beispielsweise häufig verwendete dialogfeldbezogene Funktionen aus. Jedes Programm kann die in dieser DLL enthaltene Funktionalität zur Implementierung eines Öffnen-Dialogfelds verwenden. Dies trägt zur Wiederverwendung des Codes sowie zu einer effizienten Speichernutzung bei.

Mithilfe von DLLs lässt sich ein Programm in separate Komponenten (so genannte Module) aufgliedern. Ein Buchführungsprogramm kann beispielsweise in einzelnen Modulen angeboten werden. Diese lassen sich zur Laufzeit in das Hauptprogramm laden, sofern sie installiert sind. Da die Module getrennt sind, ist die Ladezeit des Programms kürzer. Und ein Modul wird nur geladen, wenn diese Funktionalität angefordert wird.

Außerdem können Aktualisierungen einfacher auf die einzelnen Module angewendet werden, ohne dass sich dies auf andere Teile des Programms auswirkt. Beispiel: Sie besitzen ein Lohn- und Gehaltsprogramm, und die Steuersätze ändern sich jährlich. Wenn diese Änderungen in einer DLL isoliert werden, können Sie ein Update einbringen, ohne das Programm vollständig neu erstellen oder installieren zu müssen.

Die folgende Liste zählt einige der Dateien auf, die in Windows-Betriebssystemen als DLLs implementiert werden:

  • ActiveX-Steuerelementdateien (.ocx)

    Ein ActiveX-Steuerelement ist beispielsweise ein Kalendersteuerelement, über das Sie ein Datum in einem Kalender auswählen können.

  • Systemsteuerungsdateien (.cpl)

    Ein Beispiel für eine CPL-Datei ist ein Element, das sich in der Systemsteuerung befindet. Jedes Element ist eine spezielle DLL.

  • Gerätetreiberdateien (.drv)

    Ein Beispiel für einen Gerätetreiber ist ein Druckertreiber, der den Druckvorgang auf einem Drucker steuert.

Vorteile von DLLs

Nachfolgend werden einige der Vorteile aufgelistet, die die Verwendung von DLLs durch Programme bietet:

  • Geringerer Ressourcenverbrauch

    Wenn mehrere Programme dieselbe Funktionsbibliothek verwenden, kann mithilfe einer DLL verhindert werden, dass Code doppelt auf die Festplatte und in den physischen Speicher geladen wird. Dies kann die Leistungsfähigkeit nicht nur des Programms, das im Vordergrund läuft, sondern auch anderer Programme, die auf dem Windows-Betriebssystem ausgeführt werden, stark beeinflussen.

  • Unterstützung einer modularen Architektur

    Eine DLL bietet Unterstützung bei der Entwicklung von Programmen auf Modulbasis. Mithilfe von DLLs können Sie umfangreiche Programme mit mehreren Sprachversionen erstellen, oder Sie können Programme entwickeln, die eine modulare Architektur erfordern. Ein Beispiel für ein modulares Programm ist ein Buchführungsprogramm mit mehreren Modulen, die zur Laufzeit dynamisch geladen werden können.

  • Vereinfachte Bereitstellung und Installation

    Wenn eine Funktion in einer DLL aktualisiert oder korrigiert werden muss, ist es für die Bereitstellung und Installation der DLL nicht erforderlich, das Programm erneut mit der DLL zu verknüpfen. Wenn mehrere Programme dieselbe DLL verwenden, profitieren alle diese Programme von der Aktualisierung oder der Reparatur. Dieses Problem tritt eventuell häufiger im Zusammenhang mit Fremdanbieter-DLLs auf, die regelmäßig aktualisiert oder repariert werden.

DLL-Abhängigkeiten

Wenn ein Programm oder eine DLL eine DLL-Funktion einer anderen DLL verwendet, entsteht eine Abhängigkeit. Das Programm ist daher nicht mehr eigenständig, und es können Probleme auftreten, wenn die Abhängigkeit aufgehoben wird. Das Programm wird eventuell nicht ausgeführt, wenn einer der folgenden Vorgänge stattfindet:

  • Eine abhängige DLL wird auf eine neue Version aktualisiert.
  • Eine abhängige DLL wird repariert.
  • Eine abhängige DLL wird mit einer früheren Version überschrieben.
  • Eine abhängige DLL wird vom Computer entfernt.

Diese Aktionen werden auch als DLL-Konflikte bezeichnet. Wird keine Abwärtskompatibilität erzwungen, kann das Programm eventuell nicht erfolgreich ausgeführt werden.

Im Folgenden werden die Änderungen aufgelistet, die in Windows 2000 und höheren Windows-Betriebssystemen eingeführt wurden, um Abhängigkeitsprobleme zu verhindern:

  • Windows-Dateischutz

    Der Windows-Dateischutz verhindert, dass System-DLLs von einem nicht autorisierten Agenten aktualisiert oder gelöscht werden. Wenn eine Programminstallation versucht, eine als System-DLL definierte DLL zu entfernen oder zu aktualisieren, überprüft der Windows-Dateischutz, ob eine gültige digitale Signatur vorhanden ist.

  • Private DLLs

    Mithilfe von privaten DLLs können Sie ein Programm gegenüber Änderungen abschirmen, die an gemeinsam genutzten DLLs vorgenommen werden. Private DLLs verwenden versionsspezifische Informationen oder eine leere .local-Datei, um die Version der DLL zu erzwingen, die vom Programm verwendet wird. Wenn Sie private DLLs verwenden möchten, legen Sie Ihre DLLs im Stammordner des Programms ab. Fügen Sie anschließend für neue Programme versionsspezifische Informationen zur DLL hinzu. Verwenden Sie für alte Programme eine leere .local-Datei. Durch diese Vorgehensweise wird das Betriebssystem angewiesen, die im Stammverzeichnis des jeweiligen Programms abgelegten privaten DLLs zu verwenden.

DLL-Problembehandlungstools

Zur Behebung von DLL-Problemen stehen verschiedene Tools zur Verfügung. Hierzu gehören:

Dependency Walker

Das Tool Dependency Walker ist in der Lage, eine rekursive Suche nach allen abhängigen DLLs durchzuführen, die von einem Programm verwendet werden. Wenn Sie ein Programm in Dependency Walker öffnen, führt dieses Tool die folgenden Prüfungen durch:

  • Dependency Walker sucht nach fehlenden DLLs.
  • Dependency Walker sucht nach ungültigen Programmdateien oder DLLs.
  • Dependency Walker prüft, ob die Import- und Exportfunktionen übereinstimmen.
  • Dependency Walker sucht nach Ringabhängigkeitsfehlern.
  • Dependency Walker sucht nach Modulen, die ungültig sind, weil sie für ein anderes Betriebssystem bestimmt sind.

Mithilfe von Dependency Walker können Sie alle DLLs dokumentieren, die ein Programm verwendet. Dies kann dazu beitragen, dass das Auftreten von DLL-Problemen in Zukunft verhindert und korrigiert wird. Dependency Walker befindet sich im folgenden Verzeichnis, wenn Sie Visual Studio 6.0 installieren:

drive\Program Files\Microsoft Visual Studio\Common\Tools

DLL Universal Problem Solver

Das Tool DLL Universal Problem Solver (DUPS) wird zum Überwachen, Vergleichen, Dokumentieren und Anzeigen von DLL-Informationen verwendet. Nachfolgend sind die Hilfsprogramme aufgeführt, die zum Tool DUPS gehören:

  • Dlister.exe

    Dieses Hilfsprogramm zählt alle DLLs auf dem Computer auf und protokolliert diese Informationen in einer Text- oder Datenbankdatei.

  • Dcomp.exe

    Dieses Hilfsprogramm vergleicht die in zwei Textdateien aufgelisteten DLLs und erzeugt eine dritte Textdatei, in der die Unterschiede enthalten sind.

  • Dtxt2DB.exe

    Dieses Hilfsprogramm lädt die von den Hilfsprogrammen „Dlister.exe“ und „Dcomp.exe“ erstellten Textdateien in die Datenbank „dllHell“.

  • DlgDtxt2DB.exe

    Dieses Hilfsprogramm stellt eine grafische Benutzeroberfläche für das Hilfsprogramm „Dtxt2DB.exe“ bereit.

DLL-Hilfedatenbank

In der DLL-Hilfedatenbank können Sie nach bestimmten Versionen von DLLs suchen, die von Microsoft-Softwareprodukten installiert werden.

DLL-Entwicklung

In diesem Abschnitt werden die Probleme und Anforderungen erläutert, die Sie beim Entwickeln eigener DLLs berücksichtigen sollten.

DLL-Typen

Wenn Sie eine DLL in einer Anwendung laden, werden die exportierten DLL-Funktionen mithilfe von zwei verschiedenen Verknüpfungsmethoden aufgerufen. Hierbei handelt es sich um Load-Time Dynamic Linking (Dynamische Verknüpfung zum Startzeitpunkt) und Run-Time Dynamic Linking (Dynamische Verknüpfung zur Laufzeit).

Load-Time Dynamic Linking

Beim Load-Time Dynamic Linking erzeugt die Anwendung explizite Aufrufe an exportierte DLL-Funktionen (wie an lokale Funktionen). Um diese Verknüpfungsmethode zu verwenden, stellen Sie eine Header-Datei (.h) und eine Importbibliothek (.lib) bereit, wenn Sie die Anwendung kompilieren und verknüpfen. Dadurch stellt der Linker dem System die Informationen bereit, die zum Laden der DLL und Auflösen des Standortes der exportierten DLL-Funktionen zum Startzeitpunkt benötigt werden.

Run-Time Dynamic Linking

Beim Run-Time Dynamic Linking (Dynamische Verknüpfung zur Laufzeit) ruft eine Anwendung entweder die Funktion LoadLibrary oder die Funktion LoadLibraryEx auf, um die DLL zur Laufzeit zu laden. Nachdem die DLL erfolgreich geladen wurde, verwenden Sie die Funktion GetProcAddress, um die Adresse der exportierten DLL-Funktion zu erhalten, die Sie aufrufen möchten. Bei Verwendung dieser Verknüpfungsmethode benötigen Sie keine Importbibliothek.

Nachfolgend werden die Kriterien aufgeführt, nach denen entschieden werden sollte, ob Load-Time Dynamic Linking oder Run-Time Dynamic Linking zu verwenden ist:

  • Startleistung

    Wenn die Startleistung der Anwendung von vorrangiger Bedeutung ist, sollten Sie sich für Run-Time Dynamic Linking entscheiden.

  • Benutzerfreundlichkeit

    Beim Load-Time Dynamic Linking werden die exportierten DLL-Funktionen wie lokale Funktionen behandelt. Dies erleichtert Ihnen das Aufrufen dieser Funktionen.

  • Anwendungslogik

    Beim Run-Time Dynamic Linking kann eine Anwendung je nach Bedarf verschiedene Module laden. Dies ist wichtig, wenn Sie mehrsprachige Versionen entwickeln.

DLL-Einstiegspunkt

Wenn Sie eine DLL erstellen, können Sie optional eine Einstiegspunktfunktion angeben. Diese Funktion wird aufgerufen, wenn Prozesse oder Threads sich an eine DLL anfügen oder sich von einer DLL trennen. Sie können die Einstiegspunktfunktion, je nachdem, was die DLL erfordert, zum Initialisieren oder zum Entfernen von Datenstrukturen verwenden. Wenn es sich um eine Multithread-Anwendung handelt, können Sie außerdem den lokalen Threadspeicher (Thread Local Storage, TLS) verwenden, um den einzelnen Threads in der Einstiegspunktfunktion privaten Speicher zuzuweisen. Der folgende Code ist ein Beispiel für eine DLL-Einstiegspunktfunktion.

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACHED: // A process is loading the DLL.
        break;
        case DLL_THREAD_ATTACHED: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break;
        case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}

Wenn die Einstiegspunktfunktion einen FALSE-Wert zurückgibt, wird die Anwendung nicht gestartet, falls Sie Load-Time Dynamic Linking (Dynamische Verknüpfung zum Startzeitpunkt) verwenden. Bei Verwendung der Verknüpfungsmethode Run-Time Dynamic Linking wird nur die jeweilige DLL nicht geladen.

Die Einstiegspunktfunktion sollte nur einfache Initialisierungsaufgaben ausführen. Sie sollte keine anderen DLL-Lade- oder -Abbruchfunktionen aufrufen. Beispielsweise sollten Sie in der Einstiegspunktfunktion weder direkt noch indirekt die Funktion LoadLibrary oder die Funktion LoadLibraryEx aufrufen. Sie sollten darüber hinaus auch nicht die Funktion FreeLibrary aufrufen, wenn der Prozess beendet wird.

Hinweis

Stellen Sie in Multithread-Anwendungen sicher, dass der Zugriff auf die globalen DLL-Daten synchronisiert (threadsicher) ist, um eventuelle Beschädigungen von Daten zu verhindern. Verwenden Sie hierzu TLS, um eindeutige Daten für jeden Thread bereitzustellen.

Exportieren von DLL-Funktionen

Um DLL-Funktionen zu exportieren, können Sie entweder den exportierten DLL-Funktionen ein Funktionsschlüsselwort hinzufügen oder eine Moduldefinitionsdatei (.def) erstellen, in der die exportierten DLL-Funktionen aufgelistet werden.

Wenn Sie ein Funktionsschlüsselwort verwenden möchten, müssen Sie jede Funktion, die Sie exportieren möchten, mit dem folgenden Schlüsselwort deklarieren:
__declspec(dllexport)

Um exportierte DLL-Funktionen in der Anwendung zu verwenden, müssen Sie jede Funktion, die Sie importieren möchten, mit dem folgenden Schlüsselwort deklarieren: __declspec(dllimport)

In der Regel verwenden Sie eine Headerdatei mit einer „define“-Anweisung und einer ifdef-Anweisung, um die Export- und die import-Anweisung voreinander zu trennen.

Sie können auch eine Moduldefinitionsdatei verwenden, um exportierte DLL-Funktionen zu deklarieren. Wenn Sie eine Moduldefinitionsdatei verwenden, müssen Sie den exportierten DLL-Funktionen kein Funktionsschlüsselwort hinzufügen. In der Moduldefinitionsdatei deklarieren Sie die LIBRARY- und die EXPORTS-Anweisung für die DLL. Der folgende Code ist ein Beispiel für eine Definitionsdatei.

// SampleDLL.def
//
LIBRARY "sampleDLL"
EXPORTS HelloWorld

Beispiel-DLL und -Anwendung

In Microsoft Visual C++ 6.0 können Sie eine DLL erstellen, indem Sie entweder den Projekttyp Win32 Dynamic-Link Library oder den Projekttyp MFC AppWizard (dll) wählen.

Der folgende Code ist ein Beispiel für eine DLL, die in Visual C++ unter Verwendung des Projekttyps Win32 Dynamic-Link Library erstellt wurde.

// SampleDLL.cpp
//

#include "stdafx.h"
#define EXPORTING_DLL
#include "sampleDLL.h"
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
)
{
    return TRUE;
}

void HelloWorld()
{
    MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}

// File: SampleDLL.h
//
#ifndef INDLL_H
    #define INDLL_H
    #ifdef EXPORTING_DLL
        extern __declspec(dllexport) void HelloWorld();
    #else
        extern __declspec(dllimport) void HelloWorld();
    #endif

#endif

Der folgende Code ist ein Beispiel für ein Win32-Anwendung-Projekt, das die exportierte DLL-Funktion in der DLL „SampleDLL“ abruft.

// SampleApp.cpp
//
#include "stdafx.h"
#include "sampleDLL.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HelloWorld();
    return 0;
}

Hinweis

Bei der dynamischen Verknüpfung zur Ladezeit müssen Sie die Importbibliothek „SampleDLL.lib“ verknüpfen, die beim Erstellen des Projekts „SampleDLL“ erzeugt wird.

Beim Run-Time Dynamic Linking verwenden Sie zum Aufrufen der exportierten DLL-Funktion „SampleDLL.dll“ Code, der dem folgenden ähnelt:

...
typedef VOID (*DLLPROC) (LPTSTR);
...
HINSTANCE hinstDLL;
DLLPROC HelloWorld;
BOOL fFreeDLL;

hinstDLL = LoadLibrary("sampleDLL.dll");
if (hinstDLL != NULL)
{
    HelloWorld = (DLLPROC) GetProcAddress(hinstDLL, "HelloWorld");
    if (HelloWorld != NULL)
        (HelloWorld);
    fFreeDLL = FreeLibrary(hinstDLL);
}
...

Wenn Sie die Anwendung „SampleDLL“ kompilieren und verknüpfen, sucht das Windows-Betriebssystem (in der nachfolgend angegebenen Reihenfolge) an den folgenden Speicherorten nach der DLL „SampleDLL“:

  1. Im Anwendungsordner

  2. Im aktuellen Ordner

  3. Im Windows-Systemordner

    Hinweis

    Die Funktion GetSystemDirectory gibt den Pfad des Windows-Systemordners zurück.

  4. Im Ordner „Windows“

    Hinweis

    Die Funktion GetWindowsDirectory gibt den Pfad des Windows-Ordners zurück.

Microsoft .NET Framework-Assemblys

Durch die Einführung von .NET und dem .NET Framework wurden dank der Verwendung von Assemblys die meisten der Probleme behoben, die im Zusammenhang mit DLLs auftreten können. Eine Assembly ist eine logische Funktionseinheit, die unter der Steuerung der Common Language Runtime (CLR) von .NET ausgeführt wird. Eine Assembly existiert physisch als DLL-Datei oder als EXE-Datei. Intern unterscheidet sich eine Assembly jedoch von einer Microsoft Win32-DLL.

Eine Assemblydatei enthält ein Assemblymanifest, Typmetadaten, MSIL-Code (MISL = Microsoft Intermediate Language) und andere Ressourcen. Das Assemblymanifest beinhaltet die Assemblymetadaten. Diese stellen alle Informationen bereit, die erforderlich sind, damit eine Assembly selbstbeschreibend ist. Das Assemblymanifest enthält die folgenden Informationen:

  • Assemblyname
  • Informationen zur Version
  • Kulturinformationen
  • Eindeutige Namensinformationen
  • Assembly-Dateiliste
  • Typverweisinformationen
  • Referenzierte und abhängige Assembly-Informationen

Der in der Assembly enthaltene MSIL-Code kann nicht direkt ausgeführt werden. Die Ausführung des MSIL-Codes wird über die CLR gesteuert. Wenn Sie eine Assembly erstellen, ist die Assembly für die Anwendung standardmäßig privat. Um eine gemeinsam genutzte Assembly zu erstellen, müssen Sie der Assembly einen eindeutigen Namen zuweisen und die Assembly im globalen Assemblycache veröffentlichen.

Nachfolgend werden einige der Funktionen von Assemblys den Funktionen von Win32-DLLs gegenübergestellt:

  • Selbstbeschreibend

    Wenn Sie eine Assembly erstellen, sind alle Informationen, die die CLR zum Ausführen der Assembly benötigt, im Assemblymanifest enthalten. Das Assemblymanifest enthält eine Liste der abhängigen Assemblys. Daher kann die CLR mit einem konsistenten Satz Assemblys arbeiten, die in der Anwendung verwendet werden. In Win32-DLLs können Sie keine Konsistenz zwischen einem Satz DLLs aufrechterhalten, die in einer Anwendung verwendet werden, wenn Sie gemeinsam genutzte DLLs verwenden.

  • Versionsverwaltung

    In einem Assemblymanifest werden Versionsinformationen aufgezeichnet, die von der CLR erzwungen werden. Außerdem können Sie mithilfe von Versionsrichtlinien eine versionsspezifische Verwendung erzwingen. In Win32-DLLs kann die Versionskontrolle nicht vom Betriebssystem erzwungen werden. Sie müssen sicherstellen, dass die DLLs abwärtskompatibel sind.

  • Parallele Weitergabe

    Assemblys unterstützen die parallele Weitergabe. Eine Anwendung kann eine Version einer Assembly verwenden, während eine andere Anwendung eine andere Version einer Assembly verwendet. Ab Windows 2000 wird die parallele Weitergabe durch die Speicherung von DLLs im Anwendungsordner unterstützt. Außerdem verhindert der Windows-Dateischutz, dass System-DLLs von einem nicht autorisierten Agenten überschrieben oder ersetzt werden.

  • Selbständigkeit und Isolation

    Eine Anwendung, die unter Verwendung einer Assembly entwickelt wurde, kann selbständig und von anderen Anwendungen isoliert sein, die auf dem Computer ausgeführt werden. Durch diese Funktionalität können Sie nebenwirkungsfreie Installationen (Zero-Impact-Installationen) erstellen.

  • Ausführung

    Eine Assembly wird mit den im Assemblymanifest angegebenen Sicherheitsberechtigungen ausgeführt. Diese werden von der CLR überwacht.

  • Sprachunabhängigkeit

    Eine Assembly kann in einer der unterstützten .NET-Sprachen erstellt werden. Sie können eine Assembly beispielsweise in Microsoft Visual C# erstellen und die Assembly anschließend in einem Projekt von Visual Basic .NET verwenden.

References