Sunteți pe pagina 1din 28

Capitolul 2.

Noiuni de Win32 API pentru curajoi

55

2. Noiuni de Win32 API ... pentru curajoi Acronimul API este o abreviere a Application Programming Interface. Aadar Windows API (sau Win32 API) este un set de funcii oferite de sistemul de operare Windows pentru manipularea resurselor calculatorului. Orice sistem de operare ofer (sau export) un set de astfel de funcii, pentru a fi utilizate de programatori n dezvoltarea de aplicaii specifice acelui sistem de operare. Denumirea de Win32 API mai este folosit uneori pentru a marca diferena dintre sistemele de operare Windows pe 16 bii (Windows 3.X) i sistemele de operare Windows pe 32 de bii (Windows 9X, Windows NT, Windows 2000, Windows XP). Funciile din interfaa Win32 API sunt implementate n urmtoarele trei biblioteci: user32.dll, kernel32.dll i gdi32.dll. Ele sunt exportate i se pot folosi de ctre orice program, cu condiia includerii fiierului header corespunztor (care este Windows.h) i a editrii legturilor programului cu fiierul de exporturi corespunztor (user32.lib, kernel32.lib sau/i gdi32.lib). Nu v speriai, aceste trei biblioteci sunt trecute n mod automat n lista de module a editorului de legturi, n orice proiect generat de mediul Visual C++. Descrierea interfeei Win32 API poate fi gsit n help-ul on-line la indexul Platform SDK. Funciile din interfaa Win32 API sunt mprite n mai multe seciuni. Dintre acestea, cele mai importante sunt User Interface Services i Windows Base Services. 2.1. Cteva deosebiri ntre programele DOS i programele Windows n mod evident, un program Windows i un program DOS sunt foarte uor de deosebit n timpul execuiei. Un program Windows va genera interfaa de intrareieire ntr-o fereastr, prin intermediul unor controale adecvate, pe cnd un program DOS va genera o interfa intrare-ieire standard. De fapt, cu toate c fundamental programarea n C++ sub Windows i sub DOS este aceeai, diferenele dintre programele implementate sub cele dou sisteme de operare sunt mult mai multe, n cele ce urmeaz fiind enumerate cteva dintre ele: n DOS, pointerii erau mrimi reprezentate pe 16 bii. Cu alte cuvinte, prin intermediul unui pointer se putea accesa un spaiu de memorie de maximum 64 Kb. Aceasta provine din faptul c sistemul de operare DOS mparte memoria calculatorului n segmente de cte 64 de Ko, un pointer obinuit (NEAR) putnd genera adrese doar n interiorul segmentului din care face parte. Pentru a accesa o adres din alt segment, este necesar generarea unui pointer FAR (pentru aceasta exist funcia MK_FP()). n Windows nu mai exist segmentarea memoriei. Adresele sunt generate implicit pe 32 de bii, deci, n consecin i pointerii vor fi reprezentai pe 32 de bii. DOS este un sistem de operarea monotasking, adic la un moment dat poate rula un singur program. Windows este un sistem de operare multitasking, adic mai multe programe se pot afla n execuie simultan. Deci, n memoria calculatorului sunt ncrcate simultan mai multe programe, fiecare avnd bine definit spaiul

H. Vlean, 2004

56

Visual C++. Programarea Interfeelor Utilizator

propriu de adrese. Generarea unui pointer care adreseaz memoria n afara spaiului alocat programului duce la consecine dezastruoase. Windows este un sistem de operare bazat pe interfee grafice. Utilizarea funciilor de intrare-ieire scanf(), printf(), cin i cout nu va genera erori de compilare, dar nu va avea nici un efect n cadrul programului executabil. n DOS, intrrile i ieirile din programe sunt sincrone cu desfurarea lor, adic se pot introduce date doar atunci cnd programul execut instruciuni de citire i respectiv, se pot afia date, doar atunci cnd programul execut instruciuni de afiare. n Windows, pe lng intrrile-ieirile sincrone, un program poate prelua i respectiv afia date i asincron, n momentul producerii unui eveniment. Prin eveniment se nelege orice modificare n starea programului (aciuni ale utilizatorului, comenzi ale sistemului de operare, scurgerea unui interval de timp, modificarea valorii unor mrimi fanion, etc).

2.2 Tipuri de date noi folosite de funciile Win32 API Datorit diferenelor dintre programele DOS i Windows, Win32 API va utiliza o serie de tipuri de date noi. Cteva din acestea sunt: HANDLE este un tip generic (identificator) , utilizat pentru manipularea obiectelor folosite n program (fiiere, ferestre, etc.). Pentru a manipula un astfel de obiect, este necesar nti obinerea unui asemenea HANDLE, n urma apelrii unei funcii care l returneaz. Toate operaiile ulterioare cu obiectul respectiv se vor face prin intermediul mrimii HANDLE i nu prin intermediul numelui obiectului respectiv. Uzual, dac execuia funciei care returneaz identificatorul eueaz, acesta va avea valoarea NULL; HWND - este definit ca typedef HANDLE HWND; i este folosit pentru manipularea ferestrelor; DWORD (Double Word) este un ntreg fr semn pe 32 de bii. Un DWORD este compus din dou mrimi WORD. Uzual, marea majoritate a compilatoarelor permit extragerea celor dou componente WORD prin funcii de tipul high() i low(); LPVOID (Long Pointer Void) este definit ca typedef void* LPVOID, fiind deci un pointer void reprezentat pe 32 de bii; LPCSTR (Long Pointer Constant String) reprezint un pointer pe 32 de bii spre un ir de caractere constant. Este utilizat de obicei atunci cnd irul este utilizat ca parametru al unei funcii i funcia nu l modific; LPCTSTR (Long Pointer Constant To String) reprezint un pointer pe 32 de bii spre un ir de caractere constant Unicode; Unicode este un cod de caractere pe 16 bii, capabil s reprezinte caracterele tuturor limbilor. Este utilizat de platformele Windows NT (2000, XP). Windows 95, 98 i Milenium nu l utilizeaz. Pentru a defini un pointer similar, dar spre un ir ASCII, vom declara tipul LPCSTR; LPTSTR (Long Pointer To String) reprezint un pointer pe 32 de bii spre un ir de caractere n format Unicode; LPSTR (Long Pointer String) reprezint un pointer pe 32 de bii spre un ir de caractere n format ASCII; WPARAM i LPARAM cuvinte cu lungimea de 32 de bii, utilizate n general pentru a transmite parametri asociai unui mesaj Windows;

LRESULT

o valoare pe 32 de bii, returnat de o funcie;

Capitolul 2. Noiuni de Win32 API pentru curajoi

57

2.3 Ferestre ... lucrm sub Windows O fereastr este elementul fundamental, pe baza cruia se construiete orice interfa grafic utilizator. Interfaa sistemelor de operare Windows este bazat pe ferestre. Majoritatea aplicaiilor Windows posed o fereastr principal, n care ruleaz. O fereastr aloc unei aplicaii un spaiu de form dreptunghiular pe ecran, ca n fig. 2.1. O fereastr tipic este construit din 7 elemente de baz, care apoi pot fi fragmentate de programele pe care le vom construi, astfel nct unele din ele pot s lipseasc, sau pot s apar de mai multe ori. Aceste elemente sunt: cadrul fereastr (Window Frame, Main Frame) este n general zona activ care mrginete fereastra i permite redimensionarea ei. Reprezint containerul principal pentru toate celelalte componente ale ferestrei; bara de titlu (Title Bar) - afieaz titlul aplicaiei i eventual denumirea documentului deschis pentru prelucrare. Este o zon activ, care permite mutarea ferestrei pe ecran. Conine de asemenea butoanele de minimizare, maximizare i nchidere a ferestrei; butoanele de minimizare, maximizare i nchidere - apar de obicei n bara de titlu; bara de meniu (Menu Bar) - coninut tot de bara de titlu (n partea stng a acesteia). Conine unul sau mai multe meniuri pe baza crora se implementeaz diferite funcii ale programului; bara de defilare (Scroll Bar) permite utilizatorului defilarea sus-jos, respectiv dreapta-stnga n cadrul ferestrei; bara de stare (Status Bar) ofer utilizatorului informaii specifice din program; zona client a ferestrei (Client Area) - este zona pus la dispoziie pentru aplicaia ce ruleaz n fereastra respectiv;

