Sunteți pe pagina 1din 4

Revista Informatica Economic nr.

1 (37)/2006

73

Using DLL as Interface between API an VC#.NET Applications


Conf.dr. Marian DRDAL, lect. Adriana REVEIU, prof.dr. Ion SMEUREANU Catedra de Informatic Economic, A.S.E. Bucureti This paper presents a solution for using complex Win32API data structures and functions in Visual C# .NET applications. We built DLL (Dynamic Link Library) to manage the API functions and data structures and we used DLL modules in a C# application. This is an easier working way compared with the traditional way of importing and managing APIs functions in C# programs. Keywords: DLL, API (Application Programming Interface), MCI (Media Control Interface), exportable function, internal function, unmanaged code. Introducere Interfaa de programare a aplicaiilor Windows (Win32 API) este format dintr-un set consistent de funcii care ofer programelor de aplicaii diferite tipuri de servicii. Dezvoltatorii de software n limbaje precum: C, C++, Pascal etc. folosesc mai mult sau mai puin, interfee API n vederea accesrii unor resurse sau dispozitive din aplicaii Windows. Este cunoscut faptul c structurile i funciile aparinnd API conin membri respectiv parametri, variabile de tip pointer spre diferite tipuri de date. Limbajul C#.NET este un limbaj care nu utilizeaz pointerii dect n modul unsafe iar folosirea funciilor, structurilor i constantelor simbolice implic redefinirea lor folosind tipuri sinonime, adecvate din C#. Acest procedeu de lucru este facil cnd se apeleaz funcii izolate din API, dar dac complexitatea operaiilor de efectuat necesit multe apeluri de funcii i utilizarea de numeroase variabile de tip structur predefinite pentru API, atunci efortul de programare devine considerabil. Lund n considerare toate aceste aspecte este util definirea de DLL-uri de utilizator, ce export funcii, cu rol de interfa, ntre API i aplicaiile C#.NET. Astfel, funciile exportabile sunt mai uor de folosit din aplicaiile C#.NET. 2. Structura bibliotecii Win32 API Biblioteca Win32 API poate fi mprit, n funcie de serviciile pe care le ofer, n urmtoarele grupuri: Servicii Windows de baz conin servicii pentru depanare, manipularea erorilor, pentru

procese, thread-uri, fiiere, comunicaii interprocese, monitorizarea performanelor, securitate etc., Servicii pentru interfaa cu utilizatorul, numite i servicii utilizator - se ocup de gestiunea cozii de mesaje, a controalelor, a resurselor, a intrrilor la nivelul utilizatorului, Servicii pentru grafic i multimedia conin funcii pentru gestiunea culorilor, a GDI (Graphical Device Interface), a funciilor multimedia, funcii pentru gestiunea secvenelor video, a imaginilor statice, funcii OpenGL, funcii Windows Media, Servicii pentru baze de date i mesagerie conin funcii pentru gestiunea DAO (Data Access Objects), SQL server, MAPI (Messaging API), Servicii pentru reea i sisteme distribuite conin funcii pentru gestiunea cozii de mesaje, a reelei, pentru apelul procedurilor aflate la distan (Remote Procedure Call), funcii de rout-are i accesul la distan, gestiunea sincronizrilor, TAPI (Telephony API), Servicii pentru Internet, Intranet i Extranet conin funcii pentru indexare, funcii pentru manipularea Internet Explorerului, serverul web, NetShow, Servicii de gestiune a sistemului conine servicii de configurare, de gestiune sistemului i funcii setup. Fiecare grup de servicii este susinut de un set de componente ale sistemului de operare: subsistemul de DLL-uri al mediului Win32, drivere-le, serviciile sistemului de operare. Interfaa API este implementat ca un set de

74

Revista Informatica Economic nr. 1 (37)/2006

