CATEGORII DOCUMENTE |
Bibliotecile dinamice in Delphi
Fisierele Windows sunt de doua tipuri:
EXE - programe
DLL - dynamic link libraries
Intr-un program se pot utiliza functii stocate in DLL-uri.
Programul ce apeleaza o functie scrisa intr-un DLL trebuie sa respecte "conventia de apelare" (se refera la parametrii,.).
-sunt 2 tipuri de DLL-uri:
a) statice;
b) dinamice[1].
Cand o subrutina nu este scrisa in fisierul sursa, compilatorul adauga subrutina intr-o tabela interna (ce inlcude toti simbolii interni)
a) Mecanismul DLL-urilor statice
Atentie:
Dupa compilarea unei subrutine statice, se adauga codul compilat fisierului executabil.
Acelasi lucru se intampla si in cazul utilizarii unit-urilor, cel putin o functie/procedura. Compilatorul Delphi adauga doar codul pentru subrutinele apelate din unit-urile specificate.
Obs: exceptie fac doar metodele virtuale.
In cazul lucrului cu librarii link editorul utilizeaza informatia din declaratia external a subrutinei, pentru a crea diverse tabele in fisierul executabil.
Cand Windows incarca un executabil, mai intai incarca in memorie toate DLL-urile necesare acestuia, apoi incepe sa ruleze programul. In cazul in care nu gaseste toate librariile atunci se da un mesaj de eroare.
De fiecare data cand un program apeleaza o functie externa, utilizeaza tabela interna pentru apelare. (codul DLL-ului fiind aflat in spatiul de adresa al programului)
!!!!!! Atentie: NU SUNT IMPLICATE DOUA PROGRAME!!!!!![M1]
DLL-ul devine parte din programul in executie si este incarcat in aceeasi
adresa de memorie, adica pe stiva programului pe care trec si
parametrii, deoarece DLL-ul nu are o stiva de memorie proprie.
b) Mecanismul DLL-urilor dinamice
Doar la rulare se incarca DLL-ul in memorie, este cautata functia (se presupune cunoscut numele acesteia) si apoi este apelata.
Þ cod mai complex + timp mai mult pentru gasirea functiei.
Insa metoda se executa la fel de repede precum DLL-ul ar fi incarcat implicit.
Pe de alta parte, nu este necesara prezenta DLL-ului pentru a se lansa in executie programul (spre deosebire de cealalta metoda, unde mai inatai este incarcata libraria, apoi se incepe rularea aplicatiei).
In [M2]cea mai mare parte un DLL si un fisier EXE au aceeasi structura interna, ambele fiind fisiere executabile.
Un DLL, chiar si incarcat in memorie nu este un program in executie, ci este doar o colectie de functii si proceduri ce pot fi apelate de alte programe.
Aceste functii si proceduri utilizeaza stiva programului ce le apeleaza.
In Win32, deoarece un DLL este incarcat pe stiva programului apelant, orice alocare de memorie sau date globale create au viata doar in spatiul aplicatiei principale (procesului principal).
Motivele pentru care sunt folosite librariile sub Windows pot fi:
a) daca programe diferite utilizeaza acelasi DLL acesta este incarcat in memorie o singura data. DLL-urile sunt mapate in spatiul fiecarui proces ce le utilizeaza, dar codul acestuia este incarcat o singura data;
b) se pot realiza versiuni noi ale librariei, inlocuindu-le pe cele anterioare. Daca subrutinele din DLL au aceeasi parametri, atunci programul poate fi rulat pe baza noii librarii fara a fi necesara recompilarea sa. Daca noul DLL vine cu noi subrutine, nu afecteaza aplicatiile ce foloseau versiunea veche, doar daca in noua versiune lipseste o subrutina in comparatie cu versiunea anterioara. Probleme apar si atunci cand noua librarie nu implementeaza metodele intr-un mod compatibil cu vechea versiune.
Aceste avantaje generice se aplica in diverse cazuri. Daca este vorba despre o aplicatie complexa, cu forme/algoritmi utilizabili si de alte programe atunci acestea pot fi stocate in DLL-uri, reducand dimensiunea executabilului si in acelasi timp utilizand memoria interna intr-un mod mai eficient.
Un al doilea avantaj apare in cazul aplicatiilor medii, mari si foarte mari. Prin divizarea programului in mai multe DLL-uri. Astfel devine mai usoara distribuirea update-urilor sau rezolvarea unor bug-uri. Astfel se distribuie doar portiunea modificata, nu intreaga aplicatie. De exemplu: cand Microsoft pune pe piata noi update-uri nu este nevoie de recompilarea intregului cod.
O alta utilizarea a DLL-urilor este aceea pentru a stoca resurse: imagine, iconite - utilizate ulterior in diferite aplicatii. Sau, in librarii
se pot stoca stringuri pentru diverse limbaje de programare si apoi schimba limbajul in momentul rularii.
De asemenea, DLL-urile sunt independente de limbajul de programare. O librarie scrisa in Delphi poate fi utilizata si de programe scrise in alte limbaje de programare (Visual Basic, Excel,.)
DLL-urile de sistem Windows profita de avantajele oferite de aceasta tehnica de programare. S.O. are numeroase librarii de sistem, dar nucleul Windows este realizat de Kernel, User si GDI, ce sunt implementate utilizand mai multe DLL-uri. Altele sunt extensii ale S.O. precum uzualele ferestre de dialog, OLE, drivere, font+uri, controlere ActiveX.
Astfel toate programele utilizeaza DLL-uri.[2]
Este importanta versiunea pentru care a fost creata aplicatia. Daca afost scrisa pentru Windows95, cu siguranta va functiona si pe Millenium sau chiar versiuni mai recente, insa se va comporta diferit.
Exista cateva reguli de baza in vederea scrierii librariilor dinamice pentru a putea fi corect utilizate.
Astfel o functie sau procedura implementata intr-un DLL trebuie sa respecte urmatoarele principii:
trebuie sa fie trecuta in declaratia: exports. Acest lucru face rutina vizibila din exterior;
functiile exportate trebuie a fi declarate ca stdcall pentru a utiliza standardul Win32 in vederea compatibilitatii parametrilor, spre deosebire de tehnica optimizata registred - implicita in Delphi;
tipul parametrilor sa fie si tip de baza in Windows, altfel este probabil ca alte aplicatii sa nu poata utiliza DLL-ul scris;
o librarie poate avea date globale care nu vor fi transmise catre aplicatia principala.
Plasarea unor functii si proceduri intr-un DLL este o abordare aproape traditionala in programare, deoarece nu se pot exporta clase si obiecte. Exceptia o constituie utilizarea tehnologiei Microsoft COM sau alte tehnologii avansate.
Crearea librariilor devine utila atunci cand un cod este supus modificarilor foarte dese. De asemenea, cand un program trebuie sa ofere facilitati diferite in functie de clienti, atunci se pot programa versiuni diferite de librarii, pentru fiecare grup de clienti o versiune specifica nevoilor acestora.
1) Problema: min/max -> este rezolvata in Help-ul Delphi.
2) Problema: se da ca parametru un numar intreg nr si sa se implementeze doua functii: pentru dublul si, respectiv, triplul numarului dat ca paramentru.
Elementele cheie din scrierea unui DLL se vor exemplifica pe urmatorul cod Delphi:
library TestINT;
uses
SysUtils,
Classes;
function Double(x:Integer):Integer; stdcall;
begin
Result:=2*x;
end
function Triple(x:Integer):Integer; stdcall;
begin
Result:=3*x;
end
exports
Double name 'Double',
Triple name 'Triple';
end
Dupa cum am amintit si mai devreme, librariile pot fi manipulate in doua moduri: static[3] sau dinamic .
Astfel se vor prezenta doua secvente de cod: prima in care DLL-ul este necesar ca aplicatia sa ruleze si in al doilea caz cand acesta este incarcat doar in momentul utilizarii unei metode.
Codul DLL-ului nu se modifica cu nimic, ceea ce difera este doar modul in care este manipulat.
!Remeber
In vederea intelegerii celei de-a doua metode sunt necesare cunoasterea unor notiuni precum: pointeri, pointeri catre functii, etc.
Secventele de cod se vor referii doar la utilizarea efectiva a librariei, motiv pentru care acestea vor fi prezentate cat mai generic.
Utilizarea statica:
function Double(X:Integer):Integer;stdcall;external 'TestINT.DLL';
function Triple(X:Integer):Integer;stdcall;external 'TestINT.DLL';
procedure TForm1.ButtonDoubleClick(Sender: TObject);
var nr:Integer;
begin
nr:=StrToInt(Edit1.Text);
nr:=Double(nr);
ShowMessage('Dublul numarului '+Edit1.Text+' este: '
+ IntToStr(nr));
end
procedure TForm1.ButtonTripleClick(Sender: TObject);
var nr:Integer;
begin
nr:=StrToInt(Edit1.Text);
nr:=Triple(nr);
ShowMessage('Triplul numarului '+Edit1.Text+' este: '
+ IntToStr(nr));
end
Utilizarea dinamica:
procedure TForm1.ButtonDoubleClick(Sender: TObject);
const DllName='TestINT.DLL';
type TintFunction=function (I:Integer):Integer;stdcall;
var nr:Integer;
HInst:THandle;
FPointer:TFarProc;
MyFunction:TIntFunction;
begin
HInst:=SafeLoadLibrary(DllName);
if(HInst>0)then
try
FPointer:=GetProcAddress(HInst,PChar('Double'));
if FPointer<>nil then
begin
MyFunction:=TIntFunction(FPointer);
nr:=StrToInt(Edit1.Text);
//Label1.Caption:=IntToStr(MyFunction(nr));
ShowMessage('Dublul numarului '+Edit1.Text+' este: '
+ IntToStr(nr));
end
else
ShowMEssage('DLL function not found');
finally
FreeLibrary(HInst);
end
else
ShowMEssage(DllName+' library not found.');
end
Incarcarea dinamica a unei librarii se petrece prin apelarea metodei LoadLibrary -functie API care cauta DLL-ul in folder-ul programului si in subfolderele sistem indicate. Daca libraria nu este gasita, S.O. va da un mesaj de eroare. In loc de metoda amintita se poate utiliza procedura SafeLoadLibrary ce are un efect similar, dar cu diferenta ca nu mai permite generarea mesajului de eroare de catre S.O. fiind solutia indicata pentru manipularea DLL-urilor..
Daca DLL-ul a fost gasit, atunci poate fi apelata functia API GetProcAddress ce cauta in tabela de export a librariei metoda a carui nume a fost dat ca parametru. Daca este identificata o asemenea metoda in DLL, atunci este returnat un pointer catre functia/procedura solicitata din DLL. Acum se poate executa o operatie de casting asupra pointerului de functie la tipul corespunzator pentru a fi apelata.
Indiferent daca a fost gasita metoda sau nu, este necesar sa executam o operatiune de eliberare din memorie a DLL-ului.
Dar cum apelam o procedura odata ce avem un pointer la ea?
O solutie ar fi sa o convertim la un tip procedural si apoi sa o apelam utilizand tipul procedural. Atentie: este necesar ca tipul definit sa fie compatibil cu metoda din librarie. Calcaiul lui Ahile: nu sunt verificate tipurile parametrilor.
Totusi, aceasta modalitate de apelare are si avantaje. Teoretic se poate apela orice metoda din orice librarie in orice moment. In practica devine utila atunci cand avem mai multe metode compatibile (din punctul de vedere al tipurilor parametrilor). De exemplu, putem citi efectiv numele metodei ce o vom apela intr-un simplu Edit box. Aceasta operatiune nici macar nu impune recompilarea codului.
DLL-ul este incarcat in memorie doar atunci cand trebuie apelata un din metodele acestuia, astfel este posibil ca noi insine sa selectam ce librarie sa utilizeze programul pe parcursul rularii acestuia. Observati cat de dinamic si flexibil poate fi acest procedeu. La rulare aplicatia poate opta in utilizarea unei anumite librarii, fapt ce nu se poate intampla si in cazul utilizarii statice. MS Word este un exemplu in acest sens.
Doar un limbaj de programare dotat cu link editor si compilator , precum Delphi, poate opta pentru prima varianta de apelare a DLL-urilor, care este mai sigura, mai rapida si in unele cazuri extrem de puternica.
Putem pune in evidenta cu urmatorul cod faptul ca un DLL este incarcat in memorie o singura data:
procedure TForm1.Button3Click(Sender:Tobject);
var HDLLInst: Thandle;
begin
HDLLInst:=SafeLOadLibrary('dllMEM.dll');
Lable1.Caption:=Format('Adress: %p',[GetProcAddress(HDLLInst,
'SetData')]);
FreeLibrary(HDLLInst);
end;
Daca este incarcat o singura data in memorie codul unui DLL, nu la fel se intampla si cu datele globale. Libraria are o copie a datelor pe stiva fiecarei aplicatii ce o utilizeaza. Totusi, este posibil ca datele globale sa fie accesibile tuturor aplicatiilor ce utilizeaza acelasi DLL prin implementarea unor tehnici. Cea mai des utilizata (tehnica) este utilizarea fisierelor mapate in memorie, dar este posibila si tranzactionarea de date direct de la o aplicatie la alta.
//Libraria dinamica
library dllMEM;
uses
SysUtils,
DllMemU in 'DllMemU.pas';
exports
SetData, GetData,
GetSharedData, SetSharedData;
end
//Unit-ul DllMemU.pas
var PlainData: Integer = 0; //not shared
ShareData: ^Integer; //shared data
procedure SetData (I: Integer); stdcall;
begin
PlainData := I;
end
procedure SetShareData (I: Integer); stdcall;
begin
ShareData^ := I;
end
Codul pentru maparea fisierelor in memorie:
Var hMapFile: Thandle;
const VirtualFileNam='ShareDLLData.dll';
DataSize=sizeof(Integer);
initialization
//create meory mapped file
hMapFile:=CreateFileMapping($FFFFFFFF, nil, Page_ReadWrite, 0, DataSIze, VirtualFileName);
if hMapFile=0 then
raise Exception.Create('Error creating memory-mapped file');
//get the pointer to the actual data
ShareData := MapViewFileOf(hMapFile, File_Map_Write, 0, 0, DataSIze);
Sectinea de finalizare :
finalization
UnmapViewOfFile (ShareData) ;
ClsoeHandle (hMapFile);
CreateFileMapping -> nume_fisier, atribute de securitate si protectie, dimensiunea fisierului, un nume intern.
MapViewOfFile -> handler-ul pentru fisierul mapat , atribute., dimensiunea fisierului.
Intr-un DLL se poate stoca chiar si o forma, utilizabila ulterior de alti programatori in diverse limbaje.
Cea mai simpla abordare este aceea sa avem o singura metoda pentru creare, initializare si rulare. Importanta este structura metodelor deoarece este recomandat ca acestea sa fie incadrate de blocuri try-except si inca un bloc try-finally pentru protectia operatiei ce trebuie executata.
Structura unei astfel de librarii este urmatoarea:
library FormDLL;
uses
<Nume_unit> in 'Nume_unit.pas' ;
exports
end
Atentie!
-este important daca forma se va afisa ca modala sau nu.
In Delphi pachetele de componente reprezinta un tip important de DLL. Sunt deosebit de utile, deoarece in momentul cand o componenta din pachet sufera o modificare este suficienta distribuirea unui fisier patch, unde sunt salvate doar modificarile aduse pachetului si nu trebuie distribuit intreg pachet.
De asemenea nu pot fi utilizate DLL-uri atunci cand este vorba de aplicatii VisualCLX. Solutia o constituie utilizarea pachetelor, unde sunt permise aceste componente.
VisualCLX,
Cross-platform GUI components and graphics classes. VisualCLX classes make use of an underlying cross-platform widget library (Qt).
[M1] Posibila intrebare pentru cei din sala: relatia dintr DLL si programul lansat in executie poate fi caracterizata precum una dintre doua programe sau nu ?
[M2]Este posibila chiar sa fie ceruta o comparatie intre un DLL si un EXE. (asemanari si deosebiri)
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1794
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved