Sunteți pe pagina 1din 26

Programare Distribuit Lucrarea de laborator Nr.

Dezvoltarea unei aplicaii distribuite n tehnologia Microsoft COM


1. Tehnologia COM

Tehnologia COM (Component Object Model) a fost dezvoltat de firma Microsoft pentru
programare distribuit i prin componente reutilizabile. COM este un standard care prevede modul de
comunicaie ntre componente (obiecte) care pot fi localizate n aceeai staie sau distribuite n reea.
Varianta cu obiecte distribuite n reea se mai numete DCOM (Distributed Component Object
Model). n modelul COM, o component reutilizabil se numete obiect COM i este o pies de cod
(binar) care poate fi folosit de aplicaii client prin apelul metodelor suportate de obiectul respectiv.
Metodele unui obiect COM sunt prevzute prin intermediul unor interfee binare, care trebuie s fie
respectate de toate componentele aplicaiei. Chiar dac folosete termeni din programarea obiect-
orientat (obiecte, metode, interfee), standardul COM este independent de limbaj i se pot crea
obiecte COM sau aplicaii care le utilizeaz n diferite limbaje (C, C++, Visual Basic, etc).

2. Servere COM

Un server COM este un program care implementeaz clasele (coclasses) i interfeele COM.
Un server COM poate fi definit ntr-una din trei configuraii de baz:
Server in-process, sau server DLL.
Server independent (stand-alone, sau out-of-process) care este un program executabil
(.exe)
Server pe baza unui serviciu Windows.
Servere COM out-of-process. n
acest mod de execuie, serverul COM este un Server COM
program executabil (.exe) care se execut
ntr-un spaiu de adrese diferit de spaiul de Int
adrese al procesului client, eventual pe alt
calculator, i el se ocup cu crearea obiectului Client COM
Obiec
COM (alocare spaiu de memorie i lansare n t COM
execuie). (Fig. 5.1). Apelurile funciilor
interfeelor COM sunt gestionate prin
mecanisme de comunicaie inter-proces. Dac
serverul COM este plasat pe un alt calculator
dect calculatorul pe care se afl programul Fig. 5. 1. Server COM out-of-process
client, atunci serverul se numete server
DCOM (Distributed COM). Pornirea i oprirea serverelor independente se face prin serviciul SCM
(Service Control Manager) al sistemului de operare Windows.

3. Crearea unei aplicaii COM cu server independent

Obiectele COM pot fi create n diferite limbaje (C, C++, Visual Basic). Pentru crearea lor n
C++, Microsoft a pus la dispozitie o nou bibliotec, numit ATL (Active Template Library) i un
generator de aplicaie cadru (ATL COM App Wizard), integrate n mediul de programare MSVC.
Biblioteca ATL conine clase template care sunt folosite pentru crearea claselor de proxy-stub ale
fiecrui server. Pentru crearea unui server folosind ATL COM App Wizard se parcurg mai multe
etape, descrise pe rnd in seciunile care urmeaz.

1
3.1 Crearea proiectului ATL

n mediul de dezvoltare MSVC se creaz un nou spaiu de lucru (workspace) i un nou proiect
cu comenzile New-Project-ATL COM App Wizard, cu numele IonescuServer. Se selecteaz
opiunea Server Type: Executable (.exe).
n aceast faz proiectul conine, n principal, fiierul de implementare
IonescuServer.cpp care va conine codul serverului i fiierul de descriere a interfeelor
IonescuServer.idl care conine doar numele i GUID-ul pentru biblioteca de tip (Type
Library) a serverului.
Identificatorii unici ai obiectelor COM, GUID (Globally Unique Identifier) se reprezint, de
obicei, n notaie hexazecimal. Deoarece nu exist (n nici unul din limbajele standard) un tip de date
fundamental care s reprezinte un numr de 128 de bii, se folosete un tip de date derivat, de exemplu
o structur n C sau C++.

typedef struct _GUID {


unsigned long Data1;unsigned short Data2;unsigned short Data3;
unsigned char Data4[8];} GUID;

Felul n care sunt grupai biii (n patru cmpuri) nu prezint prea mare importan deoarece
identificatorii GUID sunt manevrai n totalitate, nu membru cu membru, dar explic modul n care
sunt afiai acestia, ca de exemplu:
"B626D3CD-865F-11D4-BBB3-444553540000"
n identificatorul de mai sus, prima parte este Data1 (unsigned long); a doua i a treia parte
(unsigned short) sunt Data2 i, respectiv Data3; vectorul de 8 caractere Data4 este reprezentat n dou
pari, primele 2 caractere, linie de separare, urmat de ultimele 6 caractere.
Att obiectele COM ct i interfeele COM au cte un identificator GUID (numite CLSID,
respectiv IID n implementarea C++ a componentelor).

