Exemple de creare a fișierelor DLL Delphi complexe. Se încarcă DLL în aplicația delphi

Dragi colegi!

În acest articol voi încerca să răspund la întrebările: Ce este DLL? Pentru ce este? Și cum să creați și să utilizați DLL cu ajutor Delphi.

Ce este DLL?

Biblioteca de linkuri dinamice sau pe scurt DLL este o bibliotecă care conține un set de date sau funcții pentru utilizare în alte programe.

Domenii de utilizare:

  • Stocarea resurselor: pictograme, sunete, cursoare etc. Economisim dimensiunea fișierelor executabile combinând resurse într-o singură bibliotecă.
  • Plasarea modulelor de program individuale și a formularelor de interfață. Avem posibilitatea de a actualiza parțial aplicația și, cu o conexiune dinamică, este posibilă actualizarea modulelor fără a reporni programul principal.
  • Utilizați ca plugin-uri (PlugIn). Oferim posibilitatea de a extinde funcționalitatea aplicației fără a rescrie codul principal al programului.
  • Biblioteca poate fi folosită în diferite limbaje de programare, indiferent de limba în care a fost scrisă.

Crearea propriului DLL.

Pentru a crea o bibliotecă, accesați meniul Fişier -> Alteși alegeți Proiectele Delphi -> Biblioteca de link-uri dinamice.
Textul de cod cu un șablon pentru crearea unei biblioteci se va deschide:

Proiect Biblioteca1; folosește System.SysUtils, System.Classes; ($R *.res) începe sfârşitul.

Plasarea resurselor

Să adăugăm o pictogramă în bibliotecă, pe care o vom folosi mai târziu în programul principal.
Cum să adăugați resurse la un proiect este descris în detaliu în articol.

Să adăugăm un formular „Despre program”.
Clic Fişier -> Nou -> Formular VCL. Să adăugăm text și un buton „OK”:

Să adăugăm o funcție care va afișa standardul Mesaje cu o întrebare, butoanele „Da”, „Nu” și cu un rezultat în formular Adevărat sau Fals.

Funcția YesNoDlg(const Întrebare: PChar): boolean; stdcall; începe Rezultatul:= (MessageBox(0, Întrebare, „Confirmare”, MB_YESNO + MB_ICONQUESTION) = ID_YES); Sfârşit;

Acordați atenție cuvântului cheie stdcall. Acesta determină exact modul în care parametrii și rezultatele vor fi transmise la apelarea funcțiilor. Puteți citi mai multe pe pagina wiki privind acordul de apelare.

Vom adăuga, de asemenea, o procedură care va fi folosită ca plugin pentru programul principal. Care va adăuga un buton „Despre program” în meniul principal al programului pentru a deschide fereastra pe care am creat-o.
Cod de procedură:

Procedure PlugIn(Form: TForm); stdcall; var i: întreg; mi: TMenuItem; începe pentru i:= 0 la Form.ComponentCount - 1 începe dacă (Form.Components[i].ClassName = "TMenuItem") și (Form.Components[i].Name = "miHelp"), apoi începe mi:= TMenuItem .Creare(Form.Components[i]); mi.Caption:= „Despre program”; mi.OnClick:= fmAbout.onAboutButtonClick; TMenuItem(Form.Components[i]).Add(mi); Ieșire; Sfârşit; Sfârşit; Sfârşit;

Forma programului este transmisă procedurii ca parametru. Verificăm dacă există un element de meniu numit „ miHelp„și dacă meniul este găsit, atunci adăugați butonul nostru la el.

Acum vom indica ce funcții și proceduri pot fi utilizate din biblioteca noastră.
Să adăugăm linia:

Exporturi PlugIn, YesNoDlg;

Să compilam funcția Proiect -> Construi sau folosind o tastă rapidă Shift+F9.
Dacă nu există erori în cod, atunci ar trebui să apară un fișier cu extensia în folderul proiectului DLL.

Acum să trecem la crearea unei aplicații care va folosi biblioteca noastră.

Să creăm un formular în aplicație Principal in care vom adauga o componenta cu urmatoarele butoane: Program -> Exit si Help. Pentru ultimul, să setăm un nume - miHelp:

Să trecem la codul formularului.

Funcții din bibliotecă DLL poate fi conectat în două moduri:
Static— biblioteca este conectată la pornirea programului. Dacă biblioteca sau numele funcției nu este găsită, programul va genera o eroare și nu va rula.
Dinamic— biblioteca este conectată fie imediat înainte de apelarea unei funcții, fie la un anumit eveniment.

Să luăm în considerare metoda de conectare statică:

Tip TfmMain = class(TForm) MainMenu: TMainMenu; miProgram: TMenuItem; miExit: TMenuItem; miHelp: TMenuItem; procedura FormCreate(Sender: TObject); procedura miExitClick(Expeditor: TObject); scop public privat; procedura PlugIn(Form: TForm); stdcall; extern „SampleDLL.dll”; var...

Cuvânt cheie extern indică faptul că această funcție este conectată de la o bibliotecă externă.

Pentru eveniment onCreate formular, adăugați un apel de procedură Conecteaza:

Procedura TfmMain.FormCreate(Sender: TObject); începe PlugIn(Self); Sfârşit;

Ca parametru Formă trecem forma curentă procedurii (cuvânt cheie De sine).

La pornirea programului, ar trebui să avem elementul „Despre program” în secțiunea „Ajutor” din meniul principal.

