Con le finestre si comunica ricevendo e spedendo
messaggi (da non confondersi con i "messaggi"
mostrati all'utente da MessageBox
!). Il sistema
spedisce messaggi alle finestre a fronte di vari
possibili eventi; il nostro codice, ricevendo questi
messaggi e rispondendovi, determinerà il
comportamento della nostra applicazione. Inoltre,
noi stessi spediremo messaggi a varie finestre
allo scopo di richiedere ad esse di compiere
certe azioni, o anche
per ottenere da esse delle informazioni, eccetera.
Sul flusso dei messaggi si impernia ogni normale programma windows, che dovrà anzi essere, di norma, strutturato allo scopo, "ad eventi" (in questo contesto, un evento è sinonimo di "messaggio").
Un messaggio, in certi contesti, esiste come singola
struttura MSG
:
I campi time
e pt
non sono normalmente usati; i campi
wParam
ed lParam
sono arbitrari "token", di 32 bit l'uno,
con un significato interamente dipendente dal contesto
(cioè dal tipo di messaggio) -- la distinzione fra i loro tipi
ha ragioni puramente storiche; hWnd
, quando una finestra
riceve un messaggio, sarà appunto la handle della finestra
stessa.
Il codice message
sarà normalmente una macro
del tipo WM_QUALCOSA
, per i normali "messaggi
di Windows"; sono definiti centinaia di questi codici.
Inoltre, si possono definire ulteriori codici di messaggio
per i propri scopi, e le varie classi di finestre predefinite
di Windows ("controlli comuni") lo fanno.
Più spesso, vedremo un messaggio in termini dei
quattro valori hwnd
, message
,
wParam
, ed lParam
,
"spediti" o "ricevuti" separatamente, come argomenti
di una funzione (API, o funzione da noi scritta).
Perchè, dunque, il nostro dialogo non termina quando
l'utente clicca sulla crocetta in altro a destra? Perchè,
a fronte di questo evento, il sistema non risponde in
modo automatico chiudendo la finestra: quello che fa,
invece, è spedire un messaggio WM_CLOSE
alla
finestra, *chiedendole*, in pratica, di chiudersi. Questo
schema è molto più flessibile, permettendo al programma
di controllare il proprio comportamento con precisione.
Ma, nel nostro esempietto, noi non avevamo usato
nessuna procedura che rispondesse ai messaggi; il
WM_CLOSE
, dunque, arriva, ma, poichè nessuno vi
risponde, esso resta senza effetto.
Un dialogo risponde ai messaggi usando una dialog
procedure -- una funzione il cui indirizzo viene
passato al sistema,
alla creazione del dialogo, nel parametro
di tipo DLGPROC
della API DialogBoxParam
. La
dialog procedure deve avere questa forma...:
Quando il sistema chiama la dialog procedure, essa
riceve come argomenti l'HWND
del dialogo, il codice
di messaggio in uMsg
, i parametri in wParam
ed
lParam
; deve normalmente tornare FALSE
se non
ha già interamente gestito il messaggio (e vuole che
il sistema "completi" la gestione stessa), e TRUE
se
e solo se ha già interamente gestito il messaggio in
proprio.
Per far sì che il nostro dialogo vuoto si chiuda, come è normale, al "clic" dell'utente sulla crocetta in alto a destra, basta dunque avere una dialog procedure come, ad esempio:
L'API EndDialog
termina un dialogo (la cui
HWND
essa riceve come primo parametro) con un "codice di
ritorno" pari al secondo parametro (qui usiamo zero,
per indicare "tutto OK"); il valore passato come secondo
parametro di EndDialog
è anche tornato come risultato
complessivo dalla chiamata DialogBoxParam
. In
questa dialog procedure, dunque, noi gestiamo il
solo messaggio WM_CLOSE
, cui rispondiamo con la
terminazione del dialogo -- poi, restituiamo TRUE
, per
dire al sistema che abbiamo interamente gestito noi
il messaggio stesso.
Con questa dialog procedure, e le stesse risorse di prima, il nostro programmino diventa dunque:
Per trasformare questo "scheletrico" programma in uno che faccia qualcosa che sia un minimo interessante, occorre, sostanzialmente:
Sarà dunque lungo questi due "assi" che ci muoveremo nel prossimo capitolo.
Capitolo 4: dialoghi
Capitolo 6: controlli: gli STATIC
Elenco dei capitoli