Sunteți pe pagina 1din 12

Managed C++

• Ce reprezinta .NET framework


• Ce reprezinta Managed Extensions pentru
Visual C++
• Exemplu: cod unmanaged
• Exemplu: cod managed

.NET framework

Introducere

.NET Framework este o platforma noua de programare care, pe langa faptul ca simplifica mult
procesul de dezvoltare al aplicatiiilor, isi propune sa atinga urmatoarele scopuri:
• sa asigure un mediu de programare orientat obiect robust, indiferent daca aplicatiile se
gasesc si se executa local, daca sunt distribuite in Internet si se executa local sau se executa
la distanta;
• sa asigure un mediu de executie a codului care minimizeaza problemele de distributie si
conflictele dintre versiuni;
• sa asigure un mediu de executie care garanteaza siguranta executiei, incluzand si codul de
provenienta necunoscuta sau al tertilor producatori;
• sa asigure un mediu de executie care elimina problemele de performanta ale mediilor
interpretabile sau bazate pe rularea scripturilor;
• sa asigure ca orice cod bazat pe .NET framework poate fi integrat cu orice alt asemenea cod.
.NET framework este alcatuit din doua componente principale: common language runtime (CLR) si
biblioteca de clase a framework-ului. CLR-ul reprezinta baza pentru .NET framework; el este acela
care supravegheaza executia codului, asigurand management-ul memoriei, management-ul firelor
de executie si a executiei la distanta, in acelasi timp punand accent pe securitatea si integritatea
codului. De fapt, management-ul codului este un concept fundamanetal pentru CLR. Codul care se
adreseaza CLR-ului a fost denumit cod managed in timp ce codul care nu este adresat acestuia a
fost numit cod unmanaged. Cealalta componenta a framework-ului, biblioteca de clase, este o
colectie cuprinzatoarea de clase orientate obiect care vine in intampinarea ideii de reutilizare a
codului; ea poate fi folosita pentru dezvoltarea diferitelor tipuri de aplicatii: de la aplicatii la linia de
comanda sau cu interfata grafica, pana la aplicatiile dezvoltate pe baza celor mai noi tehnologii
aduse de ASP.NET cum ar fi Web Form-urile sau serviciile web bazate pe XML.
Despre CLR

CLR-ul este acela care se ocupa de management-ul memoriei, al firelor de executie precum si a
altor servicii sistem. In ceea ce priveste securitatea, orice componenta managed are diferite grade de
securitate in functie de anumiti factori printre care este inclusa si originea lor. Asta inseamna ca o
componenta managed poate avea sau nu drepturi pentru operatii de access la fisiere, de access la
registry, sau alte tipuri de functii indiferent de aplicatiile in care ruleaza. Tot CLR-ul este acela care
accentueaza securitatea in ce priveste accesul la cod. De asemenea, prin verificarea stricta a tipurilor
de date si a codului, se ajunge la realizarea unui cod robust din toate punctele de vedere.
Management-ul memoriei a devenit automat eliminand doua dintre cele mai comune erori: referinte
invalide catre anumite zone de memorie si zone de memorie alocate si neeliberate dupa utilizare. O
mai mare productivitate se datoreaza faptului ca fiecare dezvoltator poate folosi orice limbaj de
programare care se adreseaza framework-ului beneficiind in acelasi timp de toate avantajele oferite
de CLR, de biblioteca de clase, sau de componentele scrise de diferiti dezvoltatori. In acelasi timp,
CLR-ul permite dezvoltatorilor folosirea in continuare a componentelor COM si a DLL-urilor.
Aceasta componenta din .NET framework a fost realizata avand ca obiectiv principal sporirea
performantelor. Desi CLR-ul aduce multe servicii standard, cum ar fi management-ul memoriei,
codul managed nu este un cod interpretat. Compilarea just-in-time este o caracteristica ce permite
codului managed sa ruleze in limbajul masina al sistemului pe care se executa. In cele din urma
trebuie amintit faptul ca poate fi gazduit de aplicatii server puternice cum ar fi Microsoft SQL
Server sau Internet Information Services.

Despre biblioteca de clase

