Esempi di creazione di dll Delphi complesse. Creazione di una libreria DLL in Delphi. Pratica ed esempi

Per creare nuova biblioteca DLL in Delphi, seleziona il comando di menu File > Nuovo > Altro. Nel pannello Categorie di articoli finestre Nuovi articoli seleziona nodo Progetti Delfi, quindi fare doppio clic sull'elemento Libreria a collegamento dinamico nel riquadro destro della finestra.

Maestro Procedura guidata DLL crea un file di codice sorgente DLL principale che sembra quasi esattamente uguale a codice sorgente, generato per un'applicazione regolare. L'unica differenza è. che questo file inizia con una parola riservata biblioteca , non.

programma Progetto Biblioteca1; (Nota importante sulla gestione della memoria DLL: ShareMem deve essere la prima unità nella clausola USES della libreria E nella clausola USES del progetto (seleziona Project-View Source) se la DLL esporta procedure o funzioni che passano stringhe come parametri o funzioni risultati. Ciò si applica a tutte le stringhe passate da e verso la DLL, anche quelle nidificate in record e classi. ShareMem è l'unità di interfaccia per il gestore della memoria condivisa BORLNDMM.DLL, che deve essere distribuito insieme alla DLL .DLL, passa informazioni sulla stringa utilizzando i parametri PChar o ShortString) ( Nota importante

Per quanto riguarda la gestione della memoria DLL: il modulo ShareMem deve essere il primo modulo nell'istruzione uses della tua libreria e nell'istruzione uses del tuo progetto (seleziona il comando di menu Progetto -> Visualizza sorgente) se la tua DLL esporta procedure o funzioni che passano stringhe come parametri o risultati di funzioni. Questo vale per tutte le stringhe passate o ricevute dalla DLL e anche per le stringhe annidate all'interno di record e classi. Il modulo ShareMem è un modulo di interfaccia per il gestore della memoria condivisa BORLNDMM.DLL che è necessario distribuire con la DLL. Per evitare di utilizzare BORLNDMM.DLL, passare le informazioni sulla stringa utilizzando i parametri PChar o ShortString. ) utilizza SysUtils, Classi; ($R *.res) inizio fine. Tutto quello che devi fare ora è aggiungere una subroutine prima del blocco, questo è tutto. Avrai quindi una routine interna che può essere utilizzata nella DLL, ma non in applicazioni esterne. Se vuoi richiamare la routine da altre applicazioni e da altre DLL, dovrai esportarla. Per esportare una routine per nome, aggiungila all'elenco esportazioni Se vuoi richiamare la routine da altre applicazioni e da altre DLL, dovrai esportarla. Per esportare una routine per nome, aggiungila all'elenco. Lista ha la stessa sintassi di list usi Se vuoi richiamare la routine da altre applicazioni e da altre DLL, dovrai esportarla. Per esportare una routine per nome, aggiungila all'elenco, tranne ciò che è nell'elenco

qualsiasi elemento è una subroutine, non un modulo. Se vuoi richiamare la routine da altre applicazioni e da altre DLL, dovrai esportarla. Per esportare una routine per nome, aggiungila all'elenco Lista Tutto quello che devi fare ora è aggiungere una subroutine prima del blocco solitamente posizionato immediatamente prima del blocco . Dai un'occhiata al Listato 1, che mostra il codice sorgente per una semplice libreria

FirstLib.dll

, esportando una funzione.

Listato 1. DLL semplice Se vuoi richiamare la routine da altre applicazioni e da altre DLL, dovrai esportarla. Per esportare una routine per nome, aggiungila all'elenco Biblioteca FirstLib; funzione Max3(Num1, Num2, Num3: Intero): Intero; chiamata standard; inizio Risultato:= Num1; se Num2 > Risultato allora Risultato:= Num2; se Num3 > Risultato allora Risultato:= Num3; FINE; ( Esportazione della funzione Max3 ) esporta Max3; inizio fine. Quando aggiungi una routine all'elenco, si esporta la subroutine con il suo nome. Puoi anche esportare la routine con un nome diverso utilizzando la direttiva Quando aggiungi una routine all'elenco nome

o tramite un valore ordinale utilizzando la direttiva

indice

. Applicare comunque la direttiva non raccomandato. Di seguito è riportato un esempio di esportazione di una direttiva utilizzando un valore ordinale o un altro nome:

Esporta il nome Max3 "MyMax3Function", indice SaySomething 1; Il caricamento statico è il più semplice dei due modi possibili per caricare una DLL. Il caricamento statico è anche chiamato connessione dinamica all'avvio ( collegamento dinamico in fase di caricamento

) perché le DLL utilizzate vengono caricate automaticamente all'avvio dell'applicazione. Il caricamento statico è il più semplice dei due modi possibili per caricare una DLL. Il caricamento statico è anche chiamato connessione dinamica all'avvio ( Per caricare staticamente una DLL, è necessario copiare la dichiarazione della routine e dell'applicazione chiamante e contrassegnarla con una direttiva esterno, che indica al compilatore che la routine si trova in un file oggetto o in una DLL. .:

