Meniuri i taste de
accelerare
mi amintesc o schi a lui Monty Python despre un magazin de brnzeturi. Era cam aa: un tip intr ntr-un
magazin de brnzeturi i cere un anumit sortiment de brnz. Desigur, magazinul nu avea aa ceva. Tipul
cere un alt sortiment, apoi altul i altul (n total cam 40 de sortimente de brnz) i rspunsul este n
continuare: nu, nu, nu. n sfrit, povestea se termin cu nite mpucturi.
Acest incident nefericit ar fi putut fi evitat dac s-ar fi folosit meniuri. Un meniu este o list de opiuni
disponibile. Un meniu i poate spune unui tip flmnd ce poate servi buctria sau, n cazul unui program
Windows, i poate spune utilizatorului ce operaii poate s execute aplicaia respectiv.
Meniurile sunt probabil partea cea mai important a interfeei cu utilizatorul, oferit de programele
Windows, iar adugarea unui meniu la un program este o operaie relativ uoar n programarea sub
Windows. Nu trebuie dect s definii structura meniului n fiierul de resurse i s atribuii un numr de
identificare (ID) unic fiecrui articol din meniu. Specificai apoi numele meniului n structura de clas a
ferestrei. Atunci cnd utilizatorul selecteaz o opiune de meniu, Windows trimite programului un mesaj
WM_COMMAND care conine identificatorul articolului respectiv. Dar nu ne vom opri la acest exemplu
simplu. Unul dintre cele mai interesante lucruri pe care le putei face cu meniurile este s afiai imagini
bitmap n meniu n locul unor iruri de caractere, aa c vom discuta n detaliu modul n care putei s facei
acest lucru.
Tot n acest capitol vom discuta i despre tastele de accelerare". Acestea sunt combinaii de taste
folosite, n principal, pentru dublarea unor funcii de meniu.
MENIURI
Bara de meniu a unei ferestre este afiat imediat sub bara de titlu i este numit uneori meniu principal" sau
meniul de pe primul nivel". Articolele din meniul principal sunt folosite de obicei pentru afiarea unui
meniu derulant (drop-down menu" sau popup menu") numit uneori i submeniu". Putei s definii
niveluri multiple de meniuri derulante: un articol al unui meniu derulant poate s activeze un alt meniu
derulant. Uneori articolele din meniurile derulante activeaz o caset de dialog pentru afiarea unor
informaii suplimentare. (Despre casetele de dialog vom discuta n capitolul urmtor.) Majoritatea
ferestrelor principale afieaz n partea stng a barei de titlu o pictogram mic a programului. Aceast
pictogram apeleaz meniul de sistem, care este tot un meniu derulant.
Articolele din meniurile derulante pot fi validate", ceea ce nseamn c Windows deseneaz un mic marcaj
de validare n partea stng a textului corespunztor articolului de meniu. Marcajele de validare permit
utilizatorului s-i dea seama ce opiuni au fost selectate din meniu. Aceste opiuni se pot exclude
reciproc, dar acest lucru nu este obligatoriu. Articolele din meniul principal nu pot fi validate.
Articolele din meniul principal i din meniurile derulante pot fi activate", dezactivate" (uneori se
folosesc cu acelai sens termenii active" i inactive") sau gri". Articolele de meniu activate i
dezactivate arat la fel pentru utilizatori, dar textul meniurilor gri" este scris cu un ton de gri.
Din punctul de vedere al utilizatorului, articolele de meniu activate, dezactivate sau gri pot fi selectate".
Aceasta nseamn c utilizatorul poate s execute clic pe un articol de meniu dezactivat, poate s mute bara
cursor afiat n video invers pe un articol dezactivat sau poate s marcheze articolul respectiv folosind
tasta cheie corespunztoare. Totui, din perspectiva programuui, articolele de meniu activate, dezactivate
i gri funcioneaz n mod diferit. Windows trimite programului un mesaj WM_COMMAND numai pentru
meniurile activate. Meniurile dezactivate sau gri sunt folosite pentru opiunile care n momentul respectiv
nu sunt valide. Dac vrei ca utilizatorul s tie c o anumit opiune nu este valid, afiai-o cu gri.
Structura meniurilor
Atunci cnd creai sau cnd modificai meniurile unui program, este bine s v gndii la meniul principal i
la meniurile derulante, ca la meniuri diferite. Meniul principal are o variabil handle, fiecare meniu
derulant apelat de meniul principal are o variabil handle proprie i meniul de sistem (care este tot un
meniu derulant) are o alt variabil handle.
Fiecare articol de meniu este definit prin trei caracteristici. Prima caracteristic este ceea ce apare n meniu.
Aceasta poate fi un ir de caractere sau o imagine bitmap. Cea de-a doua caracteristic este fie un numr de
identificare pe care Windows l trimite programului prin mesajul WM_COMMAND, fie un meniu
derulant afiat atunci cnd utilizatorul selecteaz articolul respectiv. A treia caracteristic descrie atributele
articolului respectiv, indiferent dac acesta este activat, dezactivat, gri sau validat.
ablonul meniurilor
Putei s creai un meniu n trei moduri. Cea mai obinuit (i mai simpl) cale este s definii
meniul n fiierul script de resurse sub forma unui ablon de meniu, cum ar fi:
HyMenu MENU { [lista meniului]
MyMenu este numele meniului. Acest nume este referit n structura de clas a ferestrei. De obicei,
numele meniului este acelai cu numele aplicaiei.
ntre acolade putei s folosii instruciunile MENUITEM i POPUP. Formatul instruciunii
MENUITEM este:
MENUITEM "&Text", id [, opiuni]
POPUP este:
POPUP "&Text", id [, opiuni] {
[lista meniului] }
n locul acoladelor, dac dorii, putei s folosii cuvintele cheie BEGIN i END. Textul afiat pentru
fiecare meniu trebuie s fie ncadrat ntre ghilimele. Caracterul care urmeaz dup
ampersand (&) va fi afiat subliniat. Acesta este caracterul pe care l va cuta sistemul de
operare Windows atunci cnd selectai meniul cu ajutorul tastei Alt. Dac textul nu conine
caracterul ampersand, nu va fi subliniat nici un caracter, iar Windows va folosi prima liter a
textului pentru combinaiile cu tasta Alt.
Opiunile pe care putei s le folosii pentru instruciunile MENUITEM i POPUP din lista
meniurilor principale sunt:
GRAYED - Articolul respectiv este dezactivat, nu genereaz mesaje
WM_COMMAND, iar textul este afiat cu gri.
INACTIVE - Articolul respectiv este dezactivat, nu genereaz mesaje
WM_COMMAND, iar textul este afiat normal.
MENUBREAK - Articolul respectiv i cele care urmeaz sunt afiate pe o
nou linie a meniului.
HELP - Articolul respectiv i cele care urmeaz sunt aliniate la dreapta.
Opiunile pot fi combinate cu ajutorul simbolului SAU orientat pe bii din C (|), dar opiunile
GRAYED i INACTIVE nu pot fi folosite mpreun. Opiunea MENUBREAK este rareori folosit
pentru articolele din meniul principal, deoarece Windows afieaz automat acest meniu pe mai
multe linii, dac fereastra este prea ngust ca s ncap toate articolele.
Dac urmeaz dup o instruciune POPUP, acoladele (sau cuvintele cheie BEGIN i END)
ncadreaz lista articolelor in meniul derulant. Urmtoarele instruciuni pot fi folosite pentru
definirea unui meniu derulant:
MENUITEM "text", id [, opiuni]
SI
MENUITEM SEPARATOR i
MENUITEM SEPARATOR deseneaz o linie orizontal n meniul derulant. Aceast linie este
deseori folosit pentru separarea grupurilor de articole nrudite.
Pentru articolele din meniurile derulante putei s folosii n irul de caractere caracterul
tab (\t). Textul care urmeaz dup acest caracter este afiat ntr-o nou coloan, destul de
departe, pentru ca n prima coloan s ncap cel mai lung ir de caractere din meniul
derulant. Vom vedea cum funcioneaz acest caracter atunci cnd vom discuta despre tastele
de accelerare, ctre sfritul acestui capitol. Dac n irul de caractere includei combinaia \a,
textul care urmeaz este aliniat la dreapta, n meniurile derulante, pentru instruciunea
MENUITEM putei s folosii urmtoarele opiuni.
CHECKED - n partea stng a textului este afiat un marcaj de validare.
GRAYED - Articolul respectiv este dezactivat, nu genereaz mesaje
WM_COMMAND, iar textul este afiat cu gri.
INACTIVE - Articolul respectiv este dezactivat, nu genereaz mesaje
WM_COMMAND, iar textul este afiat normal.
MENUBREAK - Articolul respectiv i cele care urmeaz sunt afiate pe o
nou coloan a meniului.
MENUBARBREAK - Articolul respectiv i cele care urmeaz sunt afiate
pe o nou coloan a meniului. Coloanele sunt separate de o linie vertical.
Opiunile GRAYED i INACTIVE nu pot fi folosite mpreun. Opiunile MENUBREAK i
MENUBARBREAK nu pot fi folosite mpreun. Putei s folosii opiunea MENUBREAK sau
opiunea MENUBARBREAK atunci cnd meniul derulant conine prea multe opiuni pentru a fi
afiate pe o singur coloan.
Identificatorii din instruciunile MENUITEM sunt numerele pe care Windows le \ trimite
procedurii ferestrei prin mesajele de meniu. Valorile de identificare trebuie s fie unice n cadrul
unui meniu. n locul numerelor putei s folosii identificatori definii ntr-un fiier antet. Prin
convenie, aceti identificatori ncep cu literele IDM (IDentificator de Meniu").
Programatorii folosesc deseori pentru numele meniului numele programului, astfel nct
acelai ir de caractere poate fi folosit pentru clasa ferestrei, numele pictogramei
programului i numele meniului. Totui, n locul numelui putei s folosii un numr (sau un macroidentificator). n acest caz, fiierul script de resurse va arta astfel:
45 MENU (
[definiia meniului] )
n acest caz, instruciunea de atribuire a variabilei membru IpszMenuName din structura clasei
poate fi:
wndclass.IpszMenuName = MAKEINTRESOURCE (45) ; sau
wndclass.IpszMenuName "#45" ;
Dei specificarea meniului n clasa ferestrei este calea cel mai des folosit de referire a unei
resurse de tip meniu, avei i alte posibiliti. O aplicaie Windows poate s ncarce resursa unui
meniu n memorie folosind funcia LoadMenu, asemntoare cu funciile Loadlcon i LoadCursor
descrise n Capitolul 9. Dac n fiierul script de resurse folosii un nume pentru meniu, funcia
LoadMenu returneaz o variabil handle a meniului:
hMenu = LoadMenu (hlnstance, "MyMenu") ; Dac folosii un numr, apelul funciei LoadMenu ia una
dintre formele urmtoare:
hMenu = LoadMenu (hlnstance, MAKEINTRESOURCE (45)) ;
sau
hMenu LoadMenu (hlnstance, "#45") ;
n acest caz, meniul specificat ca parametru al funciei CreateWindow suprascrie orice meniu
specificat n clasa ferestrei. Putei s considerai meniul din clasa ferestrei ca fiind meniul
prestabilit pentru ferestrele bazate pe clasa ferestrei n cazul n care cel de-al noulea parametru
al funciei CreateWindow are valoarea NULL. Ca urmare, putei s folosii meniuri diferite pentru
mai multe ferestre bazate pe aceeai clas.
Putei s avei un meniu NULL n clasa ferestrei i un meniu NULL la apelarea funciei
CreateWindow, i s atribuii ferestri un meniu dup creare:
SetMenu (hwnd, hMenu) ;
Aceast funcie v permite schimbarea dinamic a meniului unei ferestre. Vom vedea un astfel de
exemplu n programul NOPOPUPS, prezentat mai trziu n acest capitol.
Orice meniu ataat unei ferestre este distrus odat cu fereastra. Orice meniu care nu este ataat unei
ferestre trebuie s fie distrus explicit prin apelarea funciei DestroyMenu, nainte de nchiderea
programului.
Meniuri i mesaje
Sistemul de operare Windows trimite procedurii unei ferestre mai multe mesaje diferite atunci
cnd utilizatorul selecteaz un articol din meniu. n majoritatea cazurilor, programul poate s ignore
aceste mesaje i s le retransmit procedurii DefWindowProc. Un astfel de mesaj este
WMJNITMENU, cu urmtorii parametri:
wParam
Variabila handle a meniului principal
IParam
0
Parametrul wParam conine variabila handle a meniului principal, chiar dac utilizatorul selecteaz un articol din
meniul de sistem. n general, programele Windows ignor mesajul WM_INITMENU. Dei transmiterea acestui
mesaj v d posibilitatea s modificai meniul nainte de selectarea unui articol, bnuiesc c orice modificare n
meniul principal n acest moment ar fi foarte deconcertant pentru utilizator.
De asemenea, programul primete i mesaje WM_MENUSELECT. Programul poate primi mai multe mesaje
WM_MENUSELECT, pe msur ce utilizatorul mut cursorul sau mouse-ul pe diferite articole de meniu. Aa
cum vom vedea n Capitolul 12, acest mesaj este foarte util pentru implementarea unei bare de stare care conine o
descriere complet a opiunii din meniu. Parametrii mesajului WM_MENUSELECT sunt:
LOWORD (wParam)
Articolul selectat: identificatorul de meniu sau variabila
handle a meniului derulant
HIWORD (vParam)
Indicatorul flag de
selectare
IParam
Variabila handle a meniului care
conine articolul selectat
WM_MENUSELECT este un mesaj de urmrire a meniului. Cuvntul mai puin semnificativ al parametrului
wParam specific articolul de meniu care a fost selectat (marcat). Indicatorul flag de selectare" din cuvntul mai
semnificativ al parametrului wParam poate fi o combinaie a urmtorilor identificatori: MF_GRAYED, MF_DISABLED, MF_CHECKED, MF_BITMAP, MFJPOPUP, MFJHELP, MF_SYSMENU i MF_MOUSESELECT. Putei s
folosii mesajul WM_MENUSELECT dac dorii s modificai ceva n zona client a ferestrei n funcie de
deplasarea barei de selectare ntre articolele de meniu. Majoritatea programelor retransmit acest mesaj procedurii
DefWindowProc.
Atunci cnd este pregtit s afieze un meniu derulant, Windows trimite procedurii ferestrei un mesaj
WM_INITMENUPOPUP cu urmtorii parametri:
LOWORD (IParam)
HIWORD (IParam)
Variabila handle a
meniului derulant
Acest mesaj este important dac vrei s activai sau s dezactivai articole dintr-un meniu derulant nainte ca acesta
s fie afiat. De exemplu, s presupunem c programul ofer utilizatorului posibilitatea de a copia text din memoria
temporar (clipboard) cu ajutorul comenzii Paste, dintr-un meniu derulant. Atunci cnd primii mesajul
WMJNITMENUPOPUP trebuie s determinai dac n clipboard exist vreun text. Dac nu exist, ar trebui s afiai
cu gri articolul de meniu Paste. Vei vedea un astfel de exemplu n programul POPPAD revizuit, prezentat ctre
sfritul acestui capitol.
Cel mai important mesaj este WM_COMMAND. Acest mesaj indic faptul c utilizatorul a selectat un articol activat
din meniul ferestrei. V amintii din Capitolul 8 c mesajul WM_COMMAND este trimis i de controale. Dac folosii
acelai identificator pentru un articol de meniu i pentru un control, putei s difereniai mesajele n funcie de
parametrul IParam, care are valoarea 0 n cazul articolelor de meniu.
Meniu:
Control:
LOWORD (wParam)
HIWORD (wParam)
Identificatorul meniului
Identificatorul controlului
0
Cod de ntiinare
IParam
0
Variabila handle a
ferestrei descendent
Meniu de
sistem:
LOWORD
(wParam)
HIWORD
(wParam)
IParam
Identificatorul
0 (Dac mesajul
meniului
WM SYSCOMMAND a fost
trimis n urma executrii unui clic,
LOWORD (IParam) i HIWORD
(IParam) conin coordonatele X i
Y ale indicatorului mouse-ului.)
Identificatorul de meniu specific articolul selectat din meniul sistem. Pentru articolele de meniu predefinite,
ultimii patru bii ar trebui mascai. Valoarea rezultat poate fi: SC_SIZE, SC_MOVE, SC_MINIMIZE,
SCJMAXIMIZE, SC_NEXTWINDOW, SCJPREVWINDOW, SQCLOSE, SCJVSCROLL, SC_HSCROLL,
SC_ARRANGE, SC_RESTORE i SC_TASKLIST. n plus, cuvntul mai puin semnificativ al parametrului
xoPram poate fi SC_MOUSEMENU sau SC_KEYMENU.
Dac adugai noi articole n meniul sistem, cuvntul mai puin semnificativ al parametrului wParam va
conine numrul de identificare al articolului pe care l-ai definit. Pentru a evita conflictele cu identificatorii
articolelor predefinite, folosii valori mai mici de OxFOOO. Este foarte important ca mesajele
WM_SYSCOMMAND s fie trimise ctre procedura DefWindowProc. n caz contrar, vei dezactiva comenzile
normale din meniul sistem.
Ultimul mesaj despre care vom discuta este WM_MENUCHAR, care nu este un mesaj de meniu. Windows
trimite acest mesaj ctre procedura ferestrei n dou situaii: dac utilizatorul apas tasta Alt i o tast care nu
corespunde unui articol de meniu, sau atunci cnd este afiat un meniu derulant, dac utilizatorul apas o tast
care nu corespunde nici unui articol din meniul respectiv. Mesajul WM_MENU- CHAR are urmtorii
parametri:
LOWORD
(wParam)
HP/VORD (wParam)
IParam
Cod ASCII
Cod de selectare
Un program de exemplificare
Haidei s vedem un mic exemplu. Programul MENUDEMO, prezentat n Figura 10-1, are patru articole n
meniul principal - File, Edit, Background, Timer i Help. Fiecare dintre aceste articole are un meniu derulant.
MENUDEMO execut cele mai simple i mai obinuite operaii de prelucrare a meniurilor, care implic
interceptarea mesa-jmlui WM_COMMAND i verificarea cuvntului mai puin semnificativ al parametrului
wParam.
MENUDEMO.MAK
#
#Fiierul de construcie MENUDEMO.MAK
#
menudemo.exe:menudemo.objmenudemo.res
$(LINKER)$(GUIFLAGS)OUT:menudemo.exemenudemo.obj\
menudemo.res$(GUILIBS)
menudemo.obj:menudemo.cmenudemo.h
$(CC)$(CFLAGS)menudemo.c
menudemo.res:menudemo.rcmenudemo.h
$(RC)$(RCVARS)menudemo.rc
MENUDEMO.C
/*
MENUDEMO.CProgramdemonstrativpentrumeniuri
*/
#include<windows.h>
#include"menudemo.h"
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
charszAppName[]="MenuDemo";
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
HWNDhwnd;
MSGmsg;
WNDCLASSEXwndclass;
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=szAppName;
wndclass.lpszClassName=szAppName;
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hwnd=CreateWindow(szAppName,"MenuDemonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
staticintiColorID[5]={WHITE_BRUSH,LTGRAY_BRUSH,GRAY_BRUSH,
DKGRAY_BRUSH,BLACK_BRUSH};
staticintiSelection=IDM_WHITE;
HMENUhMenu;
switch(iMsg)
{
caseWM_COMMAND:
hMenu=GetMenu(hwnd);
switch(LOWORD(wParam))
{
caseIDM_NEW:
caseIDM_OPEN:
caseIDM_SAVE:
caseIDM_SAVEAS:
MessageBeep(0);
return0;
caseIDM_EXIT:
SendMessage(hwnd,WM_CLOSE,0,0L);
return0;
caseIDM_UNDO:
caseIDM_CUT:
caseIDM_COPY:
caseIDM_PASTE:
caseIDM_DEL:
MessageBeep(0);
return0;
caseIDM_WHITE://Note:Logicaurm?toaresebazeaz?pepresupunereac?indicatoriicuprinintre
IDM_WHITEiIDM_BLACKsuntnumereconsecutivenordineaar?tat?aici
caseIDM_LTGRAY://
caseIDM_GRAY://
caseIDM_DKGRAY://
caseIDM_BLACK://
CheckMenuItem(hMenu,iSelection,MF_UNCHECKED);
iSelection=LOWORD(wParam);
CheckMenuItem(hMenu,iSelection,MF_CHECKED);
SetClassLong(hwnd,GCL_HBRBACKGROUND,
(LONG)GetStockObject
(iColorID[LOWORD(wParam)IDM_WHITE]));
InvalidateRect(hwnd,NULL,TRUE);
return0;
caseIDM_START:
if(SetTimer(hwnd,1,1000,NULL))
{
EnableMenuItem(hMenu,IDM_START,MF_GRAYED);
EnableMenuItem(hMenu,IDM_STOP,MF_ENABLED);
}
return0;
caseIDM_STOP:
KillTimer(hwnd,1);
EnableMenuItem(hMenu,IDM_START,MF_ENABLED);
EnableMenuItem(hMenu,IDM_STOP,MF_GRAYED);
return0;
caseIDM_HELP:
MessageBox(hwnd,"Helpnotyetimplemented!",
szAppName,MB_ICONEXCLAMATION|MB_OK);
return0;
caseIDM_ABOUT:
MessageBox(hwnd,"MenuDemonstrationProgram.",
szAppName,MB_ICONINFORMATION|MB_OK);
return0;
}
break;
caseWM_TIMER:
MessageBeep(0);
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
MENUDEMO.RC
/*
MENUDEMO.RCfiierscriptderesurse
*/
#include"menudemo.h"
MenuDemoMENU
{
POPUP"&File"
{
MENUITEM"&New",IDM_NEW
MENUITEM"&Open...",IDM_OPEN
MENUITEM"&Save",IDM_SAVE
MENUITEM"Save&As...",IDM_SAVEAS
MENUITEMSEPARATOR
MENUITEM"E&xit",IDM_EXIT
}
POPUP"&Edit"
{
MENUITEM"&Undo",IDM_UNDO
MENUITEMSEPARATOR
MENUITEM"Cu&t",IDM_CUT
MENUITEM"&Copy",IDM_COPY
MENUITEM"&Paste",IDM_PASTE
MENUITEM"De&lete",IDM_DEL
}
POPUP"&Background"
321
{
MENUITEM"&White",IDM_WHITE,CHECKED
MENUITEM"&LtGray",IDM_LTGRAY
MENUITEM"&Gray",IDM_GRAY
MENUITEM"&DkGray",IDM_DKGRAY
MENUITEM"&Black",IDM_BLACK
}
POPUP"&Timer"
{
MENUITEM"&Start"IDM_START
MENUITEM"S&top"IDM_STOP,GRAYED
}
POPUP"&Help"
{
MENUITEM"&Help...",IDM_HELP
MENUITEM"&AboutMenuDemo...",IDM_ABOUT
}
}
MENUDEMO.H
/*
MENUDEMO.Hfiierantet
*/
#defineIDM_NEW1
#defineIDM_OPEN2
#defineIDM_SAVE3
#defineIDM_SAVEAS4
#defineIDM_EXIT5
#defineIDM_UNDO10
#defineIDM_CUT11
#defineIDM_COPY12
#defineIDM_PASTE13
#defineIDM_DEL14
#defineIDM_WHITE20
#defineIDM_LTGRAY21
#defineIDM_GRAY22
#defineIDM_DKGRAY23
#defineIDM_BLACK24
#defineIDM_START30
#defineIDM_STOP31
#defineIDM_HELP40
#defineIDM_ABOUT41
Identificatorii pentru fiecare meniu sunt definii n fiierul MENUDEMO.H. Acest fiier trebuie specificat (de
obicei printr-o instruciune Mnclude) att n fiierul script de resurse, ct i n codul surs C. Toi identificatorii ncep
cu literele IDM. Nu este nevoie ca numerele de identificare folosite pentru articolele dintr-un meniu s fie
consecutive. Totui, dac prelucrai aceti identificatori folosind instruciuni switch i case, compilatorul C poate
s optimizeze codul cu ajutorul unor tabele de salt (jump tables) dac folosii numere de identificare consecutive.
Pentru majoritatea articolelor din meniurile File i Edit, programul MENUDEMO nu face dect s emit un
semnal sonor atunci cnd primete mesajul WM_COM-MAND. Meniul derulant Background conine un set de
cinci pensule pe care putei s Ie folosii pentru colorarea fondului. n fiierul de resurse MENUDEMO.RC
articolul de meniu White (cu identificatorul IDM_WHITE) este marcat cu opiunea CHECKED, ceea ce are ca
efect afiarea unui marcaj de validare n dreptul acestui articol. n fiierul MENUDEMO.C, variabila iSeledion
are iniial valoarea IDM_WHITE.'
Cele cinci pensule din meniul Background se exclud reciproc. Atunci cnd primete un mesaj
WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam conine identificatorul unuia
dintre cele cinci articole din meniul Background, programul trebuie s tearg mai nti marcajul de validare din
dreptul articolului selectat anterior i apoi s adauge altul n dreptul noii culori. Pentru aceasta, programul are
nevoie de o variabil handle a meniului:
hMenu - GetMenu (hwnd) ;
Funcia CheckMenuItem este folosit pentru tergerea marcajului de validare din dreptul articolului curent
selectat:
CheckMenuItem (hMenu, iSelection, MFJINCHECKED) ;
Variabila iSelection primete valoarea cuvntului mai puin semnificativ al parametrului wParam i noua
culoare de fond este marcat:
iSelection = LOWORD (wParam) ;
CheckMenuItem (hMenu, iSelection, MF_CHECKED) ;
n continuare culoarea de fond din clasa ferestrei este nlocuit cu noua culoare, iar zona client a ferestrei
este invalidat. Windows terge zona client folosind noua culoare de fond.
Meniul derulant Timer (Cronometru) conine dou opiuni - Start i Stop. Iniial, opiunea Stop este scris
cu gri (aa cum indic definiia meniului din fiierul script de resurse). Atunci cnd selectai opiunea Start,
programul MENUDEMO ncearc s porneasc un cronometru i, dac reuete, afieaz cu gri opiunea
Start i activeaz opiunea Stop:
EnableMenuItem (hMenu, IDMJTART, MFJRAYED) ; EnableMenuItem (hMenu, IDM_ST0P,
MF_ENABLED) ;
La primirea unui mesaj WM_COMMAND n care cuvntul mai puin semnificativ al parametrului wParam
conine identificatorul IDM_STOP, programul MENUDEMO oprete cronometrul, activeaz opiunea Start i
dezactiveaz opiunea Stop:
EnableMenuItem (hMenu, IDM START, MF_ENABLEO) ; EnableMenuItem (hMenu, IDMJTOP,
MF_GRAYED) ;
Remarcai faptul c este imposibil ca programul s primeasc un mesaj WM_COM-MAND n care cuvntul
mai puin semnificativ al parametrului wParam s conin identificatorul IDM_START dup pornirea
cronometrului. La fel, programul nu poate s primeasc un mesaj WM_COMMAND n care cuvntul mai
puin semnificativ al parametrului wParam s conin identificatorul IDM_STOP dup oprirea cronometrului.
Atunci cnd primete un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al
parametrului wParam conine identificatorul IDM_ABOUT sau IDM_HELP, programul MENUDEMO
afieaz o caset de mesaje. (n capitolul urmtor vom nlocui aceast caset de mesaje cu o caset de
dialog.)
Atunci cnd primete un mesaj WM_COMMAND n care cuvntul mai puin semnificativ al
parametrului wParam conine identificatorul IDM_EXIT, programul MENUDEMO trimite un mesaj
WM_CLOSE. Acelai mesaj l trimite procedura DefWindowProc ctre procedura ferestrei atunci cnd
primete un mesaj WM_SYS-COMMAND n care cuvntul mai puin semnificativ al parametrului wParam
conine identificatorul SC_CLOSE. Vom discuta mai multe despre acest mesaj n programul POPPAD2,
prezentat ctre sfritul acestui capitol.
Capitolul 10 Meniuri i taste de accelerare
singura. Putei s renunai la fiierul script de resurse i s creai ntregul meniu direct n codul surs, folosind
funciile CreateMenu i Append-Menu. Dup ce definii meniul, putei s transmitei funciei CreateWindow
variabila handle a acestuia sau s apelai funcia SetMenu ca s schimbai meniul ferestrei.
Iat cum putei s facei acest lucru. Funcia CreateMenu returneaz variabila handle a meniului:
hHenu CreateMenu () ;
Iniial meniul este gol. Prin apelarea funciei AppendMenu sunt inserate articolele de meniu. Trebuie s obinei
variabile handle diferite pentru meniul principal i pentru fiecare meniu derulant. Meniurile derulante sunt
construite separat, apoi variabilele handle ale acestora sunt inserate n meniul principal. Codul prezentat n
Figura 10-2 creeaz un meniu prin aceast metod; de fapt, acesta este acelai meniu cu cel folosit de programul
MENUDEMO.
hMenu=CreateMenu();
hMenuPopup=CreateMenu();
AppendMenu(hMenuPopup,MF_STRING,IDM_NEW,"&New");
AppendMenu(hMenuPopup,MF_STRING,IDM_OPEN,"&Open...");
AppendMenu(hMenuPopup,MF_STRING,IDM_SAVE,"&Save");
AppendMenu(hMenuPopup,MF_STRING,IDM_SAVEAS,"Save&As...");
AppendMenu(hMenuPopup,MF_SEPARATOR,0,NULL);
AppendMenu(hMenuPopup,MF_STRING,IDM_EXIT,"E&xit");
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuPopup,"&File");
hMenuPopup=CreateMenu();
AppendMenu(hMenuPopup,MF_STRING,IDM_UNDO,"&Undo");
AppendMenu(hMenuPopup,MF_SEPARATOR,0,NULL);
AppendMenu(hMenuPopup,MF_STRING,IDM_CUT,"Cu&t");
AppendMenu(hMenuPopup,MF_STRING,IDM_COPY,"&Copy");
AppendMenu(hMenuPopup,MF_STRING,IDM_PASTE,"&Paste");
AppendMenu(hMenuPopup,MF_STRING,IDM_DEL,"De&lete");
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuPopup,"&Edit");
hMenuPopup=CreateMenu();
AppendMenu(hMenuPopup,MF_STRING|MF_CHECKED,IDM_WHITE,"&White");
AppendMenu(hMenuPopup,MF_STRING,IDM_LTGRAY,"&LtGray");
AppendMenu(hMenuPopup,MF_STRING,IDM_GRAY,"&Gray");
AppendMenu(hMenuPopup,MF_STRING,IDM_DKGRAY,"&DkGray");
AppendMenu(hMenuPopup,MF_STRING,IDM_BLACK,"&Black");
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuPopup,"&Background");
hMenuPopup=CreateMenu();
AppendMenu(hMenuPopup,MF_STRING,IDM_START,"&Start");
AppendMenu(hMenuPopup,MF_STRING|MF_GRAYED,IDM_STOP,"S&top");
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuPopup,"&Timer");
hMenuPopup=CreateMenu();
AppendMenu(hMenuPopup,MF_STRING,IDM_HELP,"&Help...");
AppendMenu(hMenuPopup,MF_STRING,IDM_ABOUT,"&AboutMenuDemo...");
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuPopup,"&Help");
Fig. 10.2 Codul C care creaz meniul utilizat de programul MENUDEMO, fr se foloseasc un fiier script de resurse.
Cred c suntei de acord c metoda care folosete ablonul de meniu din fiierul script de resurse este mai
simpl i mai clar. Ca urmare, nu v recomand s definii meniul j direct n codul surs, ci doar am artat c
exist i aceast cale. Desigur, putei s ( reducei substanial dimensiunea codului surs cu ajutorul unor
matrice, care s \ aonin irurile de caractere, identificatorii i indicatorii flag ai articolelor de meniu. Dar
dac facei acest lucru, putei s folosii la fel de bine cea de-a treia metod de definire a unui meniu,
prezentat n continuare.
POPMENU.MAK
#
#Fiieruldeconstruc?iePOPMENU.MAK
#
popmenu.exe:popmenu.objpopmenu.res
$(LINKER)$(GUIFLAGS)OUT:popmenu.exepopmenu.obj\
popmenu.res$(GUILIBS)
popmenu.obj:popmenu.cpopmenu.h
$(CC)$(CFLAGS)popmenu.c
popmenu.res:popmenu.rcpopmenu.h
$(RC)$(RCVARS)popmenu.rc
POPMENU.C
/*
POPMENU.Cprogramdemonstrativpentrumeniurilederulante
(c)CharlesPetzold,1996
*/
#include<windows.h>
#include"popmenu.h"
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
charszAppName[]="PopMenu";
HINSTANCEhInst;
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
HWNDhwnd;
MSGmsg;
WNDCLASSEXwndclass;
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;
wndclass.lpszClassName=szAppName;
325
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hInst=hInstance;
hwnd=CreateWindow(szAppName,"PopupMenuDemonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
staticHMENUhMenu;
staticintiColorID[5]={WHITE_BRUSH,LTGRAY_BRUSH,GRAY_BRUSH,
DKGRAY_BRUSH,BLACK_BRUSH};
staticintiSelection=IDM_WHITE;
POINTpoint;
switch(iMsg)
{
caseWM_CREATE:
hMenu=LoadMenu(hInst,szAppName);
hMenu=GetSubMenu(hMenu,0);
return0;
caseWM_RBUTTONDOWN:
point.x=LOWORD(lParam);
point.y=HIWORD(lParam);
ClientToScreen(hwnd,&point);
TrackPopupMenu(hMenu,0,point.x,point.y,0,hwnd,NULL);
return0;
caseWM_COMMAND:
switch(LOWORD(wParam))
{
caseIDM_NEW:
caseIDM_OPEN:
caseIDM_SAVE:
caseIDM_SAVEAS:
caseIDM_UNDO:
caseIDM_CUT:
caseIDM_COPY:
caseIDM_PASTE:
caseIDM_DEL:
MessageBeep(0);
return0;
caseIDM_WHITE://Logicaurm?toaresebazeaz?pepresupunereac?identificatoriicuprinin
intervalulIDM_WHITEiIDM_BLACKsuntnumereconsecutivenordineaar?tat?aici
caseIDM_LTGRAY://
caseIDM_GRAY://
caseIDM_DKGRAY://
caseIDM_BLACK://
CheckMenuItem(hMenu,iSelection,MF_UNCHECKED);
iSelection=LOWORD(wParam);
CheckMenuItem(hMenu,iSelection,MF_CHECKED);
SetClassLong(hwnd,GCL_HBRBACKGROUND,
(LONG)GetStockObject
(iColorID[LOWORD(wParam)IDM_WHITE]));
InvalidateRect(hwnd,NULL,TRUE);
return0;
caseIDM_ABOUT:
MessageBox(hwnd,"PopupMenuDemonstrationProgram.",
szAppName,MB_ICONINFORMATION|MB_OK);
return0;
caseIDM_EXIT:
SendMessage(hwnd,WM_CLOSE,0,0);
return0;
caseIDM_HELP:
MessageBox(hwnd,"Helpnotyetimplemented!",
szAppName,MB_ICONEXCLAMATION|MB_OK);
return0;
}
break;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
POPMENU.RC
/*
POPMENU.RCfiierscriptderesurse
*/
#include"popmenu.h"
PopMenuMENU
{
POPUP""
{
POPUP"&File"
{
MENUITEM"&New",IDM_NEW
MENUITEM"&Open...",IDM_OPEN
MENUITEM"&Save",IDM_SAVE
MENUITEM"Save&As...",IDM_SAVEAS
MENUITEMSEPARATOR
MENUITEM"E&xit",IDM_EXIT
}
POPUP"&Edit"
{
MENUITEM"&Undo",IDM_UNDO
MENUITEMSEPARATOR
MENUITEM"Cu&t",IDM_CUT
MENUITEM"&Copy",IDM_COPY
MENUITEM"&Paste",IDM_PASTE
327
MENUITEM"De&lete",IDM_DEL
}
POPUP"&Background"
{
MENUITEM"&White",IDM_WHITE,CHECKED
MENUITEM"&LtGray",IDM_LTGRAY
MENUITEM"&Gray",IDM_GRAY
MENUITEM"&DkGray",IDM_DKGRAY
MENUITEM"&Black",IDM_BLACK
}
POPUP"&Help"
{
MENUITEM"&Help...",IDM_HELP
MENUITEM"&AboutPopMenu...",IDM_ABOUT
}
}
}
POPMENU.H
/*
POPMENU.Hfiierantet
*/
#defineIDM_NEW1
#defineIDM_OPEN2
#defineIDM_SAVE3
#defineIDM_SAVEAS4
#defineIDM_EXIT5
#defineIDM_UNDO10
#defineIDM_CUT11
#defineIDM_COPY12
#defineIDM_PASTE13
#defineIDM_DEL14
#defineIDM_WHITE20
#defineIDM_LTGRAY21
#defineIDM_GRAY22
#defineIDM_DKGRAY23
#defineIDM_BLACK24
#defineIDM_HELP30
#defineIDM_ABOUT31
Fiierul script de resurse POPMENU.RC definete un meniu foarte asemntor cu cel definit n fiierul
MENUDEMO.RC. Diferena const n faptul c meniul principal conine un singur articol - un meniu derulant
care conine opiunile File, Edit, Background i Help.
n timpul prelucrrii mesajului WM_CREATE n procedura WndProc, POPMENU obine o variabil handle a
acestui meniu derulant:
hMenu = LoadMenu (hlnst, szAppName) ; hMenu = GetSubMenu (hMenu, 0) ;
Sistemul de operare afieaz apoi meniul derulant cu articolele File, Edit, Background i Help. Selectarea
oricruia dintre aceste articole determin afiarea meniurilor derulante corespunztoare. Funciile din meniuri au
acelai rol ca i funciile din meniul normal.
POORMENU.MAK
#
#Fiieruldeconstruc?iePOORMENU.MAKmakefile
#
poormenu.exe:poormenu.obj
$(LINKER)$(GUIFLAGS)OUT:poormenu.exepoormenu.obj$(GUILIBS)
poormenu.obj:poormenu.c
$(CC)$(CFLAGS)poormenu.c
POORMENU.C
/*
POORMENU.CMeniupentrus?raci
(c)CharlesPetzold,1996
*/
#include<windows.h>
#defineIDM_ABOUT1
#defineIDM_HELP2
#defineIDM_REMOVE3
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
staticcharszAppName[]="PoorMenu";
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
HMENUhMenu;
HWNDhwnd;
MSGmsg;
WNDCLASSEXwndclass;
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;
wndclass.lpszClassName=szAppName;
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hwnd=CreateWindow(szAppName,"ThePoorPerson'sMenu",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
hMenu=GetSystemMenu(hwnd,FALSE);
AppendMenu(hMenu,MF_SEPARATOR,0,NULL);
AppendMenu(hMenu,MF_STRING,IDM_ABOUT,"About...");
AppendMenu(hMenu,MF_STRING,IDM_HELP,"Help...");
AppendMenu(hMenu,MF_STRING,IDM_REMOVE,"RemoveAdditions");
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
switch(iMsg)
{
caseWM_SYSCOMMAND:
switch(LOWORD(wParam))
{
caseIDM_ABOUT:
MessageBox(hwnd,"APoorPerson'sMenuProgram.",
szAppName,MB_OK|MB_ICONINFORMATION);
return0;
caseIDM_HELP:
MessageBox(hwnd,"Helpnotyetimplemented!",
szAppName,MB_OK|MB_ICONEXCLAMATION);
return0;
caseIDM_REMOVE:
GetSystemMenu(hwnd,TRUE);
return0;
}
break;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
Cele trei numere de identificare ale meniurilor adugate sunt definite n partea de sus a fiierului
POORMENU.C:
fdefine IDM ABOUT 1 #define IDM~HELP 2 #define IDM^REMOVE 3
Dup crearea ferestrei programului, POORMENU obine o variabil handle a meniului sistem:
hMenu = GetSystemMenu (hwnd, FALSE) ;
La prima apelare a funciei GetSystemMenu trebuie s dai celui de-al doilea parametru valoarea FALSE ca s
pregtii modificarea meniului.
Meniul este modificat prin patru apeluri ale funciei AppendMenu:
AppendMenu (hMenu, MF SEPARATOR, 0,
NULL) ;
AppendMenu (hMenu, MF~STRING,
IDM ABOUT, "About...") ; AppendMenu (hMenu, MF~STRING,
AppendMenu (hMenu, MF~STRING,
IDM REMOVE, "Remove Additions") ; *
IDMJELP,
~
"Help...") ;
~
Primul apel al funciei AppendMenu adaug o bar de separare. Selectarea opiuni Remove Additions determin
eliminarea articolelor de meniu adugate, operaie efectuat prin apelarea funciei GetSystemMenu avnd al
doilea parametru cu valoarea TRUE:
GetSystemMenu (hwnd, TRUE) ;
Meniul sistem standard conine opiunile Restore, Move, Size, Minimize, Maximize, Close i Switch To.
Acestea genereaz mesaje WM_SYSCOMMAND n care parametrul wParam poate avea valorile SC_RESTORE,
SC_MOVE, SC_SIZE, SC.MINIMIZE, SC_MAXIMIZE, SC_CLOSE i SC_TASKLIST. Dei, n general, programele Windows nu fac acest lucru, putei s prelucrai aceste mesaje, n loc s le transmitei procedurii
DefWindowProc. De asemenea, putei s dezactivai sau s tergei unele dintre opiunile standard folosind
metodele descrise mai jos. Documentaia Windows include i alte opiuni standard pe care putei s le adugai
n meniul sistem. Aceste opiuni suplimentare folosesc identificatorii SC_NEXTWIN-DOW,
SQPREVWINDOW, SC_VSCROLL, SC_HSCROLL i SC_ARRANGE. Este posibil ca n unele aplicaii s dorii
s adugai i aceste comenzi la meniul sistem.
Modificarea meniului
Am vzut deja cum poate fi folosit funcia AppendMenu pentru definirea unui ntreg meniu direct ntr-un
program i pentru adugarea unor articole la meniul sistem, nainte de apariia versiunii Windows 3.0, pentru
aceste operaii trebuia s folosii funcia ChangeMenu. Funcia ChangeMenu, datorit flexibilitii ei, era una
dintre cele mai complexe funcii Windows. In Windows 95 funcia ChangeMenu poate fi nc folosit, dar
operaiile pe care le poate executa aceasta au fost mprite ntre alte cinci noi funcii:
AppendMenu - adaug un nou articol la sfritul unui meniu.
DeleteMenu - terge un articol existent dintr-un meniu i distruge articolul
respectiv.
InsertMenu - insereaz un nou articol ntr-un meniu.
ModifyMenu - modific un articol de meniu existent.
RemoveMenu - terge un articol existent dintr-un meniu.
Diferena dintre funciile RemoveMenu i DeleteMenu este important dac articolul respectiv face parte dintrun meniu derulant. DeleteMenu distruge meniul derulant, pe cnd RemoveMenu nu face acest lucru.
unde iPosition este indexul meniului derulant (ncepnd de la 0) n cadrul meniului principal indicat de
parametrul hMenu. Putei apoi s folosii variabila handle obinut pentru apelarea altor funcii (cum ar fi
AppendMenu).
Putei s obinei numrul curent de articole dintr-un meniu derulant astfel:
iCount = GetMenuItemCount (hMenu) ; Putei s obinei identificatorul unui articol dintr-un meniu derulant astfel:
id - GetMenuItemID (hMenuPopup, iPosition) ;
n programul MENUDEMO, hMenu era variabila handle a meniului principal, id era identificatorul meniului, iar
iCheck avea una dintre valorile MF_CHECKED sau MF_UNCHECKED. Dac hMenu este variabila handle a
unui meniu derulant, atunci id poate fi un index poziional n loc de un identificator de meniu. Dac folosirea
indexului este mai convenabil, includei identificatorul MF_B\TOSITION n cel de-al treilea parametru. De
exemplu:
ChedkMenuItem (hMenu, iPosition, MF_CHECKED j MF_BYP0SITI0N) ;
Funcia EnableMenuItem lucreaz ntr-un mod asemntor cu funcia CheckMenuItem, exceptnd faptul c cel
de-al treilea parametru poate avea una dintre valorile MF_ENABLED, MF_DISABLED sau MF_GRAYED.
Dac folosii funcia EnableMenuItem pentru un articol al meniului principal care apeleaz un meniu derulant,
n cel de-al treilea parametru trebuie s includei identificatorul MF_BYPOSITION, deoarece articolul respectiv
nu are un identificator de meniu. Vom vedea un exemplu de folosire a funciei EnableMenuItem n programul
POPPAD prezentat mai trziu n acest capitol. Funcia HUiieMenuItem este asemntoare cu funciile
EnableMenuItem i CheckMenuItem, dar folosete identificatorii MF_HILITE i MFJJNHILITE. Acest marcaj
(highlighting) este modul de afiare n video invers pe care sistemul de operare Windows l folosete atunci cnd
v deplasai de la un articol de meniu la altul. n mod normal nu avei nevoie s folosii funcia HUiieMenuItem.
Ce altceva ai mai avea nevoie s facei cu un meniu? Ai uitat ce ir de caractere ai folosit ntr-un meniu?
Putei s v mprosptai memoria cu urmtorul apel:
iByteCount = GetMenuString (hMenu, id, pString, iMaxCount, iFlag) ;
iFlag poate fi MF_BYCOMMAND (caz n care id este identificatorul meniului) sau MFJBYPOSITION (iar id
este un index poziional). Funcia copiaz cel mult iMaxCount octei n pString i returneaz numrul de octei
copiai.
Sau poate c dorii s aflai care sunt indicatoarele flag stabilite pentru un articol de meniu:
iFlags = GetMenuState (hMenu, id, iFlag) ;
Din nou, iFlag poate fi MF_BYCOMMAND sau MF_BYPOSITION. Valoarea iFlags returnat este o
combinaie a tuturor indicatoarelor flag curente. Putei s stabilii care sunt acestea comparnd aceast
valoare cu identificatorii MF_DISABLED,
MF.GRAYED, MF_CHECKED, MF_MENUBREAK, MF_MENUBARBREAK i MF_SEPARATOR.
Probabil c v-ai plictisit de meniuri. n acest caz, v vei bucura s aflai c putei scpa de un meniu de care nu
mai avei nevoie cu ajutorul funciei DestroyMenu:
DestroyMenu (hMenu) ; Apelul de mai sus invalideaz variabila handle a meniului.
#
#Fiieruldeconstruc?ieNOPOPUPS.MAK
#
nopopups.exe:nopopups.objnopopups.res
$(LINKER)$(GUIFLAGS)OUT:nopopups.exenopopups.obj\
nopopups.res$(GUILIBS)
nopopups.obj:nopopups.cnopopups.h
$(CC)$(CFLAGS)nopopups.c
nopopups.res:nopopups.rcnopopups.h
$(RC)$(RCVARS)nopopups.rc
332
NOPOPUPS.C
/*
NOPOPUPS.CProgramdemonstrativepentruutilizareameniurilorimbricate,nederulate
(c)CharlesPetzold,1996
*/
#include<windows.h>
#include"nopopups.h"
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
staticcharszAppName[]="NoPopUps";
HWNDhwnd;
MSGmsg;
WNDCLASSEXwndclass;
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;
wndclass.lpszClassName=szAppName;
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hwnd=CreateWindow(szAppName,"NoPopupNestedMenuDemonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
staticHMENUhMenuMain,hMenuEdit,hMenuFile;
HINSTANCEhInstance;
switch(iMsg)
{
caseWM_CREATE:
hInstance=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
hMenuMain=LoadMenu(hInstance,"MenuMain");
hMenuFile=LoadMenu(hInstance,"MenuFile");
hMenuEdit=LoadMenu(hInstance,"MenuEdit");
SetMenu(hwnd,hMenuMain);
return0;
caseWM_COMMAND:
switch(LOWORD(wParam))
{
caseIDM_MAIN:
SetMenu(hwnd,hMenuMain);
return0;
caseIDM_FILE:
SetMenu(hwnd,hMenuFile);
return0;
caseIDM_EDIT:
SetMenu(hwnd,hMenuEdit);
return0;
caseIDM_NEW:
caseIDM_OPEN:
caseIDM_SAVE:
caseIDM_SAVEAS:
caseIDM_UNDO:
caseIDM_CUT:
caseIDM_COPY:
caseIDM_PASTE:
caseIDM_DEL:
MessageBeep(0);
return0;
}
break;
caseWM_DESTROY:
SetMenu(hwnd,hMenuMain);
DestroyMenu(hMenuFile);
DestroyMenu(hMenuEdit);
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
NOPOPUPS.RC
/*
NOPOPUPS.RCfiierul script de resurse
*/
#include"nopopups.h"
MenuMainMENU
{
MENUITEM"MAIN:",0,INACTIVE
MENUITEM"&File...",IDM_FILE
MENUITEM"&Edit...",IDM_EDIT
}
MenuFileMENU
{
MENUITEM"FILE:",0,INACTIVE
MENUITEM"&New",IDM_NEW
MENUITEM"&Open...",IDM_OPEN
MENUITEM"&Save",IDM_SAVE
MENUITEM"Save&As...",IDM_SAVEAS
MENUITEM"(&Main)",IDM_MAIN
}
MenuEditMENU
{
MENUITEM"EDIT:",0,INACTIVE
MENUITEM"&Undo",IDM_UNDO
MENUITEM"Cu&t",IDM_CUT
MENUITEM"&Copy",IDM_COPY
MENUITEM"&Paste",IDM_PASTE
MENUITEM"De&lete",IDM_DEL
MENUITEM"(&Main)",IDM_MAIN
}
NOPOPUPS.H
/*
NOPOPUPS.Hfiierantet
*/
#defineIDM_NEW1
#defineIDM_OPEN2
#defineIDM_SAVE3
#defineIDM_SAVEAS4
#defineIDM_UNDO5
#defineIDM_CUT6
#defineIDM_COPY7
#defineIDM_PASTE8
#defineIDM_DEL9
#defineIDM_MAIN10
#defineIDM_EDIT11
#defineIDM_FILE12
Meniul principal conine trei opiuni, identificate prin irurile de caractere MAIN:", File..." i Edit...".
Opiunea MAIN:" este ns dezactivat, aa c nu trimite mesaje WM_COMMAND ctre procedura ferestrei.
Meniurile File i Edit sunt identificate prin irurile de caractere FILE:" i EDIT:". Ultima opiune din
meniurile File i Edit este (Main)"; aceast opiune permite ntoarcerea la meniul principal. Trecerea de la un
meniu la altul este simpl:
case WM COMMAND :
switch (LOWORD (wParam)) { case IDH_MAIN :
SetMenu (hwnd, hMenuMain) ; return 0 ;
case IOM FILE :
SetMenu (hwnd, hMenuFile) ; return 0 ;
case IDM EDIT :
SetMenu (hwnd, hMenuEdit) ; return 0 ;
ca fiiere .BMP; n locul acestora ar putea fi folosite orice imagini. Articolul Font din meniu apeleaz un meniu
derulant care conine trei opiuni: Courier New, Arial si Times New Roman. Acestea sunt fonturile TrueType
standard n Windows i numele fiecruia este afiat cu fontul respectiv (Figura 10-7). Aceste imagini au fost
create n program printr-o tehnic ce implic folosirea unui context de dispozitiv de memorie.
PARTEA A III-A FOLOSIREA RESURSELOR
||r|Bitn.pMl... !
n sfrit, dac derulai meniul sistem, vei vedea c avei acces la unele informaii de asisten soft (help),
opiunea Help fiind o imagine a disperrii unui utilizator nou (Figura 10-8). Aceast imagine bitmap
monocrom de 64x64 pixeli a fost creat n editorul de imagini Developer Studio.
GRAFMENU.MAK
#
#Fiierdeconstruc?ieGRAFMENU.MAK
#
grafmenu.exe:grafmenu.objgrafmenu.res
$(LINKER)$(GUIFLAGS)OUT:grafmenu.exe\
grafmenu.objgrafmenu.res$(GUILIBS)
grafmenu.obj:grafmenu.cgrafmenu.h
$(CC)$(CFLAGS)grafmenu.c
grafmenu.res:grafmenu.rcgrafmenu.h\
editlabl.bmpfilelabl.bmpfontlabl.bmpbighelp.bmp
$(RC)$(RCVARS)grafmenu.rc
GRAFMENU.C
/*
GRAFMENU.CProgramilustrativpentruarticoledemeniu
(c)CharlesPetzold,1996
*/
#include<windows.h>
#include<string.h>
#include"grafmenu.h"
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
HBITMAPStretchBitmap(HBITMAP);
HBITMAPGetBitmapFont(int);
charszAppName[]="GrafMenu";
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
HBITMAPhBitmapHelp,hBitmapFile,hBitmapEdit,
hBitmapFont,hBitmapPopFont[3];
HMENUhMenu,hMenuPopup;
HWNDhwnd;
inti;
MSGmsg;
WNDCLASSEXwndclass;
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;
wndclass.lpszClassName=szAppName;
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
hMenu=CreateMenu();
hMenuPopup=LoadMenu(hInstance,"MenuFile");
hBitmapFile=StretchBitmap(LoadBitmap(hInstance,"BitmapFile"));
AppendMenu(hMenu,MF_BITMAP|MF_POPUP,(int)hMenuPopup,
(PSTR)(LONG)hBitmapFile);
hMenuPopup=LoadMenu(hInstance,"MenuEdit");
hBitmapEdit=StretchBitmap(LoadBitmap(hInstance,"BitmapEdit"));
AppendMenu(hMenu,MF_BITMAP|MF_POPUP,(int)hMenuPopup,
(PSTR)(LONG)hBitmapEdit);
hMenuPopup=CreateMenu();
for(i=0;i<3;i++)
{
hBitmapPopFont[i]=GetBitmapFont(i);
AppendMenu(hMenuPopup,MF_BITMAP,IDM_COUR+i,
(PSTR)(LONG)hBitmapPopFont[i]);
}
hBitmapFont=StretchBitmap(LoadBitmap(hInstance,"BitmapFont"));
AppendMenu(hMenu,MF_BITMAP|MF_POPUP,(int)hMenuPopup,
(PSTR)(LONG)hBitmapFont);
hwnd=CreateWindow(szAppName,"BitmapMenuDemonstration",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,hMenu,hInstance,NULL);
hMenu=GetSystemMenu(hwnd,FALSE);
hBitmapHelp=StretchBitmap(LoadBitmap(hInstance,"BitmapHelp"));
AppendMenu(hMenu,MF_SEPARATOR,NULL,NULL);
AppendMenu(hMenu,MF_BITMAP,IDM_HELP,(PSTR)(LONG)hBitmapHelp);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DeleteObject(hBitmapHelp);
DeleteObject(hBitmapEdit);
DeleteObject(hBitmapFile);
DeleteObject(hBitmapFont);
for(i=0;i<3;i++)
DeleteObject(hBitmapPopFont[i]);
returnmsg.wParam;
}
HBITMAPStretchBitmap(HBITMAPhBitmap1)
{
BITMAPbm1,bm2;
HBITMAPhBitmap2;
HDChdc,hdcMem1,hdcMem2;
TEXTMETRICtm;
hdc=CreateIC("DISPLAY",NULL,NULL,NULL);
GetTextMetrics(hdc,&tm);
hdcMem1=CreateCompatibleDC(hdc);
hdcMem2=CreateCompatibleDC(hdc);
DeleteDC(hdc);
GetObject(hBitmap1,sizeof(BITMAP),(PSTR)&bm1);
bm2=bm1;
bm2.bmWidth=(tm.tmAveCharWidth*bm2.bmWidth)/4;
bm2.bmHeight=(tm.tmHeight*bm2.bmHeight)/8;
bm2.bmWidthBytes=((bm2.bmWidth+15)/16)*2;
hBitmap2=CreateBitmapIndirect(&bm2);
SelectObject(hdcMem1,hBitmap1);
SelectObject(hdcMem2,hBitmap2);
StretchBlt(hdcMem2,0,0,bm2.bmWidth,bm2.bmHeight,
hdcMem1,0,0,bm1.bmWidth,bm1.bmHeight,SRCCOPY);
DeleteDC(hdcMem1);
DeleteDC(hdcMem2);
DeleteObject(hBitmap1);
returnhBitmap2;
}
HBITMAPGetBitmapFont(inti)
{
staticchar*szFaceName[3]={"CourierNew","Arial",
"TimesNewRoman"};
staticLOGFONTlf;
HBITMAPhBitmap;
HDChdc,hdcMem;
HFONThFont;
SIZEsize;
TEXTMETRICtm;
hdc=CreateIC("DISPLAY",NULL,NULL,NULL);
GetTextMetrics(hdc,&tm);
lf.lfHeight=2*tm.tmHeight;
strcpy((char*)lf.lfFaceName,szFaceName[i]);
hdcMem=CreateCompatibleDC(hdc);
hFont=(HFONT)SelectObject(hdcMem,CreateFontIndirect(&lf));
GetTextExtentPoint(hdcMem,szFaceName[i],strlen(szFaceName[i]),&size);
hBitmap=CreateBitmap(size.cx,size.cy,1,1,NULL);
SelectObject(hdcMem,hBitmap);
TextOut(hdcMem,0,0,szFaceName[i],strlen(szFaceName[i]));
DeleteObject(SelectObject(hdcMem,hFont));
DeleteDC(hdcMem);
DeleteDC(hdc);
returnhBitmap;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
HMENUhMenu;
staticintiCurrentFont=IDM_COUR;
switch(iMsg)
{
caseWM_CREATE:
CheckMenuItem(GetMenu(hwnd),iCurrentFont,MF_CHECKED);
return0;
caseWM_SYSCOMMAND:
switch(LOWORD(wParam))
{
caseIDM_HELP:
MessageBox(hwnd,"Helpnotyetimplemented!",
szAppName,MB_OK|MB_ICONEXCLAMATION);
return0;
}
break;
caseWM_COMMAND:
switch(LOWORD(wParam))
{
caseIDM_NEW:
caseIDM_OPEN:
caseIDM_SAVE:
caseIDM_SAVEAS:
caseIDM_UNDO:
caseIDM_CUT:
caseIDM_COPY:
caseIDM_PASTE:
caseIDM_DEL:
MessageBeep(0);
return0;
caseIDM_COUR:
caseIDM_ARIAL:
caseIDM_TIMES:
hMenu=GetMenu(hwnd);
CheckMenuItem(hMenu,iCurrentFont,MF_UNCHECKED);
iCurrentFont=LOWORD(wParam);
CheckMenuItem(hMenu,iCurrentFont,MF_CHECKED);
return0;
}
break;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
GRAFMENU.RC
/*
GRAFMENU.RCfiierscriptderesurse
*/
#include"grafmenu.h"
BitmapEditBITMAPeditlabl.bmp
BitmapFileBITMAPfilelabl.bmp
BitmapFontBITMAPfontlabl.bmp
BitmapHelpBITMAPbighelp.bmp
MenuFileMENU
{
MENUITEM"&New",IDM_NEW
MENUITEM"&Open...",IDM_OPEN
MENUITEM"&Save",IDM_SAVE
MENUITEM"Save&As...",IDM_SAVEAS
}
MenuEditMENU
{
MENUITEM"&Undo",IDM_UNDO
MENUITEMSEPARATOR
MENUITEM"Cu&t",IDM_CUT
MENUITEM"&Copy",IDM_COPY
MENUITEM"&Paste",IDM_PASTE
MENUITEM"De&lete",IDM_DEL
}
GRAFMENU.H
/*
GRAFMENU.Hfiierantet
*/
#defineIDM_NEW1
#defineIDM_OPEN2
#defineIDM_SAVE3
#defineIDM_SAVEAS4
#defineIDM_UNDO5
#defineIDM_CUT6
#defineIDM_COPY7
#defineIDM_PASTE8
#defineIDM_DEL9
#defineIDM_COUR10
#defineIDM_ARIAL11
#defineIDM_TIMES12
#defineIDM_HELP13
EDITLABL.BMP
FILELABL.BMP
FONTLABL.BMP
BIGHELP.BMP
Unele cmpuri din structura TEXTMETRIC trebuie s fie modificate pentru a descrie un font Arial mai mare
ntr-o structur logic a fontului:
lf.lfHeight = 2 * tm.tmHeight ;
strepy ((char *) lf.lfFaceName, "Arial") ;
Urmtorul pas este s obinem un context de dispozitiv pentru ecran i s crem un context de
dispozitiv n memorie compatibil cu ecranul:
hdcMem CreateCompatibleDC (hdc) ;
Variabila handle a contextului de dispozitiv n memorie este hdcMem. n continuare, crem un font pe baza
structurii modificate //i selectm fontul respectiv n contextul de dispozitiv n memorie:
hFont = (HFONT) SelectObject (hdcMem, CreateFontlndirect (&lf)) ;
Din acest moment, dac scriem un text n contextul de dispozitiv n memorie, Windows va folosi fontul
TrueType Arial, selectat n contextul de dispozitiv.
Dar contextul de dispozitiv nu are dect o suprafa de afiare monocrom de un pixel. Trebuie s crem
o imagine bitmap destul de mare pentru afiarea textului dorit. Putei s obinei dimensiunile textului cu
ajutorul funciei GetTextExtentPoint i s creai o imagine bitmap pe baza acestor dimensiuni folosind
funcia CreateBitmap:
GetTextExtentPoint (hdcMem, "Arial", 5, &size) ; hBitmap = CreateBitmap (size.cx,
size.cy, 1, 1, NULL) ; SelectObject (hdcMem, hBitmap) ;
Contextul de dispozitiv are acum o suprafa de afiare de dimensiunile textului. Tot ce mai trebuie s
facem este s scriem textul. Ai mai vzut aceast funcie:
Text O u t ( h d c Me m , 0 , 0 , " A r i a l " , 5 ) ;
Mai avem de fcut doar operaiile de curenie. Pentru aceasta, selectm din nou fontul sistem (cu
variabila handle hFont) n contextul de dispozitiv folosind funcia
SelectObject i tergem variabila handle a fontului returnat anterior de funcia Se-lectObject, respectiv
variabila handle a fontului Arial:
DeleteObject {SelectObject (hdcMem, hFont)) ;
Am rmas cu o imagine bitmap care conine textul Arial" scris cu fontul Arial.
Variabila handle a imaginii bitmap transmis funciei este hBitmapl. Programul poate obine dimensiunile
acestei imagini cu ajutorul funciei GetObject:
GetObject (hBitmapl, sizeof (BITMAP), (PSTR) &bml) ;
Apelul de mai sus copiaz dimensiunile n structura bml, de tip BITMAP. Structura bml primete
aceleai valori ca i bml, apoi unele cmpuri sunt modificate pe baza dimensiunilor fontului sistem:
bm2 = bml ;
bm2.bmWidth
= (tm.tmAveCharWidth * bm2.bmWidth) / 4 ;
bm2.bmHeight
- (tm.tmHeight
* bm2.bmHeight) / 8 ;
bm2.bmWidthBytes = ((bm2.bmWidth + 15) / 16) * 2 ;
Apoi poate fi creat o nou imagine bitmap cu variabila handle hBiimapl, pe baza dimensiunilor
modificate:
hBitmap2 = CreateBitmapIndirect (&bm2) ;
Putei apoi s selectai cele dou imagini bitmap n contextele de dispozitiv create:
SelectObject (hdcMeml, hBitmapl) ; SelectObject (hdcMem2,
hBitmap2) ;
Dorim s copiem prima imagine bitmap n cea de-a doua i s o micorm n timpul acestei operaii.
Pentru aceasta folosim funcia StretchBH:
StretchBlt (hdcMem2, O, O, bm2.bmW idth, bm2.bmHeight,
hdcMeml, O, O, bml.bmWidth, bml.bmHeight, SRCCOPY) ;
Acum, cea de-a doua imagine bitmap este scalat corespunztor i putem s o folosim n meniu.
Operaiile de curenie sunt simple:
DeleteDC (hdcMeml) ; DeleteDC (hdcMem2) ; DeleteObject
(hBitmapl) ;
Compunerea meniului
Meniul derulant pentru opiunea File (coninnd articolele New, Open, Save i Save As) este ncrcat din
fiierul script de resurse:
hMenuPopup = LoadMenu (hlnstance, "MenuFile") ;
Imaginea bitmap care conine cuvntul FILE" este ncrcat tot din fiierul script de resurse i adus la
dimensiunile corespunztoare cu ajutorul funciei StretchBitmap:
hBitmapFile StretchBitmap (LoadBitmap (hlnstance, "BitmapFile")) ;
Variabilele handle ale imaginii bitmap i meniului derulant sunt folosite ca parametri pentru apelarea funciei
AppendMenu:
AppendMenu (hMenu, MF_BITMAP \ MF POPUP, (int) hMenuPopup, (PSTR) (LONG)
hBitmapFile) ;
Meniul derulant pentru cele trei fonturi este construit prin apelarea funciei GetBitmapFont:
CreateMenu ()
hMenuPopu
i < 3 ; 7++)
p for (i =
0 {
hBi tm apP opF ont[i] = GetB itmapFont (i ) ;
AppendMenu (hMenuPopup, MFJITMAP, IDM_C0UR + i,
(PSTR) (LONG) hMenuPopupFont[i]) ;
Acum meniul ferestrei este complet. Putei include variabila handle hMenu n apelul funciei
CreateWvndow:
hwnd = CreateWindow (szAppName, "Bitmap Menu Demonstraion", WS_OVERLAPPEDWINDOW,
CWJJSEDEFAULT, CW_USEDEFAULT, CWJJSEDEFAULT, CWJSEDEFAULT, NULL,
hMenu, hlnstance, NULL) ;
Dup obinerea variabilei hwnd, programul GRAFMENU poate modifica meniul sistem. Pentru aceasta
este nevoie de o variabil handle a meniului sistem:
hMenu = GetSystemMenu {hwnd, FALSE);
Nu uitai c imaginile bitmap sunt obiecte GDI i trebuie s fie explicit terse nainte de nchiderea
programului. Operaiile de tergere sunt executate dup ce GRAFMENU iese din bucla de prelucrare a
mesajelor:
DeleteObject
DeleteObject
DeleteObject
DeleteObject
(hBitmapHelp)
(hBitmapEdit)
(hBitmapFile)
(hBitmapFont)
;
;
;
;
for (i = 0 ; i < 3
DeleteObject (hBitmapPopFont[i]) ;
GetSystemMetrics (SM_CYMENU) ; nu
bara de meniu.
TASTE DE ACCELERARE
Descrise foarte simplu, tastele de accelerare sunt combinaii de taste care genereaz mesaje
WM_COMMAND (sau WM_SYSCOMMAND). De cele mai multe ori, programele folosesc tastele de
accelerare pentru duplicarea aciunilor unor opiuni de meniu folosite mai des. (Tastele de accelerare pot
declana ns i executarea unor aciuni care nu sunt funcii de meniu.) De exemplu, unele programe
Windows au meniuri Edit n care este inclus opiunea Delete; n mod convenional, aceste programe
stabilesc tasta Del ca accelerator pentru aceast opiune. Utilizatorul poate s selecteze opiunea Delete din
meniu apsnd o combinaie Alt+tast sau poate s apese direct tasta Del. Atunci cnd procedura ferestrei
recepioneaz mesajul WM_COMMAND, nu trebuie s determine dac a fost folosit meniul sau tasta de
accelerare.
programelor. Tastele de accelerare recomandate pentru aceste articole s-au schimbat de la Windows 3.0
la Windows 3.1, aa c nu este ceva neobinuit s gsii aplicaii care accept ambele stiluri, prezentate n
tabelul urmtor:
Funcie
Undo (Anulare)
Cut (Decupare)
Copy (Copiere)
Paste (Lipire)
Delete (tergere)
Accelerator
vechi
Alt+Backspace
Shift+Del
Ctrl+Ins
Shift+Ins
Del
Accelerator
nou
Ctrl+Z
Ctrl+X
Ctrl+C
Ctrl+V
Del
O alt tast de accelerare deseori folosit este FI, pentru apelarea sistemului de asisten soft (help).
Evitai folosirea tastelor F4, F5 i F6 deoarece acestea sunt deseori folosite pentru funcii speciale n
programele care implementeaz interfaa multidocu-ment (MDI - Multiple Document Interface), despre care
vom discuta n Capitolul 18.
Tabelul de acceleratori
Tabelul tastelor de accelerare este definit n fiierul script de resurse. Forma general a acestuia este:
MyAccelerators ACCELERATORS {
[definirea acceleratorilor] )
Numele tabelului este MyAccelerators. Tabelul ACCELERATORS nu conine opiuni de ncrcare sau
opiuni legate de folosirea memoriei. Fiierul script de resurse poate conine mai multe tabele
ACCELERATORS.
Fiecare tast de accelerare trebuie definit pe o linie separat. Exist patru tipuri de definiii de
acceleratori:
"char",
"Achar",
nCode,
nCode,
id
[.SHIFT] [.CONTROL] [,ALT]
id
[,SHIFT] [.CONTROL] [,ALT]
id, ASCII
[,SHIFT] [.CONTROL] [.ALT]
id, VIRTKEY
[.SHIFT] [.CONTROL] [,ALT]
n acest exemplu, char" nseamn un singur caracter ncadrat de ghilimele, Achar" nseamn caracterulA
urmat de un singur caracter, ncadrate de ghilimele, id este un numr care are acelai rol ca i identificatorul din
definiia unui meniu. Aceasta este valoare pe care Windows o trimite procedurii de fereastr prin mesajul
WM_COM-MAND pentru identificarea acceleratorului. De obicei, aceti identificatori sunt definii n fiierul
antet. Aproape ntotdeauna, tastele de accelerare selecteaz opiuni din meniurile derulante. Atunci cnd
tasta de accelerare dubleaz o comand de meniu, folosii acelai identificator att pentru meniu, ct i pentru
tasta de accelerare. Atunci cnd tasta de accelerare nu dubleaz o comand de meniu, folosii un identificator
unic.
Pentru prima definiie, tasta de accelerare este caracterul inclus ntre ghilimele, fcndu-se diferena ntre
literele mari i cele mici:
"char", id
Dac vrei s definii un accelerator pentru o combinaie ntre caracterul ncadrat de ghilimele i tastele Shif t,
Ctrl i Alt, adugai cuvintele cheie SHIFT, CONTROL i/sau ALT.
Pentru a doua definiie, acceleratorul este o combinaie ntre caracterul specificat si tasta Ctrl:
" Achar", id
Acest tip de definiie este identic cu primul tip dac se folosete numai identificatorul
CONTROL.
Ultimele dou tipuri folosesc un numr n locul caracterului dintre ghilimele:
nCode, id, ASCII
nCode, id, VIRTKEY
Acest numr este interpretat fie ca un cod ASCII, fcndu-se diferena ntre caracterele mari i cele mici, fie ca un cod
virtual de tast, n funcie de cuvntul cheie folosit (ASCII sau VIRTKEY).
Tipurile de acceleratori cel mai des folosite sunt al doilea i al patrulea. Al doilea tip este folosit pentru combinaiile
cu tasta Ctrl. De exemplu, linia urmtoare definete un accelerator pentru combinaia Ctrl+A:
"AA\ id
Al patrulea tip de definiie este folosit pentru codurile de taste virtuale, cum ar fi tastele funcionale. De exemplu,
linia urmtoare definete un accelerator pentru combinaia Ctrl+F9:
VKJ9, wid, VIRTKEY, CONTROL
Identificatorul VK_F9 este definit n fiierele antet Windows ca fiind codul virtual pentru tasta F9, aa c trebuie s
includei acest fiier n fiierul script de resurse:
#include <windows.h>
Primul i al treilea tip de acceleratori sunt rareori folosite. Dac vrei s le folos totui, acordai o atenie deosebit
diferenierii majusculelor de minuscule. Windo1 face verificrile de coresponden cu "char" sau nCode n funcie de
caracterul aps Dac adugai cuvntul cheie SHIFT, Windows verific dac a fost apsat tasta Sh Aceast situaie
produce uneori rezultate neateptate. De exemplu, dac "char" e "A", acceleratorul este apelat atunci cnd apsai
tasta A i este apsat tasta Sh sau este activ Caps Lock, dar nu ambele deodat. Dac folosii "A" cu SHIFT, trebi s
apsai tastele A i Shift simultan, dar acceleratorul nu poate fi apelat n nici un dac este activ Caps Lock. La fel,
acceleratorul "a" este apelat dac tasta A este aps fr tasta Shift, sau dac tasta A este apsat mpreun cu tasta
Shift, iar Caps L< este activ. Acceleratorul "a" cu SHIFT este apelat numai dac tasta A este aps mpreun cu
tasta Shift, iar Caps Lock este activ.
Atunci cnd definii un accelerator pentru un articol de meniu, este bine includei combinaia de taste n
textul articolului. Caracterul tab (\t) separ textul accelerator, astfel nct combinaia de taste este aliniat la a
doua coloan. Pen notaia combinaiilor de taste n meniu, folosii textul Ctrl, Shift sau Alt, urmat semnul + i de
caracterul corespunztor. De exemplu:
F6
Shift+F6
Ctrl+F6
Mai nti, definii o variabil handle de tipul HACCEL pentru tabelul de celeratori:
HACCEL hAccel ; Apoi ncrcai tabelul de acceleratori:
hAccel = LoadAccelerators (hlnstance, "MyAccelerators") ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
Funcia TranslateAccelerator determin dac mesajul stocat n structura msg este un mesaj de la tastatur.
Dac da, funcia caut n tabelul de acceleratori cu variabila handie hAccel un accelerator care s
corespund combinaiei de taste. Dac gsete un astfel de accelerator, apeleaz procedura ferestrei cu
variabila handie hwnd. Dac identificatorul acceleratorului este acelai cu identificatorul unui articol din
meniul sistem, mesajul transmis ferestrei este WM_SYSCOMMAND. n caz contrar, mesajul transmis este
WM_COMMAND.
Funcia TranslateAccelerator returneaz o valoare diferit de zero dac mesajul a fost convertit (i deja
transmis ctre procedura ferestrei) i 0 n caz contrar. Dac funcia TranslateAccelerator returneaz o
valoare diferit de zero, nu mai este nevoie s apelai funciile TranslateMessage i DispatchMessage, ci trebuie
s revenii la apelul funciei GetMessage.
Parametrul hwnd din apelul funciei TranslateAccelerator poate prea puin ciudat, deoarece nu apare n
celelalte funcii din ciclul de tratare a mesajelor. Mai mult, chiar structura mesajului (variabila msg) are un
membru numit hwnd care este tot o variabil handie a unei ferestre. Iat de ce TranslateAccelerator
funcioneaz puin altfel dect celelalte:
Cmpurile structurii msg sunt completate de funcia GetMessage. Dac al doilea
parametru
este
NULL,
funcia
GetMessage
intercepteaz
mesajele
tuturor
ferestrelor
care aparin aplicaiei. La ieirea din funcia GetMessage, membrul hwnd al structurii
msg conine variabila handie a ferestrei care va primi mesajul. Totui, atunci cnd
convertete un mesaj de la tastatur ntr-un mesaj WM_COMMAND sau WM_S"YSCOMMAND,
funcia
TranslateAccelerator
nlocuiete
coninutul
cmpului
msg.hwnd
cu variabila handie a ferestrei specificate ca prim parametru. Acesta este motivul
pentru care Windows transmite toate mesajele privind tastele de accelerare ctre
fereastra principal, chiar dac o alt fereastr a aplicaiei deine cursorul de intrare.
Funcia
TranslateAccelerator
nu
convertete
mesajele
de
la
tastatur
atunci
cnd
cursorul de intrare este deinut de o caset de dialog modal sau de o caset de mesaje,
deoarece mesajele pentru aceste ferestre nu sunt prelucrate n ciclul de mesaje al
programului.
S-ar putea ca n anumite cazuri n care cursorul de intrare este deinut de o alt fereastr a
programului (cum ar fi o caset de dialog nemodal) s nu dorii ca mesajele privind tastele de accelerare
s fie convertite. n capitolul urmtor vei vedea cum putei s tratai o astfel de situaie.
HIWORD (wParam)
IParam
Accelerator:
Identificatorul
acceleratorului
Meniu:
Identificatorul
meniului
Identificatorul
controlului
Cod de ntiinare
Variabila handle a
ferestrei descendent
Control:
Dac acceleratorul corespunde unui articol de meniu, procedura ferestrei primete i mesajele WMJNITMENU,
WMJNITMENUPOPUP i WM_MENUSELECT, la fel ca i n cazul selectrii unui articol de meniu. Programele
activeaz sau dezactiveaz articolele dintr-un meniu derulant n timpul prelucrrii mesajului WMJNITMENUPOPUP, aa c avei la dispoziie aceast posibilitate chiar i n cazul folosirii acceleratorilor. Dac
acceleratorul corespunde unui articol de meniu gri sau dezactivat, funcia TranslateAccelerator nu mai transmite
ctre procedura ferestrei mesajul WM_COMMAND sau mesajul WM_SYSCOMMAND.
Dac fereastra activ este minimizat, funcia TranslateAccelerator transmite ctre procedura ferestrei numai
mesajele WM_SYSCOMMAND - nu i mesajele WM_COMMAND - pentru acceleratorii corespunztori
articolelor activate din meniul sistem. De asemenea, funcia TranslateAccelerator trimite ctre procedura ferestrei
mesajele WM_COMMAND pentru acceleratorii care nu corespund nici unui articol de meniu.
POPPAD2.MAK
#
#Fiierul de construcie POPPAD2.MAK
#
poppad2.exe:poppad2.objpoppad2.res
$(LINKER)$(GUIFLAGS)OUT:poppad2.exepoppad2.objpoppad2.res$(GUILIBS)
poppad2.obj:poppad2.cpoppad2.h
$(CC)$(CFLAGS)poppad2.c
poppad2.res:poppad2.rcpoppad2.hpoppad2.ico
$(RC)$(RCVARS)poppad2.rc
POPPAD2.C
/*
POPPAD2.CProgramderulantdeeditare(includemeniuri)
(c)CharlesPetzold,1996
*/
#include<windows.h>
#include"poppad2.h"
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
charszAppName[]="PopPad2";
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,
PSTRszCmdLine,intiCmdShow)
{
HACCELhAccel;
HWNDhwnd;
MSGmsg;
WNDCLASSEXwndclass;
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(hInstance,szAppName);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=szAppName;
wndclass.lpszClassName=szAppName;
wndclass.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
RegisterClassEx(&wndclass);
349
hwnd=CreateWindow(szAppName,szAppName,
WS_OVERLAPPEDWINDOW,
GetSystemMetrics(SM_CXSCREEN)/4,
GetSystemMetrics(SM_CYSCREEN)/4,
GetSystemMetrics(SM_CXSCREEN)/2,
GetSystemMetrics(SM_CYSCREEN)/2,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
hAccel=LoadAccelerators(hInstance,szAppName);
while(GetMessage(&msg,NULL,0,0))
{
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
returnmsg.wParam;
}
AskConfirmation(HWNDhwnd)
{
returnMessageBox(hwnd,"ReallywanttoclosePopPad2?",
szAppName,MB_YESNO|MB_ICONQUESTION);
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
staticHWNDhwndEdit;
intiSelect,iEnable;
switch(iMsg)
{
caseWM_CREATE:
hwndEdit=CreateWindow("edit",NULL,
WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
WS_BORDER|ES_LEFT|ES_MULTILINE|
ES_AUTOHSCROLL|ES_AUTOVSCROLL,
0,0,0,0,
hwnd,(HMENU)1,
((LPCREATESTRUCT)lParam)>hInstance,NULL);
return0;
caseWM_SETFOCUS:
SetFocus(hwndEdit);
return0;
caseWM_SIZE:
MoveWindow(hwndEdit,0,0,LOWORD(lParam),
HIWORD(lParam),TRUE);
return0;
caseWM_INITMENUPOPUP:
if(lParam==1)
{
EnableMenuItem((HMENU)wParam,IDM_UNDO,
SendMessage(hwndEdit,EM_CANUNDO,0,0)?
MF_ENABLED:MF_GRAYED);
350
EnableMenuItem((HMENU)wParam,IDM_PASTE,
IsClipboardFormatAvailable(CF_TEXT)?
MF_ENABLED:MF_GRAYED);
iSelect=SendMessage(hwndEdit,EM_GETSEL,0,0);
if(HIWORD(iSelect)==LOWORD(iSelect))
iEnable=MF_GRAYED;
else
iEnable=MF_ENABLED;
EnableMenuItem((HMENU)wParam,IDM_CUT,iEnable);
EnableMenuItem((HMENU)wParam,IDM_COPY,iEnable);
EnableMenuItem((HMENU)wParam,IDM_DEL,iEnable);
return0;
}
break;
caseWM_COMMAND:
if(lParam)
{
if(LOWORD(lParam)==1&&
(HIWORD(wParam)==EN_ERRSPACE||
HIWORD(wParam)==EN_MAXTEXT))
MessageBox(hwnd,"Editcontroloutofspace.",
szAppName,MB_OK|MB_ICONSTOP);
return0;
}
elseswitch(LOWORD(wParam))
{
caseIDM_NEW:
caseIDM_OPEN:
caseIDM_SAVE:
caseIDM_SAVEAS:
caseIDM_PRINT:
MessageBeep(0);
return0;
caseIDM_EXIT:
SendMessage(hwnd,WM_CLOSE,0,0);
return0;
caseIDM_UNDO:
SendMessage(hwndEdit,WM_UNDO,0,0);
return0;
caseIDM_CUT:
SendMessage(hwndEdit,WM_CUT,0,0);
return0;
caseIDM_COPY:
SendMessage(hwndEdit,WM_COPY,0,0);
return0;
caseIDM_PASTE:
SendMessage(hwndEdit,WM_PASTE,0,0);
return0;
caseIDM_DEL:
SendMessage(hwndEdit,WM_CLEAR,0,0);
return0;
351
caseIDM_SELALL:
SendMessage(hwndEdit,EM_SETSEL,0,1);
return0;
caseIDM_HELP:
MessageBox(hwnd,"Helpnotyetimplemented!",
szAppName,MB_OK|MB_ICONEXCLAMATION);
return0;
caseIDM_ABOUT:
MessageBox(hwnd,
"POPPAD2(c)CharlesPetzold,1996",
szAppName,MB_OK|MB_ICONINFORMATION);
return0;
}
break;
caseWM_CLOSE:
if(IDYES==AskConfirmation(hwnd))
DestroyWindow(hwnd);
return0;
caseWM_QUERYENDSESSION:
if(IDYES==AskConfirmation(hwnd))
return1;
else
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
POPPAD2.RC
/*
POPPAD2.RCfiier script de resurse
*/
#include<windows.h>
#include"poppad2.h"
PopPad2ICONpoppad2.ico
PopPad2MENU
{
POPUP"&File"
{
MENUITEM"&New",IDM_NEW
MENUITEM"&Open...",IDM_OPEN
MENUITEM"&Save",IDM_SAVE
MENUITEM"Save&As...",IDM_SAVEAS
MENUITEMSEPARATOR
MENUITEM"&Print",IDM_PRINT
MENUITEMSEPARATOR
MENUITEM"E&xit",IDM_EXIT
}
POPUP"&Edit"
{
MENUITEM"&Undo\tCtrl+Z",IDM_UNDO
MENUITEMSEPARATOR
MENUITEM"Cu&t\tCtrl+X",IDM_CUT
MENUITEM"&Copy\tCtrl+C",IDM_COPY
352
MENUITEM"&Paste\tCtrl+V",IDM_PASTE
MENUITEM"De&lete\tDel",IDM_DEL
MENUITEMSEPARATOR
MENUITEM"&SelectAll",IDM_SELALL
}
POPUP"&Help"
{
MENUITEM"&Help...",IDM_HELP
MENUITEM"&AboutPopPad2...",IDM_ABOUT
}
}
PopPad2ACCELERATORS
{
"^Z",IDM_UNDO
VK_BACK,IDM_UNDO,VIRTKEY,ALT
"^X",IDM_CUT
VK_DELETE,IDM_CUT,VIRTKEY,SHIFT
"^C",IDM_COPY
VK_INSERT,IDM_COPY,VIRTKEY,CONTROL
"^V",IDM_PASTE
VK_INSERT,IDM_PASTE,VIRTKEY,SHIFT
VK_DELETE,IDM_DEL,VIRTKEY
VK_F1,IDM_HELP,VIRTKEY
}
POPPAD2.H
/*
POPPAD2.Hfiierantet
*/
#defineIDM_NEW1
#defineIDM_OPEN2
#defineIDM_SAVE3
#defineIDM_SAVEAS4
#defineIDM_PRINT5
#defineIDM_EXIT6
#defineIDM_UNDO10
#defineIDM_CUT11
#defineIDM_COPY12
#defineIDM_PASTE13
#defineIDM_DEL14
#defineIDM_SELALL15
#defineIDM_HELP20
#defineIDM_ABOUT22
POPPAD2.ICO
Fig. 10.10 Programul POPPAD2
POPPAD2.ICO
Opiunea Paste trebuie s fie activat numai dac memoria temporar (clipboard) conine text. Putem
determina acest lucru prin apelarea funciei IsClipboardFormat-AvaUable cu identificatorul CFJTEXT:
EnableMenuItem ((HMENU) wParam, IDM_PASTE, IsClipboardFormatAvailable (CF TEXT) ?
MF_ENABLED : MF_6RAYED) ; "
Opiunile Cut, Copy i Delete trebuie s fie activate numai dac n controlul de editare a fost selectat text.
Aflm acest lucru trimind controlului mesajul EM_GETSEL. Controlul returneaz un numr ntreg:
iSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0) ;
Cuvntul mai puin semnificativ al variabilei iSelect este poziia primului caracter selectat. Cuvntul mai
semnificativ al variabilei iSelect este poziia ultimului caracter selectat. Dac cele dou cuvinte sunt egale,
nseamn c nu a fost selectat nici un text:
if (HIWORD (iSelect) " LOWORD (iSelect))
iEnable = MFJRAYED ; else
iEnable = MFJNABLED ;
Valoarea variabilei iEnable este folosit apoi pentru opiunile Cut, Copy i Delete:
EnableMenuItem ((HMENU) wParam, IDM_CUT, iEnable) ; EnableMenuItem ((HMENU) wParam, IDM_C0PY,
iEnable) ; EnableMenuItem ((HMENU) wParam, IDM DEL,
iEnable) ;
Remarcai c secvena de instruciuni de mai sus ar fi putut fi simplificat i mai mult dac valorile
identificatorilor de meniu IDMJUNDO, IDM_CUT i aa mai departe ar fi fost egale cu valorile
corespunztoare mesajelor de fereastr WMJJNDO, WM_CUT i aa mai departe.
Opiunea About din meniul Help apeleaz o simpl caset de mesaje:
case IDM_AB0UT :
MessageBox (hwnd,
"P0PPAD2 (c) Charles Petzold, 1996", szAppName, MB_0K | MBJCONINFORMATION) ;
return 0 ;
n Capitolul 11 vom transforma aceast caset de mesaje ntr-o caset de dialog. Tot o caset de mesaje este
apelat i atunci cnd selectai opiunea Help din acest meniu, sau atunci cnd apsai tasta de accelerare FI.
Opiunea Exit trimite ctre procedura ferestrei un mesaj WM_CLOSE:
case IDMJXIT :
Acelai lucru l face procedura DefWindowProc atunci cnd primete un mesaj WM_SYSCOMMAND n care
parametrul wParam are valoarea SC_CLOSE.
n programele anterioare nu am prelucrat mesajele WM_CLOSE n procedura ferestrei, ci le-am transmis
procedurii DefWindowProc. Procedura DefWindowProc prelucreaz foarte simplu acest mesaj: apeleaz funcia
DestroyWindow. n loc s trimit mesajul WM_CLOSE ctre procedura DefWindowProc, programul POPPAD2 l
prelucreaz. Acest lucru nu este att de important acum, dar va deveni n Capitolul 11, cnd programul POPPAD2
va putea s editeze fiiere:
case WM_CLOSE : if
(IDYES --
AskConfirmation (hwnd))
AskConfirmation este o funcie din programul POPPAD2 care afieaz o caset de mesaje, cernd
utilizatorului s confirme nchiderea programului:
AskConfirmation (HWND hwnd) { return MessageBox (hwnd, "Reall y want to close Poppad2?",
szAppName, MB_YESNO | MBJCONQUESTION) ; }
Caseta de mesaje (ca i funcia AskConfirmation) returneaz valoarea IDYES dac a fost selectat butonul Yes.
Doar n acest caz programul POPPAD2 apeleaz funcia DestroyWindow. n caz contrar, execuia
programului continu.
Dac dorii s cerei confirmarea utilizatorului nainte de terminarea unui pro gram, trebuie s prelucrai
i mesajul WM_QUERYENDSESSION. La nchiderea unei sesiuni de lucru Windows, sistemul de operare
ncepe s trimit mesaje WM_QUERY-ENDSESSION fiecrei proceduri de fereastr. Dac oricare dintre
ferestrele interogate rspunde cu valoarea 0, sesiunea Windows nu este ncheiat. Iat cum prelucrm
mesajul WM_QUERYENDSESSION:
case WM QUERYENDSESSION :
if~(IDYES == AskConfirmation (hwnd))
return 1 ; else
return 0 ;