biblioteci cu legare dinamic (DLL-uri), astfel c orice aplicaie care utilizeaz funcii din API realizeaz legturi dinamice. 3. Utilizarea DLL-urilor de sistem n aplicaii C#.NET Bibliotecile cu legare dinamic (DLL) sunt module, n format executabil, care conin funcii i date. Un DLL este ncrcat la momentul execuiei prin referirea modulului. Cnd un DLL este ncrcat, el se mapeaz n spaiul de adrese al procesului care-l apeleaz. Exemplificm utilizarea bibliotecilor cu legare dinamic pentru a manipula tipul media n aplicaii C#.NET, deoarece .NET Framework nu are clase specializate n acest sens. Exist totui posibilitatea de a utiliza tipul media n C# prin folosirea bibliotecii DirectX dar ea trebuie instalat n prealabil, deci nu ofer o independen total a programului de aplicaie n raport de maina pe care el ruleaz. n plus, bibliotecile DirectX actule, implementeaz un set limitat de funcii multimedia. De aceea, utilizarea interfeelor API i MCI rmn soluii viabile pentru programarea multimedia n C# sub Windows. Apelul funciilor din DLL-uri implic utilizarea namespace-ului InteropServices, n forma: using System.Runtime.InteropServices; Prin aceast declaraie se permite utilizarea clasei DllImportAttribute prin care se indic funciile exportabile care vor fi apelate dintro bibliotec dinamic de tip unmanaged. De exemplu, dac se dorete derularea unei secvene audio, ncrcate n memorie, cu funcia sndPlaySound avnd prototipul: BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound); atunci ea trebuie redefinit n C# conform tipurilor echivalente i preciznd numele funciei aa cum ea a fost definit n DLL-ul corespunztor (winmm.dll). Fiind vorba de sunetul existent n memorie, parametrul lpszSound indic adresa zonei de memorie unde sunetul a fost ncrcat, deci nu indic numele fiierului de sunet dat printr-un ir de caractere. Pornind de la aceste ipoteze, prototipul funciei va avea forma: [DllImport("winmm.dll")] public static ex-

tern bool sndPlaySoundA(byte[] buf, uint flag); unde: buf masiv de baii care conine fiierul de sunet n memorie; flag indicator al modului de derulare a secvenei audio; sndPlaySoundA numele funciei din DLL; Funcia returneaz o valoare boolean care indic modul n care a decurs apelul funciei (cu succes sau nu). Flagurile se furnizeaz prin constante simbolice dar n C# acestea trebuie redefinite n forma: public const int SND_MEMORY=0x0004; Funciile importate dintr-un DLL unmanaged se includ ntr-o aplicaie C# ca fiind metode statice externe. In secvena urmtoare se construiete un obiect de tip StreamReader asociat fiierului care conine secvena de sunet; n vectorul de baii buf se citete coninutul fiierului, dup care se apeleaz funcia sndPlaySoundA pentru a derula secvena de sunet.
StreamReader strsunet = new StreamReader("sunet.wav"); byte[] buf = new byte[strsunet.BaseStream.Length]; strsunet.BaseStream.Read(buf,0,(int)st rsunet.BaseStream.Length); sndPlaySoundA(buf,SND_MEMORY);

Lucrurile devin complicate cnd multiple funcii API trebuie apelate, cnd acestea lucreaz cu parametri de tip structur sau cu multe constante simbolice care impun redefinirea lor n C#. Structurile care au membri de tip pointer sunt mai greu de gestionat n C# mai ales dac se impune alocarea dinamic a zonelor de memorie. O potenial soluie const n a crea DLL-uri de utilizator care s redefinesc interfaa astfel nct s fie ct mai facil de utilizat n C#, dup cum se va prezenta n continuare. 4. Construirea DLL-urilor de utilizator ca interfa ntre API i aplicaii C#.NET DLL-urile care export funcii pot conine dou tipuri de funcii: exportabile i interne. Funciile exportabile pot fi apelate din alte module, n timp ce, funciile interne pot fi apelate doar n DLL-ul n care ele au fost definite. Datele dintr-un DLL pot fi accesate prin funcii exportabile similare funciilor de acces din cadrul claselor. Bibliotecile cu legare dinamic ofer avanta-