Quando importi routine da una DLL, devi contrassegnarle con una direttiva

, seguito dal nome della DLL che contiene l'implementazione della routine. Di seguito è riportato un esempio di importazione di una funzione se Num2 > Risultato allora Risultato:= Num2;:

Funzione Max(Num1, Num2, Num3: Intero): Intero; chiamata standard; nome "FirstLib.dll" esterno "Max3";

Puoi anche importare una funzione da una DLL. Per fare ciò, è necessario creare un modulo di importazione e scrivere un'intestazione di subroutine standard nella sezione interfaccia e la sua implementazione esterna è nella sezione implementazione questo modulo. Il listato 2 mostra il codice completo per il modulo di importazione della libreria ..

Listato 2. Modulo di importazione della libreria FirstLib.dll.

Unità FirstLibInf; funzione interfaccia Max3(Num1, Num2, Num3: Intero): Intero; chiamata standard; implementazione const FirstLib = "FirstLib.dll";

(Il compilatore viene informato che l'implementazione della funzione Max3 è nella libreria FirstLib.dll) function Max3; FirstLib esterno; FINE. Dopo aver creato la DLL e il relativo importatore, testa la DLL per esserne sicuro. che la routine funziona bene. Poiché non è possibile eseguire la DLL stessa, è necessario creare un'applicazione di prova che acceda alla DLL. Il modo più veloce per farlo è creare un gruppo di progetto aggiungendo nuovo progetto al progetto attuale. Per fare ciò, è necessario fare clic con il tasto destro del mouse sull'elemento Gruppoprogetto1 nella finestra Responsabile del progetto(Browser del progetto) e selezionare menu contestuale squadra

Aggiungi nuovo progetto

, come mostrato in Fig. 1.

Listato 3. Test della routine Max3 importata da FirstLib.dll.

Unità Unità1; l'interfaccia utilizza Windows, Messaggi, SysUtils, Varianti, Classi, Grafica, Controlli, Moduli, Finestre di dialogo, FirstLibInf, StdCtrls; digitare TMainForm = class(TForm) Modifica1: TModifica;

Modifica2: TModifica; Modifica3: TModifica;. In effetti, è uno strumento abbastanza comodo, soprattutto perché la libreria, una volta scritta, può essere utilizzata in molti programmi. Nella lezione di oggi impareremo come lavorare con le dll e ovviamente crearle!

Bene, cominciamo!

Innanzitutto, creiamo la nostra prima libreria di collegamenti dinamici! Andiamo su Delphi e andiamo subito nel menu File -> Nuovo -> Altro.

Seleziona Dynamic-Link Library dall'elenco (nelle versioni precedenti a Delphi 2009, l'elemento si chiama DLL Wizard).

Di conseguenza, abbiamo solo una finestra con il codice; nota che qui non abbiamo alcun modulo!

Ora inizia il divertimento. Scriviamo le nostre prime procedure nella libreria.

libreriaProgetto2; //Probabilmente hai già notato che invece di programma //durante la creazione di una DLL, viene utilizzata la parola libreria.//Libreria di significati.

utilizza SysUtils, finestre di dialogo, Classi; // Attenzione! Non dimenticare di specificare questi moduli, altrimenti il ​​codice non funzionerà ($R *.res) (QUESTA PARTE È IL CODICE DLL) Procedura FirstCall; chiamata standard; esportare; //Stdcall – Con questo operatore i parametri vengono messi nello stack //da destra a sinistra e allineati al valore standard //Export può, in linea di principio, essere omesso, viene utilizzato per chiarire //l'esportazione di a procedura o funzione. Begin ShowMessage("La mia prima procedura in dll");//Richiama un messaggio sullo schermo Fine;

Procedura DoubleCall; chiamata standard; esportare;

Inizia ShowMessage("La mia seconda procedura");

//Richiama un messaggio sullo schermo Fine;

Esporta FirstCall, DoubleCall;

//Exports contiene un elenco di elementi esportati.

//Che verrà successivamente importato da qualche programma.

Dopo la parola chiave di implementazione, scrivi il seguente codice:

Qui, come probabilmente hai già intuito, diciamo al programma i nomi delle nostre procedure e diciamo che si trovano in una libreria dll, nel mio caso denominata Project2.dll