bara meniu bara de titlu

butoanele de minimazare, maximizare, nchidere fereastra cadru

zona client
bara de defilare bara de stare

Figura 2.1 O fereastr tipic...

Ferestrele posed dou dimensiuni: X, pe orizontal i Y, pe vertical. Cu toate acestea, mulimea ferestrelor afiate pe ecran la un moment dat trebuie privit ca fiind n spaiu. Toate ferestrele au o a treia dimensiune comun, Z, i sunt caracterizate de o anumit ordine n care sunt afiate pe axa Z. De exemplu, atunci cnd apsm click stnga n interiorul unei ferestre care nu era activ i era parial ascuns, aceasta este activat (adic i se deseneaz bara de titlu cu o alta culoare) i se schimba ordinea Z (z

H. Vlean, 2004

58

Visual C++. Programarea Interfeelor Utilizator

order) a ferestrelor, de aa manier nct fereastra activat devine ultima fereastr din ordinea Z (fereastra din fa).
F1 F2 F3

click stnga

F1 F3 F2

Figura 2.2. Manipularea ferestrelor pe axa Z

Figura 2.2 prezint o asemenea situaie. De reinut faptul c la un moment dat, o singur fereastr poate fi activ. O fereastr care este activ, pe lng desenarea ei ca ultima fereastr n ordinea Z, primete input focus-ul, adic poate recepiona evenimentele produse la tastatur. Putem distinge dou tipuri de ferestre: top-level (ferestrele principale n care ruleaz o aplicaie) i child (ferestre copil, de exemplu butoanele i alte elemente de control dintr-o caset de dialog sunt ferestre copil ale casetei de dialog). O fereastr este unic identificat n sistem printr-un identificator (o variabil de tip HWND). Acest identificator se obine n urma apelrii funciei API CreateWindow(). 2.4 Mesaje Windows. Tratarea evenimentelor asincrone Orice eveniment asincron (scurgerea unui interval de timp, apsarea unei taste, mutarea mouse-lui, etc) este recepionat de ctre sistemul de operare Windows i este transformat ntr-un mesaj. Acest mesaj este transmis apoi fie ctre sistemul de operare, fie ctre programul cruia i este destinat, pentru a se executa o aciune n concordan cu evenimentul produs. O schem simplificat a acestui mecanism este prezentat n fig. 2.3.
Windows recepioneaz evenimentul (aciunea utilizatorului, scurgerea unui interval de timp, etc) Programul execut o bucl care preia i distribuie mesajele:
while (getmsg(msg) { switch(msg) }

Windows transform aciunea n mesaj

Fereastra programului primete mesajul

Figura 2.3 Aa trateaz Windows mesajele

Toate mesajele Windows au prefixul WM_, urmat de o denumire care pune n eviden evenimentul care l-a produs. Exemple de astfel de mesaje sunt: WM_KEYDOWN mesaj produs de apsarea unei taste; WM_MOUSEMOVE mesaj produs de micarea mouse-lui; WM_LEFTBUTTONDOWN mesaj produs de apsarea butonului stng al mouse-lui; WM_CLOSE mesaj produs de apsarea butonului de nchidere a ferestrei, etc. Unele din aceste mesaje, trebuie s ofere i informaii suplimentare, cum ar fi: WM_KEYPRESSED trebuie s transmit codul ASCII i codul de scanare al tastei apsate; WM_MOUSEMOVE coordonatele X i Y al cursorului mouse-lui; WM_LEFTBUTTONDOWN coordonatele X i Y ale cursorului mouse-lui n care a fost

Capitolul 2. Noiuni de Win32 API pentru curajoi

59

apsat butonul stng, etc. Alte mesaje, cum este de exemplu WM_CLOSE nu trebuie s transmit nici o informaie suplimentar. n momentul primirii unui mesaj Windows, programul cruia i este destinat trebuie s identifice mesajul i s execute secvena de instruciuni corespunztoare. Deci, o funcie foarte important ntr-un program este aceea care accept i prelucreaz mesajele transmise de sistemul de operare. Pentru ferestrele clasice, aceast funcie este o funcie special, numit procedura fereastr:
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

Ce observm referitor la aceast funcie? n primul rnd, ea returneaz o valoare LRESULT. Aceast valoare reprezint rezultatul procesrii mesajului i depinde de mesajul trimis. Ca o noutate, aceast funcie este declarat CALLBACK. O funcie CALLBACK este o funcie care recepioneaz mesaje de la sistemul de operare. Cum WndProc() are tocmai rolul de a prelua i prelucra mesajele, este normal ca ea s fie declarat CALLBACK. Funcia primete urmtoarele argumente: HWND hwnd identificatorul ferestrei (sau programului, cci s nu uitm, orice program are ataat cel puin o fereastr) pentru care se preiau mesajele; UINT uMsg mesajul transmis de sistemul de operare; WPARAM wParam, LPARAM lParam parametrii mesajului;

n funcie de mesajul primit, funcia va executa prelucrarea corespunztoare, uzual prin intermediul unui selector switch. 2.5 nregistrarea clasei de ferestre Fereastra pe care dorim s o asociem programului, n general, nu este unic. Ea este creat pe baza unor abloane, la fel cu mai multe ferestre care pot avea aceleai caracteristici (de exemplu dimensiune, stare iniial, dac se pot redimensiona sau nu, etc.). Se spune c un grup de astfel de ferestre formeaz o clas de ferestre. O clas de ferestre poate fi considerat un ablon pe baza cruia se creeaz apoi ferestre. Pentru a putea folosi o clas de ferestre, este necesar nregistrarea ei, cu funcia API RegisterClass(). La nregistrarea unei clase de ferestre, se specific, printre alte caracteristici i procedura fereastr care se va folosi de ctre ferestrele din clasa respectiv. Funcia RegisterClass() este declarat ca i:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

Funcia returneaz o valoare de tip ATOM. Tipul ATOM, cu tot numele lui ciudat, nu este altceva dect un WORD care reprezint o referin la un ir de caractere, indiferent dac irul conine majuscule sau minuscule. Astfel, spre exemplu, irul visual c va fi echivalent cu irul VISUAL C. Funcia primete de asemenea ca i parametru un pointer la o structur de tip WNDCLASS. Aceast structur definete de fapt felul n care va arta o fereastr din clasa respectiv:

H. Vlean, 2004

60

Visual C++. Programarea Interfeelor Utilizator

typedef struct _WNDCLASS { UINT style; WNDPROC pfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS;

Cmpurile structurii au urmtoarele semnificaii:


UINT style

reprezint un stil sau o combinaie de stiluri, obinut prin intermediul operatorului OR. Cteva din stilurile posibile sunt prezentate n tabelul 2.1:
Stil Semnificaie aliniaz fereastra pe orizontal n poziia dat de BYTE ntiineaz fereastra cnd utilizatorul execut un dublu click cu mousele redeseneaz ntreaga fereastr cnd utilizatorul ajusteaz dimensiunea orizontal redeseneaz ntreaga fereastr cnd utilizatorul ajusteaz dimensiunea vertical dezactiveaz comanda i butonul Close

Tabelul 2.1
CS_BYTEALIGNWINDOW CS_DBLCLKS CS_HREDRAW CS_VREDRAW CS_NOCLOSE

numele funciei CALLBACK care prelucreaz mesajele furnizate de Windows; int cbClsExtra un numr de octei suplimentari ce trebuie alocai la sfritul structurii pentru stocarea de informaii; int cbWndExtra un numr de octei suplimentari ce trebuie alocai la crearea fiecrei instane a clasei pentru stocarea de informaii; HANDLE hInstance identificator pentru instana de care aparine clasa fereastr; HICON hIcon un identificator pentru pictograma folosit de fereastr; HCURSOR hCursor un identificator pentru cursorul folosit de fereastr; HBRUSH hbrBackground un identificator pentru pensula utilizat pentru colorarea zonei client a ferestrei; LPCTSTR lpszMenuName un pointer spre un ir de caractere terminat cu \0 care reprezint numele meniului asociat clasei. Dac este NULL, se ncarc meniul implicit al clasei fereastr; LPCTSTR lpszClassName un pointer spre un ir de caractere (terminat cu \0) care reprezint numele clasei. Acest nume va fi folosit ulterior pentru crearea unei instane a clasei, adic a unei ferestre de acest tip.
WNDPROC lpfnWndProc

2.6 Crearea unei ferestre Nu vom putea executa un program sub Windows dac nu vom crea mai nti o fereastr. Crearea unei ferestre se face cu ajutorul funciei

Capitolul 2. Noiuni de Win32 API pentru curajoi


HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, Int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID lpParam );

61

Observm c, dac crearea ferestrei este reuit, funcia returneaz un identificator la fereastra respectiv. Identificatorul va fi utilizat apoi de ctre orice alt operaie asupra ferestrei pentru a o identifica. De altfel, este identificatorul pe care-l va primi i procedura fereastr asociat ferestrei nou create. Pentru crearea unei noi ferestre, va trebui s specificm urmtorii parametri: LPCTSTR lpClassName un pointer spre un ir de caractere, reprezentnd un nume valid de fereastr. Uzual este fie irul lpszClassName definit n faza de nregistrare a clasei fereastr, fie un nume predefinit de fereastr (BUTTON, LISTBOX, EDIT, COMBOBOX, STATIC, etc); LPCTSTR lpWindowName un pointer spre un ir de caractere care conine numele ferestrei. Este n general o etichet asociat ferestrei i n funcie de stilul acesteia poate fi plasat n diferite locuri; DWORD dwStyle o valoare DWORD reprezentnd stilul ferestrei. Mai multe stiluri pot fi combinate prin intermediul operatorului OR. Cteva din stilurile posibile sunt prezentate n tabelul 2.2:
Tabelul 2.2 Stil
WS_BORDER WS_CAPTION WS_DISABLED WS_HSCROLL WS_MAXIMIZE WS_MAXIMIZEBOX WS_MINIMIZE WS_MINIMIZEBOX WS_OVERLAPPED WS_OVERLAPPEDWINDOW

WS_VISIBLE WS_VSCROLL

Semnificaie creeaz o fereastr cu o linie subire ca margine creeaz o fereastr care are o bar de titlu creeaz o fereastr iniial dezactivat. O astfel de fereastr nu reacioneaz la nici un stimul de intrare din partea utilizatorului creeaz o fereastr cu bar de defilare orizontal creeaz o fereastr iniial maximizat creeaz o fereastr care are butonul de maximizare creeaz o fereastr iniial minimizat creeaz o fereastr care are butonul de minimizare creeaz o fereastr cu bar de titlu i bordur creeaz o fereastr cu stilurile implicite WS_OVERLAPPED, WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX i WS_MAXIMIZEBOX creeaz o fereastr iniial vizibil creeaz o fereastr cu bar de defilare vertical

poziia orizontal a colului stnga sus a ferestrei; int y poziia vertical a colului stnga sus a ferestrei; int nWidth lungimea pe orizontal a ferestrei; int nHeight - nlimea pe vertical a ferestrei; Observaie: pentru aceti 4 ultimi parametri, dac valorile nu sunt importante se trece valoarea CW_USERDEFAULT;
int x

H. Vlean, 2004

62

Visual C++. Programarea Interfeelor Utilizator

un identificator al ferestrei printe. Dac fereastra este primar, deci nu este lansat din alt fereastr, acest identificator este NULL; HMENU hMenu un identificator al meniului ferestrei. Dac clasa fereastr are un meniu implicit i fereastra l folosete, se trece NULL; HANDLE hInstance identificatorul instanei programului care a produs fereastra. Este necesar, deoarece n Windows pot fi n execuie simultan mai multe instane ale aceluiai program (spre exemplu, dac lansai simultan 3 Internet Explorer); LPVOID lpParam un pointer spre un ir de parametri oferii ferestrelor copil (numai pentru aplicaii Multiple Document Interface);
HWND hWndParent

2.7 Fereastra trebuie s fie vizibil! Funcia ShowWindow() Pn n acest moment am declarat o clas de ferestre i am creat o instan a acesteia, deci o nou fereastr. Fereastra nou creat exist ca obiect n memorie, dar ea trebuie i afiat pe ecran. Afiarea se face cu ajutorul funciei ShowWindow():
BOOL ShowWindow(HWND hWnd, int nCmdShow);

Funcia returneaz TRUE n caz de succes i primete urmtoarele argumente: identificatorul ferestrei nou create, ce trebuie afiat; int nCmdShow un parametru care specific modul de afiare a ferestrei. Cteva din valorile posibile pentru acest parametru sunt prezentate n tabelul 2.3:
HWND hWnd

Tabelul 2.3 Valoare


SW_HIDE SW_MAXIMIZE SW_MINIMIZE SW_RESTORE SW_SHOW

Semnificaie ascunde fereastra i activeaz o alta, dac exist maximizeaz fereastra specificat minimizeaz fereastra specificat activeaz i afieaz fereastra n starea n care a fost creat face fereastra vizibil

2.8 i acum, s prelucrm mesajele ... Evenimentele la care trebuie s rspund un program, deci implicit mesajele recepionate de acesta pot apare ntr-un ritm mult mai rapid dect este programul capabil s prelucreze. Totui, nici un mesaj nu se pierde, deoarece fiecare mesaj este stocat ntr-o coad de mesaje. Programul va extrage apoi pe rnd mesajele din coada de mesaje i le va prelucra n mod corespunztor, prin intermediul procedurii fereastr. Spre exemplu, mecanismul de generare a mesajelor de ctre Windows la apsarea tastelor i memorarea lor n coada de mesaje este prezentat n fig. 2.4. La introducerea textului SALUT!, evenimentele generate de apsarea tastelor sunt plasate n coada de mesaje. De acolo sunt extrase de ctre bucla de mesaje asociat programului i este generat mesajul WM_CHAR care este transmis pentru prelucrare procedurii fereastr.

Capitolul 2. Noiuni de Win32 API pentru curajoi

63

COADA DE MESAJE S A L Windows preia evenimentele de la tastatur i le depune n coada de mesaje U T

A L U T

Bucla de mesaje

WM_ CHAR

Procedura fereastr

Figura 2.4. Aa se trateaz mesajele

Pentru preluarea mesajelor din coada de mesaje, orice program Windows va trebui s conin o bucl de mesaje care s preia i s proceseze mesajele. Aceast bucl de mesaje este un ciclu while, compus din 3 funcii, cu implementarea de mai jos:
MSG msg; while (GetMessage(&msg, (HWND) NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }

Prima funcie utilizat, care stabilete condiia de ieire din bucla de mesaje este
BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

Funcia recepioneaz mesajele de la sistemul de operare i le stocheaz ntr-o structur MSG. Ea returneaz TRUE atta timp ct nu se primete mesajul WM_QUIT, de terminare a programului. Cu alte cuvinte, orice program Windows va executa bucla de mesaje pn la primirea din partea sistemului de operare a mesajului de terminare. Parametrii funciei au semnificaiile: un pointer la structura MSG; un identificator pentru fereastra care primete mesajul. O valoare NULL foreaz GetMessage() s rein toate mesajele; UINT wMsgFilterMin valoarea minim a mesajului primit (de obicei 0); UINT wMsgFilterMax - valoarea maxim a mesajului primit (de obicei tot 0, pentru ca GetMessage() s accepte toate mesajele);
LPMSG lpMsg HWND hWnd

Structura MSG are declaraia

H. Vlean, 2004

64
typedef struct HWND UINT WPARAM LPARAM DWORD POINT } MSG;

Visual C++. Programarea Interfeelor Utilizator


tagMSG { hwnd; message; wParam; lParam; time; pt;

cmpurile avnd urmtoarele semnificaii: HWND hwnd identificatorul ferestrei pentru care procedura fereastr asociat primete mesajele; UINT message valoarea mesajului; WPARAM wParam , LPARAM lParam valorile parametrilor asociai mesajului; DWORD time momentul trimiterii mesajului; POINT pt poziia cursorului n coordonate ecran (referitor la colul stnga sus al ecranului) n momentul n care a fost trimis mesajul. Prima funcie utilizat n interiorul buclei de mesaje este este declarat ca:
BOOL TranslateMessage(CONST MSG *lpMsg); TranslateMessage().

Ea

cu parametrul
CONST MSG *lpMsg

un pointer la structura MSG care stocheaz mesajul.

Aceast funcie are rolul de a prelua mesajele de la tastele virtuale i a le ncapsula n mesajul WM_CHAR, pe care apoi l pune n coada de mesaje. Acest mesaj este transmis de Windows ori de cte ori este apsat o tast care are asociat un cod ASCII virtual. De asemenea mesajul este generat dup unul din mesajele WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, sau WM_SYSKEYUP. Mesajul ncapsuleaz dou valori:
chCharCode = (TCHAR) wParam lKeyData = lParam

codul ASCII al tastei apsate; codul de scanare (poziia n matricea de taste) a tastei apsate;

Funcia returneaz TRUE ori de cte ori este apsat o astfel de tast i genereaz mesajul WM_CHAR. Dac mesajul transmis de sistemul de operare nu se refer la o tast virtual, funcia TranslateMessage() va ignora mesajul. Cteva din codurile tastelor virtuale (n afar de tastele caracter obinuite) sunt prezentate n tabelul 2.4:
Tabelul 2.4 Definiie
VK_BACK VK_TAB VK_LEFT VK_RIGHT VK_UP VK_DOWN VK_RETURN VK_ESCAPE VK_CONTROL

Tasta asociat Backspace Tab Sgeat stnga Sgeat dreapta Sgeat n sus Sgeat n jos Enter Esc Ctrl

Capitolul 2. Noiuni de Win32 API pentru curajoi

65

Cea de a doua funcie utilizat n bucla de mesaje este DispatchMessage() declarat ca:
LONG DispatchMessage(CONST MSG *lpmsg);

avnd acelai parametru de intrare ca i funcia precedent. Aceast funcie trimite mesajul procedurii fereastr pentru prelucrare. 2.9 S scriem un program Windows simplu Ca o concluzie la cele artate anterior, rezult c pentru scrierea unui program Windows simplu va trebui s parcurgem urmtorii pai: s declarm (eventual ntr-un fiier header) funcia callback, n cazul nostru WndProc(); s declarm i s definim clasa de ferestre utilizate ( n fiierul surs); s crem o instan a acestei clase, utiliznd funcia CreateWindow(); s stabilim starea de vizibilitate a ferestrei cu funcia ShowWindow(); s implementm bucla de mesaje; s implementm procedura fereastr;

Pentru exemplificare, vom crea un nou proiect, numit PrimaFereastra. De data aceasta, proiectul nu va fi de tip Win32 Console Application, ci Win32 Application. i de aceast dat, vom alege la pasul 1 al programului vrjitor opiunea An empty project. Vom aduga proiectului fiierul PrimaFereastra.h, cu coninutul:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

Cu alte cuvinte, am declarat procedura fereastr. Urmeaz adugarea la proiect i implementarea fiierului surs, PrimaFereastra.cpp:
#include <Windows.h> #include "PrimaFereastra.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { HWND hwndMain; MSG msg; WNDCLASS wndCls; UNREFERENCED_PARAMETER(lpCmdLine); wndCls.style = 0; wndCls.lpfnWndProc = (WNDPROC) WndProc; wndCls.cbClsExtra = 0; wndCls.cbWndExtra = 0; wndCls.hInstance = hInstance; wndCls.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION); wndCls.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); wndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndCls.lpszMenuName = NULL;

H. Vlean, 2004

66

Visual C++. Programarea Interfeelor Utilizator


wndCls.lpszClassName = "MainWndClass"; if (!RegisterClass(&wndCls)) return FALSE; hwndMain = CreateWindow("MainWndClass", "PrimaFereastra", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, hInstance, (LPVOID) NULL); if (!hwndMain) return FALSE; ShowWindow(hwndMain, nCmdShow); UpdateWindow(hwndMain); while (GetMessage(&msg, (HWND) NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg){ case WM_CLOSE: PostMessage(hwnd, WM_QUIT, 0L, 0L); return DefWindowProc(hwnd, uMsg, wParam, lParam); default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }

S comentm puin programul. n primul rnd, funcia principal a programului nu mai este main(), ci WinMain(). Aceast funcie returneaz ntotdeauna la terminare o valoare, care este uzual valoarea cmpului wParam din structura MSG. WinMain() nu poate fi utilizat fr cele 4 argumente asociate. Programul declar identificatorul ferestrei asociate programului, coada de mesaje asociat i clasa de ferestre utilizat. Dup care, construiete aspectul clasei de ferestre i nregistreaz clasa respectiv. Dac nregistrarea eueaz, programul se termin returnnd codul de eroare FALSE. Dup nregistrarea clasei, este creat fereastra programului apelnd funcia Aceast funcie returneaz n caz de creare reuit, un identificator al ferestrei. n caz contrar, identificatorul este ncrcat cu NULL i programul se termin. Pe baza identificatorului, este stabilit starea de vizibilitate a ferestrei cu funcia ShowWindow() i apoi este reactualizat zona client a ferestrei (fundal, coninut, etc) cu ajutorul funciei UpdateWindow() (n cazul nostru simplu, apelul acestei funcii nu este necesar). n final, programul execut bucla de mesaje, iar la primirea mesajului WM_QUIT i ncheie execuia.
CreateWindow().

Capitolul 2. Noiuni de Win32 API pentru curajoi

67

Procedura fereastr trateaz doar cazul mesajului WM_CLOSE, care termin programul. n cazul apariiei acestui mesaj, se apeleaz funcia PostMessage() pentru transmiterea mesajului WM_QUIT. Funcia PostMessage() cu declaraia
BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

avnd semnificaiile cunoscute pentru parametri, plaseaz mesajul specificat n coada de mesaje asociat programului. S vedem cum putem interpreta i alte mesaje. S modificm programul, astfel nct la apsarea tastelor descrise n tabelul 2.4, s ne fie afiat un mesaj care s specifice ce tast a fost apsat. Afiarea mesajului se face cu funcia
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

unde: identificatorul ferestrei n care se va afia mesajul; LPCTSTR lpText mesajul afiat; LPCTSTR lpCaption eticheta afiat n bara de titlu; UINT uType tipul ferestrei utilizate pentru afiare;
HWND hwnd

Ce va trebui s modificm? Evident, procedura fereastr, astfel nct s trateze i mesajul WM_KEYDOWN. Pentru acest mesaj, parametrul wParam conine codul tastei apsate.
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg){ case WM_CLOSE: PostMessage(hwnd, WM_QUIT, 0L, 0L); return DefWindowProc(hwnd, uMsg, wParam, lParam); case WM_KEYDOWN: LPCTSTR text; switch(wParam){ case VK_BACK: text="Ati apasat BackSpace"; break; case VK_TAB: text="Ati apasat Tab"; break; case VK_LEFT: text="Ati apasat SageataStinga"; break; case VK_RIGHT: text="Ati apasat SageataDreapta"; break; case VK_UP: text="Ati apasat SageataSus"; break; case VK_DOWN: text="Ati apasat SageataJos"; break; case VK_RETURN: text="Ati apasat Enter"; break; case VK_ESCAPE: text="Ati apasat Escape"; break; case VK_CONTROL: text="Ati apasat Control"; break; default: text="Ati apasat alta tasta"; } MessageBox(hwnd, text, "Mesaj",MB_OK|MB_ICONEXCLAMATION); return DefWindowProc(hwnd, uMsg, wParam, lParam); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }

H. Vlean, 2004

68

Visual C++. Programarea Interfeelor Utilizator

2.10 S utilizm cteva clase Windows predefinite Am vzut la paragraful 2.6 c parametrul lpClassName poate lua n funcia CreateWindow() cteva valori predefinite, fiind astfel create ferestre din clasele predefinite. S adugm n fereastra noastr, cteva astfel de ferestre de clas predefinit. Vom modifica fiierul PrimaFereastra.cpp ca mai jos:
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { ... UpdateWindow(hwndMain); HWND hText = CreateWindow( "STATIC", "Eticheta Statica", WS_CHILD | WS_VISIBLE | SS_LEFT,20, 20, 100, 15, hwndMain,NULL, hInstance, NULL ); HWND hEdit = CreateWindow( "EDIT", "", WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER, 20, 40, 100, 20, hwndMain,NULL,hInstance, NULL ); HWND hBtn = CreateWindow( "BUTTON", "Buton de Comanda", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 80, 150, 30, hwndMain,NULL, hInstance, NULL ); HWND hListb = CreateWindow( "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , 20, 120, 150, 50, hwndMain,NULL, hInstance, NULL ); HWND hCombo = CreateWindow( "COMBOBOX", "", WS_CHILD | WS_VISIBLE , 20, 180, 150, 30, hwndMain,NULL, hInstance, NULL ); while (GetMessage(&msg, (HWND) NULL, 0, 0)) ...

Figura 2.5. Interfaa programului

Ce am fcut? Observm c am utilizat funciile CreateWindow() cu denumirea clasei predefinite pentru fiecare fereastr n parte, asociind n acelai timp un identificator. Toate ferestrele sunt ferestre copil ale ferestrei principale, identificate prin identificatorul hwnMain. Acest identificator este transmis ca parametrul hWndParent funciei CreateWindow(). Am obinut astfel interfaa din fig. 2.5.

Capitolul 2. Noiuni de Win32 API pentru curajoi

69

2.11 Fiiere de resurse. Adugarea unui meniu Un program Windows, pe lng fereastra principal, poate conine i alte elemente: bare de instrumente, bare de stare, meniuri, diferite casete de dialog, etc. Aceste resurse, n general nu se modific n timpul execuiei programului. Uzual, ele sunt descrise n fiiere text speciale, numite fiiere de resurse. Aceste fiiere au extensia .rc. Din pcate, mediul Visual C++ afieaz ntr-o form grafic coninutul unui fiier de resurse, deci pentru a putea crea un astfel de fiier i a-l gestiona n format text, va trebui s pclim mediul de programare. S crem fiierul PrimaFereastr.rc. Vom crea un fiier gol cu acest nume, prin orice metod cunoscut: copy con, Notepad, etc. Apoi, acest fiier va fi adugat la proiect. Cum? Alegem n meniu opiunea Project->Add to Project->Files i apoi, n browser se selecteaz fiierul PrimaFereastra.rc. n acest fiier, vom descrie o bar de meniu asociat ferestrei programului. nainte, s aflm cte ceva despre meniuri. Windows manipuleaz dou tipuri de meniuri: meniuri principale (top-level menu) i respectiv meniuri derulante (pop-up menu). Meniul principal este constituit dintr-un set de comenzi vizibile permanent n bara de meniu a ferestrei principale. n marea majoritate a cazurilor, acestea reprezint doar puncte de intrare pentru meniurile derulante. Aceste meniuri sunt desfurate la alegerea unei opiuni din meniul principal. S completm fiierul PrimaFereastr.rc ca mai jos:
MENIUFEREASTRA MENU DISCARDABLE BEGIN POPUP "&Caseta" BEGIN MENUITEM "&Start", IDM_START MENUITEM "&Arata", IDM_ARATA MENUITEM "Asc&unde", IDM_ASCUNDE END POPUP "&Gata" BEGIN MENUITEM "&Iesire", IDM_IESE END END

Ce am fcut? Am declarat o resurs meniu (specificat prin cuvntul rezervat pe care o vom numi MENIUFEREASTRA. Prin specificarea faptului c aceast resurs este DISCARDABLE precizm editorului de legturi s elimine informaia iniial a resursei despre meniu dup ce programul nregistreaz meniul n clasa ferestrei. Prin utilizarea acestui cuvnt rezervat pentru resursele meniu, se face o economie de memorie i viteza de execuie a programului crete. Descriptorul POPUP precizeaz nivelul cel mai de sus al meniului (corespunztor n cazul nostru meniului principal). Linia POPUP "&Caseta" creeaz o intrare de forma Caseta n meniul principal. Deci, caracterul & din definiie, va face ca litera care urmeaz s apar ca accelerator i va apare subliniat n meniu. Prin alegerea acestei opiuni, va fi deschis lista derulant care cuprinde toate elementele de meniu asociate intrrii, descrise de descriptorul MENUITEM i cuprinse ntre BEGIN i END. De exemplu, lista derulant asociat intrrii de meniu Caseta va conine intrrile Start, Arata i Ascunde, identificate prin intermediul identificatorilor
MENU)

H. Vlean, 2004

70

Visual C++. Programarea Interfeelor Utilizator

i IDM_ASCUNDE. Similar se creeaz intrarea de meniu Gata cu lista derulant Iesire, identificat prin IDM_IESE. Deoarece identificatorii sunt mrimi UINT, adic ntregi fr semn, va trebui s asociem astfel de valori pentru identificatorii elementelor de meniu. Deoarece aceti identificatori trebuie s fie recunoscui n toate fiierele proiectului, ar fi bine s-i definim n fiierul PrimaFereastra.h:
#define #define #define #define IDM_START IDM_ARATA IDM_ASCUNDE IDM_IESE 110 120 121 130

IDM_START, IDM_ARATA

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

Valorile asociate identificatorilor sunt alese la ntmplare. Cum valorile identificatorilor sunt definite n fiierul header, va trebui s includem acest fiier n fiierul resurs:
#include "PrimaFereastra.h" MENIUFEREASTRA MENU DISCARDABLE

n acest moment, resursa meniu este definit i adugat la proiect. Ea trebuie acum afiat de ctre fereastra principal a programului. Va trebui nti s ncrcm resursa meniu i apoi s-l declarm meniu implicit pentru fereastr. ncrcarea meniului se face cu ajutorul funciei
HMENU LoadMenu(HINSTANCE hInstance, LPCTSTR lpMenuName);

cu semnificaiile parametrilor: HINSTANCE hInstance identificatorul instanei programului n care se ncarc meniul; LPCTSTR lpMenuName numele (din fiierul .rc) al meniului; Meniul ncrcat este declarat ca i meniu implicit al ferestrei programului, utiliznd funcia:
BOOL SetMenu(HWND hWnd, HMENU hMenu);

unde HWND hWnd identificatorul ferestrei n care se ncarc meniul; HMENU hMenu identificatorul meniului (generat de funcia LoadMenu()); Pentru ncrcarea meniului, vom completa fiierul PrimaFereastra.cpp ca mai jos:
if (!hwndMain) return FALSE; else { HMENU hnewMenu=LoadMenu(hInstance,"MENIUFEREASTRA"); SetMenu(hwndMain,hnewMenu); }

Capitolul 2. Noiuni de Win32 API pentru curajoi

71

Astfel meniul este ncrcat numai dac crearea ferestrei este reuit. n acest caz, obinem interfaa din fig. 2.6.

Figura 2.6. Interfaa cu meniu

2.12 Interceptarea i prelucrarea evenimentelor generate de meniu Orice selectare a unui element de meniu va face ca Windows s trimit mesajul buclei de mesaje. Identificatorul articolului de meniu este transmis ca i cuvntul cel mai puin semnificativ al parametrului wParam. Deci, pentru identificarea intrrii n meniu care a generat mesajul, funcia fereastr va trebui s testeze valoarea loword(wParam). S modificm programul astfel nct alegerea opiunii Iesire s distrug fereastra i s termine programul. Avem dou posibiliti de distrugere a ferestrei i de nchidere a programului: fie s executm aceeai secven de instruciuni ca i n cazul mesajului WM_CLOSE, fie s utilizm funcia de distrugere a ferestrei:
WM_COMMAND BOOL DestroyWindow(HWND hWnd);

unde
HWND hWnd

identificatorul ferestrei care se distruge;

Pentru programul nostru, vom alege aceast din urm variant. S ne reamintim c identificatorul elementului de meniu selectat este testat de secvena loword(wParam). Va trebui s modificm procedura fereastr ca mai jos:
LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg){ case WM_CLOSE: PostMessage(hwnd, WM_QUIT, 0L, 0L); return DefWindowProc(hwnd, uMsg, wParam, lParam); case WM_KEYDOWN: LPCTSTR text;

...

H. Vlean, 2004

72

Visual C++. Programarea Interfeelor Utilizator


default: text="Ati apasat alta tasta"; break; } MessageBox(hwnd, text, "Mesaj",MB_OK|MB_ICONEXCLAMATION); return DefWindowProc(hwnd, uMsg, wParam, lParam); break; case WM_COMMAND : switch( LOWORD( wParam ) ) { case IDM_IESE: DestroyWindow(hwnd); return DefWindowProc(hwnd, uMsg, wParam, lParam); } default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }

Observm c am transmis funciei DestroyWindow() identificatorul ferestrei principale. Aceasta va fi distrus i programul se va termina. S modificm acum programul, astfel nct ferestrele de clase predefinite s nu fie create i s apar la lansarea n execuie a programului, ci doar la selecia opiunii de meniu Arata. De asemenea, la alegerea opiunii Ascunde, aceste ferestre dorim s fie distruse. Pentru aceasta, n primul rnd, va trebui s tergem liniile de program introduse la paragraful 2.10, deoarece acele ferestre sunt create doar n cadrul procedurii fereastr, la prelucrarea mesajului WM_COMMAND generat de IDM_ARATA. Apoi, va trebui s facem observaia c procedura fereastr nu primete ca parametru instana programului cruia i aparine fereastra principal, dar la crearea instanelor ferestrelor predefinite este nevoie de aceasta. Deci, va trebui s declarm o variabil HINST global, care dup crearea ferestrei principale s se ncarce cu identificatorul instanei utilizat de clasa fereastr (hInstance n cazul nostru). Aceast variabil global va putea fi utilizat apoi de ctre procedura fereastr. Pentru aceasta, vom modifica fiierul PrimaFereastr.cpp ca mai jos:
#include <Windows.h> #include "PrimaFereastra.h" HINSTANCE hInst; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { ... hwndMain = CreateWindow("MainWndClass", "PrimaFereastra", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, hInstance, (LPVOID) NULL); hInst=hInstance; if (!hwndMain) ...

Capitolul 2. Noiuni de Win32 API pentru curajoi

73

Modificrile n funcia fereastr vor fi:


LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static HWND hText=NULL; static HWND hEdit=NULL; static HWND hBtn=NULL; static HWND hListb=NULL; static HWND hCombo=NULL; switch(uMsg){ case WM_CLOSE: ... case WM_COMMAND : switch( LOWORD( wParam ) ) { case IDM_ARATA: hText = CreateWindow( "STATIC", "Eticheta Statica", WS_CHILD | WS_VISIBLE | SS_LEFT,20, 20, 100, 15, hwnd,NULL, hInst, NULL ); hEdit = CreateWindow( "EDIT", "",WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,20, 40, 100, 20, hwnd,NULL,hInst, NULL ); hBtn = CreateWindow( "BUTTON", "Buton de Comanda", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 80, 150, 30, hwnd, NULL, hInst, NULL ); hListb = CreateWindow( "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , 20, 120, 150, 50, hwnd,NULL, hInst, NULL ); hCombo = CreateWindow( "COMBOBOX", "", WS_CHILD | WS_VISIBLE , 20, 180, 150, 30, hwnd,NULL, hInst, NULL ); break; case IDM_ASCUNDE: DestroyWindow(hText); DestroyWindow(hEdit); DestroyWindow(hBtn); DestroyWindow(hListb); DestroyWindow(hCombo); break; case IDM_IESE: DestroyWindow(hwnd); return DefWindowProc(hwnd, uMsg, wParam, lParam); } default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }

S vedem ce am modificat. n primul rnd, am declarat identificatori pentru fiecare din obiectele create de apelul funciei CreateWindow(). Aceti identificatori trebuie declarai la nceputul procedurii fereastr, deoarece ei trebuie s fie vizibili n corpul a doi selectori case. Am declarat de asemenea variabilele ca fiind statice pentru ca domeniul lor de existen s fie toat durata programului. Cum identificatorii sunt variabile statice, ei trebuie iniializai i cum nu sunt asociai nici unei ferestre deocamdat, e normal s fie iniializai cu NULL. La apelul funciilor CreateWindow(), ca deosebiri fa de paragraful 2.10, se pot enumera utilizarea parametrului hwnd pentru identificarea instanei ferestrei principale i respectiv al identificatorului global hInst, n loc de hwndMain i respectiv hInstance, al cror domeniu de vizibilitate se rezum la funcia WinMain().
H. Vlean, 2004

74

Visual C++. Programarea Interfeelor Utilizator

2.13 Casete de dialog Casetele de dialog sunt un alt tip de fereastr foarte des utilizat de programele Windows pentru implementarea interfeelor. Aceste casete sunt utilizate de obicei pentru a prezenta de o manier unitar diferite controale necesare introducerii i afirii datelor. Spre deosebire de celelalte tipuri de ferestre, casetele de dialog folosesc o funcie implicit de prelucrare a mesajelor de la tastatur, fcnd mai uoar prelucrarea intrrilor furnizate de utilizator. Casetele de dialog pot fi afiate ca i fereastr principal a programului, dar, n foarte multe programe ele sunt folosite ca i ferestre copil, lansate la alegerea unor opiuni de meniu n fereastra principal a programului. Acest mod de utilizare a lor l vom descrie n cele ce urmeaz. Casetele de dialog pot fi afiate n dou moduri: ca i casete modale i respectiv, ca i casete nemodale. O caset modal acapareaz n totalitate controlul mesajelor, astfel c utilizatorul nu va putea face activ o alt fereastr a programului care a lansat caseta, pn la nchiderea casetei modale. Utilizatorul va putea ns comuta n orice alt fereastr aparinnd altui program. Ca o consecin, programul care a lansat caseta modal nu poate comanda nchiderea acesteia, acest lucru putndu-se face doar din interiorul casetei. Casetele nemodale pot primi sau pierde focusul fr nici o problem. Spre deosebire de casetele modale, ele pot fi nchise att din interiorul lor, ct i din orice alt fereastr a programului din care fac parte. nainte de utilizare, caseta de dialog trebuie construit. Construcia ei este realizat pe baza unui ablon, implementat uzual n fiierul de resurse. ablonul are urmtoare construcie:
identificator_caseta DIALOG DISCARDABLE x, y, lungime, inaltime STYLE stil1 | stil2 | | stiln CAPTION Titlul casetei de dialog FONT dimensiune_litere, nume litere BEGIN descriere control1 descriere controln END

Mrimile x, y, lungime, inaltime reprezint coordonatele colului stnga sus a casetei, respectiv dimensiunile ei. Controalele descrise n seciunea BEGIN ... END a ablonului pot fi alese din urmtoarele: BUTTON, CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, ICON, LISTBOX, LTEXT, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR, STATIC. S modificm fiierul PrimaFereastra.rc astfel nct s descriem o caset de dialog:
#include <Windows.h> #include "PrimaFereastra.h" MENIU MENU DISCARDABLE BEGIN POPUP "&Caseta"

Capitolul 2. Noiuni de Win32 API pentru curajoi


BEGIN MENUITEM "&Start", IDM_START MENUITEM "&Arata", IDM_ARATA MENUITEM "Asc&unde", IDM_ASCUNDE END POPUP "&Gata" BEGIN MENUITEM "&Iesire", IDM_IESE END END

75

CASETAMODALA DIALOG DISCARDABLE 22, 17, 200, 140 STYLE DS_MODALFRAME |WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU CAPTION "Caseta Modala/Nemodala" FONT 10, "Times New Roman"" BEGIN CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 140, 10, 50, 14 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 140, 30, 50, 14 GROUPBOX "Butoane Radio", IDC_GRUPB, 10,10, 100, 50 RADIOBUTTON "Adevarat", IDC_RADIO1, 30, 25, 110,10, WS_GROUP | WS_TABSTOP RADIOBUTTON "Fals", IDC_RADIO2, 30, 40, 110,10, WS_TABSTOP CONTROL "Introduceti textul", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 15, 100, 80, 10 EDITTEXT IDC_EDIT1, 90, 95,100,20 END

Ce descrie ablonul? O caset de dialog identificat de identificatorul CASETAMODALA, care are colul stnga sus la coordonatele (22,17) i dimensiunile 200 respectiv 140 pixeli. Caseta de dialog va avea titlul n bara de titlu Caseta Modala/Nemodala i va utiliza litere Times New Roman de dimensiune 10. Caseta va conine un buton de comand cu eticheta OK, avnd identificatorul IDOK, cu colul stnga sus de coordonate (140,10) i dimensiuni 50 i 14, etc. Se observ c descrierea controalelor afiate de caset se poate face n dou moduri: cu cuvntul CONTROL i respectiv doar cu tipul controlului. n descrierea de mai sus am folosit ambele moduri de descriere, din raiuni didactice, dar uzual, se utilizeaz doar unul din ele. Cele dou moduri de descriere sunt absolut echivalente i le putei gsi bine documentate n MSDN. Deoarece abloanele de descriere a controalelor sunt stocate n Windows.h, va trebui s includem i aceast bibliotec. De asemenea, vor trebui asociate valori n fiierul PrimaFereastra.h pentru identificatorii nou introdui:
... #define IDM_IESE #define IDC_GRUPB #define IDC_RADIO1 #define IDC_RADIO2 #define IDC_EDIT1

130 201 202 203 204

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

H. Vlean, 2004

76

Visual C++. Programarea Interfeelor Utilizator

Am obinut astfel o caset de dialog cu aspectul din fig. 2.7.

Figura 2.6. Caseta de dialog

2.13.1 Afiarea modal a casetei de dialog Caseta de dialog e creat, dar programul nu o afieaz. Dorim ca afiarea ei s se fac modal, la alegerea opiunii Start. Lansarea modal a unei casete de dialog se face cu macrocomanda (similar funciei)
int DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc );

avnd urmtorii parametri:


HINSTANCE hInstance

identificatorul instanei programului n care se lanseaz

caseta; numele sau identificatorul (din fiierul .rc) al ablonului ce descrie caseta de dialog; HWND hWndParent identificatorul ferestrei printe (din care se lanseaz caseta); DLGPROC lpDialogFunc un pointer spre o funcie CALLBACK care trateaz mesajele transmise spre caset (procedura caset de dialog);
LPCTSTR lpTemplate

WM_COMMAND

n concluzie, va trebui s modificm procedura fereastr, astfel nct la mesajul avnd ca parametru IDM_START s lanseze modal caseta de dialog:

LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { ... case IDM_IESE: DestroyWindow(hwnd); return DefWindowProc(hwnd, uMsg, wParam, lParam); case IDM_START : DialogBox( hInst, "CASETAMODALA", hwnd, (DLGPROC)Modal ); break; } default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }

Capitolul 2. Noiuni de Win32 API pentru curajoi

77

Observm c parametrul DLGPROC lpDialogFunc conine adresa unei funcii numite Modal(). Aceasta este funcia CALLBACK (pe care urmeaz s o declarm i s o definim) care va trata mesajele asociate casetei de dialog. De ce e nevoie de o conversie explicit de tip? S ne reamintim, funciile CALLBACK sunt de tip LPRESULT, deci va trebui s facem explicit o conversie la tipul DLGPROC. Acum va trebui s declarm funcia, ca o funcie CALLBACK obinuit. O vom face n fiierul PrimaFereastra.h:
... LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK Modal(HWND, UINT, WPARAM, LPARAM); Definirea funciei o vom face n fiierul PrimaFereastra.cpp, ca mai jos: LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { ... default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } LRESULT CALLBACK Modal( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return (TRUE); case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, TRUE); return (TRUE); } break; } return (FALSE); }