Revista Informatica Economic nr. 1 (37)/2006

75

jul modularizrii aplicaiilor astfel c funcionalitatea lor poate fi uor modificat sau mbuntit. Un alt avantaj al utilizrii DLLurilor se refer la reducerea consumului de
API

memorie prin faptul c mai multe aplicaii care utilizeaz aceeai bibliotec, n acelai timp, au seturi de date distincte dar partajeaz acelai cod executabil.
Aplicaie C#.NET

DLL de utilizator care export funcii

Fig. 1. DLL de utilizator cu rol de interfa Controlul unei date multimedia de tip video, prin funcii API, presupune parcurgerea unui anumit scenariu. Astfel, se acceseaz streamurile, dup care ele sunt prelucrate cu funcii specifice n funcie de tipul stream-ului (video, sunet etc.). Pentru exemplificare, se va construi o bibliotec dinamic, avnd funcii exportabile, care s permit accesul, la nivel de cadru, al fluxului de imagini pentru o dat video. DLL-ul s-a construit n limbajul C i s-a folosit biblioteca vfw32.lib care s-a adugat la proiect (Properties/Linker/Additional Dependencies).

#include <windows.h> #include <vfw.h> int cderr=0; AVIFILEINFO aviinf; PAVIFILE pfile; PAVISTREAM avs; AVISTREAMINFO avisinf; PGETFRAME fr; BITMAPFILEHEADER hdr; char *data; int sfv; // functia care deschide fisierul avi ce contine data multimedia __declspec(dllexport) void deschfv(char *numef) { AVIFileInit(); LONG hr=AVIFileOpen(&pfile,(LPCTSTR)numef,OF_READ,0L); if(hr) { cderr=1; return; } AVIFileInfo(pfile,&aviinf,sizeof(aviinf)); AVIFileGetStream(pfile,&avs,streamtypeVIDEO,0L); AVIStreamInfo(avs,&avisinf,sizeof(avisinf)); fr=AVIStreamGetFrameOpen(avs,NULL); BITMAPINFOHEADER *pbim=\ (BITMAPINFOHEADER *)AVIStreamGetFrame(fr,AVIStreamStart(avs)); sfv=pbim->biSize+pbim->biClrUsed*sizeof(RGBQUAD)+pbim->biSizeImage; data = new char[sfv+sizeof(BITMAPFILEHEADER)]; hdr.bfType = 0x4d42; hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + pbim->biSize + pbim->biClrUsed * sizeof(RGBQUAD)); hdr.bfReserved1 = hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + pbim->biSize + pbim->biClrUsed * sizeof(RGBQUAD); memcpy(data,&hdr,sizeof(BITMAPFILEHEADER)); memcpy(data+sizeof(BITMAPFILEHEADER),pbim,sfv); } // functii pentru obtinerea latimii / inaltimii unui cadru __declspec(dllexport) int get_latime() { return aviinf.dwWidth; } __declspec(dllexport) int get_inaltime() { return aviinf.dwHeight; } // functie care returneaza numarul de cadre al fluxului de imagini __declspec(dllexport) int get_nrf() { return AVIStreamLength(avs); } // functie care returneaza un cadru, identificat prin numarul lui __declspec(dllexport) char *get_frame(int nrf) { memcpy(data,&hdr,sizeof(BITMAPFILEHEADER)); memcpy(data+sizeof(BITMAPFILEHEADER),AVIStreamGetFrame(fr,nrf),sfv); return data; } // functie care returneaza marimea, in baiti, a unui cadru __declspec(dllexport) int get_sizeframe() { return sfv+sizeof(BITMAPFILEHEADER); } // functie care inchide sesiunea de lucru cu data video __declspec(dllexport) void inchide()