3.2 Definirea obiectelor COM, a interfeelor i a metodelor.


Se folosete pagina View->ClassView a spaiului de lucru (Workspace) i, cu mouse-ul
poziionat pe articolul IonescuServer, se apas pe butonul din dreapta i se selecteaz articolul Add...-
>Class.... Ca rezultat se deschide dialogul Add Class - IonescuServer, care permite definirea unui
obiect COM (ATL Simple Object). Termenul de "object" este oarecum incorect, deoarece nu se
definete un obiect COM, ci clasa acestuia (coclass), din care se va instania un obiect COM la
lansarea n execuie a serverului.
n dialogul ATL Simple Object Wizard se selecteaz pagina Names a acestui dialog si se
completeaz C++ Short Name : Ionescu. Pagina Names este o bun reprezentare a echivalenei dintre
descrierea IDL a obiectului COM (jos) i clasele de implementare n C++ a obiectului (sus).

2
n tehnologia COM, o clas COM (numit coclass) poate avea una sau mai multe interfee; fiecare
interfa are un nume i grupeaz mai multe funcii (metode). Un obiect COM este o instan a unei
coclass i poate fi accesat numai prin intermediul interfeelor sale. Interfeele sunt definite n MIDL
i ele izoleaz complet clienii de serverele pe care le acceseaz precum i declaraiile funciilor
intefeelor de impementarea acestora. Aceast izolare permite crearea i (re)utilizarea componentelor.
Limbajul MIDL (Microsoft Interface Definition Language) este limbajul de descriere a
interfeelor COM. Acesta definete propriile tipuri de date i, n plus fa de limbajele de programare
obinuite, definete atribute ale parametrilor metodelor, atribute care sunt necesare operaiei de
transfer (marshaling) al parametrilor.
Interfeele COM se definesc n limbajul MIDL, iar compilatorul MIDL transform definiia
MIDL a metodelor n definiia acestora n limbajul de implementare (C sau C++). Dac programul
client este implementat n C sau C++, prototipurile metodelor interfeelor sunt introduse prin
includerea fiierului header al serverului. Dac se utilizeaz componente COM n programe scrise n
alte limbaje (de exemplu Visual Basic), atunci se folosete biblioteca de tip a serverului (type library)
care conine informaii despre metodele intefeelor, care permit apelul acestora.
Obiectul COM este instan a coclass Ionescu, va fi implementat n server prin clasa
CIonescu care va fi definit n fiierele Ionescu.h i Ionescu.cpp. Obiectul conine interfaa
denumit IIonescu.
Atributele obiectului COM se stabilesc prin pagina Options: Threaded Model: Aparment,
Interface: Custom, Aggregation: No.

3
Pentru adugarea unei metode interfeei obiectului definit, se folosete pagina ClassView a
spaiului de lucru, se selecteaz cu mouse-ul interfaa IIonescu i se apasa pe butonul dreapta al
mouse-ului. Din meniul flotant care apare, se selecteaz articolul Add ->Add Method i se obine
dialogul Add Method Wizard - IonescuServer, care permite definirea metodei n limbajul IDL. Tipul
valorii returnate este tipul standard HRESULT. Numele metodei se completeaz cu FunctieIonescu.
Parametrii se completeaz cu : [in] double x, [in] double y, [out] double* pz .
Observaii:
Parametrii unei metode sunt calificai printr-unul sau mai multe atribute, specificate ntre
paranteze drepte naintea fiecrui parametru. Dintre atributele parametrilor, atributul de directie
trebuie specificat de fiecare dat i poate avea valoarea [in], [out] sau ambele valori [in,
out]. Un parametru cu atributul [in] este transmis de modulul apelant (client) ctre metoda
obiectului COM. Un parametru cu atributul [out] este returnat de metoda obiectului COM ctre
modulul apelant (client). Un parametru cu ambele atribute de direcie [in, out] este folosit
att pentru trimiterea unei valori de la modulul apleant ctre metoda obiectului COM, ct i pentru
returnarea unui rezultat de ctre metoda obiectului COM ctre apelant. Parametrii cu atribut
[out] sau [in, out] trebuie s fie pointeri. n exemplul de mai sus, funcia
FunctieIonescu() primete doi parametri de tip double (x i y), calculeaz suma
acestora i depune rezultatul n locaia pointat de parametrul double* pz. La returnare,
valoarea parametrului cu atribut [out] (*pz) este transmis clientului.

