Beispiele für die Erstellung komplexer Delphi-DLLs. Erstellen einer DLL-Bibliothek in Delphi. Praxis und Beispiele

Zu erschaffen neue Bibliothek DLL in Delphi, Menübefehl auswählen Datei > Neu > Andere. Im Panel Artikelkategorien Fenster Neue Artikel Knoten auswählen Delphi-Projekte, und doppelklicken Sie dann auf das Element Dynamic-Link-Bibliothek im rechten Bereich des Fensters.

Master DLL-Assistent erstellt eine Haupt-DLL-Quellcodedatei, die fast genauso aussieht wie Quellcode, generiert für eine reguläre Anwendung. Der einzige Unterschied ist. dass diese Datei mit einem reservierten Wort beginnt Bibliothek , nicht.

Programm Bibliotheksprojekt1; (Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muss die erste Einheit in der USES-Klausel Ihrer Bibliothek UND in der USES-Klausel Ihres Projekts (wählen Sie die Projektansichtsquelle) sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die Zeichenfolgen als Parameter oder Funktion übergeben Dies gilt für alle Zeichenfolgen, die an und von Ihrer DLL übergeben werden – auch für diejenigen, die in Datensätzen und Klassen verschachtelt sind. ShareMem ist die Schnittstelleneinheit zum gemeinsam genutzten Speichermanager BORLNDMM, der zusammen mit Ihrer DLL bereitgestellt werden muss .DLL, String-Informationen mit PChar- oder ShortString-Parametern übergeben) ( Wichtiger Hinweis

Bezüglich der DLL-Speicherverwaltung: Das ShareMem-Modul muss das erste Modul in der Verwendungsanweisung Ihrer Bibliothek und in der Verwendungsanweisung Ihres Projekts sein (wählen Sie den Menübefehl Projekt -> Quelle anzeigen), wenn Ihre DLL Prozeduren oder Funktionen exportiert, die Zeichenfolgen als Parameter oder Ergebnisse übergeben von Funktionen. Dies gilt für alle Zeichenfolgen, die an Ihre DLL übergeben oder von dieser empfangen werden, und sogar für Zeichenfolgen, die in Datensätzen und Klassen verschachtelt sind. Das ShareMem-Modul ist ein Schnittstellenmodul zum Shared-Memory-Manager BORLNDMM.DLL, das Sie mit Ihrer DLL bereitstellen müssen. Um die Verwendung von BORLNDMM.DLL zu vermeiden, übergeben Sie Zeichenfolgeninformationen mithilfe der Parameter PChar oder ShortString. ) verwendet SysUtils, Classes; ($R *.res) Anfang Ende. Jetzt müssen Sie nur noch ein Unterprogramm vor dem Block hinzufügen, das ist alles. Sie verfügen dann über eine interne Routine, die in der DLL verwendet werden kann, jedoch nicht in externen Anwendungen. Wenn Sie die Routine aus anderen Anwendungen und anderen DLLs aufrufen möchten, müssen Sie sie exportieren. Um eine Routine nach Namen zu exportieren, fügen Sie sie der Liste hinzu Exporte Wenn Sie die Routine aus anderen Anwendungen und anderen DLLs aufrufen möchten, müssen Sie sie exportieren. Um eine Routine nach Namen zu exportieren, fügen Sie sie der Liste hinzu. Liste hat die gleiche Syntax wie list verwendet Wenn Sie die Routine aus anderen Anwendungen und anderen DLLs aufrufen möchten, müssen Sie sie exportieren. Um eine Routine nach Namen zu exportieren, fügen Sie sie der Liste hinzu, außer was in der Liste steht

Jedes Element ist eine Unterroutine, kein Modul. Wenn Sie die Routine aus anderen Anwendungen und anderen DLLs aufrufen möchten, müssen Sie sie exportieren. Um eine Routine nach Namen zu exportieren, fügen Sie sie der Liste hinzu Liste Jetzt müssen Sie nur noch ein Unterprogramm vor dem Block hinzufügen normalerweise unmittelbar vor dem Block platziert . Schauen Sie sich Listing 1 an, das den Quellcode für eine einfache Bibliothek zeigt

FirstLib.dll

, Exportieren einer Funktion.

Listing 1. Einfache DLL Wenn Sie die Routine aus anderen Anwendungen und anderen DLLs aufrufen möchten, müssen Sie sie exportieren. Um eine Routine nach Namen zu exportieren, fügen Sie sie der Liste hinzu Bibliothek FirstLib; Funktion Max3(Num1, Num2, Num3: Integer): Integer; stdcall; begin Ergebnis:= Num1; wenn Num2 > Ergebnis, dann Ergebnis:= Num2; wenn Num3 > Ergebnis, dann Ergebnis:= Num3; Ende; (Exportieren der Max3-Funktion) exportiert Max3; Anfang Ende. Wenn Sie der Liste eine Routine hinzufügen, exportieren Sie damit das Unterprogramm anhand seines Namens. Mit der Direktive können Sie die Routine auch unter einem anderen Namen exportieren Wenn Sie der Liste eine Routine hinzufügen Name

oder über einen Ordinalwert mit der Direktive

Index

. Wenden Sie jedoch die Richtlinie an nicht empfohlen. Das Folgende ist ein Beispiel für den Export einer Direktive unter Verwendung eines Ordinalwerts oder eines anderen Namens:

