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

Visual C++. Programarea Interfeelor Utilizator

56

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;

butoanele de
minimazare,
maximizare,
nchidere
fereastra cadru

bara meniu
bara de titlu

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

Visual C++. Programarea Interfeelor Utilizator

58

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

click stnga

F2

F1
F3
F2

F3

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)

Windows transform
aciunea n mesaj

Fereastra
programului
primete
mesajul

Programul execut
o bucl care preia
i distribuie
mesajele:
while (getmsg(msg)
{
switch(msg)

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

Visual C++. Programarea Interfeelor Utilizator

60

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:

reprezint un stil sau o combinaie de stiluri, obinut prin intermediul


operatorului OR. Cteva din stilurile posibile sunt prezentate n tabelul 2.1:

UINT style

Tabelul 2.1
Stil
CS_BYTEALIGNWINDOW
CS_DBLCLKS
CS_HREDRAW
CS_VREDRAW
CS_NOCLOSE

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

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

61

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

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

Visual C++. Programarea Interfeelor Utilizator

62

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

Bucla de
mesaje

U
T

WM_ CHAR

Procedura fereastr

L
U
T

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

Visual C++. Programarea Interfeelor Utilizator

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

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:

TranslateMessage().

Ea

BOOL TranslateMessage(CONST MSG *lpMsg);

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:

codul ASCII al tastei apsate;


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

chCharCode = (TCHAR) wParam


lKeyData = lParam

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

Visual C++. Programarea Interfeelor Utilizator

66

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

Visual C++. Programarea Interfeelor Utilizator

70

IDM_START, IDM_ARATA

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

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

75

BEGIN
MENUITEM "&Start", IDM_START
MENUITEM "&Arata", IDM_ARATA
MENUITEM "Asc&unde", IDM_ASCUNDE
END
POPUP "&Gata"
BEGIN
MENUITEM "&Iesire", IDM_IESE
END
END
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

Visual C++. Programarea Interfeelor Utilizator

76

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

LPCTSTR lpTemplate

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);
n concluzie, va trebui s modificm procedura fereastr, astfel nct la mesajul
avnd ca parametru IDM_START s lanseze modal caseta de dialog:

WM_COMMAND

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

Visual C++. Programarea Interfeelor Utilizator

78

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().
S afim acum nemodal caseta de dialog. Va trebui nti s adugm stilul
la ablonul care descrie caseta de dialog:

WS_VISIBLE

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

79

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
...

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

81

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

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?

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

  • Minibaschet Regulament
    Minibaschet Regulament
    Document15 pagini
    Minibaschet Regulament
    Real Cayenne
    Încă nu există evaluări
  • Exercitii Pentru Scolioza
    Exercitii Pentru Scolioza
    Document11 pagini
    Exercitii Pentru Scolioza
    Real Cayenne
    100% (1)
  • Intrebari Frecvente
    Intrebari Frecvente
    Document13 pagini
    Intrebari Frecvente
    Daniel Macovei
    Încă nu există evaluări
  • Sibiu
    Sibiu
    Document36 pagini
    Sibiu
    Real Cayenne
    Încă nu există evaluări
  • Admitere 2013
    Admitere 2013
    Document1 pagină
    Admitere 2013
    Real Cayenne
    Încă nu există evaluări
  • Bopi 0497
    Bopi 0497
    Document162 pagini
    Bopi 0497
    Real Cayenne
    Încă nu există evaluări
  • Sibiu
    Sibiu
    Document36 pagini
    Sibiu
    Real Cayenne
    Încă nu există evaluări
  • Sibiu
    Sibiu
    Document36 pagini
    Sibiu
    Real Cayenne
    Încă nu există evaluări