Adesso, per richiamare queste procedure, dobbiamo solo inserire i loro nomi in un punto qualsiasi del codice, cosa che faremo ora. Rilascia due componenti pulsante dalla scheda Standard nel modulo e crea un gestore eventi OnClick su ciascuno

OnClick del primo pulsante:

OnClick il secondo pulsante:

Questo è tutto!

Metodo numero 2:

Più complesso del primo, ma ha i suoi vantaggi e, soprattutto, è ideale per i plugin.

Per applicare questo metodo, prima di tutto dichiariamo diverse variabili globali:

Quindi, dopo la parola chiave di implementazione, scriveremo una procedura che caricherà la nostra libreria:

Procedura LoadMyLibrary(FileName: String); Inizio LibHandle:= CaricaLibreria(PWideChar(NomeFile));//Carico la libreria! // Attenzione! PChar per le versioni precedenti alla 2009 Delphi Se LibHandle = 0 inizia MessageBox(0," Impossibile caricare la libreria",0,0); Uscita; FINE; PrimaCall:= GetProcAddress(LibHandle,"FirstCall"); //Ottiene un puntatore all'oggetto //1° collegamento del parametro al modulo della libreria //2° nome del parametro dell'oggetto nella dll DoubleCall:= GetProcAddress(LibHandle,"DoubleCall"); Se @FirstCall = nil allora inizia//Verifica la presenza di questa funzione nella libreria.

MessageBox(0,"Impossibile caricare la libreria",0,0);

Uscita; FINE; Inizio Se @DoubleCall = nil inizia//Verifica la presenza di questa funzione nella libreria.

MessageBox(0,"Impossibile caricare la libreria",0,0);

OnClick del primo pulsante:

Uscita; FINE; FINE Creiamo poi sul form un gestore di eventi OnCreate, nel quale, tramite la procedura appena creata, caricheremo la nostra libreria

OnClick il secondo pulsante:

Procedura TForm1.FormCreate(Sender: TObject); LoadMyLibrary("Progetto2.dll");

FINE;

Questo è tutto! Il secondo metodo si è rivelato piuttosto macchinoso, ma il suo vantaggio è quello di chiarire l'oggetto memorizzato nella libreria.



Introduzione

A causa del rapido sviluppo delle tecnologie di programmazione, sempre più persone si trovano ad affrontare il problema di aumentare le capacità dei propri programmi. Questo articolo è dedicato proprio a questo problema, ovvero alla programmazione DLL in Borland Delphi. Inoltre, poiché toccheremo questioni relative all'utilizzo delle DLL, toccheremo anche le funzioni di importazione da DLL esterne (comprese quelle di sistema, ovvero WinAPI).

Aree di applicazione DLL

Allora, perché sono necessarie le DLL e dove vengono utilizzate?... Elenchiamo solo alcune delle aree di applicazione:

Librerie separate Contengono utili per i programmatori funzionalità aggiuntive. Ad esempio, funzioni per lavorare con stringhe o librerie complesse per convertire immagini. Archiviazione di risorse Le DLL possono archiviare non solo programmi e funzioni, ma anche tutti i tipi di risorse: icone, immagini, array di stringhe, menu, ecc. Librerie di supporto Gli esempi includono librerie di pacchetti noti come: DirectX, ICQAPI (API per ICQ), OpenGL, ecc.

Parti di un programma Ad esempio, le finestre del programma (moduli), ecc. possono essere memorizzate in una DLL.

Plugin Qui è dove si trova il vero spazio per i pensieri di un programmatore! I plugin sono aggiunte a un programma che ne espandono le capacità. Ad esempio, in questo articolo esamineremo la teoria alla base della creazione di un plugin per

proprio programma

.


FunctionName (o ProcedureName) il nome della funzione (o procedura) che verrà utilizzata nel programma;

Par1, Par2, ... nomi dei parametri di funzione o procedura; Par1Type, Par2Type, ... tipi di parametri di funzione o procedura (ad esempio Integer); ReturnType tipo restituito (solo funzione);

direttiva stdcall, che deve corrispondere esattamente a quella utilizzata nella DLL stessa;

direttiva esterna "DLLNAME.DLL" che indica il nome della DLL esterna da cui verrà importata questa funzione o procedura (in questo caso - DLLNAME.DLL);

name Direttiva "FunctionName" ("ProcedureName") specificando il nome esatto della funzione nella DLL stessa. Questa è una direttiva opzionale che permette di utilizzare una funzione in un programma che ha un nome diverso da quello vero (che ha nella libreria);

indice FunctionIndex (ProcedureIndex) direttiva che indica il numero di indice di una funzione o procedura in una DLL. Anche questa è una direttiva facoltativa.