Exportiert Max3-Namen „MyMax3Function“, SaySomething-Index 1; Statisches Laden ist die einfachste der beiden Möglichkeiten, eine DLL zu laden. Statisches Laden wird auch als dynamische Verbindung beim Booten bezeichnet ( Dynamische Verknüpfung zur Ladezeit

), da die verwendeten DLLs beim Start der Anwendung automatisch geladen werden. Statisches Laden ist die einfachste der beiden Möglichkeiten, eine DLL zu laden. Statisches Laden wird auch als dynamische Verbindung beim Booten bezeichnet ( Um eine DLL statisch zu laden, müssen Sie die Routinedeklaration und die aufrufende Anwendung kopieren und mit einer Direktive markieren extern, was dem Compiler mitteilt, dass sich die Routine entweder in einer Objektdatei oder in einer DLL befindet. .:

Wenn Sie Routinen aus einer DLL importieren, müssen Sie diese mit einer Direktive markieren

, gefolgt vom Namen der DLL, die die Implementierung der Routine enthält. Im Folgenden finden Sie ein Beispiel für den Import einer Funktion wenn Num2 > Ergebnis, dann Ergebnis:= Num2;:

Funktion Max(Num1, Num2, Num3: Integer): Integer; stdcall; externer „FirstLib.dll“ Name „Max3“;

Sie können eine Funktion auch aus einer DLL importieren. Dazu müssen Sie ein Importmodul erstellen und einen Standard-Unterprogramm-Header in den Abschnitt schreiben Schnittstelle, und seine externe Implementierung befindet sich im Abschnitt Durchführung dieses Modul. Listing 2 zeigt den vollständigen Code für das Bibliotheksimportmodul ..

Listing 2. Importmodul der FirstLib.dll-Bibliothek.

Einheit FirstLibInf; Schnittstellenfunktion Max3(Num1, Num2, Num3: Integer): Integer; stdcall; Implementierung const FirstLib = "FirstLib.dll";

(Der Compiler wird darüber informiert, dass sich die Implementierung der Max3-Funktion in der FirstLib.dll-Bibliothek befindet) function Max3; externe FirstLib; Ende. Nachdem Sie die DLL und ihren Importer erstellt haben, testen Sie die DLL, um sicherzugehen. dass die Routine gut funktioniert. Da Sie die DLL selbst nicht ausführen können, müssen Sie eine Testanwendung erstellen, die auf die DLL zugreift. Der schnellste Weg, dies zu tun, besteht darin, durch Hinzufügen eine Projektgruppe zu erstellen neues Projekt zum aktuellen Projekt. Dazu müssen Sie mit der rechten Maustaste auf das Element klicken Projektgruppe1 im Fenster Projektmanager(Projektbrowser) und wählen Sie in aus Kontextmenü Team

Neues Projekt hinzufügen

, wie in Abb. 1.

Listing 3. Testen der aus FirstLib.dll importierten Max3-Routine.

Einheit Einheit1; Schnittstelle verwendet Windows, Nachrichten, SysUtils, Varianten, Klassen, Grafiken, Steuerelemente, Formulare, Dialoge, FirstLibInf, StdCtrls; type TMainForm = class(TForm) Edit1: TEdit;

Edit2: TEdit; Edit3: TEdit;. Tatsächlich ist es ein recht praktisches Werkzeug, zumal die Bibliothek, sobald sie geschrieben ist, in vielen Programmen verwendet werden kann. In der heutigen Lektion lernen wir, wie man mit DLLs arbeitet und diese natürlich erstellt!

Nun, fangen wir an!

Lassen Sie uns zunächst unsere erste Dynamic Link Library erstellen! Wir gehen zu Delphi und gehen sofort zum Menü Datei -> Neu -> Andere.

Wählen Sie Dynamic-Link Library aus der Liste aus (in Versionen vor Delphi 2009 heißt das Element DLL-Assistent).

Daher haben wir nur ein Fenster mit dem Code; beachten Sie, dass wir hier kein Formular haben!

Jetzt beginnt der Spaß. Schreiben wir unsere ersten Prozeduren in die Bibliothek.

BibliothekProjekt2; //Sie haben wahrscheinlich bereits bemerkt, dass beim Erstellen einer DLL anstelle von Programm // das Wort Bibliothek verwendet wird.//Bedeutungsbibliothek.

verwendet SysUtils, Dialoge, Klassen; // Aufmerksamkeit! Vergessen Sie nicht, diese Module anzugeben, sonst funktioniert der Code nicht ($R *.res) (DIESER TEIL IST DER DLL-CODE) Prozedur FirstCall; stdcall; Export; //Stdcall – Mit diesem Operator werden die Parameter //von rechts nach links auf den Stapel gelegt und am Standardwert ausgerichtet //Export kann grundsätzlich weggelassen werden; er dient der Verdeutlichung //des Exports von a Verfahren oder Funktion. Begin ShowMessage("Meine erste Prozedur in der DLL");//Eine Nachricht auf dem Bildschirm aufrufen End;

Prozedur DoubleCall; stdcall; Export;

Begin ShowMessage("Mein zweiter Vorgang");

//Eine Nachricht auf dem Bildschirm aufrufen End;

Exportiert FirstCall, DoubleCall;

//Exports enthält eine Liste der exportierten Elemente.

//Was später von einem Programm importiert wird.

Schreiben Sie nach dem Implementierungsschlüsselwort den folgenden Code:

Hier teilen wir dem Programm, wie Sie wahrscheinlich bereits vermutet haben, die Namen unserer Prozeduren mit und sagen, dass sie sich in einer DLL-Bibliothek befinden, in meinem Fall mit dem Namen Project2.dll

Um diese Prozeduren nun aufzurufen, müssen wir nur noch ihre Namen an einer beliebigen Stelle im Code einfügen, was wir jetzt tun werden. Legen Sie zwei Schaltflächenkomponenten aus der Registerkarte „Standard“ auf dem Formular ab und erstellen Sie für jede einen OnClick-Ereignishandler

Beim Klicken auf die erste Schaltfläche:

Klicken Sie auf die zweite Schaltfläche:

Das ist es!

Methode Nummer 2:

Komplexer als das erste, aber es hat seine Vorteile und ist vor allem ideal für Plugins.

Um diese Methode anzuwenden, deklarieren wir zunächst mehrere globale Variablen:

Dann schreiben wir nach dem Implementierungsschlüsselwort eine Prozedur, die unsere Bibliothek lädt:

Prozedur LoadMyLibrary(FileName: String); Beginnen LibHandle:= LoadLibrary(PWideChar(FileName));//Die Bibliothek wird geladen! // Aufmerksamkeit! PChar für Versionen unter 2009 Delphi Wenn LibHandle = 0, dann begin MessageBox(0," Bibliothek kann nicht geladen werden",0,0); Ausfahrt; Ende; FirstCall:= GetProcAddress(LibHandle,"FirstCall"); //Zeiger auf das Objekt abrufen //1. Parameter-Link zum Bibliotheksmodul //2. Parametername des Objekts in der DLL DoubleCall:= GetProcAddress(LibHandle,"DoubleCall"); Wenn @FirstCall = Null, dann beginnen//Überprüfen Sie, ob diese Funktion in der Bibliothek vorhanden ist.

MessageBox(0,"Bibliothek konnte nicht geladen werden",0,0);

Ausfahrt; Ende; Beginnen Wenn @DoubleCall = Null, dann beginnen//Überprüfen Sie, ob diese Funktion in der Bibliothek vorhanden ist.

MessageBox(0,"Bibliothek konnte nicht geladen werden",0,0);

Beim Klicken auf die erste Schaltfläche:

Ausfahrt; Ende; Ende Anschließend erstellen wir auf dem Formular einen OnCreate-Ereignishandler, in den wir mithilfe der soeben erstellten Prozedur unsere Bibliothek laden

Klicken Sie auf die zweite Schaltfläche:

Prozedur TForm1.FormCreate(Sender: TObject); LoadMyLibrary("Project2.dll");

Ende;

Das ist es! Die zweite Methode erwies sich als recht umständlich, ihr Vorteil besteht jedoch darin, das in der Bibliothek gespeicherte Objekt zu verdeutlichen.



Einführung

Aufgrund der rasanten Entwicklung der Programmiertechnologien stehen immer mehr Menschen vor dem Problem, die Leistungsfähigkeit ihrer Programme zu steigern. Dieser Artikel widmet sich genau diesem Thema, nämlich der DLL-Programmierung in Borland Delphi. Da wir außerdem auf Fragen im Zusammenhang mit der Verwendung von DLLs eingehen, werden wir auch auf den Import von Funktionen aus fremden DLLs (einschließlich System-DLLs, d. h. WinAPI) eingehen.

DLL-Anwendungsbereiche

Warum werden DLLs benötigt und wo werden sie verwendet? Lassen Sie uns nur einige ihrer Anwendungsbereiche auflisten:

Separate Bibliotheken enthalten nützliche Inhalte für Programmierer zusätzliche Funktionen. Zum Beispiel Funktionen zum Arbeiten mit Strings oder komplexe Bibliotheken zum Konvertieren von Bildern. Ressourcenspeicher-DLLs können nicht nur Programme und Funktionen, sondern auch alle Arten von Ressourcen speichern – Symbole, Bilder, String-Arrays, Menüs usw. Zu den unterstützenden Bibliotheken gehören beispielsweise Bibliotheken bekannter Pakete wie DirectX, ICQAPI (API für ICQ), OpenGL usw.

Teile eines Programms Beispielsweise können Programmfenster (Formulare) usw. in einer DLL gespeichert werden.

Plugins Hier liegt der wahre Spielraum für die Gedanken eines Programmierers! Plugins sind Ergänzungen zu einem Programm, die dessen Fähigkeiten erweitern. In diesem Artikel werden wir uns beispielsweise mit der Theorie befassen, die hinter der Erstellung eines Plugins steckt

eigenes Programm

.


FunctionName (oder ProcedureName) der Name der Funktion (oder Prozedur), die in Ihrem Programm verwendet wird;

Par1, Par2, ... Namen von Funktions- oder Prozedurparametern; Par1Type, Par2Type, ... Typen von Funktions- oder Prozedurparametern (z. B. Integer); ReturnType-Rückgabetyp (nur Funktion);

stdcall-Direktive, die genau mit der in der DLL selbst verwendeten übereinstimmen muss;

externe „DLLNAME.DLL“-Direktive, die den Namen der externen DLL angibt, aus der diese Funktion oder Prozedur importiert wird (in diesem Fall - DLLNAME.DLL);

name „FunctionName“ („ProcedureName“)-Direktive, die den genauen Namen der Funktion in der DLL selbst angibt. Dies ist eine optionale Direktive, die es ermöglicht, eine Funktion in einem Programm zu verwenden, das einen anderen als den wahren Namen (den es in der Bibliothek hat) hat;

index FunctionIndex (ProcedureIndex)-Direktive, die die Indexnummer einer Funktion oder Prozedur in einer DLL angibt. Dies ist ebenfalls eine optionale Anweisung.


Dies ist eine deutlich aufwändigere, aber auch elegantere Methode. Der Nachteil der ersten Methode besteht nicht. Das einzig Unangenehme ist die Menge an Code, die zur Implementierung dieser Technik erforderlich ist, und die Schwierigkeit besteht darin, dass auf die aus der DLL importierte Funktion nur zugegriffen werden kann, wenn diese DLL geladen und im Speicher ist ... Ein Beispiel finden Sie unten, aber vorerst -


kurze Beschreibung

Sie sollten auf die Verwendung des String-Typs in Bibliotheksfunktionen verzichten, weil Bei der Verwendung gibt es Probleme mit der „Speicherfreigabe“. Mehr dazu können Sie (allerdings auf Englisch) im Text des leeren DLL-Projekts lesen, das Delphi erstellt (Datei -> Neu -> DLL). Daher ist es besser, PChar zu verwenden und es dann bei Bedarf mit der StrPas-Funktion in einen String zu konvertieren.

Schauen wir uns nun die DLL selbst an:

Beispiel 3. Quelle des Projekts MYDLL.DPR


Platzieren von Ressourcen und Formularen in DLLs

Eine DLL kann nicht nur Funktionen, sondern auch Cursor, Bilder, Symbole, Menüs usw. enthalten. Textzeichenfolgen. Wir werden hierauf nicht näher eingehen. Ich möchte nur darauf hinweisen, dass Sie zum Laden einer Ressource die DLL laden und dann, nachdem Sie ihren Deskriptor erhalten haben, die Ressource selbst mit der entsprechenden Funktion (LoadIcon, LoadCursor usw.) laden müssen. In diesem Abschnitt gehen wir nur kurz auf die Platzierung von Anwendungsfenstern (also Formularen in Delphi) in DLLs ein.

Dazu müssen Sie eine neue DLL erstellen und ihr ein neues Formular hinzufügen (Datei -> Neu -> DLL und dann Datei -> Neues Formular). Wenn es sich bei dem Formular um ein Dialogfeld handelt (modales Formular (bsDialog)), fügen Sie der DLL die folgende Funktion hinzu (sagen wir, das Formular heißt Form1 und seine Klasse ist TForm1):

Beispiel 4: Platzieren eines Formulars in einer DLL


Wenn Sie ein nichtmodales Formular in einer DLL platzieren müssen, müssen Sie zwei Funktionen erstellen – das Öffnen und Schließen des Formulars. In diesem Fall müssen Sie die DLL zwingen, sich das Handle für dieses Formular zu merken.

Plugins erstellen

Auf Plugins gehen wir hier nicht im Detail ein, weil... Die oben bereits aufgeführten Beispiele werden Ihnen helfen, den größten Teil der DLL-Programmierung leicht zu verstehen. Ich möchte Sie nur daran erinnern, dass ein Plugin eine Ergänzung zum Programm ist, die dessen Fähigkeiten erweitert. Gleichzeitig muss das Programm selbst für das Vorhandensein solcher Ergänzungen sorgen und ihnen ermöglichen, ihren Zweck zu erfüllen.

Das heißt zum Beispiel, ein Plugin dafür zu erstellen Grafikeditor Um eine Bildkonvertierung durchzuführen, müssen Sie im Plugin mindestens zwei Funktionen bereitstellen (und diese Funktionen dementsprechend im Programm aufrufen) – eine Funktion, die den Namen des Plugins (und/oder seinen Typ) zurückgibt Fügen Sie dieses Plugin zum Menü (oder in der Symbolleiste) hinzu Hauptfunktion- Bildübertragung und -empfang. Diese. Zuerst sucht das Programm nach Plugins, dann ruft es für jedes gefundene Plugin seine Identifikationsfunktion mit einem genau definierten Namen auf (z. B. GetPluginName) und fügt das gewünschte Element zum Menü hinzu. Wenn der Benutzer dieses Element ausgewählt hat, ruft es dann das auf zweite Funktion, die das Eingabebild (oder den Dateinamen, der dieses Bild enthält) übergibt, und diese Funktion wiederum verarbeitet das Bild und gibt es in einer neuen Form zurück (oder den Dateinamen mit einem neuen Bild). Das ist die Essenz des Plugins... :-)

