Documente Academic
Documente Profesional
Documente Cultură
1 (37)/2006
73
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
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-
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
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
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;
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