4
Numele unei metode trebuie s fie unic ntr-o interfa dat, deoarece n interfeele COM nu se
admite suprancrcarea funciilor. Dac dorim s definim o funcie de adunare cu parametri de alt
tip (de exemplu, long), atunci se va folosi un alt nume de funcie, de exempu
FunctieIonescul (cu un sufix care s diferenieze numele funciilor i, eventual s dea o
informaie despre tipul argumentelor, dac acest lucru intereseaz).

Studiai ce fiiere i clase genereaz ATL Wizard n acest stadiu de dezvoltare al proiectului.
n fiierul IonescuServer.idl se pot remarca aspectele importante de descriere a
obiectelor COM n limbajul IDL:
Obiectul COM Ionescu este descris de coclass Ionescu, care conine interfaa
IIonescu i este identificat printr-un uuid.
Interfaa IIonescu este identificat printr-un uuid i conine metoda FunctieIonescu,
exact aa cum a fost definit ca nume i parametri.
n fiierul header Ionescu.h creat de ATL Wizard se observ declaraia:

5
n fiierul de implementare al clasei CIonescu (Ionescu.cpp) creat de ATL Wizard, care
implementeaz n server (n limbajul C++) coclass Ionescu din limbajul IDL se adaug codul
de implementare: *pz = x + y;

3.3 Compilarea programului server


Compilai programul server cu comanda Build-Build IonescuServer.exe care execut automat
(i transparent din punct de vedere al programatorului) o secven de operaii: (1) Compilarea
interfeei IDL; (2) Compilarea i link-area programului server (3); nregistrarea serverului n regitrii
Windows.
(1) Compilarea interfeei IDL. Limbajul MIDL ofer o modalitate standard de a descrie
interfeele n tehnologia COM, i a fost dezvoltat de Microsoft prin extinderea limbajului IDL folosit
n mecanismul RPC al sistemului de operare. MIDL (ca i IDL) folosete construcii asemantoare ca
sintax construciilor "C", pentru definiii, dar nu permite introducerea de instruciuni de execuie.
Compilatorul MIDL care are ca fiier de intrare fiierul de descriere a interfeei (n general, cu
extensia .idl) i genereaz mai multe fiiere surs. Spre deosebire de alte compilatoare, MIDL nu
genereaz cod obiect ci cod n limbajul C sau C++, care nu folosete nici clase MFC, nici clase
template ATL, ci numai funcii din interfaa Win32 API. Utilizarea unui generator de text surs
(compilatorul MIDL) este foarte util pentru programator, deoarece generatorul introduce automat o
mulime de date i funcii care au o comportare asemntoare pentru toate aplicaiile i sunt greu de
scris de mn. Compilatorul MIDL genereaz urmtoarele fiiere:
Fiierul header al programului server (IonescuServer_i.h), care nu fusese nc generat
de ATL Wizard. Fiierul header este foarte complex, aa c vom urmri numai cteva din aspectele
mai importante din codul generat de MIDL. n principal, el conine prototipurile metodelor interfeelor
i constante de identificare ale obiectelor i interfeelor, cu variante de folosire n C sau n C++. Pentru
exemplul dat, se poate observa definirea constantei IID_IIonescu, a interfeei IIonescu, a
funciei FunctieIonescu.Toate interfeele COM trebuie sunt derivate din interfaa de baz
IUnknown. Fiierul header al serverului trebuie s fie inclus n programul client, pentru ca acesta s
cunoasc prototipurile metodelor pe care le va apela.

6
Fiierul "_i.c" generat de MIDL este tot un fel de header, care conine constantele GUID ale
obiectelor i interfeelor. Pentru exemplul descris, a fost generat fiierul IonescuServer_i.c, n
care se pot gsi constantele GUID ale obiectului Ionescu i a interfeei IIonescu, care se vor
introduce n programul client (IonescuClient).

Crearea automat a modulelor proxy/stub de ctre compilatorul MIDL elibereaz


programatorul de aceast sarcin nu foarte simpl.
Crearea automat a bibiotecii de tip (Type Library). O bibliotec de tip este un fiier de date
(IonescuServer.tlb, in Debug, n exempul dat) care conine descrierea obiectelor COM i a
interfeelor, fiind reprezentarea binar a fiierului de descriere a interfeei (.idl).
Crearea fiierului de nregistrare a serverului n regitrii Windows (IonescuServer.rgs n
exemplu dat); acesta conine un script care permite nregistrarea serverului prin intermediul utilitarului
sistemului de operare regsvr32.
(2) Compilarea i link-area programului server. Aceasta este executat automat; dac nu
sunt erori, nu este necesar intervenia programatorului.
(3) nregistrarea serverului. nregistrarea serverului n regitrii Windows este efectuat
automat dup terminarea compilrii i link-rii serverului, efectund nregistrarea serverului prin
execuia scriptului de nregistrare (IonescuServer.rgs).