Questo è un metodo molto più complesso, ma anche più elegante. Non presenta lo svantaggio del primo metodo. L'unica cosa spiacevole è la quantità di codice necessaria per implementare questa tecnica, e la difficoltà è che la funzione importata dalla DLL è accessibile solo quando questa DLL è caricata e in memoria... Un esempio lo trovate qui sotto, ma per ora -


breve descrizione

Dovresti astenervi dall'utilizzare il tipo stringa nelle funzioni di libreria perché Ci sono problemi con la "condivisione della memoria" durante l'utilizzo. Puoi leggere di più a riguardo (anche se in inglese) nel testo del progetto DLL vuoto creato da Delphi (File -> Nuovo -> DLL). Quindi è meglio usare PChar e poi convertirlo in stringa usando la funzione StrPas, se necessario.

Bene, ora diamo un'occhiata alla DLL stessa:

Esempio 3. Origine del progetto MYDLL.DPR


Inserimento di risorse e moduli nelle DLL

Una DLL può contenere non solo funzioni, ma anche cursori, immagini, icone, menu, stringhe di testo. Non ci soffermeremo su questo. Noterò solo che per caricare una risorsa è necessario caricare la DLL e poi, ricevuto il suo descrittore, caricare la risorsa stessa con l'apposita funzione (LoadIcon, LoadCursor, ecc.). In questa sezione, parleremo solo brevemente del posizionamento delle finestre delle applicazioni (ovvero dei moduli in Delphi) nelle DLL.

Per fare ciò, è necessario creare una nuova DLL e aggiungervi un nuovo modulo (File -> Nuovo -> DLL, quindi File -> Nuovo modulo). Successivamente, se il modulo è una finestra di dialogo (forma modale (bsDialog)), aggiungi la seguente funzione alla DLL (diciamo che il modulo si chiama Form1 e la sua classe è TForm1):

Esempio 4: inserimento di un modulo in una DLL


Se è necessario inserire un modulo non modale in una DLL, è necessario creare due funzioni: apertura e chiusura del modulo. In questo caso, devi forzare la DLL a ricordare l'handle di questo modulo.

Creazione di plugin

Qui non considereremo i plugin in dettaglio, perché... Gli esempi già forniti sopra ti aiuteranno a comprendere facilmente la parte del leone nella programmazione DLL. Lascia che ti ricordi solo che un plugin è un'aggiunta al programma che ne espande le capacità. Allo stesso tempo, il programma stesso deve prevedere la presenza di tali integrazioni e consentire loro di raggiungere il loro scopo.

Cioè, ad esempio, per creare un plugin per redattore grafico che effettuerebbe la conversione delle immagini, è necessario fornire almeno due funzioni nel plugin (e, di conseguenza, chiamare queste funzioni nel programma) - una funzione che restituisca il nome del plugin (e/o il suo tipo) per poter aggiungi questo plugin al menu (o nella barra degli strumenti), inoltre funzione principale- trasmissione e ricezione di immagini. Quelli. prima il programma cerca i plugin, poi per ognuno trovato chiama la sua funzione di identificazione con un nome rigorosamente definito (ad esempio, GetPluginName) e aggiunge la voce desiderata al menu, quindi, se l'utente ha selezionato questa voce, chiama la voce la seconda funzione, che passa l'immagine di input (o il nome del file, contenente questa immagine), e questa funzione, a sua volta, elabora l'immagine e la restituisce in una nuova forma (o il nome del file con una nuova immagine). Questa è l'essenza del plugin... :-)

Epilogo

Questo articolo mostra le nozioni di base sull'utilizzo e sulla creazione di DLL in Borland Delphi. Se avete domande, inviatemele via e-mail:

A causa del rapido sviluppo delle tecnologie di programmazione, sempre più persone si trovano ad affrontare il problema di aumentare le capacità dei propri programmi. Questo articolo è dedicato proprio a questo problema, ovvero alla programmazione DLL in Borland Delphi. Inoltre, poiché toccheremo questioni relative all'utilizzo delle DLL, toccheremo anche le funzioni di importazione da DLL esterne (comprese quelle di sistema, ovvero WinAPI).

Aree di applicazione DLL

Allora, perché sono necessarie le DLL e dove vengono utilizzate?... Elenchiamo solo alcune delle aree di applicazione:
  • Biblioteche individuali, contenente funzioni aggiuntive utili per i programmatori. Ad esempio, funzioni per lavorare con stringhe o librerie complesse per convertire immagini.
  • Stoccaggio delle risorse. Una DLL può memorizzare non solo programmi e funzioni, ma anche tutti i tipi di risorse: icone, immagini, array di stringhe, menu, ecc.
  • Sostieni le biblioteche. Ad esempio, possiamo citare librerie di pacchetti noti come: DirectX, ICQAPI(API per ICQ), OpenGL ecc.
  • Parti del programma. Ad esempio è possibile memorizzare finestre di programma (moduli), ecc. in una DLL.
  • Plugin(Plugin). - Qui è dove si trova il vero spazio per i pensieri di un programmatore! I plugin sono aggiunte a un programma che ne espandono le capacità. Ad esempio, in questo articolo esamineremo la teoria della creazione di un plugin per il tuo programma.
  • Risorsa condivisa. DLL ( Libreria di collegamento dinamico) può essere utilizzato da più programmi o processi contemporaneamente (i cosiddetti. condivisione- risorsa condivisa)