Epilog

Dieser Artikel zeigt die Grundlagen der Verwendung und Erstellung von DLLs in Borland Delphi. Wenn Sie Fragen haben, senden Sie mir diese per E-Mail:

Aufgrund der rasanten Entwicklung der Programmiertechnologien stehen immer mehr Menschen vor dem Problem, die Leistungsfähigkeit ihrer Programme zu steigern. Dieser Artikel widmet sich genau diesem Thema, nämlich der DLL-Programmierung in Borland Delphi. Da wir außerdem auf Fragen im Zusammenhang mit der Verwendung von DLLs eingehen, werden wir auch auf den Import von Funktionen aus fremden DLLs (einschließlich System-DLLs, d. h. WinAPI) eingehen.

DLL-Anwendungsbereiche

Warum werden DLLs benötigt und wo werden sie verwendet? Lassen Sie uns nur einige ihrer Anwendungsbereiche auflisten:
  • Einzelne Bibliotheken, enthält zusätzliche Funktionen, die für Programmierer nützlich sind. Zum Beispiel Funktionen zum Arbeiten mit Strings oder komplexe Bibliotheken zum Konvertieren von Bildern.
  • Ressourcenspeicher. Eine DLL kann nicht nur Programme und Funktionen, sondern auch alle Arten von Ressourcen speichern – Symbole, Bilder, String-Arrays, Menüs usw.
  • Unterstützen Sie Bibliotheken. Als Beispiel können wir Bibliotheken so bekannter Pakete nennen wie: DirectX, ICQAPI(API für ICQ), OpenGL usw.
  • Teile des Programms. Sie können beispielsweise Programmfenster (Formulare) usw. in einer DLL speichern.
  • Plugins(Plugins). - Hier liegt der wahre Spielraum für die Gedanken eines Programmierers! Plugins sind Ergänzungen zu einem Programm, die dessen Fähigkeiten erweitern. In diesem Artikel werden wir uns beispielsweise mit der Theorie der Erstellung eines Plugins für Ihr eigenes Programm befassen.
  • Geteilte Ressource. DLL ( Dynamic Link Library) kann von mehreren Programmen oder Prozessen gleichzeitig verwendet werden (sog. Teilen- gemeinsam genutzte Ressource)