Observatie: Se compileaza si proiectul IonescuServerPS pentru a fi creat IonescuServerps.dll.


Inregistrarea modulului proxy-stub se face cu comanda regsvr32:
regsvr32 IonescuServerps.dll

3.4 Crearea unui client COM


Se creaz un nou proiect de tip Win32 Console Application cu numele IonescuClient ca An
empty project. Se adaug n proiect un nou fiier surs C++ cu numele IonescuClient cu urmtorul
cod, prezentat in figura.
n fiierul de implementare al clientului trebuie s fie inclus header-ul serverului
IonescuServer_i.h . Calea aceastui fiier depinde de modul de organizare a proiectelor n
directoare; n cazul de mai sus se presupune c directoarele IonescuClient i IonescuServer
au acelai director printe. Constantele IID i CSID se copiaz din fiierul IonescuServer_i.c
generat de compilatorul MIDL sau se poate include acest fiier.
Subsistemul COM este iniializat prin apelul funciei CoInitiaize(0), iar la
terminarea operaiilor se apeleaz CoUninitialize() care dezaloc biblioteca COM.
Cele mai multe funcii COM returneaz un cod de eroare de tip HRESULT. Acest cod
conine mai multe cmpuri care definesc diferite tipuri de erori. Valoarea macro SUCCEEDED indic
execuia normal a funciei.
Pentru obinerea unui pointer la interfaa obiectului COM se apeleaz funcia
CoCreateInstance(), ai crui parametrii sunt explicai pe scurt n comentarii. Aceast funcie
este deosebit de puternic. Ea interacioneaz cu subsistemul COM i efectueaz urmtoarele operaii:

7
Localizeaz serverul.
ncarc, starteaz sau se conecteaz la server.
Creaz un obiect COM pe server.
Returneaz un pointer la interfaa obiectului COM.

Dup obinerea pointerului la interfa, apelul metodelor interfeei se face la fel ca i pentru
obiecte normale. La execuia clientului se va afia 2 + 5 = 7.

8
4. Transformarea aplicaiei COM n aplicaie DCOM

Transformarea unei aplicaii COM n aplicaie DCOM este, n general simpl pentru
programator, datorit prelurii de ctre toolset-ul ATL a sarcinii de creare a modulelor proxy-stub
necesare apelului procedurilor la distan (remote). Aplicaiile COM locale utilizeaz mecanismul
LPC (Local Procedure Call), iar aplicaiile COM distribuite (DCOM) utilizeaz mecanismul RPC
(Remote Procedure Call), dar programatorul nu trebuie s prevad explicit aceast difereniere,
deoarece standardul COM prevede aceeai modalitate de apel a metodelor, iar codul modulelor proxy
i stub este inserat automat de ctre ATL Wizard.
Un server independent poate fi folosit fr nici-o modificare ca server DCOM, dac n staia
dorit se instaleaz si se nregistreaz att serverul ct si modulul (DLL) de proxy-stub. Clientul care
apeleaz un server DCOM trebuie ns modificat n mod corespunztor.

4.1 Modificarea unui client pentru apeluri DCOM


