Bibliotheken und Packages (Delphi)
Nach oben zu Bibliotheken und Packages - Index
Eine dynamisch ladbare Bibliothek ist unter Windows eine dynamische Linkbibliothek (DLL) oder auf dem Mac eine DYLIB. Es handelt sich dabei um eine Sammlung von Routinen, die von Anwendungen und von anderen DLLs bzw. gemeinsamen Objekten aufgerufen werden können. Dynamisch ladbare Bibliotheken enthalten wie Units gemeinsam genutzten Code und Ressourcen. Sie stellen jedoch eine separat compilierte, ausführbare Datei dar, die zur Laufzeit zu den Programmen gelinkt wird, die sie verwenden.
Delphi-Programme können DLLs und Assemblies aufrufen, die in anderen Sprachen geschrieben wurden. Anwendungen, die in anderen Sprachen programmiert wurden, können DLLs oder Assemblies aufrufen, die mit Delphi erstellt wurden.
Inhaltsverzeichnis
Dynamisch ladbare Bibliotheken aufrufen
Direkt aufgerufene Betriebssystemroutinen werden erst zur Laufzeit zur Anwendung gelinkt. Das bedeutet, dass die Bibliothek zur Compilierzeit nicht benötigt wird. Der Compiler kann also nicht überprüfen, ob eine Routine korrekt importiert wird.
Bevor Sie Routinen aufrufen können, die in einer DLL oder Assembly definiert sind, müssen Sie diese Routinen importieren. Dies kann auf zwei Arten erfolgen: durch Deklarieren einer Prozedur oder Funktion als external oder durch direkte Betriebssystemaufrufe. Bei beiden Methoden werden die Routinen erst zur Laufzeit mit der Anwendung gelinkt.
Variablen aus DLLs oder Assemblies können in Delphi nicht importiert werden.
Statisches Laden
Die einfachste Art, eine Prozedur oder Funktion zu importieren, besteht darin, sie mit der Direktive external zu deklarieren. Zum Beispiel:
procedure DoSomething; external 'MYLIB.DLL';
Mit dieser Deklaration wird beim Programmstart die Datei MYLIB.DLL geladen. Während der Programmausführung bezieht sich der Bezeichner DoSomething immer auf denselben Eintrittspunkt in derselben gemeinsamen Bibliothek.
Sie können Deklarationen von importierten Routinen direkt in das Programm oder die Unit einfügen, in dem bzw. der sie aufgerufen werden. Um Ihre Programme leichter pflegen zu können, sollten Sie aber alle external-Deklarationen in einer separaten "Import-Unit" zusammenfassen. Diese Unit enthält dann auch die Konstanten und Typen, die für das Interface zur Bibliothek erforderlich sind. Andere Module, die auf die Import-Unit zugreifen, können alle darin deklarierten Routinen aufrufen.
Verzögertes Laden
Mit der Direktive delayed kann eine externe Routine versehen werden, um das Laden der Bibliothek, die die Routine enthält, zu verzögern. Das eigentliche Laden wird erst durchgeführt, wenn die Routine zum ersten Mal aufgerufen wird. Das folgende Beispiel zeigt die Verwendung der Direktive delayed:
function GetSomething: Integer; external 'somelibrary.dll' delayed;
Im obigen Beispiel wird die Routine GetSomething aus der Bibliothek somelibrary.dll geladen. Die Direktive gewährleistet, dass somelibrary.dll nicht statisch sondern dynamisch zu der Anwendung gelinkt wird.
Die Direktive delayed eignet sich besonders für importierte Routinen, die in dem Betriebssystem, auf dem die Anwendung ausgeführt wird, nicht vorhanden sind. Bei statisch importierten Routinen ist es erforderlich, dass das Betriebssystem beim Start der Anwendung die Bibliothek findet und lädt. Wenn die Routine in der geladenen Bibliothek nicht gefunden wird, oder die Bibliothek nicht vorhanden ist, hält das Betriebssystem die Ausführung der Anwendung an. Mithilfe der Direktive delayed können Sie zur Laufzeit überprüfen, ob das Betriebssystem die erforderlichen APIs unterstützt; nur dann können Sie nämlich die importierten Routinen aufrufen.
Eine andere Anwendungsmöglichkeit für die Direktive delayed bezieht sich auf den für die Anwendung benötigten Arbeitsspeicher: je weniger wahrscheinlich Routinen verwendet werden, desto weniger Arbeitsspeicher ist erforderlich. delayed kann den benötigten Arbeitsspeicher der Anwendung reduzieren, weil die Bibliotheken nur bei Bedarf geladen werden. Eine missbräuchliche Verwendung von delayed kann die (vom Benutzer wahrgenommene) Ausführungsgeschwindigkeit des Programms beeinträchtigen.
Hinweis: Der Versuch, eine verzögerte Routine aufzurufen, die nicht aufgelöst werden kann, führt zu einem Laufzeitfehler (oder einer Exception, wenn die Unit SysUtils geladen ist).
Um das von der Delphi-RTL verwendete verzögerte Laden zu optimieren, können Sie Hook-Prozeduren registrieren. Damit lässt sich das Ladeverhalten überwachen und ändern. Verwenden Sie dazu SetDliNotifyHook2 und SetDliFailureHook2, die in der Unit SysInit deklariert sind. Siehe auch das Codebeispiel unter DelayedLoading (Delphi).
Dynamisches Laden (Nur Windows)
Sie können auf Routinen in einer Bibliothek über direkte Aufrufe von Windows-APIs zugreifen (z.B. LoadLibrary, FreeLibrary und GetProcAddress). Diese Funktionen sind in Windows.pas deklariert. In diesem Fall werden die importierten Routinen über prozedurale Variablen referenziert.
Zum Beispiel:
uses Windows, ...;
type
TTimeRec = record
Second: Integer;
Minute: Integer;
Hour: Integer;
end;
TGetTime = procedure(var Time: TTimeRec);
THandle = Integer;
var
Time: TTimeRec;
Handle: THandle;
GetTime: TGetTime;
.
.
.
begin
Handle := LoadLibrary('libraryname');
if Handle <> 0 then
begin
@GetTime := GetProcAddress(Handle, 'GetTime');
if @GetTime <> nil then
begin
GetTime(Time);
with Time do
Writeln('The time is ', Hour, ':', Minute, ':', Second);
end;
FreeLibrary(Handle);
end;
end;
Wenn Sie Routinen auf diese Weise importieren, wird die Bibliothek erst bei der Ausführung des Quelltextes geladen, der den Aufruf von LoadLibrary enthält. Später wird die Bibliothek mit einem Aufruf von FreeLibrary wieder aus dem Speicher entfernt. Auf diese Weise wird Speicherplatz gespart und das Programm auch dann ausgeführt, wenn einige der aufgerufenen Bibliotheken nicht zur Verfügung stehen.