Kurze Beschreibung der Funktionen und Techniken für die Arbeit mit DLLs

Welche Techniken und Funktionen müssen Sie also verwenden, um mit DLLs zu arbeiten? Schauen wir uns zwei Methoden zum Importieren von Funktionen aus einer Bibliothek an:

1 Weg. Binden einer DLL an ein Programm. Dies ist die einfachste und einfachste Methode zur Verwendung von aus einer DLL importierten Funktionen. Allerdings (und das sollte beachtet werden) hat diese Methode einen sehr erheblichen Nachteil: Wenn die Bibliothek, die das Programm verwendet, nicht gefunden wird, startet das Programm einfach nicht, gibt einen Fehler aus und meldet, dass die DLL-Ressource nicht gefunden wurde. Und die Bibliothek wird durchsucht: im aktuellen Verzeichnis, im Programmverzeichnis, im WINDOWS\SYSTEM-Verzeichnis usw.
Also zunächst die allgemeine Form dieser Technik:

Durchführung
...
Funktion FunctionName(Par1: Par1Type; Par2: Par2Type; ...): ReturnType; stdcall; Statisches Laden ist die einfachste der beiden Möglichkeiten, eine DLL zu laden. Statisches Laden wird auch als dynamische Verbindung beim Booten bezeichnet („DLLNAME.DLL“ wenn Num2 > Ergebnis, dann Ergebnis:= Num2;„Funktionsname“ Wenn Sie der Liste eine Routine hinzufügen FuncIndex;
// oder (wenn keine Funktion, sondern eine Prozedur):
Verfahren Prozedurname(Par1: Par1Typ; Par2: Par2Typ; ...); stdcall; Statisches Laden ist die einfachste der beiden Möglichkeiten, eine DLL zu laden. Statisches Laden wird auch als dynamische Verbindung beim Booten bezeichnet („DLLNAME.DLL“ wenn Num2 > Ergebnis, dann Ergebnis:= Num2;„Prozedurname“ Wenn Sie der Liste eine Routine hinzufügen ProcIndex;

Hier: Funktionsname(oder Prozedurname) – der Name der Funktion (oder Prozedur), die in Ihrem Programm verwendet wird;
Par1, Par2, ...- Namen von Funktions- oder Prozedurparametern;
Par1Typ, Par2Typ, ...- Arten von Funktions- oder Prozedurparametern (z. B. Ganze Zahl);
Rückgabetyp- Rückgabewerttyp (nur für Funktion);
stdcall– eine Anweisung, die genau mit der in der DLL selbst verwendeten Anweisung übereinstimmen muss;
extern „DLLNAME.DLL“- eine Direktive, die den Namen der externen DLL angibt, aus der die angegebene Funktion oder Prozedur importiert wird (in diesem Fall - DLLNAME.DLL);
Name „FunctionName“ („ProcedureName“)– eine Anweisung, die den genauen Namen der Funktion in der DLL selbst angibt. Dies ist eine optionale Direktive, die es ermöglicht, eine Funktion in einem Programm zu verwenden, das einen anderen als den wahren Namen (den es in der Bibliothek hat) hat;
index FunctionIndex(ProcedureIndex)– eine Anweisung, die die Sequenznummer einer Funktion oder Prozedur in einer DLL angibt. Dies ist ebenfalls eine optionale Anweisung.

Methode 2. Dynamisches Laden von DLLs. Dies ist eine deutlich aufwändigere, aber auch elegantere Methode. Der Nachteil der ersten Methode besteht nicht. Das Einzige, was unangenehm ist, ist die Menge an Code, die zur Implementierung dieser Technik erforderlich ist, und die Schwierigkeit besteht darin, dass auf die aus der DLL importierte Funktion nur zugegriffen werden kann, wenn diese DLL geladen ist und sich im Speicher befindet ... Sie können das folgende Beispiel sehen: Aber vorerst eine kurze Beschreibung der von dieser Methode verwendeten WinAPI-Funktionen:

LoadLibrary(LibFileName: PChar) – lädt die angegebene Bibliothek LibFileName in den Speicher. Bei erfolgreichem Abschluss gibt die Funktion ein Handle zurück ( THandle) DLL im Speicher.
GetProcAddress(Modul: THandle; ProcName: PChar) – liest die Adresse der exportierten Bibliotheksfunktion. Bei erfolgreichem Abschluss gibt die Funktion ein Handle zurück ( TFarProc) Funktionen in der geladenen DLL.
Kostenlose Bibliothek(LibModule: THandle) – macht das LibModule ungültig und gibt den damit verbundenen Speicher frei. Es ist zu beachten, dass nach dem Aufruf dieser Prozedur die Funktionen dieser Bibliothek nicht mehr zur Verfügung stehen.

Praxis und Beispiele


name „FunctionName“ („ProcedureName“)-Direktive, die den genauen Namen der Funktion in der DLL selbst angibt. Dies ist eine optionale Direktive, die es ermöglicht, eine Funktion in einem Programm zu verwenden, das einen anderen als den wahren Namen (den es in der Bibliothek hat) hat;

Dies ist eine deutlich aufwändigere, aber auch elegantere Methode. Der Nachteil der ersten Methode besteht nicht. Das einzig Unangenehme ist die Menge an Code, die zur Implementierung dieser Technik erforderlich ist, und die Schwierigkeit besteht darin, dass auf die aus der DLL importierte Funktion nur zugegriffen werden kann, wenn diese DLL geladen und im Speicher ist ... Ein Beispiel finden Sie unten, aber vorerst -

(...Hier geht es zum Dateiheader und zur Definition des Formulars TForm1 und seiner Instanz Form1)

var
Form1: TForm1;
GetSimpleText: Funktion(LangRus: Boolean): PChar;
LibHandle: THandle;

Prozedur Button1Click(Sender: TObject);
beginnen
(„Säubern“ der Funktionsadresse von „Schmutz“)
@GetSimpleText:= nil;
(Wir versuchen, die Bibliothek zu laden)
LibHandle:= LoadLibrary("MYDLL.DLL");
(Wenn alles in Ordnung ist)
Wenn LibHandle >= 32, dann beginnen
(...dann versuchen wir, die Adresse der Funktion in der Bibliothek zu bekommen)
@GetSimpleText:= GetProcAddress(LibHandle,"GetSimpleText");
(Wenn auch hier alles in Ordnung ist)
wenn @GetSimpleText<>dann null
(... dann rufen Sie diese Funktion auf und zeigen Sie das Ergebnis)
ShowMessage(StrPas(GetSimpleText(True)));
Ende;
(Und vergessen Sie nicht, Speicher freizugeben und die DLL zu entladen)
FreeLibrary(LibHandle);
Ende;

NOTIZ : Sie sollten den String-Typ nicht in Bibliotheksfunktionen verwenden, weil Bei der Verwendung gibt es Probleme mit der „Speicherfreigabe“. Mehr dazu können Sie (allerdings auf Englisch) im Text des leeren DLL-Projekts lesen, das Delphi erstellt (Datei -> Neu -> DLL). Daher ist es besser, PChar zu verwenden und es dann bei Bedarf mit der StrPas-Funktion in einen String zu konvertieren.

Schauen wir uns nun die DLL selbst an:

Platzieren von Ressourcen und Formularen in DLLs


Eine DLL kann nicht nur Funktionen, sondern auch Cursor, Bilder, Symbole, Menüs und Textzeichenfolgen enthalten. Wir werden hierauf nicht näher eingehen. Ich möchte nur darauf hinweisen, dass Sie zum Laden einer Ressource die DLL laden und dann, nachdem Sie ihren Deskriptor erhalten haben, die Ressource selbst mit der entsprechenden Funktion (LoadIcon, LoadCursor usw.) laden müssen. In diesem Abschnitt gehen wir nur kurz auf die Platzierung von Anwendungsfenstern (also Formularen in Delphi) in DLLs ein.

Dazu müssen Sie eine neue DLL erstellen und ihr ein neues Formular hinzufügen (Datei -> Neu -> DLL und dann Datei -> Neues Formular). Wenn es sich bei dem Formular um ein Dialogfeld handelt (modales Formular (bsDialog)), fügen Sie der DLL die folgende Funktion hinzu (sagen wir, das Formular heißt Form1 und seine Klasse ist TForm1):

Wenn Sie ein nichtmodales Formular in einer DLL platzieren müssen, müssen Sie zwei Funktionen erstellen – das Öffnen und Schließen des Formulars. In diesem Fall müssen Sie die DLL zwingen, sich das Handle für dieses Formular zu merken.

Plugins erstellen

Auf Plugins gehen wir hier nicht im Detail ein, weil... Die oben bereits aufgeführten Beispiele werden Ihnen helfen, den größten Teil der DLL-Programmierung leicht zu verstehen. Ich möchte Sie nur daran erinnern, dass ein Plugin eine Ergänzung zum Programm ist, die dessen Fähigkeiten erweitert. Gleichzeitig muss das Programm selbst für das Vorhandensein solcher Ergänzungen sorgen und ihnen ermöglichen, ihren Zweck zu erfüllen.

Das heißt, um beispielsweise ein Plugin für einen Grafikeditor zu erstellen, der die Bildkonvertierung durchführt, müssen Sie mindestens zwei Funktionen im Plugin bereitstellen (und diese Funktionen dementsprechend im Programm aufrufen) – eine Funktion, die das zurückgibt Name des Plugins (und/oder seines Typs), um dieses Plugin zum Menü (oder zur Symbolleiste) hinzuzufügen, plus die Hauptfunktion – Senden und Empfangen von Bildern. Diese. Zuerst sucht das Programm nach Plugins, dann ruft es für jedes gefundene Plugin seine Identifikationsfunktion mit einem genau definierten Namen auf (z. B. GetPluginName) und fügt das gewünschte Element zum Menü hinzu. Wenn der Benutzer dieses Element ausgewählt hat, ruft es dann das auf zweite Funktion, die das Eingabebild (oder den Dateinamen, der dieses Bild enthält) übergibt, und diese Funktion wiederum verarbeitet das Bild und gibt es in einer neuen Form zurück (oder den Dateinamen mit einem neuen Bild). Das ist die Essenz des Plugins... :-)

Mit einer DLL-Bibliothek können Sie wiederverwendbaren Code zu einem Ganzen kombinieren. Funktionen aus DLL-Bibliotheken können zur Laufzeit dynamisch verknüpft werden, im Gegensatz zu Funktionen aus Delphi-Paketen, die in der Kompilierungsphase der Anwendung statisch verknüpft werden.

Um eine DLL-Bibliothek zu erstellen, müssen Sie zunächst den Menübefehl Datei|Neu|Sonstiges ausführen und auf der Seite Neu des Dialogfelds Neues Element das Element DLL-Assistent auswählen.

Der DLL-Assistent erstellt automatisch eine leere Vorlage für die DLL. Im Gegensatz zu einem regulären Modul, das mit dem Schlüsselwort „unit“ beginnt, beginnt ein DLL-Bibliotheksmodul mit dem Schlüsselwort „library“. Der Abschnitt „uses“ des DLL-Moduls erfordert die Einbindung von nur zwei Paketen: SysUtils und Classes.

Das Erstellen einer DLL-Funktion besteht aus mehreren Schritten:

1. Zunächst müssen Sie im Abschnitt „Modulimplementierung“ die Funktionssignatur eingeben und den Code programmieren, den die Funktion ausführt.

3. Schließlich sollte eine Funktion, die nicht nur innerhalb eines Moduls verwendet werden soll, sondern auch von anderen Anwendungen aufgerufen werden soll, im Abschnitt „Exports“ als exportierbar deklariert werden.

Funktionen aus einer DLL können sowohl von in Delphi entwickelten Anwendungen als auch von in anderen Programmiersprachen wie C++ geschriebenen Anwendungen aufgerufen werden.

Die Reihenfolge, in der Speicher für Parameter zugewiesen und freigegeben wird, ist unterschiedlich verschiedene Sprachen Programmierung. Um einen Laufzeitfehler zu vermeiden, müssen die Funktionsdeklaration in der DLL und die Funktionsdeklaration in der Anwendung denselben Parameterübergabemechanismus verwenden. Bei der Deklaration einer Prozedur oder Funktion kann einer der folgenden Mechanismen zur Parameterübergabe angegeben werden:

Die Art der Parameterübergabe wird durch ein Semikolon nach der Funktionsbeschreibung angegeben. Zum Beispiel:

Funktion F1 (X, Y, Z: Real]: Real; stdcall;.

Verschiedene Möglichkeiten Parameterübergaben definieren die Reihenfolge, in der Parameter übergeben werden (von links nach rechts oder von rechts nach links) und geben außerdem an, wer den Stapelspeicher freigibt (die aufgerufene Prozedur oder die aufrufende Prozedur). Wenn Sie DLLs als Komponenten verwenden, die von Anwendungen in anderen Programmiersprachen aufgerufen werden, sollten Sie den entsprechenden Aufrufmodifikator verwenden. Für C++-Anwendungen wird der Aufrufmodifikator stdcall verwendet.

Damit eine in einer DLL beschriebene Funktion von einer anderen Anwendung aufgerufen werden kann, muss die Funktion exportiert werden. Die Liste aller exportierten Funktionen wird im Abschnitt „Exporte“ durch Kommas getrennt angezeigt

und endet mit einem Semikolon. Das Exportieren von Funktionen kann auf drei Arten erfolgen:

Nach dem in der DLL verwendeten Funktionsnamen;

Durch den als Exportnamen angegebenen Funktionsnamen;

Durch den der Funktion zugewiesenen Index.

Um einer Funktion einen bestimmten Index zuzuweisen, sollte dieser im Exports-Abschnitt hinter dem Funktionsnamen mit angegeben werden Stichwort Index.

Damit die exportierte Funktion unter einem anderen Namen als dem in der DLL-Bibliothek verwendeten Namen aufgerufen werden kann, müssen Sie im Exportabschnitt nach dem Funktionsnamen den Schlüsselwortnamen und den neuen Exportnamen für diese Funktion angeben.

DLL – die Bibliothek ist kein ausführbares Modul. Um den Code zu erhalten, reicht es aus, das Projekt zu kompilieren.

Bibliotheksprojekt;

SysUtils, Klassen;

Funktion F1(X, Y: Ganzzahl): Ganzzahl; stdcall;

Statisches Verknüpfen einer DLL-Bibliothek

Die DLL kann entweder statisch oder dynamisch verknüpft werden. Wenn Sie eine DLL einbinden, wird diese in den Anwendungsspeicher geladen.

Bei einer statischen Verbindung wird die DLL einmalig beim Start der Anwendung geladen. Während der gesamten Ausführung der Anwendung verweist der Name einer aus einer statisch verknüpften DLL importierten Funktion auf dieselbe Funktion (den Einstiegspunkt zur DLL) in derselben DLL. Alle Funktionen aus der DLL, die zunächst in der Anwendung verwendet werden, müssen als extern deklariert werden. In diesem Fall sollten Sie ggf. einen Aufrufmodifikator angeben. Wird eine Funktion per Index aufgerufen, muss ihr der in der Anwendung verwendete Name und der Index der Funktion in der DLL mitgeteilt werden.

Anzeigen externe Funktionen werden im Implementierungsabschnitt ausgeführt, bevor diese Funktionen verwendet werden.

Erklärung von außen Funktionen mit dem Schlüsselwort external gibt an, dass statische Verlinkung verwendet wird.

TForml = Klasse(TForm)

Editl: TEdit; [Feld zur Eingabe des ersten Wertes)

Edit2: TEdit; (Feld zur Eingabe des zweiten Wertes)

Edit3: TEdit; (Feld zur Anzeige des Ergebnisses

eine Funktion aus einer DLL ausführen)

Buttonl: TButton; (Es erfolgt ein Aufruf der namentlich verwendeten Funktion)

Button2: TButton; [Ein Funktionsaufruf erfolgt über den Index)

procedure ButtonlClickfSender: TObject);

