Win32 API
Trattare con Windows
Ricerca…
Creare una finestra
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, PTSTR cmdline,
int cmdshow)
{
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
return DefWindowProc(hwnd, wm, wp, lp);
}
La prima cosa che si vede sono le due macro definizioni, UNICODE
e _UNICODE
. Queste macro fanno in modo che il nostro programma comprenda stringhe di caratteri estese ( wchar_t[n]
), non stringhe strette ( char[n]
). Di conseguenza, tutti i valori letterali stringa devono essere racchiusi in un TEXT(
macro. Il tipo di carattere generico per le stringhe Win32 è TCHAR
, la cui definizione dipende dal fatto che UNICODE
sia definito o meno. È inclusa una nuova intestazione: <tchar.h>
contiene il dichiarazione di TCHAR
.
Una finestra è composta da ciò che è noto come classe della finestra . Questo descrive le informazioni su una finestra che deve essere condivisa tra le sue istanze, come l'icona, il cursore e altre. Una classe di finestre è identificata da un nome di classe della finestra, che viene fornito nella variabile globale CLSNAME
in questo esempio. Il primo atto di WinMain
consiste nel compilare la struttura della classe della finestra, WNDCLASSEX wc
. I membri sono:
- cbSize: la dimensione, in byte, della struttura
- stile: gli stili di classe della finestra. Questo è 0 per ora.
- lpfnWndProc: questo è uno dei campi più importanti. Memorizza l'indirizzo della procedura della finestra . La procedura di finestra è una funzione che gestisce gli eventi per tutte le finestre che sono istanze di questa classe di finestre.
- cbClsExtra: il numero di byte extra da allocare per la classe della finestra. Per la maggior parte delle situazioni, questo membro è 0.
- cbWndExtra: il numero di byte extra da allocare per ogni singola finestra. Non confondere questo con
cbClsExtra
, che è comune a tutte le istanze. Questo è spesso 0. - hInstance: l'handle dell'istanza. Assegna semplicemente l'argomento
hInst
inWinMain
a questo campo. - hIcon: l'icona di gestione per la classe della finestra.
LoadIcon(NULL, IDI_APPLICATION)
carica l'icona dell'applicazione predefinita. - hCursore: l'handle del cursore per la classe della finestra.
LoadCursor(NULL, IDC_ARROW)
carica il cursore predefinito. - hbrBackground: una maniglia per il pennello di sfondo.
GetStockObject (WHITE_BRUSH)
dà una maniglia a un pennello bianco. Il valore restituito deve essereGetStockObject
perchéGetStockObject
restituisce un oggetto generico. - lpszMenuName: il nome della risorsa della barra dei menu da utilizzare. Se non è necessaria alcuna barra dei menu, questo campo può essere NULL.
- lpszClassName: il nome della classe che identifica questa struttura della classe della finestra. In questo esempio, la variabile globale
CLSNAME
memorizza il nome della classe della finestra. - hIconSm: un handle per l'icona della piccola classe.
Dopo aver inizializzato questa struttura, viene chiamata la funzione RegisterClassEx
. Ciò fa sì che la classe della finestra sia registrata con Windows, rendendola nota all'applicazione. Restituisce 0 in caso di fallimento.
Ora che la classe della finestra è stata registrata, possiamo visualizzare la finestra usando CreateWindowEx
. Gli argomenti sono:
- stylesex: gli stili di finestra estesi. Il valore predefinito è WS_EX_LEFT.
- clsname: il nome della classe
- cap: il titolo della finestra o didascalia. In questo caso, è la didascalia che viene visualizzata nella barra del titolo di una finestra.
- stili: gli stili di finestra. Se si desidera creare una finestra (padre) di livello superiore come questa, il flag da passare è WS_OVERLAPPEDWINDOW.
- x: la coordinata x dell'angolo in alto a sinistra della finestra.
- y: la coordinata y dell'angolo in alto a sinistra della finestra
- cx: la larghezza della finestra
- cy: l'altezza della finestra
- hwndParent: l'handle della finestra padre. Poiché questa finestra è di per sé una finestra genitore, questo argomento è NULL.
- hMenuOrID: se la finestra che si sta creando è una finestra genitore, allora questo argomento è un handle per il menu della finestra. Non confondere questo con il menu di classe, che è
WNDCLASSEX::lpszClassName
. Il menu di classe è comune a tutte le istanze di Windows con lo stesso nome di classe. Questo argomento, tuttavia, è specifico solo per questa istanza. Se la finestra che si sta creando è una finestra figlia, allora questo è l'ID della finestra figlia. In questo caso, stiamo creando una finestra genitore senza menu, quindi viene passato NULL. - hInst: l'handle dell'istanza dell'applicazione.
- etc: le informazioni extra che vengono passate alla finestra della finestra. Se non devono essere trasmesse informazioni aggiuntive, passare NULL.
Se x
o y
o cx
o cy
è CW_USEDEFAULT
, allora il valore di quel argomento sarà determinato da Windows. Questo è ciò che viene fatto in questo esempio.
CreateWindowEx
restituisce l'handle alla finestra appena creata. Se la creazione della finestra non è riuscita, ha restituito NULL
.
Mostriamo quindi la finestra chiamando ShowWindow
. Il primo argomento per questa funzione è l'handle della finestra. Il secondo argomento è lo stile di visualizzazione, che indica come deve essere visualizzata la finestra. La maggior parte delle applicazioni passa solo l'argomento cmdshow
passato in WinMain
. Dopo che la finestra viene mostrata, deve essere aggiornata con una chiamata a UpdateWindow
. Fa sì che un messaggio di aggiornamento venga inviato alla finestra. Impareremo cosa significa in un altro tutorial.
Ora arriva il cuore dell'applicazione: il messaggio pompa. Pompa i messaggi inviati a questa applicazione dal sistema operativo e invia i messaggi alla procedura della finestra. La chiamata GetMessage
restituisce un valore diverso da zero finché l'applicazione riceve un messaggio che lo interrompe, nel qual caso restituisce 0. L'unico argomento che ci interessa è il puntatore a una struttura MSG
che verrà riempito con informazioni sul messaggio. Gli altri argomenti sono tutti 0.
All'interno del ciclo dei messaggi, TranslateMessage
traduce i messaggi della chiave virtuale in messaggi di caratteri. Il significato di questo, ancora una volta, non è importante per noi. Prende un puntatore a una struttura MSG
. La chiamata che la segue direttamente, DispatchMessage
, invia il messaggio puntato dal suo argomento alla procedura della finestra della finestra. L'ultima cosa che WinMain
deve fare è restituire un codice di stato. Il membro wParam
della struttura MSG
contiene questo valore di ritorno, quindi viene restituito.
Ma questo è solo per la funzione WinMain
. L'altra funzione è winproc
, la procedura della finestra. Gestirà i messaggi per la finestra che gli vengono inviati da Windows. La firma per winproc
è:
- hwnd: un handle per la finestra i cui messaggi sono in fase di elaborazione.
- wm: l'identificativo del messaggio della finestra
- wp: uno degli argomenti delle informazioni del messaggio. Questo dipende dall'argomento
wm
- lp: uno degli argomenti delle informazioni del messaggio. Questo dipende dall'argomento
wm
. Questo argomento viene solitamente utilizzato per trasmettere puntatori o maniglie
In questo semplice programma, non gestiamo alcun messaggio da soli. Ma questo non significa neanche Windows. Questo è il motivo per cui è necessario chiamare DefWindowProc
, che contiene il codice di gestione della finestra predefinito. Questa funzione deve essere chiamata alla fine di ogni procedura di finestra.
Cos'è una maniglia?
Un handle è un tipo di dati che rappresenta un oggetto unico. Sono indicatori, ma per strutture dati segrete gestite dal sistema operativo. I dettagli di queste strutture non devono interessarci. Tutto ciò che un utente deve fare è semplicemente creare / recuperare un handle usando una chiamata API, e passarlo ad altre chiamate API prendendo quel tipo di handle. L'unico tipo di handle che abbiamo utilizzato eraHWND
restituito da CreateWindowEx
. costanti
In questo esempio, incontriamo una manciata di costanti, che sono in maiuscolo e iniziano con un prefisso di 2 o 3 lettere. (I tipi di Windows sono anche in maiuscolo)- IDI_APPLICATION: il nome della risorsa contenente l'icona dell'applicazione predefinita. Questo è usato con
LoadIcon
oLoadImage
(LoadIcon in questo esempio). - IDC_ARROW: il nome della risorsa che contiene il cursore dell'applicazione predefinito. Questo è usato con
LoadIcon
oLoadImage
(LoadIcon in questo esempio). - WHITE_BRUSH: il nome di un oggetto di magazzino. Questo oggetto è il pennello bianco.
- MB_ICONERROR: un flag utilizzato con
MessageBox
per visualizzare un'icona di errore. - WS_EX_LEFT: lo stile di finestra esteso predefinito. Ciò fa sì che la finestra abbia proprietà allineate a sinistra.
- WS_OVERLAPPEDWINDOW: uno stile di finestra che indica che la finestra deve essere una finestra padre con una barra del titolo, una casella di dimensione e altri elementi tipici delle finestre di livello superiore.
- CW_USEDEFAULT: utilizzato con gli argomenti
x
,y
,cx
ocy
CreateWindowEx
. Fa in modo che Windows scelga un valore valido per l'argomento per il qualeCW_USEDEFAULT
stato passatoCW_USEDEFAULT
.
Tipi di Windows
Quando si programma per Windows, è necessario abituarsi ai tipi Win32, che sono alias per i tipi built-in. Questi tipi sono in maiuscolo. I tipi di alias utilizzati in questo programma sono:- TCHAR: il tipo di carattere generico. Se
UNICODE
è definito, questo è unwchar_t
. Altro, è unchar
. - UINT: un numero intero senza segno. Utilizzato per rappresentare l'identificativo del messaggio nelle procedure di finestra e altri scopi.
- WPARAM: In Win16, questo era un argomento WORD (da cui il prefisso
W
). Con l'introduzione di Win32, tuttavia, questo è ora unUINT_PTR
. Questo illustra il punto di questi alias di Windows; sono lì per proteggere i programmi dai cambiamenti. - LPARAM: questo è un argomento
LONG
(LONG_PTR
in Win64). - PTSTR:
P
significa puntatore. LaT
significa carattere generico eSTR
significa stringa. Quindi, questo è un puntatore a una stringaTCHAR
. Altri tipi di stringhe includono:- LPTSTR: come
PTSTR
- LPCTSTR: significa
const TCHAR *
- PCTSTR: come
LPCTSTR
- LPWSTR: stringa larga (
wchar_t *
) - LPCWSTR: significa
const wchar_t *
- PWSTR: come
LPWSTR
- e molto altro Come potete vedere, i tipi Win32 possono essere una seccatura da capire, specialmente con così tanti tipi, che è un artefatto di Win16.
- LPTSTR: come
- LRESULT: questo tipo viene utilizzato per rappresentare il valore restituito dalle procedure della finestra. Di solito è un LUNGO (da qui il
L
).