Biblioteca de clase a framework-ului este o colectie de tipuri de date orientate obiect ce poate fi
reutilizata cu usurinta si care se integreaza cu CLR-ul. Orice nou cod managed poate dobandi
functionalitate prin derivarea din clasele deja existente. Acest lucru face ca toate tipurile de date
definite in .NET framework sa fie usor de folosit iar timpul pentru invatarea functionalitatilor aduse
de framework sa scada simtitor. In acelasi timp, componetele produse de terti dezolvatatori se pot
integra foarte bine cu clasele din .NET framework. Pentru a raspunde tutoror solicitarilor in ce
priveste o biblioteca de clase orientate obiect, tipurile de date definite in .NET framework permit
efectuarea unui vast domeniu de operatii cum ar fi management-ul string-urilor, structuri de date,
conectarea la baze de date sau accesul la fisiere. In plus fata de aceste cerinte comune, biblioteca
vine cu pachete de clase menite sa suporte cele mei diferite operatii, pentru scenarii specifice tuturor
tipurilor de aplicatii. De exemplu, se poate folosi framework-ul pentru dezolvoltarea urmatoarelor
tipuri de aplicatii si servicii:
• aplicatii consola;
• aplicatii bazate pe scripturi;
• aplicatii Windows cu interfata grafica;
• aplicatii ASP.NET;
• servicii web bazate pe XML;
• servicii Windows.
Ce reprezinta Managed Extensions pentru Visual C++

Managed Extensions

Managed Extensions pentru Visual C++ reprezinta un set de extensii aduse limbajului C++
pentru a ajuta dezoltatorii ce folosesc Visual C++ sa dezvolte aplicatii pentru .NET framework.
Managed Extensions ne permit sa intercalam cod unmanaged si managed in cadrul aceleiasi
aplicatii C++. Noile aplicatii scrise cu ajutorul acestor extensii beneficiaza astfel de intreaga forta a
codului unmanaged la care se adauga avantajele aduse de codul managed. Componentelor deja
existente li se pot adauga noi componente bazate pe Managed Extensions astfel incat vechea
functionalitate sa se pastreze intacta, in acelasi timp reusind sa se integreze si cu aplicatiile pentru
.NET framework. Folosirea acestor extensii este recomandata in urmatoarele cazuri:
• in cazul migrarii vechilor aplicatii C++ catre .NET framework: Daca avem o aplicatie
C++ realizata din cod unmanaged, extensiile amintite mai sus permit o migrare lejera catre
.NET framework. Deoarece codul managed si unmanaged poate coexista in cadrul aceleiasi
aplicatii, portarea ei se poate face in timp, componenta cu componenta. In acelasi timp, se
poate continua dezvoltarea de cod unmanaged pentru a benificia de forta acestuia, in timp ce
se pot dezvolta mici clase wrapper de cod managed care pot asigura layer-ul necesar pentru
comunicarea cu .NET framewok.
• in cazul in care se doreste accesarea unei componente C++ din limbaje de programare
compatibile cu .NET framework: Managed Extensions permite ca orice clasa C++ sa poata
fi apelata din limbajele compatibile cu .NET framework. Acest lucru este posibil prin
realizarea unor clase wrapper care nu trebuie sa faca altceva decat sa expuna in cod
managed vechiul cod C++. Avand in vedere ca aceste noi clase sunt managed ele pot fi
apelate din orice limbaj de programare care suporta .NET framework. Clasele wrapper vor
reprezenta un layer subtire intre .NET framework si codul unmanaged nefacand altceva
decat sa paseze apelurile de metode direct catre codul unmanaged. De asemenea, Managed
Extensions permite apeluri catre orice biblioteca sau DLL de cod unmanaged la fel ca si
catre orice alta clasa unmanaged.
• in cazul in care se doreste sa se apeleze .NET framework-ul din cod unmanaged:
Folosind Managed Extensions se poate creea si apela din C++ orice obiect din .NET
framework. Mai mult, se poate scrie cod C++ care trateaza orice componenta din .NET
framework ca si cum ar fi o componenta managed.
• in cazul in care este nevoie de cod managed si unmanaged in cadrul aceluiasi
executabil: Compilatorul de Visual C++ este capabil sa foloseasca date, pointeri, exceptii si
instructiuni atat in contexte de cod managed cat si unmanaged trecerile facandu-se automat
si transparent. Acest lucru permite codului managed C++ sa interopereze fara nici o
problema cu codul unmanaged din aceeasi aplicatie.

Tipuri de date