procedure Button2Click(Sender: TObject);

(Private Erklärungen)

(Öffentliche Erklärungen)

(Deklaration der exportierten Funktionen)

Funktion Fl (i: Ganzzahl; j: Ganzzahl): Ganzzahl; stdcall;

extern „Projectl.dll“;

Funktion F2 (i: Ganzzahl; j: Ganzzahl): Ganzzahl; stdcall;

extern „Projectl.dll Index 2;

procedure TForml.ButtonlClick(Sender: TObject);

(Exportierte Funktion aufrufen)

Edit3.Text:=IntToStr(Fl(StrToInt(Editl.Text),StrToInt(Edit2.Text) ));

procedure TForml.Button2Click(Sender: TObject);

Edit3.Text:=JntToStr(F2(StrToInt(Editl.Text),StrToInt(Edit2.Text)));

Dynamisches Verknüpfen einer DLL-Bibliothek

Im Gegensatz zum statischen Verknüpfen einer DLL, das beim Laden der Anwendung erfolgt, kann das dynamische Verknüpfen einer DLL zu jedem Zeitpunkt der Programmausführung erfolgen. Nachdem Sie eine Funktion aus einer DLL aufgerufen haben, können Sie sie deaktivieren. Bei gleichzeitiger Verwendung mehrerer DLLs führt dies zu erheblichen Speichereinsparungen. Windows-API-Funktionen werden verwendet, um eine DLL-Bibliothek dynamisch zu verbinden. Windows-API – Hierbei handelt es sich um eine Reihe von Standardfunktionen, die zur Implementierung der Interaktion mit dem Betriebssystem verwendet werden.