Se modific programul IonescuClient descris n capitolul precedent astfel nct s poat
starta i apela metodele serverului IonescuServer pe o alt staie din reea. n forma cea mai
simpl, programul client va arta ca in figura de mai jos.
Comunicaia DCOM ncepe prin cererea unui client de a obine un pointer la o interfa a unui
obiect COM creat de un server. Pentru a obine un pointer la o interfa n DCOM, clientul trebuie s
apeleze funcia CoCreateInstanceEx(), creia i paseaz ca parametri identificatorii GUID al
clasei obiectului i al interfeei acestuia i, n plus fa de metoda CoCreateInstance(), adresa
staiei unde se afl serverul la distan. Serviciul SCM va starta serverul DCOM pe staia indicat,
dup care apelurile metodelor interfeei sunt direcionate de modulele proxy i stub folosind
mecanismul RPC, care transmit parametrii prin reeaua de interconectare folosind un anumit protocol
de comunicaie (de exemplu TCP-IP, NetBios, NetBEUI sau UDP).
Denumirile metodelor intefeelor ca i identificatorii interfetelor i ai clasei serverului
(IID_IIonescu i CLSID_Ionescu) pot fi gsite de ctre client prin importarea bibliotecii de
tip a serverului, prin comanda:
#import "..\IonescuServer\IonescuServer.tlb" no_namespace named_guids
Aceasta comand va nlocui liniile de includere a fiierului header al serverului (n cazul de
fa IonescuServer_i.h) i cele cu constantele IID si CLSID. De asemenea, prima
macroinstruciune (#define _WIN32_DCOM ) care valideaz apelurile DCOM poate s lipseasc n
acest caz, deoarece este coninut de biblioteca .tlb.

9
Din cauz c este necesar clasa CString, se include biblioteca MFC (versiunea Dll) n
proiectul client. Pentru introducerea bibliotecii MFC n proiectul de tip Win32 Console Application se
includ fiierele header afxwin.h, afxext.h i afxdisp.h i se seteaz opiunea Use MFC
in a Shared DLL n pagina de proprietati a proiectului, Project->IonescuClientD Properties:

10
Pentru instalarea unui client DCOM trebuie s fie copiat executabilul pe statia dorit i s se
nregistreze modulul proxy/stub al serverului (n acest exemplu, IonescuServerps.dll) cu
comanda regsvr32 executat pe staia respectiv.

4.2 Instalarea unui server DCOM


Pentru ca un server COM s funcioneze pe o alt staie dect cea pe care a fost creat, este
necesar instalarea acestuia, care const n copierea fiierului executabil (de exemplu, fiierul
IonescuServer.exe) pe staia dorit i nregistrarea n regitrii Windows prin lansare n execuie
cu parametrul Regserver:

IonescuServer -RegServer

De asemenea este necesar nregistrarea modulului DLL proxi-stub. Modulul DLL proxi-stub
se creeaz dup compilarea serverului cu sufixul PS. Inregistrarea modulului proxy-stub se face cu
comanda regsvr32, pe fiecare staie pe care ruleaz o component client sau server. Pentru exemplul
prezentat, se execut comanda:
regsvr32 IonescuServerps.dll
La rularea clientului, se va obtine:

11
EXERCIII

1. Creai i rulai o aplicaie COM cu Nume_studentServer ca nume al proiectului server i


Nume_studentClient ca nume al proiectului client dup exemplul descris n lucrare.
2. Transformai aplicaia COM realizat la exercitiul anterior n aplicaie DCOM i rulai aplicaia pe
dou staii de lucru din laborator.

Apeluri inverse n tehnologia COM-DCOM


Toate exemplele dezvoltate pn acum au fost strict uni-direcionale: programul client se
conecteaz la un server i apeleaz metodele acestuia. n astfel de aplicaii, toate operaiile sunt
conduse de client: clientul realizeaz conexiunea, apeleaz metodele serverului i eventual, termin
(oprete) serverul.
n aplicaiile mai complexe, acest mod de lucru nu acoper toate cerinele posibile. De multe
ori este necesar ca serverul s ntiineze clientul de anumite situaii (evenimente) intervenite, i acest
lucru trebuie s fie fcut asincron (independent) fa de orice metod invocat de client.
O metod simplist ca un client s afle ce informaii ar avea serverul s-i transmit este aceea
n care clientul execut o baleiere de testare a serverului (pooling), apelnd n mod repetat o metod a
serverului prin care acesta s-l ntiineze de situaiile intervenite. O astfel de metod este ns
ineficient, deoarece, n unele situaii poate s intervin o ntrziere semnificativ ntre momentul n
care a avut loc situaia (evenimentul) n server i momentul n care clientul a executat testarea
serverului, iar n alte situaii, operaiile de testare s fie efectuate de client degeaba, serverul ne-avnd
nimic de transmis acestuia. Este foarte dificil de a stabili intervalul la care ar trebui s fie executat
pooling-ul de ctre client, pentru a minimiza cele dou inconveniente; de fapt, este chiar imposibil,
dac evenimentele sunt asincrone i imprevizibile.
Metoda eficient de a proiecta astfel de aplicaii COM-DCOM este aceea n care se asigur
posibilitatea ca serverul s poat s se conecteze din proprie iniiativ la client. Exist dou modaliti
de a realiza acest tip de execuie: interfee de apeluri inverse (callback interfaces) i puncte de
conexiune (connection points). n aceast lucrare se vor studia interfeele callback.

1. Interfee callback

ntr-o abordare cu interfa callback, serverul are posibilitatea s apeleze metode ale
programului client, la fel cum clientul apeleaz metode ale serverului, deci se obine o comunicaie
bidirecional i asincron ntre cele dou componente. n aceast situaie, diferenierea dintre server
i client nu mai este att de pregnant, fiecare component devenind o component dual, care joac
att rol de server (atunci cnd execut metodele invocate de ceallalt component), ct i rol de client
(atunci cnd invoc metodele celeilaltei componente). Totui, o difereniere ntre componente rmne,
n principal ca modalitate de dezvoltare a proiectului.
O interfa callback conine una sau mai multe funcii callback; o funcie callback este o
funcie implementat i expus de client, care poate fi apelat de server ca in figura.
Interfaa
primar

Aplicaie Aplicatie
Client Server

Interfaa
callback
Interfeele aplicaiilor COM.

12
Dei interfeele i funciile callback sunt relativ simplu de realizat, interaciunile care au loc
sunt destul de complexe, iar inelegerea acestora nu se poate face dect urmrind simultan operaiile
care au loc n cele dou componente.
Pentru dezvoltarea unei aplicaii cu componente COM duale folosind interfee callback, este
necesar mai nti ca serverul s implementeze metode de interfa care s permit clientului s se
nregistreze ca asculttor al apelurilor serverului, prin intermediul unei interfee callback; o dat ce
clientul s-a nregistrat, serverul are posibilitatea s se conecteze la acesta, apelnd metodele interfeei
callback. n terminologia COM, nregistarea interfeei callback a clientului este realizat de funcia
Advise(); atunci cnd clientul se deconecteaz, acesta terge (elibereaz) nregistrarea fcut prin
apelul funciei UnAdvise(); aceste funcii se definesc n interfaa serverului i se implementeaz n
server.

2. Dezvoltarea unei aplicaii cu interfa callback

Se va dezvolta o aplicaie cu componente COM duale n care serverul este o aplicaie consol,
iar clientul este o aplicaie MFC de dip dialog.

2.1 Crearea Serverului

Pentru crearea serverului se vor parcurge urmtorii pai:


(1) Se creaz un proiect ATL COM AppWizard de tipul executabil (.exe) cu numele
DualServer.

(2) Se adaug un obiect COM cu numele Simple. ATL Wizard seteaz n mod corespunztor
numele clasei de implementare (CSimple) i al interfeei (ISimple). Atributul Threading model
:Apartment; tipul interfeei poate fi Custom sau Dual, iar modelul de thread-uri Aggregation poate fi
selectat sau nu.

(3) Se adaug metode interfeei ISimple. Metodele Now() i Later() sunt metodele pe
care le va apela clientul pentru a obine diferite rezultate de la server; la aceestea se adaug metodele
Advise()i UnAdvise(), necesare pentru nregistrarea/eliberarea interfeei callback. Parametrii
metodelor pot fi dedui din definiiile metodelor create de Wizard care se vor gsi n fiierul
DualServer.idl:

(4) Se definete interfaa callback (cu numele ICallback), care va fi implementat n client.
Aceast interfa difer de interfaa precedent deoarece nu necesit implementare n server i
adugarea se face manual, deoarece nu se poate folosi utilitarul ATL Object Wizard care creeaz
implicit i fiierele de implementare. Se vor aduga urmtoarele linii de program n fiierul
DualServer.idl:

13
// Interfata implementata in client
[
object,
uuid(282A2502-9BD8-11D6-8326-525405C258FC),
helpstring("ICallback Interface"),
]
interface ICallback : IUnknown
{
[helpstring("method Awake")]HRESULT Awake( long lVal );
};

(5) Se adaug n definiia clasei CSimple (n fisierul Simple. h) variabilele necesare


metodelor Advise() i UnAdvise():
long m_lCookie;
ICallback *m_ICallback;

(6) Se implementeaz metoda Advise(). Metoda Advise(), apelat de client la


nregistrare, trebuie s salveze pointerul interfeei callback a acestuia (de tip ICallback) pentru a fi
folosit n apelurile callback (efectuate de server ctre client). Implementarea metodei se completeaza
n fiierul Simple.cpp:

Apelul metodei AddRef() al interfeei ICallback are rolul de a incrementa numrul de


referine al interfeei n client, aceasta devenind astfel activ.
Parametrul cookie seamn ntr-o oarecare msur cu cel folosit ntre serverele de Web i
browsere. n aplicaiile COM, parametrul cookie este un numr unic n contextul combinaiei
respectivei aplicaii server-clieni; el este iniializat cu pointerul la obiectul COM din server (this),
este memorat (n variabila m_lCookie) i transmis clientului care se nregistreaz (prin parametrul
de tip out cu numele lCoockie al metodei Advise()).

(7) Se implementeaz metoda UnAdvise(). Metoda UnAdvise()este apelat de client


pentru eliberarea interfeei i nchiderea unei conexiuni care a fost nregistrat n prealabil printr-un
apel Advise(). Implementarea metodei se completeaza n fiierul Simple.cpp:

14
n metoda UnAdvise() se verific mai nti parametrul cookie, pentru a se nchide
conexiunea numai dac a fost nregistrat pe acest server (care are o valoare specific a pointerului la
obiectul COM, considerat unic n contextul relaiei cu clienii). Dup aceasta se elibereaz interfaa
din client cu funcia Release()).