Funcia trateaz dou mesaje: primul, WM_INITIALOG, este mesajul transmis de Windows procedurii dialog chiar nainte de afiarea casetei. Este utilizat de obicei pentru iniializarea controalelor coninute de caset. n cazul nostru, nu face altceva dect s marcheze faptul c, crearea i afiarea casetei de dialog a reuit, dar n capitolele urmtoare ne va fi deosebit de util. Al doilea mesaj tratat este WM_COMMAND, care trateaz apsarea butoanelor OK i Cancel. Identificatorii acestora sunt transmii n cadrul mesajului n partea cea mai puin semnificativ a parametrului wParam. La apsarea unuia din butoane, se apeleaz funcia:

H. Vlean, 2004

78

Visual C++. Programarea Interfeelor Utilizator

BOOL EndDialog(HWND hDlg,int nResult);

unde
HWND hDlg

identificatorul casetei de dialog creia i este asociat procedura

dialog;
int nResult

valoarea returnat aplicaiei de funcia ce a creat caseta de dialog;

Astfel, la apsarea unuia din cele 2 butoane, caseta va fi nchis. 2.13.2 Afiarea nemodal a casetei de dialog O caset este afiat nemodal prin intermediul macrocomenzii
HWND CreateDialog(HINSTANCE hInstance,LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc);