Wenn Sie eine Funktion aus einer dynamisch verknüpften DLL aufrufen, sollten Sie, anstatt den Funktionsnamen bei statischer Verknüpfung als extern zu definieren, einen neuen Typ definieren, der dem Typ der aufgerufenen Funktion entspricht, und eine Variable dieses Typs erstellen.

Gehen Sie folgendermaßen vor, um einen Funktionsaufruf von einer Dynamic-Link-DLL durchzuführen:

1. Erstellen Sie einen neuen Typ. entsprechend dem Typ der aufgerufenen Funktion (der Name des neuen Typs kann nach dem Typabschnitt eingegeben werden).

Zum Beispiel:

TMyFl=function(i,j:Integer):Integer; stdcall;

2. Erstellen Sie im Abschnitt „var“ des Abschnitts „interface“ des Moduls eine Variable des erstellten Funktionstyps. Zum Beispiel: MyFl: TMyFl;

3. Deklarieren Sie, bevor Sie die DLL laden Typvariable Ganzzahl, die den Deskriptor der zu verbindenden Bibliothek enthält.

4. Rufen Sie die LoadLibrary-Methode auf, die die DLL lädt. Zum Beispiel; h:=LoadLibrary("Projectl.dll");

5. Überprüfen Sie, ob die Bibliotheksverbindung erfolgreich ist. Wenn der DLL-Name falsch ist oder die DLL nicht gefunden wird, gibt die LoadLibrary-Funktion 0 zurück.