(8) Apelul clientului din server (apel callback). Serverul poate apela, oricnd, orice metod a
interfeei callback, dat fiind c acesta cunoate pointerul la interfaa callback (m_ICallback, setat n
funcia de nregistarea a clientului (Advise()) i prototipul (prototipurile) metodelor acestei
interfeei. n exemplul ales, metoda Awake() este apelat n execuia metodei Now():

Prin aceast implementare funcionarea obinut este urmtoarea: atunci cnd clientul apeleaz metoda
Now(), serverul la rndul lui apeleaz metoda Awake() din client, i revenirea din funcia Now()
va avea loc numai dup ce clientul a terminat de executat funcia Awake(). n client aceast funcie
va avea o implementare simpl, de exemplu o ntiinare c a fost apelat, printr-un mesaj sonor
(Beep) sau un mesaj afiat pe ecran (AfxMessageBox).
Se observ c pn acum s-a realizat doar un apel invers (de la server la client) i nu s-a
obinut nc asincronismul dorit ntre apelurile client-server, dar aceast posibilitate este pregtit prin
existena apelului invers i va fi ilustat mai trziu (dup ce va fi creat i clientul), prin implementarea
metodei Later().

15
2.2 Crearea Clientului

Generatorul de cod ATL Wizard este conceput pentru crearea serverelor i nu poate fi folosit
pentru crearea clientului. De aceea, indiferent de tipul de proiect al clientului (aplicaie consol sau
aplicaie MFC), partea de COM se adaug manual, ceea ce este mai laborios, dar nu deosebit de
dificil.
n exemplul din aceast lucrare, clientul va fi o aplicaie MFC de tip dialog cu dou butoane
de comand (numite Now i Later), la acionarea crora se apeleaz una din metodele serverului
(Now() sau respectiv, Later()). Caseta de editare care mai este inclus n dialog permite stabilirea
ntrzierii de rspuns a serverului la comanda Later.

Paii care se vor efectua pentru crearea clientului sunt urmtorii:

(1). Se creeaz proiectul de tip MFC dialog cu numele DualClient:

16
Se adaug (folosind editorul de resurse Toolbox) butoanele (Button) Now i Later, o caset
de editare (Edit Control) si o eticheta (Static Text) si se seteaza etichetele butoanelor Now si Later (
din Properties):

17
si o variabil membr a clasei dialog (m_delay) asociat valorii acestei casete:

(2) Se adaug (manual) n proiect fiierul header care conine definiia template-urilor
COM (ATL - Active Template Library) prin introducerea n fiierul Stdafx.h (aproape de sfritul
fiierului) a liniei:
#include <atlbase.h>

(3) Se definete clasa pentru obiectul COM care va implementa interfaa ICallback.
Pentru aceasta, n fiierul DualClient.cpp se adaug urmtorul cod, imediat dup seciunea
#include:

18
Aceast parte de cod necesit mai multe explicaii.
(a) Modulul cu numele _Module, de clas CComModule trebuie s fie adugat n proiect
deoarece acesta asigur operaiile de pornire, nregistrare i oprire a serverului COM. Pentru a merge
mai departe cu exemplul nceput, nu este necesar s prezentm toate detaliile acestor operaii, dar ele
pot fi studiate ulterior.
(b) Clasa obiectului COM care implementeaz interfaa ICallback va avea numele
CCallback (conform conveniei folosite n aplicaiile COM) i este derivat i din clasa
CComObjectRoot, care este clasa de baz pentru toate obiectele ATL i ofer implementarea
interfeei de baz IUnknown (adic a metodelor QueryInterface, AddRef i Release).
(c) Clasa CCallback prevede i o hart a interfeelor COM, care conine lista
identificatorilor (IID) ai intefeelor corespunztoare numelor lor. n exemplul prezentat exist o
singur interfa (ICallback) i aceasta este prevzut n harta de interfee care este marcat prin
macro-urile BEGIN_COM_MAP(CCallback).. END_COM_MAP().

19
(d) Clasa CCallback mai conine i o hart a obiectelor COM. n acest exemplu harta
obiectelor (marcat de macro-urile COM BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()) este vid.

(4) Legarea programului client la fiierele header ale serverului se face, la fel ca i n celelalte
proiecte de clieni COM, prin urmtoarele includeri n fiierul DualClient.cpp:
#include "..\DualServer\DualServer_i.c"
#include "..\DualServer\DualServer_i.h"

Aa cum s-a mai artat, fiierul DualServer_i.c conine identificatorii unici ai obiectelor
i intefeelor(GUID), iar fiierul DualServer_i.h conine definiia interfeei serverului i a
intefeei callback. Cile acestor fiiere pot diferi, n funcie de directoarele n care sunt create
proiectele server i client.
(5) Implementarea metodelor callback. n acest exemplu, interfaa callback conine o singur
metod (Awake()), a crei implementare afieaz un mesaj sau produce un semnal sonor:

(6) Conectarea la server. Operaiile de conectare a clientului la server sunt n cea mai mare
parte aceleai ca i n proiectele precedente, la care se adaug operaiile de creare a obiectului COM
care implementeaz interfaa callback. Aceste operaii sunt prevzute n funcia InitCom():

20
21
Metoda InitCOM() se este invocat la inializarea aplicaiei, n funcia InitInstance():

(8) nchiderea conexiunilor i eliberarea interfeelor se face n funcia ExitInstance() a


aplicaiei client care se adauga in acelasi mod ca functia InitCOM():

22
(9) Implementarea metodelor interfeei serverului. Metodele OnNow() i OnLater() sunt
metode de tratare a mesajelor de comand de la cele dou butoane i servesc pentru testarea
comunicaiei bidirecionale ntre client i server. Se adauga in program prin dublu clic pe butonul
asociat in pagina de resurse urmata de schimbarea numelui functiei si apoi completarea codului:

23
Se adauga variabilele m_pSimple si m_lCookie:

si se adauga la inceputul fisierului:

#include "..\DualServer\DualServer_i.h"

La acionarea butonului Now se execut funcia OnNow() n care este apelat metoda Now()
pe server; parametrul transmis nu este de fapt folosit. La acionarea butonului Later se execut funcia
OnLater() n care este apelat metoda Later() pe server avnd ca parametru o valoare de
ntrziere preluat din caseta de editare din dialog. Din punct de vedere al clientului, apelurile celor
dou metode sunt asemntoare; diferena de rspuns este realizat n server.

24
2.3 Finalizarea aplicaiei: implementarea metodei Later()

La apelul metodei Now() de ctre client, serverul face un apel callback, apelnd metoda
Awake() implementat de client; s-a obinut o comunicaie bidirecional dar sincron. Pentru
funcionarea asincron, adic serverul s apeleze clientul mai trziu (cnd s-au terminat unele operaii
n server, fr ca n acest timp clientul s atepte) se pot folosi mai multe metode, n funcie de
cerinele aplicaiei. n continuare se va exemplifica apelul invers asincron prin intermediul unui timer.
Variabilele i funciile necesare pentru apelul invers asincron prin intermediul unui timer
sunt urmtoarele:

n metoda Later() se memoreaz pointerul la propriul obiect COM (this) ntr-o variabil
global (CSimple* pSimple) i se starteaz un timer, dup un interval de timp minim (1
milisecund). n procedura de timer (LaterTimerProc) se simuleaz o durat de execuie prin
funcia Sleep(), dup care se invoc metoda de apel invers Awake() folosind pointerul memorat
(pSimple).

25
Se inregistreaza serverul.

Se porneste serverul. Se lanseaza clientul.


La invocarea metodei Later() din client (prin acionarea butonul Later), clientul va fi apelat
(prin callback) de server dup un interval de timp egal cu durata cerut (n caseta de editare) i se va
emite un semnal sonor sau se va afia o caset de dialog.

Acest mod de execuie este cel mai simplu posibil dar prezint, bineneles, mai multe
inconveniente, dintre care cel mai pregnant este acela c serverul nu mai poate rspunde la un nou apel
al clientului pn nu s-a terminat operaia precedent.
O abordare cu caracter mult mai general pentru apelurile inverse este prin proiectarea
serverelor multi-threading. ntr-un astfel de proiect, thread-ul principal al severului va crea un thread
se lucru pentru rezolvarea fiecrei cereri de la client, i acest thread se conecteaz la client, dup
terminarea operaiilor.
Exerciiu
Realizai aplicaia cu apeluri inverse descris, folosind propriul nume pentru server i client (de
exemplu, PopescuCallbackServer, PopescuCallbackClient, etc).

26

S-ar putea să vă placă și