Tipurile de date managed aduse de extensiile amintite anterior sunt clasele, enumerarile, pointerii
si referintele. Un rol important il reprezinta clasele. Acestea sunt de trei tipuri:
• clasele __gc ( __gc class ) sunt alocate in memoria heap a CLR-ului si sunt sub
management-ul direct al garbage collector-ului ( a nu se confunda cu adunatorii de
gunoaie☺). Aceste clase managed pot fi folosite pentru cele mai generale scopuri;
• clasele __value ( __value class ) au fost gandite pentru a reprezenta clase de dimensiuni
mici, ale caror obiecte au o viata relativ scurta si pentru care efortul realizat de garbage
collector ar fi fost mult prea costisitor;
• interfetele __gc ( __gc interface ) ofera un suport pentru programarea folosind modelul
interfetelor, model asemanator programarii obiectelor COM.
Aceste extensii aduc nu doar specificatii noi, dar si un numar de 14 cuvinte cheie:
__abstract __box __delegate __event

__gc __identifier __interface __nogc

__pin __property __sealed __try_cast

__typeof __value

Prezentarea lor nu se va regasi in acest material deoarece este mult prea vasta; in orice caz,
documentatia on-line va sta la dispozitie pentru a afla cele mai mici detalii despre cele amintite mai
sus.

Clasele __gc

Deoarece consider acest tip de clase un punct cheie pentru Managed Extensions si deoarece vom
si implementa in cele ce urmeaza astfel de clase, am considerat ca trebuie prezentate putin mai in
detaliu. In momentul in care precedam cuvintele cheie class si struct cu mai noul cuvant cheie __gc
obtinem o clasa din categoria amintita anterior. Cuvantul cheie __gc specifica faptul ca obiectele
din aceasta clasa se afla sub directa grija a garbage collector-ului ☺, CLR-ul fiind acela care
controleaza viata acestor obiecte; de aceea, in programul client nu sunt necesare apelurile delete.
Pentru a va face o idee mai buna despre ce inseamna o astfel de clasa cel mai bine ar fi sa dam un
exemplu:
Fig.1 Exemplu de clase __gc
Ca si in C++, diferenta intre clasele __gc si structurile __gc il reprezinta tipul de acces si tipul de
mostenire implicit: la structuri acesta este public, la clase acesta este private. Dintre caracteristicile
acestor clase ar trebui amintite urmatoarele:
• declaratia unei clase __gc trebuie sa contina intotdeauna cuvantul cheie __gc;
• o clasa __gc poate poate avea membrii de tip pointer catre orice tip de date unmanaged;
• o clasa __gc poate avea un constructor, un constructor static sau un destructor definit de
utilizator;
• se poate apela operatorul delete aspura unui pointer catre un obiect dintr-o clasa __gc, insa
efectul acestuia este doar ca destructorul acelei clase sa fie apelat imediat;
• o clasa __gc poate implementa oricate interfete __gc si poate contine proprietati.
Din restrictiile care se impun claselor __gc voi aminti urmatoarele:
• o clasa __gc nu poate mosteni o clasa unmanaged;
• dintr-o clasa __gc nu poate fi derivata o clasa unmanaged;
• o clasa __gc nu poate mosteni mai mult de o clasa managed;
• o clasa __gc nu trebuie sa declare un constructor de copiere definit de utilizator;
• o clasa __gc nu trebuie sa declare sau sa defineasca clase sau functii prietene;
• o clasa __gc nu trebuie sa declare sau sa defineasca operatorii new si delete;
• o clasa __gc nu trebuie sa contina declaratii using;
• asupra obiectelor unei clase __gc nu trebuie sa se apeleze operatorii sizeof si offsetof; de
asemenea, pentru ca versionalizarea sa functioneze intr-adevar, codul client nu trebuie sa
contina hard-coded dimensiunea obiectelor ☺;
• functiile membre ale unei clase __gc nu trebuie sa contina modificatorii const si volatile;
• o clasa __gc nu trebuie sa mosteneasca mai mult de o clasa __gc; in cazul in care nu este
specificata nici o clasa de baza, se presupune ca aceasta este System::Object, clasa de baza
pentru .NET framework;
• operatorul delete nu trebuie chemat pe un obiect al unei clase __gc care nu a implementat un
destructor;
Cele prezentate mai sus nu reprezinta toate caracteristicile sau restrictiile aplicate claselor __gc,
insa, acestea sunt cele care mi s-au parut semnificative. Pentru lista completa a acestora se poate
consulta documentatia on-line.

Exemplu: cod unmanaged

Scopul

In aceasta sectiune ca si in cea care urmeaza, vrem sa urmarim ceea ce trebuie facut pentru a
porta o aplicatie deja existenta al carei cod a fost scris in Visual C++ intr-o aplicatie pentru .NET
framework. Mai precis, aplicatia noastra existenta isi va pastra functionalitatea, insa interfata cu
utilizatorul va fi realizata in C#.

Ce avem

Pentru a prezenta cele amintite mai sus avem la dispozitie o aplicatie cat se poate de simpla scrisa
in Visual C++ folosind MFC-ul linkeditat dinamic. Aplicatia este compusa din trei module,
reprezentate prin intermediul a trei proiecte:
• CCDll este un proiect de tipul MFC DLL, mai precis un DLL care extinde MFC-ul, el
continand clase derivate din CObject, serializabile, capabile sa transporte informatie intre
diverse componente ale unei aplicatii. Pentru a pastra relevanta exemplului vom considera in
acest proiect o singura clasa CInformationItem, care are urmatoarea declaratie:
Fig. 1 Declaratia clasei CInformationItem
• UseCCDll este proiect tot MFC DLL, insa, de aceasta data nu mai extinde MFC-ul, dar este
linkeditat dinamic la acesta. De asemenea, acest proiect foloseste DLL-ul CCDll, mai precis
obiecte de tipul CInformationItem. Pentru exemplificare s-a declarat o functie globala,
MyGlobalFunction, care primeste ca parametru o referinta a unui obiect de tipul
CInformationItem, prin intermediul careia sunt setate anumite valori pentru variabilele
membre ale obiectului:

Fig. 2 Implementarea functiei globale


• MFCTest este un proiect de tip MFC Application, mai precis o aplicatie Dialog Based.
Aplicatia foloseste MFC-ul la care se linkediteaza dinamic precum si DLL-urile rezultate
din compilarea proiectelor prezentate mai sus, CCDll si UseCCDll. Aplicatia are o singura
functionaliate, butonul Test, la actionarea caruia este afisata o fereastra de tipul
MessageBox care prezinta valorile unui obiect de tipul CInformationItem setate prin
intermediul functiei globale MyGlobalFunction.
Fig 3. Aplicatia MFC Test

Fig. 4 Implementarea functionalitatii butonului Test

Ce vrem

Ceea ce vrem sa facem in sectiunea urmatoare este sa pastram functionalitatea aplicatiei


prezentate mai sus, insa dorim ca aceasta sa fie inclusa intr-o aplicatie .NET, mai precis intr-o
aplicatie Windows scrisa in C# folosind Windows Forms; la fel de bine am fi putut realiza o
aplicatie ASP.NET care sa aduca functionalitatea descrisa mai sus in cadrul unei aplicatii web.

Cum facem

Prima intrebare pe care ar trebui sa ne-o punem este daca .NET framework ne pune la dispozitie
posibilitatea de a apela DLL-uri non-.NET. Raspunsul la aceasta intrebare este unul afrmativ, insa,
in cazul nostru acest lucru este lipsit de valoare deoarece functia noastra globala din UseCCDll are
ca parametru un obiect de tipul CInformationItem, obiect ce nu poate fi instantiat din limbaje ca
C#. Daca functia ar fi avut parametrii cu tipuri standard aceasta posibilitate ar fi putut fi luata in
calcul.
A solutie care poate fi luata in calcul cu succes este folosirea unui layer COM intermediar intre
functionalitatea actuala si .NET framework. Acest layer ar trebui sa scoata prin intermediul
interfetelor atat un obiect COM care sa se suprapuna peste un obiect de tipul CInformationItem
cat si o functie care sa ascunda apelul catre functia globala MyGlobalFunction. Dupa cate se pare
nu este o metoda foarte usoara ci una care necesita destul cod pentru o functionalitate minora;
imaginati-va ce ar insemna realizarea unui layer COM pentru o functionalitate semnificativa!
Cea mai buna solutie este realizarea unui layer de cod managed C++ care sa interfateze actuala
functionalitate si sa o faca disponibila pentru apelarea din diferitele limbaje de programare care
suporta .NET framework. Aceasta metoda este mai buna din mai multe motive, din care as vrea sa
amintesc doar urmatoarele doua: in primul rand, necesita mult mai putin cod ( si cunostinte de
programare ☺) decat realizarea unui layer COM peste functionalitatea actuala; in al doilea rand,
specificatiile pentru .NET framework arata ca performantele relativ la viteza de executie si memorie
sunt mai bune comparativ cu folosirea unui layer COM. Pentru a realiza acest lucru, va trebui sa
realizam clase managed care sa interfateze atat obiecte de tipul CInformationItem, cat si apeluri
catre functia globala MyGlobalFunction. Pentru lizibilitatea layer-ului de cod managed am
considerat necesar ca impartirea aplicatiei initiale pe module sa se pastreze si la nivelul noii
aplicatii.