6. Wenn Sie die DLL-Bibliothek erfolgreich verbunden haben, müssen Sie als Nächstes die Funktionsadresse abrufen. Zu diesem Zweck wird es verwendet Windows-Funktion API GetProcAddress, deren Parameter der DLL-Bibliotheksdeskriptor und der Name der verbundenen Funktion sind. Zum Beispiel: @MyFl: =GetProcAddress(h, "Fl");

7. Wenn die Funktionsadresse empfangen wird, sollte der Wert der Adresse (in unserem Beispiel @MyFl) nicht gleich Null sein.

8. An dieser Stelle können Sie eine Funktion aus einer dynamisch verknüpften DLL aufrufen.

9. Um die DLL freizugeben und damit zu entladen, rufen Sie die FreeLibrary-Methode auf, die die DLL deaktiviert.

Windows, Nachrichten, SysUtils, Varianten, Klassen, Grafiken,

Steuerelemente, Formulare, Dialoge, StdCtrls;

TForml = Klasse(TForm)

Button3: TButton;

Verfahren Button3Click

procedure TForml.Button3Click(Sender: TObject);

h:=LoadLibrary("Projectl.dll");

wenn h<>0 dann

@MyFl:=GetProcAddress(h,"Fl");

wenn @MyFl<>dann null

Edit3.Text:=IntToStr(MyFl(StrToInt(Editl.Text),

StrToInt(Edit2.Text)));

Verwenden einer DLL zum Aufrufen allgemeiner modaler Dialoge.

Das Ergebnis der Ausführung einer Prozedur aus einer DLL-Bibliothek kann die Anzeige eines modalen Dialogs sein. Erstellen Sie dazu in der exportierten Methode ein Formularobjekt, zeigen Sie es als modalen Dialog an und löschen Sie dann das Formularobjekt. In diesem Fall sollte das Formular selbst einen Aufruf der Close-Methode bereitstellen, um den Dialog zu beenden.

Um ein Formular zu erstellen, verwenden Sie die Create-Methode, der als Parameter ein Zeiger auf das übergeordnete Formular – das Formular der aufrufenden Anwendung – übergeben wird. Dieser Parameter wird an die aufgerufene DLL-Funktion übergeben.

Bibliotheksprojekt;

Unitl_DLL in „Unitl_DLL.pas“ (Forml);

procedure MyModalForm (var Z:Integer ;F:TForm1); stdcall;

Form1:=TForml.Create(F);

(Der F-Parameter wird beim Aufruf der Prozedur übergeben und enthält einen Zeiger

zum übergeordneten Formular - dem Formular der aufrufenden Anwendung)