Breve descrizione delle funzioni e delle tecniche per lavorare con le DLL

Quindi, quali tecniche e funzioni devi utilizzare per lavorare con le DLL? Diamo un'occhiata a due metodi per importare funzioni da una libreria:

1 modo. Associazione di una DLL a un programma. Questo è il metodo più semplice e facile per utilizzare le funzioni importate da una DLL. Tuttavia (e questo va notato) questo metodo presenta uno svantaggio molto significativo: se la libreria utilizzata dal programma non viene trovata, il programma semplicemente non si avvierà, dando un errore e segnalando che la risorsa DLL non è stata trovata. E la libreria verrà cercata: nella directory corrente, nella directory del programma, nella directory WINDOWS\SYSTEM, ecc.
Quindi, in primo luogo, la forma generale di questa tecnica:

implementazione
...
funzione NomeFunzione(Par1: Tipo Par1; Par2: Tipo Par2; ...): TipoRitorno; stdcall; Il caricamento statico è il più semplice dei due modi possibili per caricare una DLL. Il caricamento statico è anche chiamato connessione dinamica all'avvio ("NOMEDLL.DLL" se Num2 > Risultato allora Risultato:= Num2;"NomeFunzione" Quando aggiungi una routine all'elenco FuncIndice;
// oppure (se non è una funzione, ma una procedura):
procedura NomeProcedura(Par1: Tipo Par1; Par2: Tipo Par2; ...); stdcall; Il caricamento statico è il più semplice dei due modi possibili per caricare una DLL. Il caricamento statico è anche chiamato connessione dinamica all'avvio ("NOMEDLL.DLL" se Num2 > Risultato allora Risultato:= Num2;"NomeProcedura" Quando aggiungi una routine all'elenco ProcIndice;

Qui: NomeFunzione(O Nomeprocedura) - il nome della funzione (o procedura) che verrà utilizzata nel programma;
Par1, Par2, ...- nomi di parametri di funzione o procedura;
Tipo Par1, Tipo Par2, ...- tipi di parametri di funzione o procedura (ad esempio, Intero);
ReturnType- tipo di valore restituito (solo per funzione);
stdcall- una direttiva che deve corrispondere esattamente a quella utilizzata nella DLL stessa;
"DLLNAME.DLL" esterno- una direttiva che indica il nome della DLL esterna da cui verrà importata la funzione o procedura data (in questo caso - NOMEDLL.DLL);
nome "NomeFunzione" ("NomeProcedura")- una direttiva che indica il nome esatto della funzione nella DLL stessa. Questa è una direttiva opzionale che permette di utilizzare una funzione in un programma che ha un nome diverso da quello vero (che ha nella libreria);
indice IndiceFunzione(IndiceProcedura)- una direttiva che indica il numero di sequenza di una funzione o procedura in una DLL. Anche questa è una direttiva facoltativa.

Metodo 2. Caricamento dinamico delle DLL. Questo è un metodo molto più complesso, ma anche più elegante. Non presenta lo svantaggio del primo metodo. L'unica cosa spiacevole è la quantità di codice necessaria per implementare questa tecnica, e la difficoltà è che la funzione importata dalla DLL è accessibile solo quando questa DLL è caricata ed è in memoria... Potete vedere l'esempio qui sotto, ma per ora - una breve descrizione delle funzioni WinAPI utilizzate da questo metodo:

Carica libreria(NomeFileLib: PCar) - carica in memoria la libreria specificata LibFileName. In caso di completamento positivo, la funzione restituisce un handle ( Maniglia)DLL in memoria.
OttieniIndirizzoProc(Modulo: Maniglia; NomeProc: PCar) - legge l'indirizzo della funzione di libreria esportata. In caso di completamento positivo, la funzione restituisce un handle ( TFarProc) funzioni nella DLL caricata.
Biblioteca gratuita(LibModulo: Maniglia) - invalida il LibModule e libera la memoria ad esso associata. È da notare che dopo aver richiamato questa procedura, le funzioni di questa libreria non sono più disponibili.

Pratica ed esempi


name Direttiva "FunctionName" ("ProcedureName") specificando il nome esatto della funzione nella DLL stessa. Questa è una direttiva opzionale che permette di utilizzare una funzione in un programma che ha un nome diverso da quello vero (che ha nella libreria);