Să trecem la metoda de conectare dinamică.

Vom avea nevoie de trei funcții WinApi:

LoadLibrary
Încarcă biblioteca în memoria computerului. Ca rezultat, returnează un pointer către biblioteca din memorie. În caz de eroare, va returna 0.

LoadLibrary(lpLibFileName: LPCWSTR): HMODULE;

lpLibFileName— Numele fișierului bibliotecă.

GetProcAddress
Găsiți o funcție într-o bibliotecă după nume. Rezultatul va fi un indicator de funcție. Dacă funcția nu este găsită, va reveni zero.

GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC;

hModul
lpProcName— Numele funcției.

FreeLibrary
Descarcă biblioteca din memoria computerului. Rezultatul va fi Adevărat în caz de succes și Fals în caz de eroare.

FreeLibrary(hLibModule: HMODULE): BOOL;

hLibModule— Indicator către biblioteca încărcată.

Acum, folosind metoda dinamică, vom obține resurse, pictograma noastră și vom adăuga un apel de funcție la butonul „Ieșire”. DaNuDlg pentru a confirma că programul este închis.
Adăugați următorul cod la același eveniment onCreate:

Procedura TfmMain.FormCreate(Sender: TObject); var DLLHandle: THandle; începe PlugIn(Self); DLLHandle:= LoadLibrary ("SampleDLL.dll"); dacă DLLHandle = 0, atunci ridicați Exception.Create ("Nu a putut include biblioteca 'SampleDLL'!"); încercați Self.Icon.LoadFromResourceName(DLLHandle, „icoana_mea”); în cele din urmă FreeLibrary(DLLHandle); Sfârşit; Sfârşit;

Și pentru eveniment onClick element de meniu „Ieșire”:

Procedura TfmMain.miExitClick(Expeditor: TObject); var DLLHandle: THandle; Dlg: function(const Întrebare: PChar): boolean; stdcall; începe DLLHandle:= LoadLibrary ("SampleDLL.dll"); dacă DLLHandle = 0, atunci ridicați Exception.Create ("Nu a putut include biblioteca 'SampleDLL'!"); încercați @Dlg:= GetProcAddress(DLLHandle, "YesNoDlg"); dacă nu este Assigned(@Dlg), atunci ridicați Exception.Create("Funcția numită "YesNoDlg" nu a fost găsită în biblioteca "SampleDLL"!"); if Dlg("Ieșiți din program?"), apoi Închideți; în cele din urmă FreeLibrary(DLLHandle); Sfârşit; Sfârşit;

Dacă ați scris totul corect, atunci după pornirea programului pictograma formularului ar trebui să se schimbe, trebuie adăugat butonul „Despre program”, când se face clic pe el, formularul va afișa Despre iar când apăsați butonul de ieșire, programul vă va cere confirmarea: „Ieșiți din program?”

Sper că veți găsi util acest mic exemplu de utilizare a funcțiilor. DLL biblioteci.
Sursele proiectului pot fi descărcate.

Cel puțin majoritatea utilizatorilor de computere știu ce este un DLL, în special programatorii, ceea ce cel mai probabil sunteți dacă citiți acest articol. În acest articol voi încerca să trec peste toate întrebările generale referitoare la DLL-uri.

La ce ne vom uita mai exact:

  1. Ca de obicei, din zona „Hello World”, vom crea primul nostru DLL.
  2. Să învățăm cum să folosim funcțiile acestui DLL din programele noastre.
  3. Să învățăm cum să vedem funcțiile pe care le exportă un anumit DLL.
  4. Poate fi altceva....

Procesul de creare a DLL

Să începem cu cel mai simplu lucru - să scrieți primul DLL, care va conține o singură funcție care afișează mesajul „Hello World”.

  1. Să lansăm Delphi (folosesc Delphi 6).
  2. Următorul: Fișier -> Nou ->Altul

În fila Nou, faceți dublu clic pe obiectul DLL Wizard. Se va deschide un nou proiect. Salvați-l cu numele MyFirstDLL, de exemplu.

Un modul pur are ceva de genul:

Biblioteca MyFirstDLL; folosește SysUtils, Classes; ($R *.res) începe sfârşitul.

Acum să scriem o singură funcție care va apela ShowMessage() din modulul Dialogs. Prin urmare, înainte de a începe procedura, să adăugăm modulul Dialogs la secțiunea Utilizări. Ce ar trebui să obțineți aproximativ:

Biblioteca MyFirstDLL; folosește dialoguri; procedura MyFirstFunc; stdcall; începe ShowMessage("Bună lume"); Sfârşit; exportă MyFirstFunc; începe sfârşitul.

După cum puteți vedea, nu este nimic foarte complicat aici. Singurul lucru pe care îl voi spune este că puteți apela funcții atât după nume, cât și după index (număr), pentru aceasta trebuie să scrieți astfel:

Exportă MyFirstFunc index 1;

Dacă ceva nu este clar în acest cod, încercați mai întâi să vă dați seama singur. Cred că nu vor fi probleme cu asta... Dar dacă e ceva, atunci forum.! Mergând mai departe, cum poți folosi acum această funcție (MyFirstFunc) din alte proiecte?

Utilizarea funcțiilor DLL

Primul pas a fost făcut, este doar o chestiune de timp... Cum putem folosi această funcție?

Există cel puțin două metode de descărcare:

  1. Static
  2. Dinamic

