|
celor doua biblioteci,editati o aplicatie de genul
|
səhifə | 9/18 | tarix | 12.09.2018 | ölçüsü | 1,36 Mb. | | #81721 |
| celor doua biblioteci,editati o aplicatie de genul:
#include
#include
#include
main()
{
cout << "Maximum dintre 12 si 7 este: "<
cout << "Minimum dintre 12 si 7 este: "<
getch();
return 0;
}
-54-
O alta metoda destul de practica este cea prin care biblioteca statica
realizeaza atat exportul cat si importul datelor din fila DLL.Pentru
acest scop,in fila DLL se declara o variabila oarecare cu ajutorul careia
biblioteca statica va putea face distinctia dintre fila DLL si fila
aplicatie.Daca variabila este definita,biblioteca va exporta datele iar
daca variabila nu este definita biblioteca va importa datele:
EXEMPLU: (vezi si directorul DLLTest3)
In acest caz,primul pas este reprezentat de editarea filei header:
//Test3.h
#ifdef MODULDLL
#define IMPEXP __declspec(dllexport)
#else
#pragma comment(lib,"DLL3.LIB")
#define IMPEXP __declspec(dllimport)
#endif
IMPEXP int fnTest(int a);
Salvati fila cu numele Test3.h in directorul INCLUDE.
In rest se procedeaza identic,dar fila dll3.cpp va arata astfel:
#define MODULDLL
#include
IMPEXP int fnTest(int a){ a=a+33; return a;};
int WEP(int b)
{
b=1;
return b;
};
Iar fila .cpp din aplicatia test3.cpp va arata astfel:
#include
#include
#include
main()
{
cout << "text \n";
int b;
b=fnTest(15);
cout << "Functia fnTest() returneaza: " << b;
getch();
return 0;
}
Observati ca in loc de "_export" s-a utilizat: "__declspec(dllexport)" iar
in loc de "_import" s-a utilizat: "__declspec(dllimport)".
Pentru versiunile noi,cele doua cuvinte cheie au fost inlocuite prin
formulele de mai sus,care asigura o mai buna compatibilitate cu formatul
de 32 de biti.Pentru toate DLL-urile Windows si pentru cele nou create
se recomanda utilizarea acestor formule.Cuvintele cheie vor fi rezervate
doar pentru compatibilitatea cu programele mai vechi.
Asadar,cele doua tipuri de biblioteci pot fi combinate cu succes pentru
a beneficia de avantajele oferite de fiecare tip in parte.
Exemplele de mai sus,ofera doar o imagine simplista a modului in care
se pot crea sau apela diversele tipuri de biblioteci.Solutia optima de-
pinde de necesitatile programului si de experienta programatorului.
-55-
Adevaratele probleme apar atunci cand se utilizeaza mai mult decat o
singura biblioteca DLL.Fiecare biblioteca DLL,in momentul in care este
"linkata" la o aplicatie,creaza un fel de "spatiu virtual" in care toate
elementele exportabile sunt vizibile in mod egal.Daca in doua sau mai
multe biblioteci DLL exista date care au fost denumite cu acelasi iden-
tificator,apar fenomene de supraincarcare sau conflicte de identificator.
Daca nu detineti fila sursa a tuturor filelor DLL,depanarea unui astfel
de program este extrem de dificila sau chiar imposibila.Acest gen de
situatie a fost denumit "DLL HELL" (infernul DLL-urilor).In aceste situ-
atii,in timpul executiei se va returna fie un mesaj de eroare,fie o
valoare eronata preluata din prima biblioteca linkata in care exista o
definitie valabila.In plus,alocarea de memorie de operare se va face dupa
un alt algoritm decat cel proiectat si pot interveni diverse tipuri de
incompatibilitati,suprascrieri,supraincarcari etc.Din acest motiv este
bine sa nu utilizati file DLL pentru care nu detineti si fila sursa,
sa nu utilizati excesiv de multe file DLL in spatiu de memorie limitat,
sa verificati cu atentie memoria libera in urma fiecarui apel posibil,din
fiecare fila,cat si al tuturor combinatiilor posibile de apel intersectat
al mai multor biblioteci.Acest gen de programare,incepe sa semene tot
mai mult cu un joc de tipul "PronoExpres" si nu se recomanda decat celor
cu notiuni avansate de gestionare a memoriei.Lucrurile se simplifica
foarte mult daca utilizati programe automate de gestioanre si analiza a
memoriei.Acest gen de programe vor apela si evalua toate apelurile posi-
bile si vor semnala eventualele incompatibilitati.Regula de aur este urma-
toarea: " nu va lansati in operatii pe care nu puteti sa le controlati cu
resursele proprii".O solutie extrem de simpla pentru evitarea conflictelor
de identificator este sa utilizati spatii denumite ("namespace") in edita-
rea bibliotecilor.In acest fel,puteti avea un spatiu special pentru toate
bibliotecile DLL editate de d-voastra,care nu va interfera cu celelalte
biblioteci DLL programate de alti programatori.Pentru importul datelor
utilizati si formula "using namespace NUMELE" (vezi si inceputul capito-
lului).Visual C++ utilizeaza un astfel de spatiu standardizat denumit
std.Pentru aplicatiile d-voastra puteti utiliza un astfel de standard,cu
un numa cat mai discriminativ (eventual numele si prenumele personal).
Nu va lansati in procese sofisticate de "depanare" a filelor DLL cu
provenienta nesigura sau necunoscuta.Daca exista orice fel de suspiciuni
este mai usor sa abandonati biblioteca respectiva si sa editati una noua.
Atunci cand actualizati o fila DLL,trebuie sa aveti in vedere ca mo-
dificarea efectuata va interesa toate aplicatiile care utilizeaza fila
respectiva.De cele mai multe ori,este preferabil sa pastrati fila veche
si a creati si o noua fila care contine toate modificarile necesare.Astfel
fiecare aplicatia va putea apela fila DLL necesara.
Daca realizati si distribuiti biblioteci DLL,este bine sa distribuiti si
fila sursa (fila .cpp din care a fost creata).Este un obicei bun sa ada-
ugati fila .cpp in proiect,impreuna cu fila dll.dll (la fel ca in exemple-
le prezentate).De obiecei fila sursa este destul de mica si nu ocupa prea
mult spatiu.Nu este bine sa includeti file header in filele DLL decat daca
este absolut necesar.Nu are rost se creati o fila DLL de tip Windows in
care sa includeti fila "windows.h" doar pentru a defini o clasa sau o
functie care realizeaza operatii elementare.Fiecare byte conteaza.Fila DLL
poate contine insa,nelimitate operatii cu vizibilitate locala.
-56-
Fila de tip DLL se compileaza si se construieste la fel ca orice fila
executabila.Exista si biblioteci cu legare dinamica,care au alta extensie
decat .DLL(Exemple: .EXE sau .drv).Pentru aplicatiile Windows,filele DLL
pot fi incarcate si explicit,cu functia LoadLibrary(),urmata de GetProc-
Address() pentru a obtine adresa functiei dorite si de FreeLibrary()
pentru eliberarea memoriei.
Biblioteca DLL poate contine functii interne si poate sa execute o
serie de operatii,la fel ca orice program executabil.Nu se recomanda
utilizarea acestei facilitati decat pentru operatii indispensabile.In
restul situatiilor,se pot utiliza module de program independente,care pot
fi puse in executie cu functii usor de apelat (fara incarcarea memoriei):
EXEMPLU WINDOWS: (vezi si cplus36.cpp)
#include
#include
#include
main()
{
WinExec("cplus2.exe",5);
getch();
return 0;
}
EXEMPLU C++ : (vezi si cplus37.cpp)
#include
#include
#include
main()
{
cout << "text din fila cplus37 \n";
cout << "urmeaza apelul modulului cplus2.exe: \n";
system("cplus2.exe");
getch();
return 0;
}
Pentru programele recente,se recomanda utilizarea functiilor moderne,gen
CreateProcess(),etc.
Bibliotecile DLL pot fi utilizate pentru a arhiva filele de resurse.
In acest caz,la crearea proiectului se va utiliza AddNode pemtru a include
in proiect toate filele de tip .RC necesare.Dupa compilare,rezulta o fila
DLL.Fila DLL poate fi manipulata monobloc,pentru a asigura toate resursele
necesare pentru interfata grafica: meniuri,icons,imagini,sunete etc.
O alta aplicatie frecventa o reprezinta suportul multilingual.Pentru
fiecare limba oferita se distribuie si fila DLL necesara,in care sunt
incluse toate particularitatile versiunii respective.
In mod similar,se creaza si distribuie resursele software necesare
pentru implementarea si exploatarea unor resurse hardware.In acest caz,
de obicei filele vor avea extensia .drv,dar exista si drivere cu extensia
clasica .dll.
O privire sintetica asupra acestui capitol,atrage atentia asupra posi-
bilitatilor de suprastructurare a aplicatiilor si programelor realizate de
d-voastra.Prezentarea nu este exhaustiva,este doar un pretext pentru a va
stimula dorinta de a lectura si alte manuale de specialitate.
-57-
BIBLIOTECA OWL (Object Windows Library)
Biblioteca OWL contine un set de 125 de file header,in care sunt defi-
nite clase si constante,utile pentru a realiza programe si aplicatii ce
utilizeaza o intefata grafica formata din obiecte de tip Windows.OWL este
o alternativa pentru API-Windows (API exploateaza fila windows.h).
Biblioteca OWL nu este prezenta in toate versiunile de C++.In Visual C++
a fost inlocuita prin MFC(Microsoft Foundation Classes) iar in versiunea
C++ Builder a fost inlocuita prin VCL(Visual Component Library).
In esenta,toate aceste variante realizeaza acelasi lucru: definesc o
serie de clase,din care se vor deriva obiectele necesare pentru a realiza
o interfata grafica.Fiecare obiect,detine unul sau mai multi constructori,
un destructor si o serie de metode proprii specializate.
Versiunea Borland C++ 5.A,nu contine explicatii destul de clare despre
modul in care poate fi utilizata aceasta biblioteca,dar contine o serie
destul de bogata de exemple si programe si un tutorial destul de clar (in
directorul Examples/Owl).Exemplele si obiectele nu sunt compilate si
link-ate.Pentru a putea utiliza aceste exemple,deschideti proiectul,apoi
construiti fiecare nod cu BuildNode(click drept de mouse) si in final
asigurati legaturile dintre modulele componente executand un click de
mouse drept pe fila de tip .exe si selectand optiunea Link.Executati apoi
fiecare exemplu si aplicatie sau program si observati modul in care au
fost realizate.Fiecare dintre aceste exemple si programe poate reprezenta
punctul de plecare pentru un program realizat de d-voastra.Un tutorial
foarte bun si o serie de informatii utile despre OWL se gasesc si la
adresa: http://owlnext.
Cea mai simpla aplicatie posibila este deschiderea unei ferestre de tip
Windows:
EXEMPLU: (vezi si OWL_ABC / owl1)
Deschideti un nou proiect,cu New si Project.Eliminati fila .rc si cea .def
cu DeleteNode,apoi adaugati cu AddNode fila default.def din directorul
LIB si o fila de tip .rc care contine urmatorul text:
#include
#include
#include
Apoi deschideti fila de tip .cpp si introduceti urmatorul text:
#include
#include
int
OwlMain(int, char* [])
{
return TApplication("Titlul Ferestrei !").Run();
}
Compilati,construiti nodul cu build node,apoi selectati fila .exe,constru-
iti nodul cu Build Node si adigurati legaturile cu Link (dupa click drept
de mouse).Proiectul este finalizat si poate fi executat.
Un exercitiu identic este si la adresa Examples\Owl\Apps\Hello.
Puteti utiliza direct exercitiul "Hello" ca punct de pornire.Nu trebuie
decat sa schimbati textul pentru titlul ferestrei.In general,nu trebuie
sa evitati sa folositi modulele realizate anterior.
-58-
Daca analizam putin exemplul de mai sus,observam ca include doua file
header,dupa care apeleaza functia Run() pentru un obiect de tip TAppli-
cation(functia Run() apeleaza constructorul clasei,care realizeaza un
obiect din tipul respectiv).
Biblioteca contine definita clasei TApplication.Nu
exista in manualul Help o descriere a claselor de obiecte din OWL,astfel
incat va trebui sa va obisnuiti sa lucrati direct cu fila header,sau sa
extrageti pe niste planse toate obiectele impreuna cu definitia lor.
Daca deschideti fila "applicat.h" (din INCLUDE\OWL) observati ca printre
alte definitii,contine si definitia pentru clasa TApplication.
In rezumat,definitia este cam asa:
class _OWLCLASS TApplication : virtual public TEventHandler
public Tmodule
public TMsgThread
{ public:
TApplication( ...parametrii primului constructor...);
TApplication( ...parametrii constructorului secund...);
~TApplication();
....o serie de functii Get si Set
CanClose();
Run();
Start();
}
Asadar,clasa TApplication mosteneste clasele TEventHandler,TModule si
TMsgThread,are doi constructori,un destructor si o serie de metode,dintre
care se disting: Run(),CanClose() si Start().
Nu este o regula absoluta,dar foarte multe programe au ca punct de
pornire un obiect derivat in clasa TApplication,deoarece prin simpla
apelare a metodei Run() se va apela automat si constructorul implicit al
obiectului.Daca doriti,puteti sa nu utilizati un astfel de obiect,dar
in acest caz va trebui sa apelati explicit fiecare constructor,sa faceti
toate operatiile de initializare si sa gestionati singur si toate opera-
tiile de eliberare a memoriei.Obiectul TApplication,prin destructorul
implicit asigura si eliberarea automata a memoriei.
Observati ca fila "applicat.h" a inclus automat in memorie si filele
header , si necesare
pentru derivarea clasei Taplication si respectiv
necesara pentru definitile generice ale optiunilor de compilare.
Cealalata fila header include automat fila .
Fila "owlcore.h" incarca in memorie principalele file necesare pentru o
aplicatie obisnuita(adica defs.h,module.h,applicat.h,dc.h,menu.h,window.h
mdi.h,mdichild.h,decmdifr.h,dialog.h,control.h).
Pentru exemplul de mai sus,aceste clase nu sunt necesare,astfel incat
se poate renunta la ele.Fila header a fost inclusa in acest
exemplu doar pentru a va atrage atentia ca exista si aceasta optiune.
Fila "pch.h" este foarte comoda,atunci cand incepeti editarea unui proiect
si nu stiti inca exact ce anume doriti sa faceti.Pentru a evita consulta-
rea permaneta a tuturor filelor,puteti utiliza aceasta optinue,sau respec-
tiv fila "owlall.h> care incarca toate filele din biblioteca OWL.Dupa
ce proiectul este finalizat,puteti sa alegeti cu strictete doar filele
strict necesare,astfel incat executabilul construit sa fie cat mai mic.
-59-
Daca va place sa gestionati singur memoria,renuntati la si
includeti doar filele strict neceare.Construiti executabilul si faceti
comparatia pentru volumul de memorie consumata.Pentru programele mari,
difernta va fi din ce in ce mai nesemnificativa si va fi mai simplu sa
apelati direct "owlall.h".Decizia este in functie de dimensiunea memoriei
de RAM a hard-ului instalat si in functie de importanta programului,sau
in functie de mediul de operare in care lucrati (ce alte programe ruleaza
in paralel).Pe cat posibil se va cauta intotdeauna solutia cea mai eco-
nomica (mai ales daca utilizati mai multe programe in paralel).
Primul program,este extrem de simplu,dar nu lasa prea mult loc pentru
dezvoltare.Se pot utiliza si functiile Start() pentru a efectua o serie
de operatii pregatitoare inainte de a apela constructorul,sau respectiv
CanClose(),pentru a executa o serie de operatii inainte de a apela des-
tructorul.Prin inchiderea ferestrei(cu butonul x),destructorul este
apelat automat si se efectueaza eliberarea automata a memoriei.
Pentru a putea introduce o serie intrega de functii si proceduri noi,
fereastra generata automat de catre constructorul implicit trebuie sa
fie redefinita.Pentru acest scop se va deriva o clasa de tip TFrameWindow
in care se pot apoi introduce procedurile specifice:
EXEMPLU: (vezi si OWL_ABC / owl2 )
Deschideti un proiect nou,ca mai sus,dar in fila .cpp introduceti un text
de genul:
#include
#include
#include
class Fer1 : public TWindow {
public:
Fer1(); };
Fer1::Fer1() : TWindow(0,0,0) { };
class Aplicatie1 : public TApplication {
public:
Aplicatie1() : TApplication() { };
void InitMainWindow();
};
void Aplicatie1::InitMainWindow()
{
MainWindow = new TFrameWindow(0,"Test",new Fer1);
}
int
OwlMain(int, char* [])
{
return Aplicatie1().Run();
}
Compilati,construiti si executati.Rezultatul este identic cu cel din exer-
citiul precedent,adica o fereastra simpla de tip Windows.De aceasta data
insa am materializat un obiect din clasa TApplication si am utilizat o
clasa denumita Fer1,derivata din TWindow,la care am redefinit constructo-
rul.Apoi am utilizat functia InitMainWindow pentru a deschide o fereastra
de tipul Fer1,cu ajutorul constructorului implicit al obiectului de tip
TApplication.Constructia pare complicata,dar este foarte prcatica pentru
redefinirea proprietatilor ferestrei in care vom executa operatii.
-60-
Deschideti fila "framewin.h" si observati definitia pentru clasa _OWLCLASS
TFrameWindow (are un numar foarte mare de metode implicite).
Fila a fost inclusa automat de ,dar a fost
specificata si explicit pentru a va atrage atentia asupra acestei file.
In continuare,se pot defini noi metode pentru fereastra Fer1.
EXEMPLU: (vezi si OWL_ABC / owl3)
Deschideti un nou proiect,iar in fila .cpp introduceti un text de genul:
#include
#include
#include
#include
class Fer1: public TWindow {
public:
Fer1();
void EvLButtonDown(uint, TPoint&);
void EvRButtonDown(uint, TPoint&);
DECLARE_RESPONSE_TABLE(Fer1); };
DEFINE_RESPONSE_TABLE1(Fer1,TWindow)
EV_WM_LBUTTONDOWN,
EV_WM_RBUTTONDOWN,
END_RESPONSE_TABLE;
Fer1::Fer1():TWindow(0,0,0) { };
void Fer1::EvLButtonDown(uint,TPoint& point)
{
TClientDC dc1(*this);
dc1.Rectangle(point.x-50,point.y-50,point.x+50,point.y+50);
dc1.TextOut(point,"Text:",5);
};
void Fer1::EvRButtonDown(uint,Tpoint&)
{
MessageBox("Butonul drept a fost apasat !","Text:",MB_OK);
};
class Aplicatie1 : public TApplication {
public:
Dostları ilə paylaş: |
|
|