76

Revista Informatica Economic nr. 1 (37)/2006

{ delete []data; AVIStreamGetFrameClose(fr); AVIStreamRelease(avs); AVIFileRelease(pfile); AVIFileExit(); }

Se observ c funciile exportabile care constituie interfaa cu aplicaiile ce vor folosi aceast bibliotec au parametri i returneaz valori de tipuri fundamentale, deci folosirea DLL-ului din aplicaii C# nu necesit redefiniri complexe de tipuri de date. In plus, toate tipurile definite pe baza structurilor (AVIFILEINFO, BITMAPINFOHEADER, AVISTREAMINFO etc) sunt ascunse utilizatorului
[DllImport("test_dll.dll")] [DllImport("test_dll.dll")] [DllImport("test_dll.dll")] [DllImport("test_dll.dll")] [DllImport("test_dll.dll")] [DllImport("test_dll.dll")] [DllImport("test_dll.dll")] public public public public public public public static static static static static static static

la fel ca i funciile care primesc pointeri la structuri complexe ori lucreaz cu constante simbolice (AVIFileOpen, AVIFileGetStream, AVIStreamInfo, AVIStreamGetFrameOpen etc). Utilizarea bibliotecii create, ntr-o aplicaie C#.NET, necesit redeclararea funciilor exportabile dup cum urmeaz:
extern extern extern extern extern extern extern void deschfv(string numef); int get_nrf(); int get_inaltime(); int get_latime(); IntPtr get_frame(int nrf); int get_sizeframe(); void inchide(); MemoryStream ms=new MemoryStream(pz); Bitmap bmp = new Bitmap(ms);

Se observ c funcia get_frame care returneaz cadrul propriu-zis, printr-un vector de baii a fost redeclarat cu ajutorul tipului IntPtr, folosit n C# pentru compatibilitate cu tipul pointer sau handle din C. Scenariul care trebuie urmat, const din succesiunea operaiilor: iniializare: - se declar dou variabile, una de tip ntreg i un vector de baii
int szf; byte [] pz;

- crearea unui obiect Bitmap din streamul ms - afiarea imaginii ntr-un PictureBox (pb) prin setarea proprietii Image cu bitmap-ul bmp
pb.Image=bmp;

terminare: - se finalizeaz lucrul cu data video


inchide();

- se deschide fiierul care conine video-ul


deschfv("d:\\mar\\dll\\f2.avi");

- se obine dimensiunea n baii a unui cadru (imagine fixa)


szf=get_sizeframe();

- se creaz zona de memorie n care se va copia cadrul


pz=new byte[szf];

5. Concluzii Avantajele oferite de acest mod de lucru nu se refer doar la manipularea tipului media. Exist programatori care au creat aplicaii n tehnologia SDK i prefer s reutilizeze codul deja scris pentru a realiza anumite operaii, chiar dac acum dezvolt aplicaiile n C#.NET. Bibliografie * * *, Microsoft Developer Network Library, Microsoft Press, 2005; Rimmer, S., Multimedia Programing for Windows, McGraw-Hill, 1994; Smeureanu, I., Drdal, M., Multimedia Programming Objects, Al cincilea Simpozion de Informatic Economic, A.S.E., Bucureti, 2001; Yuan, F., Window Graphics Programming Win32 GDI and DirectDraw, Prentice Hall, 2000

prelucrare (afiarea cadrului): - obinerea cadrului nrc din fluxul de imagini al filmului sub forma unui pointer
IntPtr sfr=get_frame(nrc);

- copierea n vectorul de baii, identificat prin pz, a cadrului referit de variabila sfr Marshal.Copy(sfr,pz,0,szf); Clasa Marshal conine metode pentru alocarea zonelor de memorie unmanaged, pentru conversia din tipuri de date managed n tipuri unmanaged i pentru interaciunea cu codul unmanaged. - crearea unui stream de date, n memorie, din vectorul pz

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