A doua metodă este de preferat, deoarece în timpul încărcării putem monitoriza tot ceea ce se întâmplă și putem corecta toate erorile care apar în timpul încărcării. Dar mai întâi, să ne uităm la prima metodă:

Creăm un nou proiect, plasăm un buton pe formular și, la evenimentul OnClick al acestui buton, scriem următoarele:

Procedura TForm1.Button1Click(Expeditor: TObject); începe MyProc(); Sfârşit;

Dar asta nu este tot! În secțiunea de implementare a proiectului, scrieți:

Procedura de implementare MyProc(); stdcall; numele extern „MyFirstDLL.dll” „MyFirstFunc”;

Gata! Compilați proiectul și apăsați butonul! Daca apare mesajul tau, atunci totul este ok!

Acum să ne uităm la metoda de încărcare dinamică. Pentru această metodă, utilizați funcția LoadLibrary(), iar la final, pentru descărcare, utilizați FreeLibrary().

Uita-te la exemplu:

Procedura TForm1.Button1Click(Expeditor: TObject); tip TMyFunc = procedura; var DLLInstance: THandle; MyFunc: TMyFunc; începe DLInstance:= LoadLibrary(PChar("MyFirstDLL.dll")); if (DLLInstance = 0) atunci începe MessageDlg("Nu se poate încărca DLL", mtError, , 0); Ieșire; Sfârşit; încercați @MyFunc:= GetProcAddress(DLLInstance, "MyFirstFunc"); if Assigned(@MyFunc) then MyFunc() else MessageDlg("Procedura necesară nu a fost găsită!.", mtError, , 0); în sfârșit FreeLibrary(DLLInstance); Sfârşit; Sfârşit;

După încărcarea cu succes a DLL-ului cu funcția LoadLibrary(), folosind GetProcAddress() vom găsi adresa funcției noastre, la care vom apela procedura noastră din DLL. În cele din urmă, cu siguranță trebuie să faci FreeLibrary(). Acest lucru este atât de important încât am inclus tot codul după o descărcare cu succes, până la FreeLibrary(), într-un bloc try finally. Acest lucru asigură că FreeLibrary se va executa chiar dacă apare o excepție neașteptată la executarea acțiunilor din blocul try except.

Ideea este că apelurile de succes la LoadLibrary și FreeLibrary trebuie să fie asociate. Si de aceea. Sistemul, pentru fiecare bibliotecă încărcată de un proces, menține un contor intern care crește cu 1 cu fiecare apel reușit la LoadLibrary. În consecință, atunci când FreeLibrary este executat, scade acest contor, iar dacă devine egal cu zero, aceasta înseamnă că această bibliotecă nu mai este necesară pentru acest proces și poate fi eliminată în siguranță din memorie.

Dacă regula de împerechere nu este respectată, acest lucru poate duce fie la descărcarea prematură (dacă există o FreeLibrary suplimentară) a bibliotecii din memorie, fie la „blocarea” acesteia acolo (dacă nu există suficientă FreeLibrary).

Dacă urmați această regulă, nu trebuie să vă faceți griji cu privire la posibila imbricare a apelurilor LoadLibrary / FreeLibrary.

Vizualizarea funcțiilor unui anumit DLL

Acum să vedem cum putem extrage toate numele funcțiilor din fișierele în format PE, care includ DLL-uri. Nu vom lua în considerare aici structura formatului PE, prin urmare, sursa va fi fără explicații.

Deci, creați un nou proiect, plasați un ListBox pe formular, în el vom afișa numele funcțiilor.

Iată tot proiectul:

Unitatea Unitatea 1; interfața folosește Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; tip TForm1 = class(TForm) lb: TListBox; procedura FormCreate(Sender: TObject); private ( Declarații private ) cmdline: String; ImageBase: DWord; DosHeader: PImageDosHeader; PeHeader: PImageNtHeaders; PExport: PImageExportDirectory; pname:PDWord; nume: PChar; public ( Declarații publice ) end; var Form1: TForm1; procedura de implementare ($R *.dfm) TForm1.FormCreate(Sender: TObject); procedura FatalOsError; începe ShowMessage(SysErrorMessage(GetLastError())); Avorta; Sfârşit; Var i: Integer; începeți încercați dacă (ParamCount() IMAGE_DOS_SIGNATURE) apoi FatalOsError; PEHeader:= PImageNtHeaders(DWord(ImageBase) + DWord(DosHeader^._lfanew)); if (PEHeader^.Signature IMAGE_NT_SIGNATURE) atunci FatalOsError; PExport:= PImageExportDirectory(ImageBase + DWord(PEHeader^.OptionalHeader.DataDirectory.VirtualAddress)); pname:= PDWord(ImageBase + DWord(PExport^.AddressOfNames)); Pentru i:= 0 la PExport^.NumberOfNames - 1 nu începe numele:= PChar(PDWord(DWord(ImageBase) + PDword(pname)^)); lb.Items.Add(nume); inc(pname); Sfârşit; în sfârșit FreeLibrary(ImageBase); Sfârşit; cu excepția Application.ShowMainForm:= False; Aplicație.Terminare; Sfârşit; Sfârşit; Sfârşit.

Dacă doriți să vă dați seama singur codul și ceva nu merge pentru dvs., atunci forumul nostru vă va ajuta cu siguranță, intrați!

Atașăm vizualizatorul nostru la toate DLL-urile