cu un identificator al instanei programului care conine ablonul de creare a casetei de dialog; LPCTSTR lpTemplate numele sau identificatorul (din fiierul .rc) al ablonului ce descrie caseta de dialog; HWND hWndParent identificatorul ferestrei printe (din care se lanseaz caseta); DLGPROC lpDialogFunc un pointer spre o funcie CALLBACK care trateaz mesajele transmise spre caset (procedura caset de dialog);
HINSTANCE hInstance

Funcia returneaz n caz de succes un identificator al casetei de dialog create. Pentru a fi vizibil, caseta trebuie neaprat s aib stilul WS_VISIBLE, spre deosebire de caseta modal, de a crei afiare este responsabil macrocomanda DialogBox().O caset creat cu macrocomanda CreateDialog() va trebui la nchidere distrus cu funcia DestroyWindow().
WS_VISIBLE

S afim acum nemodal caseta de dialog. Va trebui nti s adugm stilul la ablonul care descrie caseta de dialog:

CASETAMODALA DIALOG DISCARDABLE 22, 17, 200, 140 STYLE DS_MODALFRAME |WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_VISIBLE ...

Acest nou stil adugat nu influeneaz cu nimic afiarea modal a casetei. Acum, va trebui s crem o nou intrare n meniu, care s permit lansarea nemodal. Fie Deschide Nemodal aceast intrare. Pentru aceasta, va trebui s modificm fiierul de resurse,
... MENIU MENU DISCARDABLE BEGIN POPUP "&Caseta" BEGIN ...

