Realizzazione di una Finestra con le API Windows | |||
Mer 03 Ott 2007 |
|
Una Semplice Finestra
Per costruire una semplice finestra si crea una Win32 Application nel modo visto in precedenza e si scrive il seguente programma
simplewin.c
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE: DestroyWindow(hwnd); break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND handle;
MSG message;
//Registrazione della Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "simplewin";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Registrazione della Finestra Fallita!", "Errore!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Creazione della finestra
// Una volta registrata la classe si passa a costruire la finestra.
handle = CreateWindowEx(WS_EX_CLIENTEDGE, "simplewin",
"Titolo della mia finestra", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, 340, 120,NULL, NULL, hInstance, NULL);
// si verifica se la finestra è stata creata verificando se l'handle è valido
if(handle == NULL)
{
MessageBox(NULL, "Creazione della Finestra Fallita!", "Errore!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(handle, nCmdShow); // Si visualizza la finestra
UpdateWindow(handle); // si aggiorna la finestra
// Ci si pone in ascolto dei messaggi verso la finestra
while(GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return message.wParam; // exit value restituito al sistema
}
Figura 6. Una Semplice Finestra.
-
si definiscono tre variabili
- la variabile wc di tipo WNDCLASSEX, che conterrà delle informazioni sulla finestra che si vuole costruire;
- la variabile handle di tipo HWND (Window Handle), che conterrà l’handle della finestra che si vuole costruire;
- la variabile message di tipo MSG;
WNDCLASSEX wc;
HWND handle;
MSG message;
-
si definiscono le proprietà della finestra fissando i campi
della variabile wc
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "simplewin";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
-
una volta definita la finestra la si deve registrare. Questo
si fa tramite l’istruzione RegisterClassEx
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Registrazione della Finestra Fallita!", "Errore!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
-
viene creata la finestra tramite l’istruzione CreateWindowEx
handle = CreateWindowEx(WS_EX_CLIENTEDGE, "simplewin",
"Titolo della mia finestra", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, 340, 120,NULL, NULL, hInstance, NULL);
-
si verifica se la finestra è stata creata verificando se l’handle è valido
if(handle == NULL)
{
MessageBox(NULL, "Creazione della Finestra Fallita!", "Errore!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
-
si visualizza la finestra tramite l’istruzione ShowWindow, e la
si ridisegna tramite l’istruzione UpdateWindow
ShowWindow(handle, nCmdShow); // Si visualizza la finestra
UpdateWindow(handle); // si aggiorna la finestra
-
si entra in un ciclo in cui si accettano tutti i messaggi diretti
alla finestra e li si invia alla funzione WndProc che li processerà
while(GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
tramite la funzione GetMessage ci si pone in ascolto e in attesa di un messaggio inviato verso la finestra. Non appena arriva un messaggio questo viene tradotto tramite la funzione TranslateMessage (il segnale che arriva, dal sistema operativo, viene tradotto in un valore che consentirà poi alla procedura WndProc di processarli). Il messaggio tradotto viene passato, tramite l'istruzione DispatchMessage, alla funzione WndProc che provvederà a processarlo.
Il programma resterà in ascolto, tramite la funzione GetMessage, fino a quando non si verificherà un errore, nel qual caso la GetMessage restituirà il valore -1, o fino a quando non sarà prelevato dalla coda dei messaggi il messaggio WM_QUIT, nel qual caso la GetMessage restituirà il valore 0.
Quindi finché il valore restituito dalla GetMessage sarà maggiore di zero il programma resterà in ascolto. -
si definisce la funzione WndProc che si occuperà di processare
tutti i messaggi in arrivo per la finestra.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE: DestroyWindow(hwnd); break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
La funzione riceve i messaggi inviati da DispatchMessage e li processa. La funzione è definibile dall'utente che potrà decidere il comportamento da seguire in corrispondenza ai vari possibili messaggi che si possono ricevere.
Nell'esempio qui proposto la funzione riceve il messaggio msg, quindi se il messaggio è WM_CLOSE (è stato premuto il close button) la finestra viene chiusa invocando la funzione DestroyWindow passandogli come parametro l'handle della finestra, se il messaggio è WM_DESTROY (la finestra è stata chiusa) viene specificato l'exit code dell'applicazione invocando la funzione PostQuitMessage.
In caso arrivi un qualsiasi altro messaggio viene richiamata la funzione DefWindowProc a cui vengono passati gli stessi parametri della funzione WndProc.
La funzione GetMessage restituisce un messaggio
ottenuto dalla coda dei messaggi del thread. Invia i messaggi in arrivo fino a quando vi sono
messaggi disponibili nella coda.
Se dalla coda dei messaggi viene estratto un messaggio diverso da WM_QUIT viene restituito un valore diverso da zero, altrimenti viene restituito zero. Se si verifica un errore viene restituito -1.
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
Se dalla coda dei messaggi viene estratto un messaggio diverso da WM_QUIT viene restituito un valore diverso da zero, altrimenti viene restituito zero. Se si verifica un errore viene restituito -1.
lpMsg | [out] Puntatore ad una struttura MSG in cui si metterà il messaggio prelevato dalla coda dei messaggi del thread. |
hWnd | [in] Handle della finestra a cui andranno inviati i messaggi. La finestra deve appartenere al thread corrente. Se hWnd è NULL il messaggio viene inviato a tutte le finestre che appartengono al thread corrente. Se hWnd è -1 restituisce solo i messaggi presenti nella coda il cui valore hnwd è NULL. |
wMsgFilterMin | [in] Specifica l'indice del primo messaggio da restituire. Se wMsgFilterMin e wMsgFilterMax sono entrambi zero, GetMessage restituisce tutti i messaggi disponibili. |
wMsgFilterMax | [in] Specifica l'indice dell'ultimo messaggio da restituire. Se wMsgFilterMin e wMsgFilterMax sono entrambi zero, GetMessage restituisce tutti i messaggi disponibili. |
La funzione TranslateMessage traduce il messaggio costituito da
parole chiave (ad es. WM_KEYDOWN, WM_KEYUP, WM_CLOSE, WM_DESTROY, ecc.) in un messaggio
costituito da caratteri.
Ogni parola chiave viene tradotta in una stringa di caratteri che la identifica, così, ad esempio,
quando viene passato a TranslateMessage il messaggio costituito
dalla parola chiave WM_CLOSE questo viene tradotto nella stringa di caratteri "WM_CLOSE".
La funzione traduce il messaggio lpMsg sovrascrivendo lpMsg (il messaggio tradotto è sovrascritto al messaggio iniziale). lpMsg è un puntatore ad una struttura MSG che conterrà il messaggio ottenuto dalla coda dei messaggi del thread. Se il messaggio viene tradotto viene restituito un valore diverso da zero. Se il messaggio non viene tradotto (non vi sono messaggi nella coda dei messaggi del thread) viene restituito zero.
BOOL TranslateMessage(
const MSG *lpMsg
);
La funzione traduce il messaggio lpMsg sovrascrivendo lpMsg (il messaggio tradotto è sovrascritto al messaggio iniziale). lpMsg è un puntatore ad una struttura MSG che conterrà il messaggio ottenuto dalla coda dei messaggi del thread. Se il messaggio viene tradotto viene restituito un valore diverso da zero. Se il messaggio non viene tradotto (non vi sono messaggi nella coda dei messaggi del thread) viene restituito zero.
La funzione DispatchMessage invia un
messaggio alla window procedure (WndProc). è usata tipicamente per inviare i messaggi
ottenuti dalla funzione GetMessage
Il valore restituito è il valore restituito dalla funzione WndProc.
LRESULT DispatchMessage(
const MSG *lpmsg
);
Il valore restituito è il valore restituito dalla funzione WndProc.
La funzione DestroyWindow
distrugge la finestra il cui handle è hWnd. La funzione invia il messaggio WM_DESTROY alla finestra, la funzione distrugge anche il menù della finestra, svuota la coda di messaggi del thread, ecc. Distrugge automaticamente anche eventuali finestre figlie.
Se la funzione ha successo restituisce un valore diverso da zero, se non ha successo restituisce zero.
BOOL DestroyWindow(HWND hWnd);
distrugge la finestra il cui handle è hWnd. La funzione invia il messaggio WM_DESTROY alla finestra, la funzione distrugge anche il menù della finestra, svuota la coda di messaggi del thread, ecc. Distrugge automaticamente anche eventuali finestre figlie.
Se la funzione ha successo restituisce un valore diverso da zero, se non ha successo restituisce zero.
La funzione PostQuitMessage
indica al sistema che un thread ha chiesto di terminare l'esecuzione. È tipicamente utilizzata in risposta alla ricezione del messaggio WM_DESTROY. Il parametro nExitCode specifica l'exit code dell'applicazione.
La funzione invia il messaggio WM_QUIT alla coda di messaggi del thread e termina. Quando il thread preleva il messaggio WM_QUIT dalla sua coda dei messaggi restituisce il controllo al sistema. L'exit value restituito al sistema è il parametro wParam del messaggio WM_QUIT.
void PostQuitMessage(int nExitCode);
indica al sistema che un thread ha chiesto di terminare l'esecuzione. È tipicamente utilizzata in risposta alla ricezione del messaggio WM_DESTROY. Il parametro nExitCode specifica l'exit code dell'applicazione.
La funzione invia il messaggio WM_QUIT alla coda di messaggi del thread e termina. Quando il thread preleva il messaggio WM_QUIT dalla sua coda dei messaggi restituisce il controllo al sistema. L'exit value restituito al sistema è il parametro wParam del messaggio WM_QUIT.
La struttura WNDCLASSEX contiene
informazioni sulla finestra. è usata dalle funzioni RegisterClassEx e
GetClassInfoEx.
è definita come
dove
typedef struct {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;
dove
cbSize | Indica la dimensione in bytes della struttura che conterrà tutte le informazioni sulla finestra. Fissare tale valore a sizeof(WNDCLASSEX) |
style | Indica lo stile della classe. È possibile combinare più stili. |
lpfnWndProc | Conterrà il puntatore alla funzione (WndProc) che processerà i messaggi passati dal sistema operativo alla finestra; |
cbClsExtra | Quantità di memoria extra da allocare per la classe. Il sistema inizializza questo valore a zero. |
cbWndExtra | Quantità di memoria (in byte) allocata per i dati extra da passare alle finestre create sulla base di questa classe. In genere è 0 |
hInstance | Handle dell’istanza di questo programma. Viene passata come parametro a WinMain. È fornita dal sistema operativo all’atto della creazione dell’istanza |
hIcon | Handle dell'icona della classe. Se è pari a NULL il sistema fornisce una icona di default |
hCursor | Handle del cursore della classe Se è pari a NULL una applicazione si occuperà di disegnare il cursore quando passa sulla finestra |
hbrBackground | Handle del Brush di Background della classe per settare il colore di sfondo della finestra |
lpszMenuName | Puntatore ad una stringa che indica il nome della risorsa del menù della finestra |
lpszClassName | Indica il nome della classe, ovvero quello che utilizzeremo per creare la finestra con CreateWindowEx |
hIconSm | Handle di una icona piccola associata alla classe. |
La funzione CreateWindowEx è definita come
i cui parametri sono
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
i cui parametri sono
dwExStyle | Specifica lo stile della finestra appena creata. Se non si vogliono stili particolari si fissa NULL |
lpClassName | Il nome della classe che si vuole creare. |
lpWindowName | Puntatore ad una stringa che contiene il nome della finestra |
dwStyle | Specifica lo stile della finestra appena creata. Questo parametro può essere una combinazione di stili |
x | Specifica la posizione orizzontale iniziale della finestra |
y | Specifica la posizione verticale iniziale della finestra |
nWidth | La larghezza iniziale della finestra |
nHeight | L’altezza iniziale della finestra |
hWndParent | L’handle della finestra genitore, ovvero quella che conterrà la finestra che noi vogliamo creare. Se si crea una finestra di dialogo il genitore sarà il desktop, in tal caso sarà sufficiente settarlo a NULL. È un parametro opzionale per le finestre di pop-up |
hMenu | L’handle dell’eventuale menu che vorremo inserire nella nostra finestra. Se non vogliamo mettere menu, deve essere NULL |
hInstance | È l'istanza del modulo associato alla finestra |
lpParam | Puntatore ad un valore da passare alla finestra attraverso la struttura di CREATESTRUCT |
La funzione ShowWindow è definita come
i cui parametri sono hWnd, che è l'handle della finestra, e nCmdShow che specifica come la finestra deve essere visualizzata. La prima volta che viene chiamata all'interno della WinMain riceve il valore dal parametro nCmdShow della WinMain. Nelle chiamate seguenti questo parametro può assumere i seguenti valori, alcuni descritti in precedenza: SW_FORCEMINIMIZE, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW, SW_SHOWDEFAULT, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE, SW_SHOWNA, SW_SHOWNOACTIVATE, SW_SHOWNORMAL.
Se la finestra era visibile restituirà un valore diverso da zero, se la finestra era nascosta restituirà zero.
BOOL ShowWindow(
HWND hWnd,
int nCmdShow
);
i cui parametri sono hWnd, che è l'handle della finestra, e nCmdShow che specifica come la finestra deve essere visualizzata. La prima volta che viene chiamata all'interno della WinMain riceve il valore dal parametro nCmdShow della WinMain. Nelle chiamate seguenti questo parametro può assumere i seguenti valori, alcuni descritti in precedenza: SW_FORCEMINIMIZE, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOW, SW_SHOWDEFAULT, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE, SW_SHOWNA, SW_SHOWNOACTIVATE, SW_SHOWNORMAL.
SW_FORCEMINIMIZE | Minimizza la finestra se il thread che la gestisce non risponde. |
SW_SHOWDEFAULT | Attiva la finestra e la visualizza nella sua posizione e dimensione corrente. |
Se la finestra era visibile restituirà un valore diverso da zero, se la finestra era nascosta restituirà zero.