Avem un DLL gata făcut cu o funcție și avem un vizualizator de funcții. Rămâne să adăugați unele funcționalități pentru confortul lucrărilor ulterioare. Să facem asta... Deschideți orice folder în Explorer. Accesați Instrumente -> Opțiuni folder... Accesați fila „Tipuri de fișiere”. Căutăm formatul DLL în listă. Dacă nu există așa ceva, faceți clic pe butonul „Creați” și în câmpul „Extensie” scrieți - DLL. Faceți clic pe OK. Găsim tipul pe care l-am creat - DLL. Selectați-l și faceți clic pe „Avansat”. În continuare „Creare”, în câmpul „Acțiuni” scriem ceea ce va fi afișat în meniul contextual, de exemplu DLL Viewer. Prin recenzie căutăm programul nostru.

Totul este gata!

Acum, când faceți clic dreapta pe un fișier în format DLL, vizualizatorul nostru DLL va apărea în meniu. Selectează-l și vezi toate funcțiile!

Asta e tot, multumesc pentru atentie!

Vă aduc în atenție următorul număr al buletinului informativ, în care continui să discut
probleme legate de dezvoltarea și utilizarea DLL-urilor în Borland Delphi. Pentru noii abonati va informez,
că se pot uita la prima parte a articolului din arhiva de corespondență, numărul 13.
Îmi cer scuze celor care mi-au scris dar nu au primit răspuns. Voi încerca să repar asta în viitorul apropiat.
Deci hai sa continuam.

Înainte de a începe să utilizați orice procedură sau funcție aflată într-o bibliotecă dinamică,
trebuie să încărcați DLL-ul în RAM. Biblioteca poate fi încărcată
într-unul din două moduri: încărcare statică și încărcare dinamică.
Ambele metode au atât avantaje, cât și dezavantaje.
Încărcarea statică înseamnă că biblioteca dinamică este încărcată automat
când este lansată aplicația care o folosește. Pentru a utiliza această metodă de descărcare,
trebuie să utilizați cuvântul cheie extern când descrieți din ce se exportă
funcție sau procedură de bibliotecă dinamică. DLL-ul este încărcat automat când programul pornește,
și veți putea folosi orice rutine exportate din acesta în același mod ca
ca și cum ar fi descrise în interiorul modulelor de aplicație.
Acesta este cel mai simplu mod de a utiliza codul plasat într-un DLL.
Dezavantajul acestei metode este că dacă fișierul de bibliotecă pe care
există un link în aplicație, dacă acesta lipsește, programul va refuza să se încarce.
Semnificația metodei dinamice este că nu încărcați biblioteca atunci când pornește aplicația,
și în momentul în care chiar ai nevoie de el. Judecă singur, pentru că dacă funcția descrisă
într-o bibliotecă dinamică, folosită doar în 10% din lansările programelor, apoi absolut nu
Nu are sens să folosești o metodă de încărcare statică. Descărcarea bibliotecii din memorie în acest caz
se desfășoară și sub controlul dumneavoastră. Un alt avantaj al acestei metode
încărcarea DLL-urilor înseamnă reducerea (din motive evidente) a timpului de pornire a aplicației dvs.
Care sunt dezavantajele acestei metode? Principalul, mi se pare, este că folosirea
Această metodă este mai deranjantă decât încărcarea statică discutată mai sus.
Mai întâi trebuie să utilizați funcția Windows API LoadLibrary.
Pentru a obține un pointer către procedura sau funcția exportată, trebuie
utilizați funcția GetProcAddress. După ce ați terminat de utilizat DLL
trebuie să fie descărcat folosind FreeLibrary.
Apelarea procedurilor și funcțiilor încărcate din DLL-uri.
Modul în care sunt apelate procedurile și funcțiile depinde de modul în care ați încărcat biblioteca dinamică,
în care se află aceste subrutine.
Apelarea funcțiilor și procedurilor din DLL-uri încărcate static este destul de simplă. Inițial în aplicație
trebuie să conțină o descriere a funcției (procedura) exportată. După aceea, le puteți folosi
la fel ca și cum ar fi descrise într-unul dintre modulele dvs. de aplicație.
Pentru a importa o funcție sau o procedură conținută într-un DLL, trebuie să utilizați
modificator extern în declarația lor. De exemplu, pentru procedura HelloWorld pe care am considerat-o mai sus
Aplicația de apelare ar trebui să aibă următoarea linie:
procedura SayHello(AForm: TForm); extern myfirstdll.dll";
Cuvântul cheie extern îi spune compilatorului că procedura poate fi găsită în
bibliotecă dinamică (în cazul nostru - myfirstdll.dll).
Apelul la această procedură arată astfel:
...
HelloWorld(self);
...
Când importați funcții și proceduri, fiți deosebit de atenți când scrieți numele și interfețele acestora!
Faptul este că în timpul compilării aplicației nu se verifică corectitudinea numelor obiectelor,
exportate din DLL nu vor fi implementate, iar dacă ați descris incorect orice funcție,
atunci excepția va fi aruncată doar în faza de execuție a aplicației.
Importul din DLL poate fi efectuat prin numele procedurii (funcției), numărul secvenței sau
cu alt nume.
În primul caz, pur și simplu declarați numele procedurii și biblioteca din care o importați
(ne-am uitat la asta puțin mai sus). Importarea după numărul de secvență necesită să specificați chiar acest număr:
procedura HelloWorld(AForm: TForm); index extern myfirstdll.dll 15;
În acest caz, numele pe care îl dați procedurii la import nu trebuie să fie același cu
care a fost specificat pentru acesta în DLL-ul propriu-zis. Acestea. intrarea de mai sus înseamnă,
că importați din biblioteca dinamică myfirstdll.dll procedura care a fost exportată în ea
al cincisprezecelea, iar în cadrul aplicației dumneavoastră această procedură se numește SayHello.
Dacă dintr-un motiv oarecare nu utilizați metoda de import descrisă mai sus,
dar totuși doriți să schimbați numele funcției importate (procedură), puteți utiliza a treia metodă:
procedura CoolProcedure; numele extern myfirstdll.dll „DoSomethingReallyCool”;
Aici, procedura CoolProcedure importată se numește DoSomethingReallyCool.
Apelarea procedurilor și funcțiilor importate din biblioteci încărcate dinamic
ceva mai complicată decât metoda pe care am discutat-o ​​mai sus. În acest caz, trebuie să declarați
un indicator către funcția sau procedura pe care urmează să o utilizați.
Vă amintiți procedura HelloWorld? Să vedem ce trebuie făcut
pentru a-l apela să se execute în cazul încărcării dinamice a unui DLL. În primul rând, tu
este necesar să se declare un tip care ar descrie această procedură:
tip
THelloWorld = procedura(AForm: TForm);
Acum trebuie să încărcați biblioteca dinamică, folosind GetProcAddress get
un pointer către o procedură, apelați această procedură pentru execuție și, în final, descărcați DLL-ul din memorie.
Mai jos este codul care demonstrează cum se poate face acest lucru:

DLInstance: THandle ;

HelloWorld:THelloWorld;

ÎNCEPE

(încărcați DLL)

(primim un indicator)

(apelați procedura de executare)

HelloWorld(Sine);

(descărcați DLL din RAM)

FreeLibrary(DLLInstance) ;

Sfârşit ;

După cum am menționat mai sus, unul dintre dezavantajele încărcării statice a unui DLL este incapacitatea de a face acest lucru
continuarea funcționării aplicației în absența uneia sau a mai multor biblioteci. În cazul dinamicii
Prin descărcare, aveți posibilitatea de a gestiona în mod programatic astfel de situații și de a preveni programul
a căzut” de la sine. Pe baza valorilor returnate de funcțiile LoadLibrary și GetProcAddress, puteți
stabiliți dacă biblioteca a fost încărcată cu succes și dacă procedura cerută de aplicație a fost găsită în ea.
Codul de mai jos demonstrează acest lucru.

procedura TForm1.DynamicLoadBtnClick (Expeditor: TObject) ;

tip

THelloWorld = procedura (AForm: TForm);

DLInstance: THandle ;

HelloWorld:THelloWorld;

ÎNCEPE

DLInstance:= LoadLibrary("myfirstdll.dll");

dacă DLInstance = 0 atunci începe

MessageDlg( „Nu se poate încărca DLL”, mtError, [ mbOK], 0 ) ;

Ieșire ;

Sfârşit ;

@HelloWorld:= GetProcAddress(DLLInstance, „HelloWorld”);

dacă @HelloWorld nul atunci

HelloWorld (Eu)

altfel

MessageDlg( „Procedura necesară nu a fost găsită!”., mtError, [ mbOK], 0 ) ;

FreeLibrary(DLLInstance) ;

Sfârşit ;

DLL-urile pot stoca nu numai cod, ci și formulare.
Mai mult, crearea și plasarea formularelor într-o bibliotecă dinamică nu este prea diferită de lucru
cu forme într-un proiect obișnuit. Mai întâi ne vom uita la cum poate fi scrisă o bibliotecă,
care conțin formulare și apoi vom vorbi despre utilizarea tehnologiei MDI într-un DLL.
Voi demonstra dezvoltarea unui DLL care conține un formular folosind un exemplu.
Deci, mai întâi, să creăm un nou proiect de bibliotecă dinamică.
Pentru a face acest lucru, selectați elementul de meniu Fișier|Nou, apoi faceți dublu clic pe pictograma DLL.
După aceasta, veți vedea un cod similar cu următorul:

Salvați proiectul rezultat. Să-i spunem DllForms.dpr.
Acum trebuie să creați un formular nou. Acest lucru se poate face în moduri diferite.
De exemplu, selectând elementul de meniu Fișier|Formular nou. Adăugați câteva componente în formular.
Să denumim formularul DllForm și să salvăm modulul rezultat sub numele DllFormUnit.pas.
Să revenim la modulul principal al proiectului și să plasăm în el funcția ShowForm, a cărei sarcină va include
crearea unui formular și afișarea lui pe ecran. Utilizați codul de mai jos pentru aceasta.

Formular: TDLLForm;

ÎNCEPE

Rezultat:= Form.ShowModal ;

Form.Free ;

Sfârşit ;