Capitolul 2. Noiuni de Win32 API pentru curajoi


MENUITEM "Asc&unde", IDM_ASCUNDE MENUITEM "&Deschide Nemodal", IDM_DNEMOD END ... i s definim n fiierul header noul identificator adugat: ... #define IDM_IESE 130 #define IDM_DNEMOD 140 ...

79

Va trebui acum, s declarm n fiierul surs, un identificator HWND care s fie actualizat de macrocomanda CreateDialog() n caz de succes. Deoarece acest identificator va trebui s fie vizibil att n procedura fereastr, care lanseaz nemodal caseta, ct i n procedura dialog asociat casetei, l vom declara global:
#include <Windows.h> #include "PrimaFereastra.h" HINSTANCE hInst; HWND pDlgNemod=NULL; ...

Nu ne mai rmne altceva de fcut, dect s interceptm n cadrul procedurii fereastr a mesajului WM_COMMAND generat de alegerea intrrii de meniu Deschide Nemodal (avnd identificatorul IDM_DNEMOD):
LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { ... case IDM_START : DialogBox( hInst, "CASETAMODALA", hwnd, (DLGPROC)Modal ); break; case IDM_DNEMOD: if (!pDlgNemod) pDlgNemod=CreateDialog(hInst, "CASETAMODALA", hwnd, (DLGPROC)Nemodal); break; } default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }

Cum funcioneaz? Dac pDlgNemod e NULL, adic nu este ncrcat cu adresa nici unei casete nemodale, se apeleaz macrocomanda CreateDialog(). Dac aceasta se execut cu succes, va actualiza identificatorul pDlgNemod cu adresa casetei nemodale. Astfel, va exista la un moment dat o singur caset nemodal lansat, crearea i afiarea unei noi casete nemodale fiind mpiedicat de condiia if(). Macrocomanda CreateDialog() primete ca ultim argument un pointer spre o procedur dialog care trateaz mesajele generate de Windows spre caset. Aceast procedur dialog am numit-o Nemodal() i va trebui declarat i definit.

H. Vlean, 2004

80

Visual C++. Programarea Interfeelor Utilizator

Pentru aceasta, n fiierul PrimaFereastr.h vom aduga linia


... LRESULT CALLBACK Modal(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK Nemodal(HWND, UINT, WPARAM, LPARAM); iar n fiierul PrimaFereastra.cpp vom defini funcia ca mai jos: LRESULT CALLBACK Nemodal( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return (TRUE); case WM_COMMAND: if ( LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { DestroyWindow(hDlg); pDlgNemod=NULL; return (TRUE); } break; } return (FALSE); }

La apsarea butoanelor IDOK sau IDCANCEL, este apelat funcia DestroyWindow(), care distruge caseta nemodal. Apoi, identificatorul pDlgNemod este ncrcat cu NULL, pentru a putea fi lansat o nou caset de dialog. Spre deosebire de casetele modale, o caset nemodal poate fi nchis chiar de programul care a lansat-o. Este oarecum normal, dac ne gndim c o astfel de caset nu captureaz n totalitate controlul interfeei ca i o caset modal. Haidei s ncercm s implementm i aceast activitate. Pentru nceput, n fiierul PrimaFereastr.rc s declarm o nou intrare de meniu:
... MENIU MENU DISCARDABLE BEGIN POPUP "&Caseta" BEGIN ... MENUITEM "&Deschide Nemodal", IDM_DNEMOD MENUITEM "&Inchide Nemodal", IDM_INEMOD END ... Acum, dup cum deja tim, va trebui s asociem o valoare noului identificator (n fiierul PrimaFereastr.h): ... #define IDM_DNEMOD #define IDM_INEMOD ... 140 141

i, n final, s tratm mesajul corespunztor n procedura fereastr:

Capitolul 2. Noiuni de Win32 API pentru curajoi


case IDM_DNEMOD: ... break; case IDM_INEMOD: if (pDlgNemod) { DestroyWindow(pDlgNemod); pDlgNemod=NULL; } break; ...

81

Observm c modul de distrugere a casetei de dialog este similar cu cel din funcia De aceast dat ns, funcia DestroyWindow() primete ca parametru identificatorul pDlgNemodal. E corect, acesta identific caseta nemodal.
Nemodal().

Ca o observaie, vom putea lansa simultan caseta, att modal ct i nemodal. (fig. 2.7):

caseta nemodal

caseta modal

Figura 2.7. Se pot lansa simultan o caset modal i una nemodal

ntrebri i probleme propuse 1. 2. 3. 4. Implementai i executai toate exemplele propuse n capitolul 2; Cum se transmite o aciune a utilizatorului ctre un program aflat n execuie? Ce este un identificator? De ce tip este identificatorul unei ferestre? Adugai programului dumneavoastr urmtoarea secven de cod aferent ferestrei principale:
case WM_CLOSE: MessageBox(hwnd, "Aplicatie terminata!", "Mesaj", MB_OK|MB_ICONEXCLAMATION); PostMessage(hwnd, WM_QUIT, 0L, 0L); return DefWindowProc(hwnd, uMsg, wParam, lParam);

Unde trebuie adugat i ce efect are?

H. Vlean, 2004

82

Visual C++. Programarea Interfeelor Utilizator

5. Modificai programul astfel nct fereastra principal a programului s nu mai aib butoanele de minimizare i maximizare i nici barele de defilare orizontal i vertical. 6. La ce folosesc fiierele de resurse? 7. De ce identificatorul pDlgNemod este definit global?