Exemplu: cod managed

Ce facem

Dupa cum spuneam si in sectiunea anterioara, in realizarea layer-ului de cod managed vom
pastra aceeasi organizare pe module ca si aplicatia de la care am pornit. Astfel, noua aplicatie va fi
compusa pe langa proiectele CCDll si UseCCDll din inca trei proiecte:
• MCDll - este un proiect de tipul Managed C++ Class Library care va contine un pachet de
clase echivalente cu cele definte in proiectul CCDll; aceste clase nu fac altceva decat sa
expuna catre .NET framework informatiile din CCDll.
• UseMCDll - este un proiect de tipul Managed C++ Class Library care va contine clase
wrapper peste functionalitatea prezenta in UseCCDll.
• CSTest - este un proiect de tipul Windows Application scris in C# care nu face altceva
decat sa expuna utilizatorului functionalitatea pe care o prezenta aplicatia MFCTest.

Proiectul MCDll

Acest proiect va contine ca si CCDll o singura clasa, insa aceasta va fi scrisa in managed C++.
Trebuie sa amintim ca acest proiect va folosi biblioteca CCDll.lib si prin urmare va fi linkeditat
dinamic si la MFC. Pentru realizarea clasei care expune functionalitatea clesei CInformationItem
avem la dispozitie mai multe variante; am considerat ca metoda standard de portare a codului
unmanaged C++ catre managed C++ se preteaza foarte bine la exemplul nostru.
Noua clasa va purta numele CMInformationItem si va face parte din namespace-ul MCDll;
clasa este de fapt o clasa __gc ( ☺ ) declarata publica fapt ce ne permite sa o putem folosi si in
afara namespace-ului definit anterior. Aceasta clasa are urmatoarea declaratie:
Fig. 1 Declaratia clasei CMInformationItem
Clasa CMInformationItem contine o singura variabila membru si anume o variabila privata de
tipul CInformationItem. Aceasta va contine practic informatia pe care obiectele din aceasta clasa o
poarta, informatie ce va fi expusa pri intermediul proprietatilor declarate in continuare. Proprietatile
sunt practic functii de acces la niste variabile ce vor fi injectate in cod la compilare si pe care nu
este necesar sa le declaram; este obligatoriu insa ca tipul returnat de functia set_ sa coincida cu cel
primit ca parametru de functia get_, acesta fiind si tipul proprietatii. Proprietatile faciliteaza codarea
in limbajele de programare ce suporta .NET framewrok; pentru citirea sau scrierea de valori intr-o
proprietate nu este necesar sa apelam functia corespunzatoare ci este suficient sa folosim numele
proprietatii indiferent de ce parte a operatorului de atribuire ne gasim ( a se vedea in urmatoarele
sectiuni modul de apelare al proprietatilor atat din managed C++ cat si din C#. Constructorul clasei
nu face altceva decat sa aloce memorie pentru variabila membra a clasei; avand in vedere ca aceasta
este de tip unmanaged acest obiect nu va fi alocat din memoria heap a .NET framework-ului,
memorie de care raspunde garbage collector-ul, cu va fi alocat din memoria heap standard motiv
pentru care trebuie sa avem grija sa o si eliberam. Acest lucru este realizat in cadrul destructorului
clasei. Singura functie despre care mai trebuie sa mai amintesc este GetInformationItem care
expune sub forma un unui pointer catre void variabila membra de tipul CInformationItem. Acest
pointer ne va fi necesar in momentul in care vom dori sa apelam functia globala
MyGlobalFunction din proiectul UseCCDll. Nu doresc sa insist foarte mult pe implementarea
clasei CMInformationItem deoarece poate fi urmarita cu usurinta in fisierul
MInformationItem.cpp din cadrul proiectului MCDll.
Singura parte de cod ce ar putea pune ceva probleme in intelegerea ei este implementarea
proprietatii set_StringInformation care primeste ca parametru un pointer catre un obiect de tipul
System::String. Valoarea continuta de aceasta trebuie copiata in variabila membra corespunzatoare
a obiectului referit de catre m_pInnerData. Avand in vedere ca cele doua obiecte se gasesc in
spatii de memorie diferite, pentru a evita eventuale memory leak-uri, vom folosi clasa Marshal din
namespeace-ul System::Runtime::InteropServices. Aceasta clasa ne pune la dispozitie un pachet
intreg de functii pentru transferul informatiilor intre cele doua spatii de memorie. Noi vom folosi
StringToHGlobalAnsi pentru a obtine matricea de caractere a textului continut in parametrul de
intrare. Aceasta matrice o vom folosi pentru creerea unui nou obiect de tipul CString pe care il vom
stoca in variabila membra a obiectului referentiat de catre m_pInnerData, si deoarece nu mai avem
nevoie de aceasta, trebuie sa eliberam memoria folosind functia complementara FreeHGlobal.

Proiectul UseMCDll

Acest proiect a fost realizat pentru a expune functionalitatea echivalentului sau, UseCCDll.
Deoarece limbaje suportate de catre .NET framework cum ar fi C#, sunt orientate obiect in totalitate,
functia noastra globala, MyGlobalFunction va fi interfatata prin intermediul unei clase. Clasa
CTestClass va contine functia MyGlobalFunctionWrapper care nu va face decat sa apeleze la
randul sau functia MyGlobalFunction. De remarcat este faptul ca MyGlobalFunctionWrapper
are ca parametru un pointer catre un obiect de tipul CMInformationItem care este un obiect
managed. Acest lucru ne permite ca aceasta functie sa poata fi apelata cu usurinta din orice limbaj
de programare care suporta .NET framework. Proiectul foloseste bibliotecile CCDll.lib si
UseCCDll.lib si prin urmare este si linkedintat dinamic la MFC; de asemeanea, este folosit si
MCDll.dll pentru de importarea claselor managed. Clasa noastra CTestClass va face parte dintr-un
namespace separat UseMCDll, namespace care alaturi de MCDll, va fi folosit din proiectul de test
scris in C#. Singura functie a clasei amintite mai sus a fost implementata dupa cum urmeaza:

Fig. 2 Implementarea clasei functiei wrapper


Dupa cum se vede din implementarea de mai sus, din obiectul referit de catre pointerul primit ca
parametru, se extrage obiectul intern declarat in vechea aplicatie si este pasat pe post de parametru
pentru MyGlobalFunction. In acest fel ne asiguram ca vechea functionalitate ramane intacta,
rezultatul fiind continut si accesibil acum dintr-un obiect managed.

Proiectul CSTest

Acest proiect va contine si interfata cu utilizatorul a noii aplicatii; din fereastra principala a
aplicatiei vom putea actiona butonul de test care ne va confirma faptul ca vechea functionalitate a
ramas intacta. Proiectul este unul C#, de tipul Windows Application. Fereastra principala a fost
modificata dupa cum se vede in figura 3, pastrand o interfata simpla care sa reflecte scopul
aplicatiei:

Fig 3. Design-ul ferestrei principale


Pe evenimentul Click al butonului Test a fost de implementata functia OnButtonTest, prezentata
mai jos, functie care nu face altceva decat sa declare un obiect de tipul CTestClass si un obiect de
tipul CMInformationItem folosit de primul obiect pentru a apela vechea functionalitate. Rezultatul
operatiei este apelat prin intermediul unei ferestre de tipul MessageBox. Mai trebuie spus ca
proiectul CSTest refera cele doua proiecte realizate mai sus si foloseste cele doua namespace-uri pe
care acestea le implementeaza. In rest, rezultatul vorbeste de la sine☺.

La final

Sper ca subiectul sa nu va fi speriat mai mult decat este nevoie☺. Sper ca toata lumea este
constienta ca aceste exetensii sunt intr-un numar mult mai mare decat cele prezentate aici. Eu am
vrut doar sa va dau un punct de plecare in portarea/realizarea aplicatiilor .NET folosind C++.
Drumul in aceasta directie este mult mai lung, si dupa cum poate unii veti vedea, este pe alocuri si
anevoios. Succes !!! ☺

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