Vă rugăm să rețineți că pentru ca proiectul să fie compilat fără erori, trebuie să adăugați modulul Formulare la secțiunea de utilizări.
Exportăm funcția noastră folosind cuvântul cheie exports:
exporturi
ShowForm;
Compilăm proiectul și obținem fișierul dllforms.dll. Acești pași simpli sunt totul
ce trebuie să faceți pentru a observa că funcția ShowForm este declarată folosind cuvântul cheie stdcall.
Semnalizează compilatorului să folosească convenția atunci când exportă o funcție
prin convenția standard de apelare. Exportarea unei funcții în acest fel creează
capacitatea de a utiliza DLL-ul dezvoltat nu numai în aplicațiile create în Delphi.
Convențiile de apelare determină modul în care sunt transmise argumentele la apelarea unei funcții.
Există cinci convenții de bază: stdcall, cdecl, pascal, register și safecall.
Puteți afla mai multe despre acest lucru uitându-vă la secțiunea „Convenții de apelare” din fișierul de ajutor Delphi.
De asemenea, rețineți că valoarea returnată de funcția ShowForm este
corespunde valorii ShowModal. În acest fel puteți transfera unele informații
despre starea formularului la cererea de apelare.
Mai jos sunt două liste, dintre care prima conține codul complet pentru fișier
Proiectul DLL (modulul cu formularul nu este afișat aici), iar al doilea este modulul aplicației care apelează,
care folosește biblioteca pe care tocmai am dezvoltat-o.

libraryDllForms;

utilizări

DllFormUnit în „DllFormUnit.pas” (DllForm);

($R *.RES)

funcția ShowForm: Integer ; stdcall ;

Formular: TDLLForm;

ÎNCEPE

Form:= TDLLForm.Create(Application) ;

Rezultat:= Form.ShowModal ;

Form.Free ;

Sfârşit ;

ÎNCEPE

Sfârşit.


unitate TestAppUnit;

interfata

utilizări

Windows, Mesaje, SysUtils, Clasuri, Grafică,

Controale, Formulare, Dialoguri, StdCtrls;

tip

TForm1 = clasa (TForm)

Buton1: TBbutton;

procedura Buton1Click(Expeditor: TObject) ;

privat

(Declarații private)

public

(Declarații publice)

Sfârşit ;

Form1: TForm1;

funcția ShowForm: Integer ; stdcall ;

"dllforms.dll" extern;

implementare

($R *.DFM)

procedura TForm1.Button1Click (Expeditor: TObject) ;

ÎNCEPE

Sfârşit ;

Sfârşit.

Vă rugăm să rețineți că cuvântul cheie stdcall a fost folosit și la exportul funcției.
Ar trebui să acordați o atenție deosebită lucrului cu formulare copil în DLL-uri. Dacă, de exemplu,
în aplicația de apelare, formularul principal are o valoare a proprietății FormStyle egală cu MDIForm,
apoi, când încercați să apelați formularul MDIChild din DLL, pe ecran apare un mesaj de eroare,
care va spune că nu există o formă MDI activă.
În momentul în care încercați să afișați fereastra copilului, VCL verifică corectitudinea
Proprietățile FormStyle ale formularului principal al aplicației. Cu toate acestea, în cazul nostru totul pare să fie adevărat.
Deci care e treaba? Problema este că atunci când se efectuează o astfel de verificare, obiectul Aplicație este luat în considerare,
aparținând nu aplicației care apelează, ci bibliotecii dinamice în sine.
Ei bine, desigur, deoarece DLL-ul nu are o formă principală, verificarea aruncă o eroare.
Pentru a evita această situație, trebuie să atribuiți obiectul Aplicație al bibliotecii dinamice
obiectul Aplicație al aplicației apelante. Desigur, acest lucru va funcționa numai dacă
când programul apelant este o aplicație VCL. În plus, înainte de a descărca biblioteca din memorie
este necesar să readuceți valoarea obiectului Aplicație al bibliotecii la starea inițială.
Acest lucru va permite managerului de memorie să curețe memoria RAM ocupată de bibliotecă.
Prin urmare, trebuie să stocați un pointer către obiectul aplicație nativ al bibliotecii
într-o variabilă globală care poate fi folosită pentru a-i restabili valoarea.
Deci, să revenim puțin înapoi și să enumerăm pașii cu care trebuie să lucrăm plasați
în formularele DLL MDIChild.
În biblioteca dinamică creăm o variabilă globală de tip TApplication.
Stocăm un pointer către obiectul Application DLL într-o variabilă globală.
Atribuim un pointer la Aplicație obiectului Aplicație al bibliotecii dinamice
aplicație de apelare.
Creăm un formular MDIChild și lucrăm cu el.
Revenim valoarea obiectului Aplicație al bibliotecii dinamice la starea sa originală
și descărcați DLL-ul din memorie.
Primul pas este simplu. Pur și simplu plasăm următorul cod în partea de sus a modulului DLL:
var
DllApp:TAplicație;
Apoi creăm o procedură care va schimba valoarea obiectului Aplicație și va crea un formular copil.
Procedura ar putea arăta cam așa:

procedura ShowMDIChild(MainApp: TApplication) ;

Copil: TMDIChild;

ÎNCEPE

dacă nu este atribuit (DllApp), atunci începe

DllApp:= Aplicație;

Aplicație:= MainApp;

Sfârşit ;

Copil:= TMDIChild.Create(Application.MainForm) ;

Copil.Show ;

Sfârşit ;

Tot ce trebuie să facem acum este să furnizăm valoarea returnată a obiectului Aplicație
la starea sa originală. Facem acest lucru folosind procedura MyDllProc:

procedura MyDLLProc(Reason: Integer) ;

ÎNCEPE

dacă Motivul = DLL_PROCESS_DETACH atunci

(DLL este descărcat. Restabiliți valoarea indicatorului de aplicație)

dacă este atribuit (DllApp), atunci