Questo è un metodo molto più complesso, ma anche più elegante. Non presenta lo svantaggio del primo metodo. L'unica cosa spiacevole è la quantità di codice necessaria per implementare questa tecnica, e la difficoltà è che la funzione importata dalla DLL è accessibile solo quando questa DLL è caricata e in memoria... Un esempio lo trovate qui sotto, ma per ora -

(...Qui c'è l'intestazione del file e la definizione del modulo TForm1 e la sua istanza Form1)

var
Modulo1: TForm1;
GetSimpleText: funzione(LangRus: booleano): PChar;
LibHandle: THandle;

Procedura Pulsante1Click(Mittente: TObject);
inizio
(“Pulizia” l'indirizzo della funzione dallo “sporco”)
@GetSimpleText:= zero;
(Stiamo provando a caricare la libreria)
LibHandle:= CaricaLibreria("MYDLL.DLL");
(Se è tutto ok)
se LibHandle >= 32 allora inizia
(...quindi stiamo cercando di ottenere l'indirizzo della funzione nella libreria)
@GetSimpleText:= GetProcAddress(LibHandle,"GetSimpleText");
(Se anche qui va tutto bene)
se @GetSimpleText<>zero allora
(...quindi chiama questa funzione e mostra il risultato)
ShowMessage(StrPas(GetSimpleText(True)));
FINE;
(E non dimenticare di liberare memoria e scaricare DLL)
Libreria libera(LibHandle);
FINE;

NOTA : Dovresti astenervi dall'utilizzare il tipo stringa nelle funzioni di libreria perché Ci sono problemi con la "condivisione della memoria" durante l'utilizzo. Puoi leggere di più a riguardo (anche se in inglese) nel testo del progetto DLL vuoto creato da Delphi (File -> Nuovo -> DLL). Quindi è meglio usare PChar e poi convertirlo in stringa usando la funzione StrPas, se necessario.

Bene, ora diamo un'occhiata alla DLL stessa:

Inserimento di risorse e moduli nelle DLL


Una DLL può contenere non solo funzioni, ma anche cursori, immagini, icone, menu e stringhe di testo. Non ci soffermeremo su questo. Noterò solo che per caricare una risorsa è necessario caricare la DLL e poi, ricevuto il suo descrittore, caricare la risorsa stessa con l'apposita funzione (LoadIcon, LoadCursor, ecc.). In questa sezione, parleremo solo brevemente del posizionamento delle finestre delle applicazioni (ovvero dei moduli in Delphi) nelle DLL.

Per fare ciò, è necessario creare una nuova DLL e aggiungervi un nuovo modulo (File -> Nuovo -> DLL, quindi File -> Nuovo modulo). Successivamente, se il modulo è una finestra di dialogo (forma modale (bsDialog)), aggiungi la seguente funzione alla DLL (diciamo che il modulo si chiama Form1 e la sua classe è TForm1):

Se è necessario inserire un modulo non modale in una DLL, è necessario creare due funzioni: apertura e chiusura del modulo. In questo caso, devi forzare la DLL a ricordare l'handle di questo modulo.

Creazione di plugin

Qui non considereremo i plugin in dettaglio, perché... Gli esempi già forniti sopra ti aiuteranno a comprendere facilmente la parte del leone nella programmazione DLL. Lascia che ti ricordi solo che un plugin è un'aggiunta al programma che ne espande le capacità. Allo stesso tempo, il programma stesso deve prevedere la presenza di tali integrazioni e consentire loro di raggiungere il loro scopo.

Cioè, ad esempio, per creare un plugin per un editor grafico che esegua la conversione di immagini, è necessario fornire almeno due funzioni nel plugin (e, di conseguenza, chiamare queste funzioni nel programma) - una funzione che restituisca il nome del plugin (e/o il suo tipo) per aggiungere questo plugin al menu (o alla barra degli strumenti), oltre alla funzione principale: trasmettere e ricevere immagini. Quelli. prima il programma cerca i plugin, poi per ognuno trovato chiama la sua funzione di identificazione con un nome rigorosamente definito (ad esempio, GetPluginName) e aggiunge la voce desiderata al menu, quindi, se l'utente ha selezionato questa voce, chiama la voce la seconda funzione, che passa l'immagine di input (o il nome del file, contenente questa immagine), e questa funzione, a sua volta, elabora l'immagine e la restituisce in una nuova forma (o il nome del file con una nuova immagine). Questa è l'essenza del plugin... :-)

Una libreria DLL consente di combinare codice riutilizzabile in un unico insieme. Le funzioni delle librerie DLL possono essere collegate dinamicamente in fase di runtime, a differenza delle funzioni dei pacchetti Delphi, che sono collegate staticamente nella fase di compilazione dell'applicazione.

Per creare una libreria DLL, devi prima eseguire il comando di menu File|Nuovo|Altro e selezionare l'elemento Creazione guidata DLL nella pagina Nuovo della finestra di dialogo Nuovo elemento.

La procedura guidata DLL creerà automaticamente un modello vuoto per la DLL. A differenza di un modulo normale, che inizia con la parola chiave unit, un modulo di libreria DLL inizia con la parola chiave Library. La sezione uses del modulo DLL richiede l'inclusione di soli due pacchetti: SysUtils e Classes.

La creazione di una funzione DLL consiste in diversi passaggi:

1. Innanzitutto, nella sezione di implementazione del modulo, è necessario inserire la firma della funzione e programmare il codice che la funzione esegue.

3. Infine, una funzione che dovrebbe essere utilizzata non solo all'interno di un modulo, ma anche richiamata da altre applicazioni, dovrebbe essere dichiarata come esportabile nella sezione esportazioni.

Le funzioni di una DLL possono essere chiamate sia da applicazioni sviluppate in Delphi che da applicazioni scritte in altri linguaggi di programmazione, come C++.

L'ordine di allocazione della memoria per i parametri e di liberazione della stessa è diverso per lingue diverse programmazione. Per evitare un errore di runtime, la dichiarazione di funzione nella DLL e la dichiarazione di funzione nell'applicazione devono utilizzare lo stesso meccanismo di passaggio dei parametri. Quando si dichiara una procedura o una funzione, è possibile specificare uno dei seguenti meccanismi per il passaggio dei parametri:

Il metodo di passaggio dei parametri è indicato con un punto e virgola dopo la descrizione della funzione. Per esempio:

funzione F1 (X, Y, Z: Reale]: Reale; stdcall;.

Vari modi i passaggi dei parametri definiscono l'ordine in cui i parametri vengono passati (da sinistra a destra o da destra a sinistra) e indicano anche chi deallocherà la memoria dello stack (la procedura chiamata o la procedura chiamante). Quando si utilizzano DLL come componenti chiamati da applicazioni in altri linguaggi di programmazione, è necessario utilizzare il modificatore di chiamata appropriato. Per le applicazioni C++ viene utilizzato il modificatore di chiamata stdcall.

Affinché una funzione descritta in una DLL possa essere richiamata da un'altra applicazione, è necessario esportare la funzione. L'elenco di tutte le funzioni esportate è indicato nella sezione esportazioni, separate da virgole

e termina con un punto e virgola. Le funzioni di esportazione possono essere eseguite in tre modi:

In base al nome della funzione utilizzata nella DLL;

Per nome della funzione specificato come nome di esportazione;

Dall'indice assegnato alla funzione.

Per assegnare un determinato indice a una funzione, è necessario specificarlo nella sezione esportazioni dopo il nome della funzione con parola chiave indice.

Affinché la funzione esportata venga chiamata con un nome diverso dal nome utilizzato nella libreria DLL, nella sezione esportazioni dopo il nome della funzione, è necessario specificare il nome della parola chiave e il nuovo nome di esportazione per questa funzione.

DLL: la libreria non è un modulo eseguibile. Per ottenere il suo codice è sufficiente compilare il progetto.

progetto biblioteca;

SysUtils, Classi;

funzione F1(X, Y: intero): intero; chiamata standard;

Collegamento statico di una libreria DLL

La DLL può essere collegata staticamente o dinamicamente. Quando includi una DLL, questa viene caricata nella memoria dell'applicazione.

Con una connessione statica, la DLL viene caricata una volta all'avvio dell'applicazione. Durante l'esecuzione dell'applicazione, il nome di una funzione importata da una DLL collegata staticamente punta alla stessa funzione (il punto di ingresso alla DLL) nella stessa DLL. Tutte le funzioni della DLL che verranno utilizzate inizialmente nell'applicazione devono essere dichiarate come esterne. In questo caso è necessario specificare, se necessario, un modificatore di chiamata. Se una funzione viene chiamata per indice, è necessario fornirle il nome utilizzato nell'applicazione e l'indice della funzione nella DLL.

Pubblicità funzioni esterne eseguito nella sezione di implementazione prima di utilizzare queste funzioni.

Dichiarazione di esterno funzioni con la parola chiave external specifica che verrà utilizzato il collegamento statico.

TForml = classe(TForm)

Modifica: TModifica; [Campo per l'inserimento del primo valore)

Modifica2: TModifica; (Campo per l'inserimento del secondo valore)

Modifica3: TModifica; (Campo per visualizzare il risultato

eseguire una funzione da una DLL)

Pulsante: TPulsante; (Viene richiamata la funzione utilizzata dal nome)

Pulsante 2: Pulsante T; [Una chiamata di funzione viene effettuata utilizzando l'indice)

procedura ButtonlClickfSender: TObject);

procedura Button2Click(Sender: TObject);

(Dichiarazioni private)

(Dichiarazioni pubbliche)

(Dichiarazione delle funzioni esportate)

funzione Fl (i: intero; j: intero): intero; chiamata standard;

"Projectl.dll" esterno;

funzione F2 (i: intero; j: intero): intero; chiamata standard;

esterno "Indice Projectl.dll 2;

procedura TForml.ButtonlClick(Sender: TObject);

(Funzione di chiamata esportata)

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

procedura TForml.Button2Click(Sender: TObject);

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

Collegamento dinamico di una libreria DLL

A differenza del collegamento statico di una DLL, che avviene al caricamento dell'applicazione, il collegamento dinamico di una DLL può essere eseguito in qualsiasi momento dell'esecuzione del programma. Dopo aver chiamato una funzione da una DLL, puoi disabilitarla. Quando si utilizzano più DLL contemporaneamente, ciò fornisce un notevole risparmio di memoria. Le funzioni API di Windows vengono utilizzate per connettere dinamicamente una libreria DLL. API di Windows- si tratta di un insieme di funzioni standard utilizzate per implementare l'interazione con il sistema operativo.

Quando si chiama una funzione da una DLL collegata dinamicamente, invece di definire il nome della funzione come esterno nel caso del collegamento statico, è necessario definire un nuovo tipo corrispondente al tipo della funzione chiamata e creare una variabile di quel tipo.

Per effettuare una chiamata di funzione da una DLL di collegamento dinamico, attenersi alla seguente procedura:

1. Crea un nuovo tipo. corrispondente al tipo della funzione chiamata (il nome del nuovo tipo può essere inserito dopo la sezione tipo).

Per esempio:

TMyFl=funzione(i,j:Intero):Intero; chiamata standard;

2. Nella sezione var della sezione interfaccia del modulo, creare una variabile del tipo di funzione creata. Ad esempio: MyFl: TMyFl;

3. Prima di caricare la DLL, dichiarare tipo variabile Intero, che conterrà il descrittore della libreria collegata.

4. Chiamare il metodo LoadLibrary che carica la DLL. Per esempio; h:=LoadLibrary("Projectl.dll");

5. Controllare se la connessione alla libreria ha avuto esito positivo. Se il nome della DLL non è corretto o la DLL non viene trovata, la funzione LoadLibrary restituirà 0.

6. Se si collega correttamente la libreria DLL, è necessario ottenere successivamente l'indirizzo della funzione. A questo scopo viene utilizzato Funzione Windows API GetProcAddress, i cui parametri sono il descrittore della libreria DLL e il nome della funzione connessa. Ad esempio: @MyFl: =GetProcAddress(h, "Fl");

7. Se viene ricevuto l'indirizzo della funzione, il valore dell'indirizzo (nel nostro esempio @MyFl) non deve essere uguale a zero.

8. A questo punto è possibile chiamare una funzione da una DLL collegata dinamicamente.

9. Per liberare e quindi scaricare la DLL, chiamare il metodo FreeLibrary, che disabilita la DLL.

Windows, Messaggi, SysUtils, Varianti, Classi, Grafica,

Controlli, moduli, finestre di dialogo, StdCtrl;

TForml = classe(TForm)

Pulsante 3: Pulsante T;

procedura Button3Click

procedura TForml.Button3Click(Sender: TObject);

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

se h<>0 allora

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

se @MyFl<>zero allora

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

StrToInt(Modifica2.Testo)));

Utilizzo di una DLL per chiamare finestre di dialogo modali comuni.

Il risultato dell'esecuzione di una procedura da una libreria DLL può essere la visualizzazione di alcune finestre di dialogo modali. A tale scopo, creare un oggetto modulo nel metodo esportato, visualizzarlo come finestra di dialogo modale, quindi eliminare l'oggetto modulo. In questo caso, il modulo stesso dovrebbe fornire una chiamata al metodo Close per terminare la finestra di dialogo.

Per creare un form, utilizzare il metodo Create, al quale viene passato come parametro un puntatore al form genitore, il form dell'applicazione chiamante. Questo parametro viene passato alla funzione DLL chiamata.

progetto biblioteca;

Unitl_DLL in "Unitl_DLL.pas" (Forml);

procedura MyModalForm (var Z:Integer ;F:TForm1); chiamata standard;

Modulo1:=TForml.Create(F);

(Il parametro F viene passato quando si chiama la procedura e contiene un puntatore

al modulo principale - il modulo della domanda di convocazione)