Documente Academic
Documente Profesional
Documente Cultură
2
ÎNCEPUTUL ................................................................................................................................................................................. 2
PROVOCAREA PROGRAMATORULUI ................................................................................................................................... 2
REGULI DE BAZĂ ................................................................................................................................................................... 2
UN SCURT ISTORIC AL SISTEMULUI DE OPERARE WINDOWS .................................................................................. 3
ESTE TIMPUL SĂ ÎNCEPEM.................................................................................................................................................. 4
Capitolul 2. Hello, Windows 95! ................................................................................................................................................... 5
CE ADUCE NOU SISTEMUL DE OPERARE WINDOWS .................................................................................................... 5
Interfaţa grafică cu utilizatorul (GUI) ........................................................................................................................................ 5
Conceptele şi fundamentele GUI ............................................................................................................................................... 5
Consecvenţa privind interfaţă cu utilizatorul ............................................................................................................................. 5
Avantajul oferit de multitasking ................................................................................................................................................ 6
Gestionarea memoriei ................................................................................................................................................................ 6
Interfaţa grafică independentă de dispozitiv .............................................................................................................................. 6
Dacă optaţi pentru Windows... ................................................................................................................................................... 7
Apelurile de funcţii .................................................................................................................................................................... 7
Programarea orientată pe obiecte ............................................................................................................................................... 7
Arhitectura bazată pe mesaje ..................................................................................................................................................... 7
Procedura de fereastră ................................................................................................................................................................ 8
PRIMUL DUMNEAVOASTRĂ PROGRAM WINDOWS ...................................................................................................... 8
Ce este greşit în acest program? ................................................................................................................................................. 8
Fişierele programului HELLOWIN ........................................................................................................................................... 9
Fişierul de construcţie .............................................................................................................................................................. 11
Fişierul sursă C ........................................................................................................................................................................ 11
Apelurile de funcţii Windows .................................................................................................................................................. 11
Identificatori cu majuscule ....................................................................................................................................................... 12
Noi tipuri de date ..................................................................................................................................................................... 12
Câteva cuvinte despre variabilele handle ................................................................................................................................. 13
Notaţia ungară .......................................................................................................................................................................... 13
Punctul de intrare în program................................................................................................................................................... 13
Înregistrarea clasei de fereastră ................................................................................................................................................ 14
Crearea terestrei ....................................................................................................................................................................... 16
Afişarea ferestrei ...................................................................................................................................................................... 16
Ciclul de mesaje ....................................................................................................................................................................... 17
Procedura de fereastră .............................................................................................................................................................. 18
Prelucrarea mesajelor ............................................................................................................................................................... 18
Redarea unui fişier de sunet ..................................................................................................................................................... 19
Mesajul WM_PAINT............................................................................................................................................................... 19
Mesajul WM_DESTROY ........................................................................................................................................................ 20
PROBLEME LEGATE DE PROGRAMAREA SUB WINDOWS ......................................................................................... 20
Nu ne apela, te apelăm noi!...................................................................................................................................................... 20
Mesaje în coada de aşteptare şi în afara acesteia ..................................................................................................................... 21
Nu fiţi egoist! ........................................................................................................................................................................... 22
Ciclul de învăţare ..................................................................................................................................................................... 22
Fişierul MSC.BAT poate fi găsit în directorul CHAP01 de pe discheta care însoţeşte această carte.
Voi descrie rolul instrucţiunilor de mai sus în capitolele care urmează.
Acest tip de multitasking se mai numeşte şi „multitasking cooperativ", (n.t)
include <stdio.h>
main ()
{
printf ("Hello, world\n");
}
În acest capitol vă voi prezenta un program asemănător, scris pentru Microsoft Windows 95. Programul se numeşte
HELLOWIN, afişează pe ecran şirul de caractere „Hello, Windows 95!" şi redă un fişier de sunet cu vocea mea rostind
aceleaşi cuvinte.
Dacă nu v-aţi prăbuşit atunci când aţi văzut pentru prima dată codul programului HELLOWIN, vă avertizez că are mai
mult de 80 de linii. Majoritatea acestor linii reprezintă cod de întreţinere (overhead code) şi veţi include un asemenea cod în
toate programele Windows pe care le veţi scrie.
În loc să ne întrebăm de ce programul „Hello, Windows 95!" este atât de lung şi de complex, haideţi să vedem de ce
programul „Hello, world!" tradiţional este atât de scurt şi de simplu.
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.
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.
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ă.
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
Î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.
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 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:
#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:
Î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.)
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.
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.
WNDCLASSEX wndclass ;
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 ferestrelor, 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
parametri 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.
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 ferestrei
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.
Variabila msg este o structură de tip MSG, definită în fişierele antet din Windows astfel:
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 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 programul 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) ;
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 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.
Î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 contextului 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,
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ă.