Sunteți pe pagina 1din 16

Ce este greşit în acest program?

Modelul de afişare pentru programul „Hello, world!" şi pentru alte programe C tradiţionale este o componentă
hardware antică numită teleimprimator. Teleimprimatorul seamănă cu o maşină de scris cu o rolă de hârtie
continuă. Într-un trecut nu prea îndepărtat, programatorii stăteau în faţa unui astfel de teleimprimator şi scriau
comenzi al căror „ecou" apărea pe hârtie. Calculatorul răspundea la comenzi prin tipărirea răspunsurilor tot pe
hârtie.
Odată cu apariţia terminalelor sistemelor mainframe şi a calculatoarelor personale, ideea teleimprimatorului a
fost extinsă şi pentru monitoarele video. Monitoarele video erau folosite ca un „teleimprimator de sticlă" care, pur
şi simplu, derula imaginea în momentul când textul scris ajungea în partea de jos a ecranului.
Cum poate programul tradiţional „Hello, world!" să afişeze text fără să îi comunice sistemului de operare la ce
dispozitiv de ieşire să fie afişat textul? Simplu, deoarece există un singur dispozitiv de ieşire - ecranul, folosit ca
teleimprimator. Dacă utilizatorul doreşte ca rezultatele să fie trimise în altă parte, trebuie să le redirecţioneze
folosind linia de comandă.
Cum poate programul să afişeze text fără să îi comunice sistemului de operare în ce poziţie urmează să fie
afişat acesta? Textul este afişat întotdeauna acolo unde se află cursorul - de obicei pe următoarea linie după
comanda de executare a programului. Dacă vreţi să afişaţi mesajul „Hello, world!" în centrul ecranului, trebuie să
folosiţi o serie de coduri dependente de dispozitiv ca să poziţionaţi mai întâi cursorul în poziţia dorită.
Să presupunem că vreţi să rulaţi mai multe programe „Hello, world!" în acelaşi timp. Ce mizerie! Copiile
programului se vor amesteca unele cu altele. Teleimprimatorul nu furnizează nici o metodă de separare a ieşirilor
de la mai multe programe rulate simultan.
Un alt lucru interesant este faptul că textul „Hello, world!" rămâne pe ecran chiar şi după terminarea
programului, în loc să cureţe ecranul după terminare, programul lasă „urme" ale existenţei sale.
Programul „Hello, world!" este atât de simplu pentru că este proiectat pentru calculatoare mai simple şi pentru
dispozitive de ieşire mai simple. Nu numai că nu este ceea ce numim astăzi un produs software modern, dar nici
nu se află măcar pe acelaşi teren.
Fişierele programului HELLOWIN
Două dintre cele trei fişiere necesare pentru crearea programului HELLOWIN sunt prezentate în Figura 2-1.
Acestea sunt fişierul „de construcţie " HELLOWIN.MAK şi fişierul sursă HELLOWIN.C. Cel de-al treilea fişier
este stocat pe discheta ataşată cărţii, cu numele HELLOWIN.WAV şi conţine varianta sonoră a textului afişat de
program.
#------------------------
# HELLOWIN.MAK make file
#------------------------
hellowin.exe : hellowin.obj
$(LINKER) $(GUIFLAGS) -OUT:hellowin.exe hellowin.obj $(GUILIBS)
hellowin.obj : hellowin.c
$(CC) $(CFLAGS) hellowin.c
/*------------------------------------------------------------
HELLOWIN.C -- Displays "Hello, Windows 95!" in client area
(c) Charles Petzold, 1996
------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "HelloWin" ;
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;
wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 1 din 16


wndclass.lpszClassName = szAppName ;
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
RegisterClassEx (&wndclass) ;
hwnd = CreateWindow (szAppName, // window class name
"The Hello Program", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (iMsg)
{
// case WM_CREATE :
//PlaySound ("hellowin.wav", NULL, SND_FILENAME | SND_ASYNC) ;//
//return 0 ;
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, "Hello, Windows 95! ", -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
Figura 2-1. Programul HELLOWIN.
În Capitolul 9 veţi întâlni un alt tip de fişier frecvent folosit pentru programele Windows, numit „fişier script"
(„resource script") şi având extensia .RC. Până acolo, majoritatea programelor, fiind mai simple, vor folosi un
fişier de construcţie, un fişier sursă şi, eventual, un fişier antet.
Aşa cum am menţionat anterior, cea mai mare parte din codul programului HELLOWIN.C este cod de
întreţinere (overhead code) inclus în aproape toate programele Windows. Nimeni nu se străduieşte să ţină minte
sintaxa acestui cod; în general, programatorii Windows creează un nou program copiind un program existent şi
făcând modificările necesare în acesta. Sunteţi liber să folosiţi în acest mod oricare dintre programele de pe
discheta care însoţeşte cartea.
Dacă aţi instalat pe calculatorul dumneavoastră sistemul de operare Windows 95 si mediul Microsoft Visual
C++ 4.0 şi aţi rulat fişierul de comenzi VCVARS32.BAT inclus în Visual C++ şi fişierul de comenzi MSC.BAT
prezentat în acest capitol, ar trebui să puteţi crea fişierul executabil HELLOWIN.EXE cu comanda:
Hello, Windows 95!
NMAKE HELLOWIN.MAK
din linia de comandă MS-DOS.

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 2 din 16


Dacă totul merge bine, puteţi să rulaţi programul din linia de comandă MS-DOS cu comanda:
HELLOWIN
Programul creează o fereastră normală, prezentată în Figura 2-2. În centrul zonei client a ferestrei este afişat
textul „Hello, Windows 95!". Dacă aveţi pe calculator o placă de sunet, veţi auzi şi mesajul vorbit. (Iar dacă nu
aveţi încă, ce mai aşteptaţi?)

Figura 2-2. Rularea programului HELLOWIN sub Windows 95.


De fapt, această fereastră are o mulţime de funcţii pentru cele numai 80 de linii de cod. Puteţi să „agăţaţi" bara
de titlu cu mouse-ul şi să mutaţi fereastra pe ecran sau, trăgând chenarul ferestrei, puteţi redimensiona fereastra.
Atunci când fereastra îşi schimbă dimensiunea, programul repoziţionează automat textul în noul centru al zonei
client. Puteţi să executaţi clic pe butonul de mărire a ferestrei (maximize) si fereastra va umple ecranul. Puteţi să
executaţi clic pe butonul de micşorare a ferestrei (minimize) şi fereastra va elibera ecranul. Toate aceste opţiuni
pot fi apelate şi din meniul sistem. De asemenea, puteţi să închideţi programul selectând opţiunea Close din
meniul sistem, executând clic pe butonul de închidere a ferestrei din partea dreaptă a barei de titlu sau executând
dublu clic pe pictograma din partea stângă a barei de titlu.
Deşi s-ar putea să vă placă faptul că programul HELLOWIN are toate funcţiile unui program Windows
normal, probabil nu veţi fi la fel de fericit atunci când veţi examina codul sursă necesar pentru crearea
programului. Dar haideţi să ne luăm inima în dinţi şi să „disecăm" acest program bucată cu bucată.

FIŞIERUL DE CONSTRUCŢIE
Pentru simplificarea compilării programelor Windows puteţi să folosiţi utilitarul NMAKE, inclus în setul de
programe Microsoft Visual C++ 4.0. De fiecare dată când vreţi să modificaţi ceva în codul sursă al programului
HELLOWIN.C trebuie să rulaţi programul NMAKE, aşa cum am arătat mai sus, ca să creaţi un fişier executabil
actualizat.
Un fişier de construcţie este format din una sau mai multe secţiuni, fiecare începând cu un rând de text aliniat
la stânga, care conţine un fişier destinaţie, urmat de două puncte şi de unul sau mai multe fişiere dependente.
Această linie este urmată de una sau mai multe linii de comandă aliniate mai în interior. Aceste comenzi creează
fişierul destinaţie din fişierele dependente. Dacă data sau ora de modificare ale oricăruia dintre fişierele
dependente este ulterioară datei sau orei de creare a fişierului destinaţie, programul NMAKE execută liniile de
comandă.
În mod normal, programul NMAKE actualizează numai fişierul destinaţie din prima secţiune a fişierului de
construcţie. Totuşi, dacă unul sau mai multe dintre fişierele dependente sunt la rândul lor fişiere destinaţie în alte
secţiuni ale fişierului de construcţie, NMAKE le va actualiza întâi pe acestea.
Fişierul HELLOWIN.MAK conţine două secţiuni. Prima secţiune rulează programul de editare a legăturilor
dacă HELLOWIN.OBJ a fost modificat mai recent decât HELLOWIN.EXE. A doua secţiune rulează compilatorul
C dacă HELLOWIN.C a fost modificat mai recent decât HELLOWIN.OBJ. Deoarece fişierul HELLOWIN.OBJ
este fişier dependent în prima secţiune şi fişier destinaţie în a doua secţiune, programul NMAKE va verifica mai
întâi dacă HELLOWIN.OBJ trebuie să fie actualizat înainte ca fişierul HELLOWIN.EXE să fie re-creat. În această
situaţie, fişierul de construcţie este de fapt executat de la un capăt la celălalt. Rularea compilatorului C creează
modulul obiect HELLOWIN.OBJ din fişierul sursă HELLOWIN.C. Rularea programului de editare a legăturilor
creează fişierul executabil HELLOWIN.EXE din HELLOWIN.OBJ.
În Capitolul 1 am arătat cum sunt furnizaţi macro-identificatorii din fişierul de construcţie de către variabilele
de mediu stabilite de fişierele de comenzi prezentate în capitolul respectiv. Aceasta înseamnă stabilirea unor
indicatori flag de compilare şi a numelor de biblioteci folosite de programul de editare a legăturilor. Dacă doriţi
amănunte, reveniţi la secţiunea respectivă din Capitolul 1.

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 3 din 16


Fişierul sursă C
Al doilea fişier prezentat în Figura 2-1 este HELLOWIN.C, fişierul care conţine codul sursă C. Va trece un
timp pană când vă veţi da seama că acest program este într-adevăr scris în limbaj C!
Înainte de a intra în detalii, haideţi să aruncăm o privire generală asupra fişierului HELLOWIN.C. Fişierul
conţine numai două funcţii: WinMain şi WndProc. Funcţia WinMain reprezintă punctul de intrare în program.
Aceasta este echivalentul funcţiei main din programele scrise în limbajul C. Orice program pentru Windows
trebuie să aibă o funcţie WinMain.
WndProc este „procedura de fereastră" a ferestrei create de programul HELLOWIN. Orice fereastră -
indiferent dacă este fereastra principală a aplicaţiei sau fereastra unui mic buton de apăsare - are o procedură de
fereastră. Procedura de fereastră este un mod de încapsulare a codului care răspunde intrărilor (în general de la
tastatură şi de la mouse) şi afişează elementele grafice pe ecran. Aşa cum veţi vedea, procedura de fereastră face
acest lucru prin prelucrarea „mesajelor" trimise către fereastră. Pentru moment nu vă bateţi capul cu modul de
funcţionare a acestui mecanism. Veţi avea destul timp să vă luptaţi cu acest concept.
Nici o instrucţiune din fişierul HELLOWIN.C nu apelează direct funcţia WndProc: WndProc este apelată de
sistemul de operare Windows. Totuşi, în funcţia WinMain apare o referire la funcţia WndProc, acesta fiind
motivul pentru care WndProc este declarată în partea de început a programului, înainte de WinMain.
Apelurile de funcţii Windows
HELLOWIN apelează nu mai puţin de 17 funcţii Windows. Aceste funcţii, împreună cu o scurtă descriere,
sunt prezentate în continuare, în ordinea apariţiei în programul HELLOWIN:
• LoadIcon - încarcă o pictogramă care urmează să fie folosită de un program.
• LoadCursor - încarcă un indicator pentru mouse, care urmează să fie folosit de un program.
• GetStockObject - obţine un obiect grafic (în acest caz o pensulă folosită pentru desenarea fondului ferestrei).
• RegisterClassEx - înregistrează o clasă de fereastră pentru fereastra programului.
• CreateWindow - creează o fereastră pe baza unei clase de fereastră.
• ShowWindow - afişează o fereastră pe ecran.
• UpdateWindow - cere unei ferestre să se redeseneze.
• GetMessage - preia un mesaj din coada de mesaje.
• TranslateMessage - converteşte unele dintre mesajele de la tastatură.
• DispatchMessage - trimite un mesaj către o procedură de fereastră.
• PlaySound - redă un fişier de sunet.
• BeginPaint - iniţiază o operaţie de desenare a ferestrei.
• GetClientRect - obţine dimensiunile zonei client a ferestrei.
• DrawText - afişează un text.
• EndPaint - încheie o operaţie de desenare.
• PostQuitMessage - inserează un mesaj de încheiere în coada de aşteptare.
• DefWindowProc - execută operaţiile prestabilite de prelucrare a mesajelor.
Aceste funcţii sunt documentate în cărţi şi în sursele incluse de compilator şi sunt declarate în diferite fişiere
antet incluse în fişierul WINDOWS.H.
Identificatori cu majuscule
Veţi observa că în fişierul HELLOWIN.C sunt folosiţi câţiva identificatori scrişi cu majuscule. Aceşti
identificatori sunt definiţi în fişierele antet din Windows. Câţiva dintre ei conţin un prefix de două sau trei litere,
urmat de o liniuţă de subliniere:
CS_HREDRAW DT_VCENTER WM_CREATE
CS_VREDRAW IDC_ARROW WM_DESTROY
CW_USEDEFAULT IDI_APPLICATION WM_PAINT
DT_CENTER SND_ASYNC WS_OVERLAPPEDWINDOW
DT_SINGLELINE SND_FILENAME
Acestea sunt simple constante numerice. Prefixul indică o categorie generală căreia îi aparţine constanta
respectivă, aşa cum se arată în tabelul următor:

Prefix Categorie
CS Opţiune pentru stilul clasei
IDI Număr de identificare pentru o pictogramă
IDC Număr de identificare pentru un cursor
WS Stil de fereastră
CW Opţiune de creare a unei ferestre
WM Mesaj de fereastră
SND Opţiune pentru sunete
DT Opţiune de desenare a textului

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 4 din 16


În mod normal nu este nevoie să reţineţi nici o constantă numerică pentru scrierea unui program pentru
Windows. De fapt, toate constantele numerice folosite în Windows au un identificator definit în fişierele antet.
Noi tipuri de date
Alţi identificatori folosiţi în fişierul HELLOWIN.C sunt noi tipuri de date, definite în fişierele antet cu
ajutorul instrucţiunii typedef sau #define. Aceste definiţii au fost stabilite iniţial pentru a simplifica tranziţia
programelor Windows originale de la sistemele pe 16 biţi originale la viitoarele sisteme pe 32 de biţi, sau la cele
bazate pe o altă tehnologie. Această tranziţie nu s-a făcut chiar atât de uşor şi de transparent cum ar fi crezut unii la
momentul respectiv, dar conceptul este destul de bun.
Uneori aceste noi tipuri de date sunt doar abrevieri mai uşor de folosit. De exemplu, tipul de date UINT
folosit pentru al doilea parametru al funcţiei WndProc este prescurtarea de ia unsigned int, ceea ce în Windows 95
înseamnă o valoare întreagă pe 32 de biţi. Tipul de date PSTR folosit pentru al treilea parametru al funcţiei
WinMain este un pointer la un şir de caractere, adică înlocuieşte tipul char*.
Alte tipuri de date nu sunt la fel de evidente. De exemplu, al treilea şi al patrulea parametri ai funcţiei
WndProc sunt definiţi cu tipurile de date WPARAM si LPARAM. Originea acestor nume ţine oarecum de istoria
sistemului Windows: pe când Windows era un sistem pe 16 biţi, al treilea parametru al funcţiei WndProc era
definit ca WORD, adică un număr întreg scurt, fără semn, pe 16 biţi (unsigned short) iar al patrulea parametru era
definit ca LONG, adică un număr întreg pe 32 de biţi (long) - de aici provenind prefixele „W" şi „L" ale
cuvântului „PARAM". În Windows 95, WPARAM este definit ca UINT iar LPARAM este definit ca LONG (care
este chiar tipul long din C), aşa că ambii parametri ai procedurii de fereastră sunt valori pe 32 de biţi. Deoarece
tipul de date WORD este definit în Windows 95 ca un număr întreg fără semn pe 16 biţi (unsigned short), prefixul
„W" din WPARAM este oarecum impropriu şi poate crea confuzii.
Funcţia WndProc returnează o valoare LRESULT, definit ca un număr de tip LONG. Funcţia WinMain este
de tipul WINAPI, iar funcţia WndProc este de tipul CALLBACK. Ambii identificatori sunt definiţi ca __stdcall,
care defineşte o secvenţă specială de apelare pentru apelurile de funcţii dintre Windows şi aplicaţii.
Programul HELLOWIN foloseşte patru structuri de date (despre care vom discuta mai târziu în acest capitol)
definite în fişierele antet din Windows. Aceste structuri de date sunt:

Structura Semnificaţie
MSG Structura mesajului
WNDCLASSEX Structura clasei de fereastră
PAINTSTRUCT Structură pentru desenare
RECT Dreptunghi

Primele două structuri sunt folosite în funcţia WinMain pentru definirea a două structuri numite msg şi
wndclass. Celelalte două sunt folosite în funcţia WndProc pentru definirea altor două structuri, numite ps şi rect.
Câteva cuvinte despre variabilele handle
În sfârşit, în program sunt folosiţi trei identificatori cu majuscule pentru diferite tipuri de variabile handle:

Identificator Semnificaţie
HINSTANCE Variabilă handle a unei „instanţe" - programul însuşi
HWND Variabilă handle a unei ferestre
HDC Variabilă handle a unui context de dispozitiv

Variabilele handle sunt folosite destul de des în Windows. În acest capitol veţi face cunoştinţă cu variabila
handle a unei pictograme (HICON), variabila handle a unui cursor (HCURSOR) şi cea a unei pensule (HBRUSH).
O variabilă handle este pur şi simplu un număr (de obicei pe 32 de biţi) care face trimitere la un obiect.
Variabilele handle din Windows sunt asemănătoare cu cele folosite pentru fişiere (file handles) în programele
convenţionale C sau MS-DOS. Un program obţine aproape întotdeauna o variabilă apelând o funcţie Windows.
Programul foloseşte apoi variabila handle obţinută pentru trimiterea la obiect în alte funcţii. Valoarea reală a
variabilei handle nu este importantă pentru program, dar modulul Windows care o furnizează programului ştie
cum să îl manipuleze pentru trimiterea la obiect.
Notaţia ungară
S-ar putea să fi observat că unele dintre variabilele folosite în programul HELLOWIN.C au nume ciudate. Un
astfel de exemplu este szCmdLine, transmis ca parametru funcţiei WinMain.
Mulţi programatori Windows folosesc „notaţia ungară", o convenţie de denumire a variabilelor intitulată astfel
în onoarea legendarului programator de la Microsoft, Charles Simonyi. Convenţia este foarte simplă - fiecare
nume de variabilă începe cu una sau mai multe litere mici care specifică tipul de date al variabilei. De exemplu,
prefixul sz al variabilei szCmdLine semnifică „şir de caractere terminat cu zero". Prefixul h al variabilelor
hInstance şi hPrevInstance înseamnă „variabilă handle"; prefixul i al variabilei iCmdShow înseamnă „întreg". Şi

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 5 din 16


ultimii doi parametri ai funcţiei WndProc respectă notaţia ungară, deşi, aşa cum am arătat mai devreme, wParam
ar fi trebuit să se numească uiParam (de la „unsigned integer"). Totuşi, deoarece aceşti doi parametri se definesc
folosind tipurile de date WPARAM şi LPARAM, am păstrat denumirile originale.
Atunci când denumiţi variabilele de tip structură, puteţi să folosiţi numele de tip al structurii (sau o abreviere a
acestuia) ca prefix al numelui variabilei sau chiar ca nume al variabilei. De exemplu, în funcţia WinMain din
programul HELLOWIN.C, variabila msg este o structură de tip MSG iar wndclass este o variabilă de tip
WNDCLASSEX. În funcţia WndProc, ps este o structură de tip PAINTSTRUCT iar rect este o structură de tip
RECT.
Notaţia ungară vă ajută să descoperiţi erorile înainte ca acestea să ajungă în programele finale. Deoarece
numele unei variabile descrie atât modul de folosire a acesteia, cât şi tipul de date, este mai puţin probabil să faceţi
erori de programare care implică amestecarea unor tipuri de date incompatibile.
Prefixele folosite pentru variabilele din această carte sunt prezentate în tabelul următor:

Prefix Tip de date


c char
by BYTE (unsigned char)
n short
i int
x, y int (folosit pentru coordonate)
cx, cy int (folosit pentru dimensiuni pe axele x si y, c vine de la „contor")
b sau f BOOL (int); f vine de la „flag" (indicator)
w WORD (unsigned short)
l LONG (long)
dw DWORD (unsigned long)
fn funcţie
s şir de caractere
sz sir de caractere terminat cu zero
h variabilă handle
p pointer

Punctul de intrare în program


După ce v-aţi format o idee generală despre programul HELLOWIN.C, putem să disecăm programul linie cu
linie. Codul începe cu o instrucţiune #include pentru includerea fişierului antet WINDOWS.H:

#include <windows.h>

Fişierul WINDOWS.H include la rândul lui mai multe fişiere antet care conţin declaraţiile funcţiilor,
structurilor, noilor tipuri de date şi constantelor numerice din Windows.

Instrucţiunea #include este urmată de declaraţia avansată a funcţiei WndProc :

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

Declararea în avans a acestei funcţii este necesară deoarece WndProc este referită în cadrul funcţiei WinMain.
Punctul de intrare al unui program C scris pentru un mediu convenţional este o funcţie numită main. De la
această funcţie începe execuţia programului. (De fapt, funcţia main este punctul de intrare la acea parte a
programului scrisă de programator. De obicei, compilatorul C inserează în fişierul executabil unele secvenţe de
cod pentru lansarea în execuţie. Funcţia main este apoi apelată de acest cod de lansare). Punctul de intrare într-un
program Windows este o funcţie numită WinMain. Funcţia WinMain este întotdeauna definită astfel:

int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

Această funcţie foloseşte secvenţa de apelare WINAPI şi la terminare returnează sistemului de operare o
valoare întreagă. Numele funcţiei trebuie să fie WinMain. Această funcţie are patru parametri:
Parametrul hlnstance este numit „variabilă handle a instanţei" („instance handle"). Acesta este un număr care
identifică în mod unic toate programele rulate în Windows. Utilizatorul poate rula simultan mai multe copii ale
aceluiaşi program. Aceste copii se numesc „instanţe" şi fiecare are o valoare diferită pentru parametrul hlnstance.
Variabila handle a instanţei este asemănătoare cu „identificatorul de operaţie" („task ID") sau „identificatorul de
proces" („process ID") din alte sisteme de operare multitasking.

Într-un program C funcţiile pot fi declarate înainte de a fi definite. Declaraţia unei funcţii precizează tipul parametrilor primiţi de funcţie şi
tipul valorii returnate de aceasta, fără să definească şi corpul acesteia. Acest lucru este necesar atunci când funcţia este indicată înainte de a fi
definită, dar uşurează şi citirea programului, (n.t.)

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 6 din 16


hPrevInstance („previous instance" - instanţa anterioară) este un parametru învechit. În versiunile Windows
anterioare acest parametru conţinea variabila handle a celei mai recente instanţe încă activă a aceluiaşi program.
Dacă nu erau încărcate alte instanţe ale programului, hPrevInstance avea valoarea 0 sau NULL. În Windows 95,
parametrul hPrevInstance are întotdeauna valoarea NULL.
Parametrul szCmdLine este un pointer la un şir de caractere terminat cu zero care conţine eventualii parametri
transmişi programului în linia de comandă. Puteţi să rulaţi un program Windows cu parametri incluzând parametrii
respectivi după numele programului în linia de comandă MS-DOS sau specificându-i în caseta de dialog Run
apelată din meniul Start.
Parametrul iCmdShow este un număr care indică modul iniţial de afişare a ferestrei în Windows. Acest număr
este atribuit de programul care lansează în execuţie programul aflat în discuţie. Programele verifică rareori
valoarea acestui parametru, dar o pot face dacă este nevoie. În majoritatea cazurilor, iCmdShow are valoarea 1 sau
7. Dar cel mai bine este să nu vă gândiţi la aceste valori numerice. Mai sugestivi sunt identificatorii
SW_SHOWNORMAL (definit în Windows ca 1) şi SW_SHOWMINNOACTIVE (definit cu valoarea 7). Prefixul
SW vine de la „show window" (afişare fereastră). Acest parametru specifică dacă fereastra programului este
afişată normal sau dacă este afişată iniţial doar ca o pictogramă.
Înregistrarea clasei de fereastră
O fereastră este întotdeauna creată pe baza unei clase de fereastră. Aceasta identifică procedura de fereastră
care prelucrează toate mesajele trimise către fereastră.
Pe baza aceleiaşi clase pot fi create mai multe ferestre. De exemplu, toate butoanele din Windows sunt create
pe baza unei singure clase de fereastră. Aceasta defineşte procedura de fereastră şi alte caracteristici ale ferestrei
create pe baza clasei respective. Atunci când creaţi o fereastră, definiţi şi atributele suplimentare ale acesteia, care
sunt unice pentru fereastra respectivă.
Înainte de a crea fereastra programului trebuie să înregistraţi o clasă de fereastră, apelând funcţia
RegisterClassEx. Aceasta este o versiune extinsă (de aici sufixul „Ex") a funcţiei RegisterClass din versiunile
anterioare ale sistemului de operare Windows. Totuşi, funcţia RegisterClass poate fi încă folosită în Windows 95.
Funcţia RegisterClassEx acceptă un singur parametru: un pointer la o structură de tipul WNDCLASSEX.
Structura WNDCLASSEX este definită în fişierele antet din Windows astfel:
typedef struct tagWNDCLASSEX
{
UINT cbSize ;
UINT style ;
WNDPROC lpfnWndProc ;
int cbClsExtra ;
int cbWnExtra ;
HINSTANCE hinstance ;
HICON hicon ;
HCURSOR hCursor ;
HBRUSH hbrBackground ;
LPCSTR lpszMenuName ;
LPCSTR lpszClassName ;
HICON hIconSm ;
}
WNDCLASSEX ;

Sunt necesare câteva observaţii privind tipurile de date şi notaţia ungară folosită în această structură: prefixele
LP şi lp sunt prescurtări pentru „long pointer" şi sunt „rămăşiţe" din versiunile Windows pe 16 biţi, în cazul cărora
programatorii trebuie să facă diferenţa între pointerii de tip short (sau near) pe 16 biţi şi pointerii de tip long (sau
far) pe 32 de biţi. În Windows 95 toţi pointerii au valori pe 32 de biţi. Am încercat să elimin toate prefixele l ale
tipurilor de pointeri din exemplele de programe pe care le-am ales pentru această carte, dar cu siguranţă că le veţi
mai întâlni în alte programe.
Remarcaţi şi alte moduri de folosire a notaţiei ungare: lpfn vine de la „long pointer to a function" („pointer de
tip long la o funcţie"). Prefixul cb provine de la „count of bytes" („contor de octeţi"). Prefixul hbr vine de la
„handle to a brush" („variabilă handle a unei pensule").
În funcţia WinMain trebuie să definiţi o structură de tipul WNDCLASSEX, cum ar fi:

WNDCLASSEX wndclass ;

Apoi definiţi cele 12 câmpuri ale structurii şi apelaţi funcţia RegisterClassEx:


RegisterClassEx (&wndclass) ;
Cele mai importante câmpuri ale structurii sunt al treilea şi penultimul. Penultimul câmp conţine numele
clasei de fereastră (şi în programele care creează o singură fereastră are, de obicei, acelaşi nume ca şi programul).

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 7 din 16


Al treilea câmp (lpfnWndProc) este adresa procedurii de fereastră folosită pentru toate ferestrele create pe baza
acestei clase (care este funcţia WndProc din programul HELLOWIN.C). Celelalte câmpuri descriu caracteristicile
tuturor ferestrelor create pe baza acestei clase.
Câmpul cbSize reprezintă dimensiunea structurii. Instrucţiunea: wndclass.style = CS_HREDRAW |
CS_VREDRAW ; combină doi identificatori pentru „stilul de clasă" („class style") folosind operatorul SAU
orientat pe biţi din limbajul C. În fişierele antet din Windows sunt definiţi mai mulţi identificatori cu prefixul CS_.
Acestea sunt constante pe 32 de biţi în care un singur bit are valoarea 1. De exemplu, identificatorul
CS_VREDRAW este definit ca 0x0001 iar CS_HREDRAW este definit ca 0x0002. Identificatorii definiţi în acest
fel sunt numiţi uneori „identificatori pe biţi". Aceştia pot fi combinaţi cu ajutorul operatorului SAU orientat pe biţi
din limbajul C.
Cei doi identificatori pentru stilul clasei indică faptul că toate ferestrele create pe baza acestei clase sunt
redesenate complet, ori de câte ori se modifică dimensiunea pe orizontală (CS_HREDRAW) sau cea pe verticală
(CS_VREDRAW) a ferestrei. Dacă redimensionaţi fereastra programului HELLOWIN veţi vedea că textul este
redesenat, astfel încât să apară în centrul noii ferestre. Acest lucru este asigurat de cei doi identificatori de stil.
Vom vedea imediat cum este informată procedura de fereastră privind modificarea dimensiunii ferestrei.
Al treilea câmp al structurii WNDCLASSEX este iniţializat prin instrucţiunea:
wndclass.lpfnWndProc = WndProc ;
Această instrucţiune stabileşte ca procedură de fereastră funcţia WndProc, adică a doua funcţie definită în
fişierul HELLOWIN.C. Această procedură va prelucra toate mesajele trimise către toate ferestrele create pe baza
acestei clase de fereastră. Aşa cum am arătat mai sus, prefixul lpfn înseamnă, în notaţia ungară, „pointer de tip
long la o funcţie".
Următoarele două instrucţiuni:
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
rezervă un spaţiu suplimentar în structura clasei şi în structura ferestrei, păstrată în interiorul sistemului de
Windows. Un program poate să utilizeze spaţiul suplimentar în scopuri proprii. Programul HELLOWIN nu
foloseşte această posibilitate, aşa că nu se rezervă nici un spaţiu suplimentar. În alte situaţii, aşa cum indică şi
notaţia ungară, câmpurile vor avea rolul de „contor de octeţi".
Următorul câmp este variabila handle a instanţei (care este chiar unul dintre parametrii funcţiei WinMain):
wndclass.hInstance = hinstance ;
Instrucţiunea:
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
şi instrucţiunea:
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
definesc o pictogramă pentru ferestrele create pe baza acestei clase. Pictograma este o mică imagine de tip bitmap
care apare în bara de taskuri a sistemului de operare şi în bara de titlu a ferestrei. Mai târziu veţi învăţa cum să
creaţi pictograme proprii pentru programele Windows. Pentru moment, vom aborda o metodă mai simplă şi vom
folosi o pictogramă predefinită.
Pentru obţinerea unei variabile handle a unei pictograme predefinite apelaţi funcţia LoadIcon cu primul
parametru având valoarea NULL. (Atunci când încărcaţi o pictogramă proprie, acest parametru va conţine
variabila handle a instanţei programului.) Al doilea parametru este un identificator cu prefixul IDI_ definit în
fişierele antet din Windows. Pictograma IDI_APPLICATION este o mică imagine a unei ferestre. Funcţia
LoadIcon returnează o variabilă handle a acestei pictograme. Nu ne interesează valoarea reală a acestei variabile,
ci doar o stocăm în câmpurile hIcon şi hIconSm. Aceste câmpuri sunt definite în structura WNDCLASSEX de
tipul HICON („handle to an icon").
Instrucţiunea:
wndclass.hCursor = LoadCursor (NULL, IDC_ ARROW) ;
este foarte asemănătoare cu cele două instrucţiuni anterioare. Funcţia LoadCursor încarcă un cursor predefinit
pentru mouse, numit IDC_ARROW, şi returnează o variabilă handle a acestui cursor. Atunci când este deplasat
deasupra zonei client a ferestrei create pe baza acestei clase, indicatorul mouse-ului este afişat sub forma unei
săgeţi.
Următorul câmp precizează culoarea fondului zonei client a ferestrelor create pe baza acestei clase. Prefixul
hbr al numelui hbrBackground vine de la „handle to a brush" („variabilă handle a unei pensule"). O pensulă este
un termen grafic care se referă la un model colorat de pixeli folosit pentru umplerea unei suprafeţe. Windows are
mai multe pensule standard (sau pensule „de stoc"). Funcţia GetStockObject returnează o variabilă handle a unei
pensule albe:
wndclass.hbrBackground =
(HBRUSH) GetStockObject (WHITE_BRUSH);
Aceasta înseamnă că fondul zonei client a ferestrei va fi colorat cu alb, ceea ce este un lucru obişnuit.
Următorul câmp specifică meniul ferestrei. Programul HELLOWIN nu are nici un meniu, aşa că acest câmp
are valoarea NULL:
wndclass.lpszMenuName = NULL ;

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 8 din 16


În sfârşit, clasei trebuie să i se dea un nume. Pentru programele mai mici, acesta poate fi chiar numele
programului, deci în variabila szAppName este stocat şirul de caractere „HelloWin":
wndclass.IpszClassName = szAppName ;
După iniţializarea celor 12 câmpuri ale structurii, HELLOWIN înregistrează clasa de ferestre prin apelarea
funcţiei RegisterClassEx. Singurul parametru al funcţiei este un pointer către structura WNDCLASSEX:
RegisterClassEx (&wndclass) ;

Crearea ferestrei
Clasa de fereastră defineşte caracteristicile generale ale unei ferestre, permiţând astfel folosirea aceleiaşi clase
pentru crearea mai multor ferestre. Atunci când creaţi o fereastră apelând funcţia Create Window, puteţi să
specificaţi mai multe detalii despre fereastra respectivă.
Programatorii Windows mai noi sunt uneori derutaţi de diferenţele între o clasă de fereastră şi o fereastră, şi
nu înţeleg de ce nu pot să specifice toate caracteristicile unei ferestre printr-o singură operaţie. De fapt, împărţirea
informaţiilor în acest fel este foarte convenabilă. De exemplu, toate butoanele de apăsare sunt create pe baza unei
singure clase de fereastră. Procedura de fereastră asociată acestor butoane este localizată chiar în Windows. Clasa
de fereastră are ca sarcini prelucrarea tuturor mesajelor de la tastatură şi de la mouse trimise către butonul de
apăsare şi definirea aspectului vizual al butonului pe ecran. Din acest punct de vedere, toate butoanele de apăsare
funcţionează în acelaşi mod. Acestea însă pot avea diferite dimensiuni, diferite poziţii pe ecran şi diferite etichete.
Aceste caracteristici fac parte din definiţia ferestrei.
În loc să folosească o structură de date, aşa cum face funcţia RegisterClassEx, funcţia CreateWindow cere ca
toate informaţiile să fie transmise ca parametri. Iată cum este apelată funcţia CreateWindow în programul
HELLOWIN.C:

hwnd =CreateWindow (szAppName, // numele clasei de fereastra


"The Hello Program", // titlul ferestrei
WS_OVERLAPPEDWINDOW, // stilul ferestrei
CW_USEDEFAULT, // poziţia iniţiala pe axa x
CW_USEDEFAULT, // poziţia iniţiala pe axa y
CW_USE DEFAULT, // dimensiunea iniţiala pe axa x
CW_USEDEFAULT, // dimensiunea iniţiala pe axa y
NULL, // variabila handle a ferestrei părinte
NULL, // variabila handle a meniului
hlnstance, // variabila handle a instanţei programului
NULL) ; // parametri de creare

Pentru o citire mai uşoară, am folosit simbolul // pentru notarea comentariilor pe o singură linie care descriu
parametrii funcţiei Create Window.
Parametrul notat cu „numele clasei de fereastră" este szAppName, care conţine şirul de caractere „HelloWin" -
numele clasei de fereastră pe care tocmai am înregistrat-o. În acest fel, fereastra este asociată unei clase de
fereastră.
Fereastra creată de acest program este o fereastră normală suprapusă, cu o bară de titlu; în partea stângă a
barei de titlu se află caseta cu meniul sistem; în partea dreaptă se află butoanele de mărire, de micşorare şi de
închidere; fereastra are un chenar îngroşat, care permite redimensionarea. Acesta este stilul standard al ferestre lor,
numit WS_OVERLAPPEDWINDOW; în funcţia CreateWindow îi corespunde comentariul „stilul ferestrei".
„Titlul ferestrei" este textul afişat în bara de titlu.
Parametrii notaţi cu „poziţia iniţială pe axa x" şi „poziţia iniţială pe axa y" specifică poziţia iniţială a colţului
din stânga-sus al ferestrei, relativ la colţul din stânga-sus al ecranului. Prin folosirea identificatorului
CW_USEDEFAULT pentru aceşti para metri indicăm sistemului de operare să folosească valorile prestabilite
pentru o fereastră suprapusă. (CW_USEDEFAULT este definit ca 0x80000000.) În mod prestabilit, Windows
poziţionează mai multe ferestre suprapuse succesive la o distanţă crescătoare pe verticală şi pe orizontală faţă de
colţul din stânga-sus al ecranului. La fel, parametrii „dimensiunea iniţială pe axa x" şi „dimensiunea iniţială pe axa
y" specifică dimensiunile iniţiale ale ferestrei. Identificatorul CW_USEDEFAULT indică sistemului de operare să
folosească valorile prestabilite.
Parametrul indicat ca „variabilă handle a ferestrei părinte" are valoarea NULL, deoarece această fereastră nu
are nici o fereastră părinte. Atunci când între două ferestre există o relaţie părinte-descendent, fereastra descendent
este afişată întotdeauna pe suprafaţa ferestrei părinte. Parametrul indicat ca „variabilă handle a meniului" are tot
valoarea NULL, deoarece fereastra nu are meniu. Parametrul indicat ca „variabilă handle a instanţei programului"
are ca valoare variabila handle transmisă programului ca parametru la apelarea funcţiei WinMain. În sfârşit,
„parametrul de creare" are valoarea NULL. Puteţi să folosiţi acest parametru pentru adresarea unor date folosite
ulterior în program.

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 9 din 16


Funcţia Create Window returnează o variabilă handle a ferestrei create. Aceasta este salvată în variabila hwnd,
definită ca fiind de tipul HWND (variabilă handle a unei ferestre). Orice fereastră din Windows are o variabilă
handle. Programul foloseşte variabila handle pentru indicarea ferestrei. Multe funcţii Windows au un parametru
hwnd, care specifică fereastra la care se referă funcţia respectivă. Dacă un program creează mai multe ferestre,
fiecare are o variabilă handle diferită. Variabila handle a unei ferestre este una dintre cele mai importante variabile
folosite în Windows.
Afişarea terestrei
După executarea funcţiei CreateWindow, fereastra a fost creată de Windows, dar încă nu este afişată pe ecran.
Pentru aceasta mai sunt necesare încă două apeluri de funcţii. Primul este:
ShowWindow (hwnd, iCmdShow) ;
Primul parametru este o variabilă handle a ferestrei create de funcţia CreateWindow. Al doilea parametru este
variabila iCmdShow, transmisă funcţiei WinMain. Dacă iCmdShow este SW_SHOWNORMAL (egal cu 1),
fereastra este afişată normal. Dacă iCmdShow este SW_SHOWMINNOACTIVE (egal cu 7), atunci fereastra nu
este afişată, dar numele şi pictograma acesteia apar pe bara de taskuri.
În programul HELLOWIN funcţia ShowWindow afişează fereastra pe ecran. Dacă al doilea parametru al
funcţiei este SW_SHOWNORMAL, Windows şterge zona client a ferestrei folosind pensula specificată în clasa
ferestrei. Apelul:
UpdateWindow (hwnd) ;
determină redesenarea zonei client. Acest lucru se face prin trimiterea către procedura de fereastră (funcţia
WndProc din HELLOWIN.C) a unui mesaj WM_PAINT. Vom vedea imediat cum tratează funcţia WndProc
aceste mesaje.
Ciclul de mesaje
După apelarea funcţiei UpdateWindow, fereastra devine vizibilă pe ecran. Programul trebuie să fie acum
pregătit să citească intrările de la mouse şi de la tastatură. Windows formează o „coadă de mesaje" pentru fiecare
program rulat concurenţial. Atunci când apare un eveniment exterior, Windows converteşte acest eveniment într-
un mesaj pe care îl plasează în coada de aşteptare.
Un program preia mesajele din coada de aşteptare prin executarea unei secvenţe de cod numită „ciclu de
mesaje" („message loop"):
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;

Variabila msg este o structură de tip MSG, definită în fişierele antet din Windows astfel:

typedef struct tagMSG


{
HWND hwnd ;
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
}
MSG ,
Tipul de date POINT este tot o structură, definită astfel:
typedef struct tagPOINT
{
LONG x ;
LONG y ;
}
POINT ;

Funcţia GetMessage apelată la începutul ciclului de mesaje preia un mesaj din coada de aşteptare:
GetMessage (&msg, NULL, 0, 0)
Acest apel transmite sistemului de operare un pointer, numit msg, la o structură de tip MSG. Al doilea, al
treilea şi al patrulea parametru au valoarea NULL sau 0, ceea ce indică faptul că programul vrea să preia toate

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 10 din 16


mesajele, pentru toate ferestrele create de program. Windows completează câmpurile structurii de mesaje cu urmă
torul mesaj din coada de aşteptare. Câmpurile acestei structuri sunt:
• hwnd - variabila handle a ferestrei căreia îi este destinat mesajul. În pro gramul HELLOWIN, aceasta este
aceeaşi cu valoarea hwnd returnată de funcţia CreateWindow, deoarece aceasta este singura fereastră a
programului.
• message - identificatorul mesajului. Acesta este un număr folosit pentru identificarea mesajului. Pentru fiecare
mesaj în fişierele antet din Windows este definit un identificator care începe cu prefixul WM_ („window
message"). De exemplu, dacă poziţionaţi indicatorul mouse-ului în zona client a programului HELLOWIN şi
apăsaţi butonul din stânga, Windows va insera în coada de aşteptare un mesaj pentru care câmpul message
conţine identificatorul WM_LBUTTONDOWN, adică valoarea 0x0201.
• wParam - un parametru pe 32 de biţi a cărui valoare depinde de mesajul trimis.
• lParam - un alt parametru pe 32 de biţi dependent de mesaj.
• time - momentul inserării mesajului în coada de mesaje.
• pt - coordonatele poziţiei mouse-ului în momentul inserării mesajului în coada de mesaje.
Dacă în câmpul message este transmisă orice altă valoare decât WM_QUIT (egală cu 0x0012), funcţia
GetMessage returnează o valoare diferită de zero. Mesajul WM_QUIT determină ieşirea din ciclul de mesaje.
Programul se încheie, returnând valoarea parametrului wParam al structurii msg.
Instrucţiunea:
TranslateMessage (&msg) ;
retransmite structura msg sistemului de operare, pentru convertirea unor mesaje de la tastatură. (Vom discuta mai
multe despre aceasta în Capitolul 5.)
Instrucţiunea:
DispatchMessage (&msg) ;

ca şi funcţia TranslateMessage, retransmite structura msg sistemului de operare. Windows trimite apoi mesajul
către procedura de fereastră corespunzătoare, în vederea prelucrării - cu alte cuvinte, Windows apelează procedura
de fereastră. În programul HELLOWIN, procedura de fereastră este WndProc. După ce prelucrează mesajul,
funcţia WndProc predă controlul sistemului de operare, care încă elaborează răspunsul la apelul DispatchMessage.
Atunci când Windows returnează controlul programului HELLOWIN, după executarea apelului
DispatchMessage, ciclul de tratare a mesajelor continuă cu următorul apel al funcţiei GetMessage.
Procedura de fereastră
Tot codul descris până în acest moment este cod de întreţinere: a fost înregistrată clasa de fereastră, a fost
creată fereastra, care apoi a fost afişată pe ecran şi programul a intrat în ciclul de tratare a mesajelor în vederea
preluării mesajelor din coada de aşteptare.
Operaţiile reale au loc însă în procedura de fereastră. Procedura de fereastră arată ce afişează fereastra în zona
client şi cum răspunde fereastra la intrările utilizatorului.
În programul HELLOWIN procedura de fereastră este funcţia WndProc. O procedură de fereastră poate avea
orice nume (cu condiţia ca numele respectiv să nu existe deja). Un program pentru Windows poate conţine mai
multe proceduri de fereastră. O procedură de fereastră este întotdeauna asociată unei clase de fereastră, înregistrată
cu ajutorul funcţiei RegisterClassEx. Funcţia CreateWindow creează o fereastră pe baza unei anumite clase. Pe
baza aceleiaşi clase pot fi create mai multe ferestre.
Procedura de fereastră este definită întotdeauna astfel:
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam. LPARAM lParam)
Remarcaţi faptul că cei patru parametri ai procedurii de fereastră sunt identici cu primele patru câmpuri ale
structurii MSG.
Primul parametru este hwnd, variabila handle a ferestrei care recepţionează mesajul. Aceasta este aceeaşi
variabilă cu cea returnată de funcţia CreateWindow. Pentru un program care creează o singură fereastră, precum
HELLOWIN, aceasta este singura variabilă handle cunoscută de program. Dacă programul creează mai multe
ferestre pe baza aceleiaşi clase (şi deci foloseşte aceeaşi procedură de fereastră), atunci hwnd identifică fereastra
care primeşte mesajul.
Al doilea parametru este un număr (mai precis, un întreg fără semn - UINT - pe 32 de biţi) care identifică
mesajul. Ultimii doi parametri (wParam, de tipul WPARAM si lParam, de tipul LPARAM) furnizează mai multe
informaţii despre mesaj. Aceştia sunt numiţi „parametri de mesaj". Conţinutul acestor parametri este specific
fiecărui tip de mesaj.
Prelucrarea mesajelor
Fiecare mesaj recepţionat de o procedură de fereastră este identificat printr-un număr, acesta fiind parametrul
iMsg al procedurii de fereastră. În fişierele antet din Windows sunt definiţi identificatori, cu prefixul WM
(„window message"), pentru fiecare parametru de mesaje.
În general, programatorii Windows folosesc o construcţie switch sau case ca să determine ce mesaje a primit
fereastra şi să stabilească modul de prelucrare a fiecărui mesaj. Atunci când prelucrează un mesaj, procedura de

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 11 din 16


fereastră trebuie să returneze valoarea 0. Orice mesaj pe care procedura de fereastră nu-l prelucrează este transmis
unei funcţii Windows numită DefWindowProc. Valoarea returnată de funcţia DefWindowProc trebuie să fie
returnată şi de procedura de fereastră.
În programul HELLOWIN, procedura de fereastră (WndProc) prelucrează numai trei mesaje: WM_CREATE,
WM_PAINT şi WM_DESTROY. Procedura de fereastră este structurată astfel:

switch (iMsg)
{
case WM_CREATE :
[prelucrează mesajul WM_CREATE]
return 0 ;

case WM_PAINT :
[prelucrează mesajul WM_PAINT]
return 0 ;

case WM_DESTROY :
[prelucrează mesajul WM_DESTROY]
return 0 ;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam) ;

Este esenţial să apelaţi funcţia DefWindowProc pentru prelucrarea tuturor mesajelor ignorate de procedura de
fereastră a programului.
Redarea unui fişier de sunet
Primul mesaj pe care îl primeşte o procedură de fereastră - şi primul mesaj prelucrat de funcţia WndProc -
este WM_CREATE. WndProc recepţionează acest mesaj în timp ce Windows execută funcţia Create Window din
WinMain. Aceasta înseamnă că atunci când HELLOWIN apelează funcţia CreateWindow, Windows face ce are de
făcut şi apelează funcţia WndProc, transmiţându-i variabila handle a ferestrei şi mesajul WM_CREATE. WndProc
prelucrează mesajul WM_CREATE şi returnează controlul sistemului de operare. Windows poate apoi să încheie
execuţia funcţiei CreateWindow şi să se întoarcă la programul HELLOWIN pentru alte operaţii din funcţia
WinMain.
Deseori, procedurile de fereastră fac toate operaţiile de iniţializare a ferestrei în timpul prelucrării mesajului
WM_CREATE. În timpul prelucrării acestui mesaj, programul HELLOWIN redă un fişier de sunet, numit
HELLOWIN.WAV. Acest lucru se face prin apelarea funcţiei PlaySound. Primul parametru al funcţiei este
numele fişierului. Acesta ar putea să fie şi un alias (nume de înlocuire) definit în secţiunea Sounds a panoului de
control (Control Panel) sau o resursă de program. Al doilea parametru este folosit numai dacă fişierul de sunet este
o resursă. Al treilea parametru specifică un set de opţiuni. În acest caz am indicat faptul că primul parametru este
un nume de fişier şi că sunetul trebuie să fie redat asincron, adică funcţia PlaySound trebuie să returneze controlul
imediat după începerea operaţiei de redare, fără să aştepte terminarea acesteia.
WndProc încheie prelucrarea mesajului WM_CREATE cu returnarea valorii zero din procedura de fereastră.
Mesajul WM_PAINT
Al doilea mesaj prelucrat de funcţia WndProc este WM_PAINT. Acest mesaj este foarte important în
programarea sub Windows, deoarece informează fereastra privind faptul că o parte sau întreaga zonă client a
acesteia este „invalidă" şi trebuie să fie redesenată.
Cum poate să devină invalidă o zonă client? Atunci când fereastra este creată, întreaga zonă client a ferestrei
este invalidă, deoarece programul nu a desenat încă nimic în fereastră. Primul mesaj WM_PAINT (care apare, în
mod normal, atunci când programul apelează funcţia UpdateWindow din WinMain) cere procedurii de fereastră să
deseneze ceva în zona client.
Zona client devine invalidă şi atunci când redimensionaţi fereastra programului HELLOWIN. Vă amintiţi că
parametrul de stil al structurii wndclass din HELLOWIN conţine identificatorii CS_VREDRAW şi
CS_HREDRAW. Aceşti identificatori determină sistemul de operare Windows să invalideze întreaga fereastră
atunci când aceasta îşi schimbă dimensiunea şi apoi să trimită un mesaj WM_PAINT către procedura de fereastră.
Dacă micşoraţi la o pictogramă fereastra programului HELLOWIN şi apoi îi refaceţi dimensiunea iniţială.
Windows nu salvează conţinutul zonei client. Într-un mediu grafic ar fi mult prea multe date de salvat. De aceea.
Windows invalidează fereastra. Procedura de fereastră primeşte mesajul WM_PAINT şi reface conţinutul acesteia.
Atunci când mutaţi ferestrele astfel încât să se suprapună. Windows nu salvează porţiunea unei ferestre care a
fost acoperită de o altă fereastră. În schimb, atunci când fereastra respectivă este readusă la suprafaţă, porţiunea

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 12 din 16


anterior acoperită este invalidată. Procedura de fereastră primeşte un mesaj WM_PAINT pentru redesenarea
porţiunii respective.
Aproape întotdeauna, prelucrarea mesajului WM_PAINT începe prin apelarea funcţiei BeginPaint:
hdc = BeginPaint (hwnd, &ps) ;

şi se termină cu apelarea funcţiei EndPaint:

EndPaint (hwnd, &ps) ;

În ambele situaţii, primul parametru este variabila handle a ferestrei programului, iar al doilea parametru este
un pointer la o structură de tip PAINTSTRUCT. Structura PAINTSTRUCT conţine unele informaţii pe care
programul le poate folosi pentru redesenarea zonei client. (Vom discuta despre acest câmp al structurii în
următorul capitol.)
În timpul apelării funcţiei BeginPaint, Windows şterge fondul zonei client, dacă acesta nu a fost deja şters.
Fondul este şters folosindu-se pensula specificată în câmpul hbrBackground al structurii WNDCLASSEX, folosită
pentru înregistrarea clasei de fereastră, în cazul programului HELLOWIN, aceasta este o pensulă de stoc albă,
ceea ce înseamnă că Windows şterge fondul ferestrei colorându-l, în acelaşi timp, cu alb. Funcţia BeginPaint
validează întreaga zonă client şi returnează o „variabilă handle a contextului de dispozitiv". Un context de
dispozitiv se referă la un dispozitiv fizic de ieşire (cum ar fi un monitor video) împreună cu driverul care
controlează acest dispozitiv. Aveţi nevoie de o variabilă handle a contextului de dispozitiv ca să afişaţi text şi
elemente grafice în zona client a ferestrei. Folosind variabila handle a con textului de dispozitiv returnată de
funcţia BeginPaint nu puteţi să desenaţi în afara zonei client a ferestrei, chiar dacă încercaţi. Funcţia EndPaint
eliberează variabila handle a contextului de dispozitiv, astfel încât aceasta nu mai este validă.
Dacă procedura de fereastră nu prelucrează mesajele WM_PAINT - ceea ce se întâmplă foarte rar - acestea
trebuie să fie transmise funcţiei DefWindowProc. Funcţia DefWindowProc apelează funcţiile BeginPaint şi
EndPaint, astfel încât zona client a ferestrei să fie din nou validată.
După funcţia BeginPaint, WndProc apelează funcţia GetClientRect:
GetClientRect (hwnd. &rect) ;
Primul parametru al funcţiei GetClientRect este variabila handle a ferestrei programului. Al doilea parametru
al funcţiei este un pointer la o variabilă numită rect, de tipul RECT, definită în WndProc.
RECT este o structură pentru un „dreptunghi" definit în fişierele antet din Windows. Structura conţine patru
câmpuri de tip LONG, numite left, top, right şi bottom. Funcţia GetClientRect atribuie acestor câmpuri valorile
corespunzătoare dimensiunilor zonei client a ferestrei. Câmpurile left şi top au întotdeauna valoarea 0. Câmpurile
right şi bottom conţin lăţimea şi înălţimea zonei client, în pixeli.
WndProc transmite funcţiei DrawText un pointer către structura RECT, prin cel de-al patrulea parametru al
funcţiei:
DrawText (hdc, "Hello, Windows 95!", -1, &rect,
DT_SINGLELINE : DT_CENTER ! DT_VCENTER) ;
Funcţia DrawText, aşa cum arată şi numele, este folosită pentru „desenarea" unui text. Deoarece funcţia
desenează ceva, primul parametru este o variabilă handle a contextului de dispozitiv, returnatâ de funcţia
BeginPaint. Al doilea parametru este textul care urmează să fie afişat, iar al treilea parametru are valoarea -1, ceea
ce indică faptul că textul de afişat se termină cu un octet 0.
Ultimul parametru al funcţiei este o combinaţie de indicatori flag pe biţi, definiţi în fişierele antet din
Windows. Indicatorii flag folosiţi determină afişarea textului pe o singură linie, centrată orizontal şi vertical relativ
la dreptunghiul specificat prin al patrulea parametru. Ca urmare, funcţia DrawText afişează textul „Hello,
Windows 95!" în centrul zonei client a ferestrei.
De fiecare dată când zona client devine invalidă (aşa cum se întâmplă atunci când modificaţi dimensiunea
ferestrei), funcţia WndProc recepţionează un mesaj WM_PAINT. WndProc obţine noua dimensiune a ferestrei şi
afişează din nou textul în centrul acesteia.
Mesajul WM_DESTROY
Un alt mesaj important este WM_DESTROY. Acest mesaj indică faptul că sistemul de operare desfăşoară un
proces de distrugere a ferestrei pe baza unei comenzi de la utilizator. Mesajul este trimis atunci când utilizatorul
execută clic pe butonul Close, selectează opţiunea Close din meniul sistem sau apasă fastele Alt+F4.
Programul HELLOWIN răspunde la acest mesaj printr-o metodă standard, apelând funcţia PostQuitMessage:
PostQuitMessage (0) ;
Această funcţie inserează în coada de aşteptare a programului un mesaj WM_QUIT. Am spus anterior că
funcţia GetMessage returnează o valoare diferită de zero în cazul preluării oricărui mesaj în afară de WM_QUIT.
Atunci când preia din coada de aşteptare un mesaj WM_QUIT, funcţia GetMessage returnează valoarea 0, ceea ce
determină ieşirea din ciclul de tratare a mesajelor din funcţia WinMain şi închiderea programului.
PROBLEME LEGATE DE PROGRAMAREA SUB WINDOWS

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 13 din 16


Chiar şi după explicaţiile legate de programul HELLOWIN, structura şi modul de funcţionare ale programelor
Windows s-ar putea să fi rămas ceva misterios. Într-un scurt program C scris pentru un mediu convenţional,
întregul program poate fi conţinut de funcţia main. În programul HELLOWIN, funcţia WinMain conţine numai
codul de întreţinere (overhead) necesar pentru înregistrarea clasei, crearea ferestrei şi obţinerea şi livrarea
mesajelor din coada de mesaje.
Toată „acţiunea" programului se desfăşoară în procedura de fereastră. În pro gramul HELLOWIN, aceasta nu
face prea multe - redă un fişier de sunet şi afişează un text în fereastră. În următoarele capitole veţi vedea cam tot
ce poate face un program Windows ca răspuns la un mesaj. Prelucrarea mesajelor este unul dintre principalele
obstacole pe care trebuie să le depăşiţi atunci când scrieţi un program pentru Windows.
Nu ne apela, te apelăm noi!
Aşa cum am menţionat mai devreme, programatorii sunt obişnuiţi cu ideea apelării unor funcţii ale sistemului
de operare, pentru îndeplinirea unei anumite operaţii. De exemplu, programatorii C folosesc funcţia fopen ca să
deschidă un fişier. Funcţiile de bibliotecă livrate odată cu compilatorul conţin secvenţe de cod care apelează
funcţii ale sistemului de operare pentru deschiderea unui fişier. Nici o problemă.
În Windows, însă, lucrurile se petrec altfel. Deşi sistemul de operare are mai mult de o mie de funcţii pe care
programele le pot apela, şi Windows poate să apeleze funcţii ale programului. Mai precis. Windows poate să
apeleze procedurile de fereastră, precum WndProc. Procedura de fereastră este asociată unei clase de fereastră pe
care programul o înregistrează prin apelarea funcţiei RegisterClassEx. O fereastră creată pe baza acestei clase
foloseşte procedura de fereastră specificată de clasă pentru prelucrarea tuturor mesajelor recepţionate. Windows
trimite un mesaj către o fereastră prin apelarea procedurii de fereastră a acesteia.
Windows apelează funcţia WndProc atunci când fereastra este creată. Windows apelează funcţia WndProc
atunci când fereastra este distrusă. Windows apelează funcţia WndProc atunci când fereastra este redimensionată,
mutată sau redusă la o pictogramă. Windows apelează funcţia WndProc atunci când utilizatorul selectează o
opţiune dintr-un meniu. Windows apelează funcţia WndProc atunci când o bară de derulare este manipulată sau
când utilizatorul execută clic pe aceasta. Windows apelează funcţia WndProc pentru a-i comunica ferestrei că
trebuie să redeseneze zona client.
Toate aceste apeluri sunt făcute sub forma unor mesaje. În majoritatea programelor Windows, cea mai mare
parte a codului este folosit pentru tratarea mesajelor. Windows poate trimite unei proceduri de fereastră peste 200
de mesaje. Aceste mesaje sunt identificate prin nume care încep cu literele WM şi sunt definite în fişierele antet
din Windows.
De fapt, ideea includerii într-un program a unei proceduri care să poată fi apelată din exterior există şi în
programarea convenţională. Funcţia signal din limbajul C interceptează codul combinaţiei de taste Ctrl+Break.
Probabil aţi folosit metode de interceptare a întreruperilor hardware în limbaj de asamblare sau una dintre
construcţiile ON din Microsoft BASIC. Driverul Microsoft Mouse conţine o metodă pe care o pot folosi
programele non-Windows pentru a fi „la curent" cu activitatea mouse-ului.
În Windows, acest concept este extins, acoperind orice operaţie. Toate evenimentele legate de o fereastră sunt
transmise procedurii de fereastră sub forma unor mesaje. Procedura de fereastră răspunde la aceste mesaje sau le
retransmite către procedura DefWindowProc, pentru operaţii de prelucrare prestabilite.
Parametrii wParam şi lParam ai procedurii de fereastră nu sunt folosiţi în programul HELLOWIN decât
pentru a fi retransmişi funcţiei DefWindowProc. Aceşti parametri furnizează procedurii de fereastră informaţii
suplimentare despre mesajul primit. Semnificaţia acestor parametri este dependentă de mesaj.
Haideţi să vedem un exemplu. Ori de câte ori zona client a unei ferestre îşi modifică dimensiunea, Windows
apelează procedura ferestrei respective. Parametrul hwnd al procedurii de fereastră este variabila handle a ferestrei
care şi-a modificat dimensiunea. Parametrul iMsg are valoarea WM_SIZE. Parametrul wParam poate conţine unul
dintre identificatorii SIZENORMAL, SIZEICONIC, SIZEFULLSCREEN, SIZEZOOMSHOW şi
SIZEZOOMHIDE (definiţi în fişierele antet din Windows cu valori de la 0 la 4). Parametrul wParam arată dacă
fereastra a fost redusă la o pictogramă, a fost mărită la dimensiunea ecranului sau a fost mascată (în urma
acoperirii de către o altă fereastră). Parametrul lParam conţine noua dimensiune a ferestrei. Noua lăţime (o valoare
pe 16 biţi) şi noua înălţime (tot o valoare pe 16 biţi) sunt împachetate în parametrul lParam, care este o valoare pe
32 de biţi. În fişierele antet din Windows este definită o macroinstrucţiune care vă ajută să extrageţi cele două
valori din parametrul lParam. Vom face acest lucru în capitolul următor.
Uneori mesajele generează alte mesaje ca rezultat al prelucrării în funcţia DefWindowProc. De exemplu, să
presupunem că rulaţi programul HELLOWIN şi selectaţi opţiunea Close din meniul sistem, folosind tastatura sau
mouse-ul. Funcţia DefWindowProc prelucrează intrările de la tastatură sau de la mouse. Atunci când detectează
selectarea opţiunii Close, trimite un mesaj WM_SYSCOMMAND către procedura de fereastră. WndProc
retransmite acest mesaj funcţiei DefWindowProc. Funcţia DefWindowProc răspunde prin trimiterea unui mesaj
WM_CLOSE către procedura de fereastră. WndProc retransmite şi acest mesaj către funcţia DefWindowProc.
Funcţia DefWindowProc răspunde la acest mesaj prin apelarea funcţiei Destroy Window. Funcţia Destroy Window
determină sistemul de operare să trimită un mesaj WM_DESTROY către procedura de fereastră. WndProc
răspunde la acest mesaj apelând funcţia PostQuitMessage, care inserează un mesaj WM_QUIT în coada de
aşteptare. Acest mesaj determină ieşirea din ciclul de tratare a mesajelor şi închiderea programului.

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 14 din 16


Mesaje în coada de aşteptare şi în afara acesteia
Am vorbit despre faptul că Windows trimite mesaje către o fereastră, ceea ce înseamnă că Windows apelează
procedura de fereastră. Dar un program Windows are si un ciclu de tratare a mesajelor care preia mesajele din
coada de aşteptare apelând funcţia GetMessage şi le distribuie procedurii de fereastră apelând funcţia
DispatchMessage.
Aşadar, un program Windows interoghează coada de aşteptare (aşa cum un program convenţional
interoghează bufferul de intrare de la tastatură) şi apoi retransmite mesajele în anumite locuri? Sau primeşte
mesajele direct din exterior? Ei bine, sunt folosite ambele metode.
Mesajele pot fi trimise prin coada de aşteptare sau direct. Mesajele trimise prin coada de aşteptare sunt
preluate de program şi sunt distribuite în ciclul de tratare a mesajelor. Mesajele care nu trec prin coada de aşteptare
sunt trimise ferestrei direct, atunci când Windows apelează procedura de fereastră. Rezultatul este faptul că
procedura de fereastră primeşte toate mesajele, indiferent dacă sunt trimise prin coada de aşteptare sau direct. Din
punct de vedere structural, programele Windows sunt foarte clare, deoarece prelucrarea mesajelor se face
centralizat, într-un singur punct. Aşadar, mesajele preluate de funcţia GetMessage sunt inserate în coada de
aşteptare, iar mesajele care nu trec prin coada de aşteptare sunt trimise procedurii de fereastră.
Mesajele din coada de aşteptare sunt, în principal, rezultatul acţionării tastelor (aşa sunt, de pildă,
WM_KEYDOWN şi WM_KEYUP) sau caractere trimise de la tastatură (WM_CHAR), rezultatul deplasării
mouse-ului (WM_MOUSEMOVE) şi al apăsării butoanelor mouse-ului (WM_LBUTTONDOWN). Tot în
categoria mesajelor inserate în coada de aşteptare intră şi mesajele trimise de la ceas (WM_TIMER), mesajele de
redesenare (WM_PAINT) şi mesajele de încheiere (WM_QUIT). Mesajele trimise direct sunt cele rezultate din
alte evenimente. În multe cazuri, mesajele trimise direct sunt rezultatul unor mesaje din coada de aşteptare. Atunci
când transmiteţi un mesaj din procedura de fereastră către funcţia DefWindowProc, de multe ori Windows
prelucrează mesajul prin trimiterea altor mesaje către procedura de fereastră.
Evident, acest proces este foarte complex dar, din fericire, de cea mai mare parte răspunde sistemul de
operare, nu programul. Din perspectiva procedurii de fereastră, aceste mesaje sunt recepţionate în ordine, şi
sincronizat. Procedura de fereastră poate să prelucreze mesajele sau să le ignore. Din acest motiv, este numită
uneori „ultimul hop". Prin mesaje, procedura de fereastră este informată privind aproape toate evenimentele care
afectează fereastra.
Mesajele care nu trec prin coada de aşteptare rezultă din apelarea unor funcţii Windows sau din expedierea în
mod explicit a unui mesaj, prin apelarea funcţiei SendMessage. (Mesajele din cealaltă categorie sunt inserate în
coada de aşteptare prin apelarea funcţiei PostMessage.)
De exemplu, atunci când WinMain apelează funcţia CreateWindow, Windows creează fereastra şi trimite
procedurii de fereastră un mesaj WM_CREATE. Atunci când WinMain apelează funcţia ShowWindow, Windows
trimite procedurii de fereastră mesajele WM_SIZE şi WM_SHOWWINDOW. Atunci când WinMain apelează
funcţia UpdateWindow, Windows trimite procedurii de fereastră un mesaj WM_PAINT.
Mesajele nu seamănă cu întreruperile hardware. În timpul prelucrării unui mesaj într-o procedură de fereastră,
programul nu poate fi întrerupt de un alt mesaj. Procedura de fereastră va prelucra un alt mesaj înainte de
returnarea controlului numai dacă apelează o funcţie care generează un nou mesaj.
Ciclul de mesaje şi procedura de fereastră nu sunt executate simultan. Atunci când procedura de fereastră
prelucrează un mesaj extras din coada de aşteptare, acest mesaj este rezultat în urma apelării funcţiei
DispatchMessage în WinMain. Funcţia DispatchMessage nu returnează controlul decât după ce procedura de
fereastră termină prelucrarea mesajului.
Remarcaţi faptul că procedura de fereastră trebuie să fie reentrantă. Windows trimite deseori funcţiei
WndProc un nou mesaj atunci când aceasta apelează funcţia DefWindowProc pentru mesajul anterior. În
majoritatea cazurilor reentranţa procedurii de fereastră nu este o problemă, dar trebuie să fiţi conştient de această
posibilitate.
De exemplu, să presupunem că în procedura de fereastră stabiliţi valoarea unei variabile în timpul prelucrării
unui mesaj, apoi apelaţi o funcţie Windows. După returnarea din funcţia apelată, puteţi fi sigur că valoarea
variabilei a rămas aceeaşi? Nu este obligatoriu - de exemplu, este posibil ca funcţia Windows apelată să genereze
un alt mesaj, iar procedura de fereastră să modifice valoarea aceleiaşi variabile în timpul prelucrării acestui mesaj.
Acesta este unul dintre motivele pentru care unele forme de optimizare ale compilatorului trebuie să fie
dezactivate atunci când compilaţi programe Windows.
În multe situaţii, procedura de fereastră poate să reţină anumite informaţii în timpul prelucrării unor mesaje şi
să le folosească pentru prelucrarea altor mesaje. Aceste informaţii trebuie să fie stocate fie în variabile statice
definite în procedura de fereastră, fie în variabile globale.
Desigur, veţi înţelege mai bine toate aceste lucruri în următoarele capitole, pe măsură ce vom extinde
procedurile de fereastră astfel încât să prelucreze şi alte mesaje.
Nu fiţi egoist!
Windows 95 este un mediu care asigură multitaskingul controlat. Aceasta înseamnă că atunci când un
program execută o operaţie de durată, sistemul de operare permite utilizatorului să treacă în alt program. Acesta

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 15 din 16


este un lucru bun şi este unul dintre avantajele oferite de Windows 95 faţă de versiunile Windows bazate pe MS-
DOS.
Totuşi, datorită structurii Windows, multitaskingul controlat nu funcţionează întotdeauna aşa cum ar trebui.
De exemplu, să presupunem că programul are nevoie de mai multe minute pentru prelucrarea unui mesaj. Este
adevărat că utilizatorul poate trece într-un alt program, dar nu poate face nimic cu programul respectiv.
Utilizatorul nu poate să mute fereastra programului, să o redimensioneze sau să o închidă. Nu poate face absolut
nimic, deoarece aceste operaţii trebuie să fie executate de procedura de fereastră, iar procedura de fereastră este
ocupată cu o operaţie de durată, chiar dacă nu ea pare a fi cea care execută operaţiile de mutare şi de
redimensionare. Aceste operaţii sunt executate de funcţia DefWindowProc, care trebuie considerată o parte a
procedurii de fereastră.
Dacă programul trebuie să execute o operaţie de durată în timpul prelucrării unui anumit mesaj, puteţi să
faceţi acest lucru şi într-un mod mai politicos, aşa cum vom vedea în Capitolul 14. Chiar şi într-un mediu cu
multitasking controlat, nu este o idee prea bună să blocaţi o fereastră pe ecran. Acest lucru deranjează utilizatorii şi
îi face să gândească lucruri urate despre programul dumneavoastră.
Ciclul de învăţare
Aşa cum v-aţi dat seama din acest capitol, programarea sub Windows este foarte diferită de programarea
pentru un mediu convenţional, cum ar fi MS-DOS, şi nu pretinde nimeni că programarea sub Windows este
uşoară.
Atunci când am început să învăţ programarea sub Windows, am vrut să fac ceea ce făceam de obicei pentru a
învăţa un nou sistem de operare sau un nou limbaj de programare - să scriu un program simplu, care să afişeze
conţinutul hexazecimal al unui fişier. Sub MS-DOS, un astfel de program implică lucrul de la linia de comandă,
operaţii rudimentare de intrare/ieşire cu fişiere şi formatarea rezultatelor pe ecran. Programul de afişare sub
Windows s-a dovedit a fi ceva monstruos. A trebuit să învăţ o mulţime de lucruri despre meniuri, casete de dialog,
bare de derulare şi altele. Desigur, acest prim efort de învăţare care se impunea nu era un punct în favoarea
programării sub Windows.
Cu toate acestea, odată terminat, programul de afişare hexazecimală nu semăna cu nici unul dintre programele
pe care le scrisesem până atunci în acelaşi scop. În loc să obţină numele fişierului din linia de comandă,
WINDUMP (acesta era numele pe care l-am dat programului) folosea o casetă de dialog în care erau prezentate
toate fişierele din directorul curent, în loc să scrie rezultatele pe ecran după modelul unui teleimprimator,
WINDUMP avea bare de derulare ce permiteau deplasarea în orice parte a fişierului. Ca un avantaj suplimentar,
puteam să rulez simultan două copii ale programului WINDUMP, ceea ce îmi permitea să compar două fişiere
afişate în două ferestre alăturate. Pe scurt, WINDUMP a fost primul program de afişare hexazecimală de care am
fost cu adevărat mândru.
Trebuie să vă puneţi următoarea întrebare: doresc să folosesc o interfaţă modernă şi eficientă, care să includă
meniuri, casete de dialog, bare de derulare şi elemente grafice? Dacă răspunsul este afirmativ, trebuie să vă puneţi
o altă întrebare: doresc să scriu chiar eu codul pentru aceste meniuri, casete de dialog, bare de derulare şi elemente
grafice? Sau voi profita de faptul că acest cod există deja în Windows? Cu alte cuvinte, ce este mai uşor - să
învăţaţi să folosiţi 1000 de funcţii, sau să le scrieţi chiar dumneavoastră? Este mai uşor să vă orientaţi gândirea
către arhitectura bazată pe mesaje a sistemului de operare Windows, sau preferaţi să luptaţi cu aceasta folosind
diverse surse de intrare, după modelul tradiţional?
Dacă doriţi să scrieţi codul unei interfeţe proprii, mai bine închideţi această carte şi apucaţi-vă de treabă. În
acest timp, noi ceilalţi vom învăţa cum să afişăm şi să derulăm textul într-o fereastră.

/opt/scribd/conversion/tmp/scratch6820/52479975.doc28.02.11 08:10 pagina 16 din 16