Introduzione alle API Win32

Capitolo 14: un esempio (1)

Abbiamo trattato, nei recenti capitoli, parecchie questioni che, benchè molto importanti, possono parere piuttosto "teoriche"; in questo capitolo, e per alcuni capitoli a seguire, ricapitoleremo varie nozioni già viste (e ne introdurremo alcune altre, quindi, mi raccomando, seguite!-) -- il tutto, nel contesto di un piccolo esempio. (Un "esempio- giocattolo", senza dubbio, non certo un'applicazione di valore commerciale... nondimeno, speriamo che la maggior "concretezza" portata da un esempio rispetto a una pura trattazione teorica possa aiutare il lettore nel compito di apprendimento).

L'obbiettivo è quello di mostrare un dialogo che ha quattro bottoni (pushbutton), cliccando ciascuno dei quali si ottiene un qualche effetto visibile. Visto che, dopo tutte queste chiacchiere, vi starete certo chiedendo dove stia la "G" di "GUI", vogliamo esagerare: ciascuno dei bottoni avrà un "look", appunto, "grafico", e, come "effetto visibile", scegliamo lo spostamento di un'altra immaginetta "grafica" entro il nostro dialogo.

 

Dobbiamo, naturalmente, cominciare progettando il dialogo stesso, nel file di risorse (con identificatori che, come abbiamo accennato, definiremo come macro, con #define, in un file di header che, per convenzione, chiameremo resource.h). Ecco una possibilità, ad esempio:

#include "resource.h" IDD_DIALOG1 DIALOG 0, 0, 186, 134 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Grafica a go-go!" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "Button1",IDC_BUTTON1,130,30,20,20,BS_BITMAP PUSHBUTTON "Button2",IDC_BUTTON2,150,30,20,20,BS_BITMAP PUSHBUTTON "Button3",IDC_BUTTON3,140,10,20,20,BS_BITMAP PUSHBUTTON "Button4",IDC_BUTTON4,140,50,20,20,BS_BITMAP ICON "",IDC_STICON,68,58,20,20 END

Nulla di nuovo nell'inizio, ma, immagino, vi starete chiedendo cosa siano quei nuovi statement PUSHBUTTON e ICON fra la BEGIN e la END del dialogo...?

Nulla di preoccupante...! Sono solo delle "abbreviazioni", potenzialmente comode, che il Resource Compiler RC ci offre, per esprimere cose che potremmo dire anche in altri modi.

(Nessuno accuserà mai la Microsoft di "minimalismo funzionale"... nei suoi sistemi [e nelle sue applicazioni], magari, non c'è alcun modo ragionevole di fare una data cosa importante X, ma, per un'altra cosa, magari marginale, Y, se c'è un modo, non vi stupite se ce ne sono mezza dozzina, equivalenti, o magari [peggio...] QUASI equivalenti...:-)

PUSHBUTTON non indica altro che un CONTROL, di classe BUTTON, con i tipici bit di stile del pushbutton -- qui, inoltre, abbiamo aggiunto, dandolo esplicitamente, il bit di stile BS_BITMAP, che, ricorderete dall'accenno fatto al Capitolo 10, indica che questo bottone non mostra del testo, bensì, appunto, una bitmap. L'idea è di sistemare i quattro bottoni "a croce", diretti "ai 4 punti cardinali" (aggiustate pure le coordinate come vi aggrada, naturalmente!).

Analogamente, ICON indica un CONTROL di classe STATIC, con i tipici bit di stile necessari perchè esso mostri una icona (usiamo sia bitmap, sia icone, in questo esempio, per mostrare diverse possibilità).

Naturalmente, non abbiamo ancora detto quali bitmap, o icone, intendiamo mostrare sui nostri controlli... quello lo faremo "al volo" nel corso dell'inizializzazione del nostro dialogo, cioè, nella dialog procedure, in risposta al messaggio WM_INITDIALOG. Notare, in particolare, che non abbiamo nè bitmap, nè icone, fra le risorse del nostro programma (se ne volete, rivolgetevi a qualcuno che sappia disegnare meglio di me -- non dovrebbe esservi molto difficile trovarlo!-); dovremo dunque "andarle a prendere" da qualche altra parte, come vedremo.

 

La nostra procedura WinMain sarà più o meno la solita, cioè, supponendo di avere già definito in modo opportuno una procedura di dialogo, sarà qualcosa del tipo...:

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0); return 0; } avendo, naturalmente, posto l'#include "resource.h" verso l'inizio del file sorgente, per rendere visibile qui la macro IDD_DIALOG1.

Per la struttura-base della dialog procedure, accettiamo, ad esempio, l'impostazione offerta da windowsx.h, che abbiamo già esaminato; accertatevi dunque di includere windowsx.h -- oltre, naturalmente, al resto di windows.h, con i soliti #define prima dell'include, e un altro che ancora non avevamo visto:

#define OEMRESOURCE che è necessario per potere accedere ad alcune "risorse standard" che ci faranno comodo.

 

Sappiamo già che vogliamo gestire i messaggi:

e quindi, la dialog procedure non sarà molto diversa da...: BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { HANDLE_MSG(hwndDlg,WM_CLOSE,OnDlgClose); HANDLE_MSG(hwndDlg,WM_INITDIALOG,OnDlgInitDialog); HANDLE_MSG(hwndDlg,WM_COMMAND,OnDlgCommand); } return FALSE; } La macro HANDLE_MSG, come abbiamo già accennato, comprende il "case WM_qualcosa:", gli "spezzettamenti" (cracking) veri e propri, ed eventuali cast, necessari per lo specifico messaggio, la chiamata alla funzione il cui nome riceve come terzo parametro (che dev'essere dichiarata con numeri e tipi di parametri opportuni a seconda del messaggio in gioco), e il return dall'intera dialog procedure (non sempre torna il TRUE che vorremmo per indicare che il messaggio già l'abbiamo gestito, ma poichè questi messaggi non sono soggetti a nessuna particolare "gestione di default" che sia importante per noi prevenire, in questo caso, poco male; se no, per come la macro è scritta, si potrebbe rimediare generalmente ponendo un ,TRUE dopo la sua chiusa parentesi e prima del punto-e-virgola). Ci resta, dunque, da scrivere le tre procedure che abbiamo scelto di chiamare OnDlgClose, OnDlgInitDialog, e OnDlgCommand, ciascuna con gli opportuni parametri previsti da windowsx.h. Ma di questo ci occuperemo al prossimo capitolo.

Capitolo 13: message crackers
Capitolo 15: un esempio (2)
Elenco dei capitoli