Aplicație:= DllApp;

Sfârşit ;

În loc de o concluzie.
Utilizarea bibliotecilor de link-uri dinamice nu este atât de dificilă pe cât ar părea la prima vedere.

Utilizarea bibliotecilor de link-uri dinamice nu este atât de dificilă pe cât ar părea la prima vedere.
DLL-urile oferă oportunități extinse pentru optimizarea performanței aplicațiilor,
precum și munca programatorilor înșiși. Folosește DLL și poate viața ta va deveni mai ușoară!
http://subscribe.ru/
E-mail: [email protected] Căutare
la APORT pe Subscribe.Ru

Mediul de programare Delphi oferă instrumente încorporate pentru crearea rapidă a DLL-urilor.

Să creăm o bibliotecă care să conțină funcția pentru a fi specific

GetArea(a, b, c: REAL):REAL.

Această funcție ia ca intrare lungimile laturilor triunghiului. Funcția returnează aria triunghiului dat:

p:=(a+b+c)/2;

Rezultat:=SQRT(p*(p-a)*(p-b)*(p-c))

Lansați Delphi, iar apoi acționăm neconvențional. Selectați elementele de meniu FileNewOacolo, în fereastra care se deschide în fila Newfaceți clic pe pictograma DLL Wizard. ( algoritmul depinde de versiune)

Aceasta creează un fișier DLL șablon. Este foarte asemănător cu un modul obișnuit (unitate) Delphi, începe doar cu operatorulBibliotecă. Salvați proiectul sub numele pe care DLL-ul îl va avea în viitor, să zicemObtine o. NumeGetAreanu poate fi folosit - este deja ocupat de numele funcției.

Acum, după operatorUTILIZĂRIscriem textul funcției noastre, dar cu unele modificări în titlu:

FUNCȚIE GetArea(a, b, c:REAL):REAL;export;

Cuvântul cheie EXPORT indică faptul că funcția este exportabilă și va fi vizibilă din programele externe.

După textul funcției vom adăuga

GetArea;

Instrucțiunea EXPORTS listează toate procedurile și funcțiile exportate din bibliotecă. Acesta este un fel de catalog al bibliotecii noastre.

Este imposibil să rulați biblioteca; aceasta poate fi doar compilată. Pentru a face acest lucru, selectați elementul de meniu Proiect → Construire. Dacă totul a fost făcut corect, un fișier numit geta.dll va fi creat pe discul din directorul curent. Aceasta este biblioteca noastră.

Notă importantă: Există o anumită subtilitate la trecerea parametrilor de tip STRING către procedurile și funcțiile aflate în bibliotecă.

Pentru a putea trece parametri de tip STRING, va trebui să specificați conexiunea modulului ShareMem în instrucțiunile USES atât ale bibliotecii, cât și ale programului care o apelează și chiar și așa ca acest modul să fie primul în listă. . Mai mult, alături de bibliotecă va trebui să includeți și fișierul borlndmm.dll (este inclus în distribuția Delphi). Este ușor să evitați această situație: pentru parametrii de tip text, ar trebui să utilizați tipurile de date ShortString (acesta este un șir obișnuit, dar cu o lungime de până la 255 de caractere) și PChar (un pointer către un șir de text).

Apelați la dll

Există două moduri de a apela proceduri și funcții dintr-un DLL. În primul caz, știm dinainte, în stadiul dezvoltării programului, ce DLL ne vom conecta la el (cel mai des creăm singuri acest DLL). În al doilea caz, ne conectăm la o bibliotecă arbitrară, inclusiv la una „străină”.

Legătura statică

Pentru a implementa prima metodă, numită legătură statică, creați o nouă aplicație obișnuită, plasați trei câmpuri de intrare LabeledEdit1...LabeledEdit3, un buton și o componentă Tlabel pe formular. După instrucțiunea IMPLEMENTATION, adăugați o linie care importă funcția GetArea din biblioteca geta.dll:

Funcția GetArea(a,b,c:real):REAL; DEPARTE; EXTERN „geta”;

Cuvântul EXTERNAL indică faptul că corpul acestei funcții se află în biblioteca cu numele specificat, iar cuvântul FAR specifică utilizarea adreselor „lungi” de patru octeți, ceea ce este necesar deoarece programul apelant este situat pe o pagină de memorie. , iar biblioteca DLL este pe alta. Desigur, fișierul geta.dll trebuie plasat în același director în care se află toate fișierele aplicației curente.

În manipulatorul de clic pe butonul, trebuie să creați o matrice și să o transmiteți funcției de bibliotecă și să afișați rezultatul pe ecran:

procedura TForm1.Button1Click(Expeditor: TObject);

Lucrul cu DLL-uri

DLL- Dynamic Link Library este o bibliotecă de linkuri dinamice care vă permite să reutilizați aceleași funcții în programe diferite. De fapt, este un instrument destul de convenabil, mai ales că biblioteca, odată scrisă, poate fi folosită în multe programe. În lecția de astăzi vom învăța cum să lucrăm cu dll-uri și, desigur, să le creăm!

Ei bine, să începem!

Mai întâi, să creăm prima noastră bibliotecă de linkuri dinamice! Mergem la Delphi și mergem imediat la meniul File -> New -> Other.

Selectați Dynamic-Link Library din listă (în versiunile anterioare Delphi 2009, elementul se numește DLL Wizard).

Prin urmare, avem doar o fereastră cu codul, rețineți că nu avem niciun formular aici!

Acum începe distracția. Să scriem primele noastre proceduri în bibliotecă.

libraryProject2; //Probabil ați observat deja că în loc de program //când creați un dll, este folosită biblioteca de cuvinte. //Biblioteca de semnificații. folosește SysUtils, dialoguri, clase; // Atenție! Nu uitați să specificați aceste module, altfel codul nu va funcționa ($R *.res) (ACESTA PARTEA ESTE CODUL DLL) Procedura FirstCall; stdcall; export; //Stdcall – Cu acest operator, parametrii sunt plasați pe stivă //de la dreapta la stânga, și aliniați la valoarea standard //Exportul poate fi, în principiu, omis, este folosit pentru a clarifica //exportul unei proceduri; sau funcție. Begin ShowMessage ("Prima mea procedură în dll"); //Apelați un mesaj pe ecran Sfârșit; Procedura DoubleCall; stdcall; export; Begin ShowMessage ("A doua mea procedură"); //Apelați un mesaj pe ecran Sfârșit; Exportă FirstCall, DoubleCall; //Exports conține o listă de elemente exportate. // Care va fi ulterior importat de un program. început Sfârșit.

Ne oprim aici deocamdată pentru că... pentru un exemplu simplu, acest lucru va fi suficient. Acum ne salvăm proiectul, l-am salvat personal sub numele Project2.dll și apăsăm combinația de taste CTRL+F9 pentru a compila biblioteca. În folderul în care ați salvat fișierul dpr, va apărea un fișier cu extensia dll, aceasta este biblioteca noastră tocmai creată. L-am numit Project2.dll

Să începem acum să apelăm proceduri din această bibliotecă. Creăm o nouă aplicație conform schemei standard. Înaintea noastră nu este nimic neobișnuit, doar o formă. Salvați noua aplicație într-un folder. Și copiați biblioteca dll nou creată în același folder. Acestea. în acest exemplu Project2.dll

Acum trebuie să alegeți cum să apelați funcții din bibliotecă. Există două metode de apelare în total.

Metoda nr. 1

Poate că aceasta este cea mai simplă metodă de a apela procedurile aflate în bibliotecă.

Ideal pentru a lucra cu o singură bibliotecă.

Începem...

După cuvântul cheie de implementare, scrieți următorul cod:

Aici, așa cum probabil ați ghicit deja, spunem programului numele procedurilor noastre și spunem că acestea se află într-o bibliotecă dll, în cazul meu numită Project2.dll

Acum, pentru a apela aceste proceduri, trebuie doar să le introducem numele oriunde în cod, ceea ce vom face acum. Introduceți 2 componente Button din fila Standard în formular și creați un handler de evenimente OnClick pe fiecare

OnClick pe primul buton:

OnFaceți clic pe al doilea buton:

Asta e tot!

Metoda numărul 2:

Mai complex decât primul, dar are avantajele sale și, cel mai important, este ideal pentru pluginuri.

Pentru a folosi această metodă, în primul rând declarăm mai multe variabile globale:

Apoi, după cuvântul cheie de implementare, vom scrie o procedură care ne va încărca biblioteca:

Procedura LoadMyLibrary(FileName: String);ÎNCEPE LibHandle:= LoadLibrary(PWideChar(FileName));//Se încarcă biblioteca! // Atenție! PChar pentru versiunile sub 2009 Delphi Dacă LibHandle = 0, atunci începe MessageBox(0," Nu se poate încărca biblioteca", 0,0); Ieșire; Sfârşit; FirstCall:= GetProcAddress(LibHandle,"FirstCall");//Obțineți un pointer către obiect //Primul parametru link către modulul bibliotecii //Al doilea parametru al obiectului din dll DoubleCall:= GetProcAddress(LibHandle,"DoubleCall"); Dacă @FirstCall = nil atunci începe//Verificați prezența acestei funcții în bibliotecă. MessageBox(0,"Nu se poate încărca biblioteca", 0,0); Ieșire; Sfârşit; Dacă @DoubleCall = nil atunci începe//Verificați prezența acestei funcții în bibliotecă. MessageBox(0,"Nu se poate încărca biblioteca", 0,0); Ieșire; Sfârşit; Sfârşit

Apoi pe formular creăm un handler de evenimente OnCreate, în care, folosind procedura tocmai creată, vom încărca biblioteca noastră

Procedura TForm1.FormCreate(Sender: TObject);ÎNCEPE LoadMyLibrary ("Project2.dll"); Sfârşit;

Acum, din nou, pentru a apela procedurile necesare din biblioteca noastră, trebuie doar să le introducem numele oriunde în cod. Pentru a face acest lucru, plasați 2 componente Button din fila Standard în formular și creați un handler de evenimente OnClick pe fiecare

OnClick pe primul buton:

Procedura TForm1.Button1Click(Expeditor: TObject);Începeți FirstCall; // Numele procedurii care se află în dll End;

OnFaceți clic pe al doilea buton:

Procedura TForm1.Button2Click(Expeditor: TObject);Începeți DoubleCall; // Numele procedurii care se află în dll End;

Și, în sfârșit, creăm un handler de evenimente OnDestroy pe formular, în care descarcăm biblioteca dll din memorie

Asta e tot! A doua metodă s-a dovedit a fi destul de greoaie, dar avantajul ei este de a clarifica obiectul stocat în bibliotecă.