Il programma seguente disegna una linea orizzontale che divide la finestra in due. Un po' al di sopra della linea, stampa la stringa "Ciao, Mondo":
codice:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("CiaoMondo");
HWND hwnd;
MSG msg;
WNDCLASS 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;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL,
TEXT ("Errore nella registrazione della classe di finestra!"),
szAppName,
MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, // Nome della window class
TEXT ("Il titolo"), // Stringa che appare sulla barra del titolo
WS_OVERLAPPEDWINDOW, // Stile window
CW_USEDEFAULT, // Questo e i successivi
CW_USEDEFAULT, // tre parametri definiscono
CW_USEDEFAULT, // la posizione iniziale
CW_USEDEFAULT, // della finestra.
NULL, // Handle alla finestra padre
NULL, // Handle al menu della finestra
hInstance, // Handle all'istanza del programma
NULL); // Parametri di creazione della finestra
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
static int cxClient, cyClient;
switch (message)
{
case WM_CREATE:
return 0;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);
rect.top -= 20;
DrawText (hdc, TEXT ("Ciao, Mondo!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
EndPaint (hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
Come vedi, un programma winapi ha il suo punto di ingresso nella funzione WinMain(al contrario dei programmi console che hanno il punto di ingresso nella funzione main).
Nella WinMain si definisce una struttura WNDCLASS e si impostano i vari campi(fra i quali, importantissimo, il campo lpfnWndProc che è un puntatore alla Window Procedure).
La Window Procedure è la funzione che si occupa di gestire i messaggi che Windows invia al programma, come la creazione della finestra o, ed è il caso che più ci interessa, il messaggio WM_PAINT che serve per disegnare nella client area della finestra.
Successivamente vengono chiamate quattro funzioni:
RegisterClass
CreateWindow
ShowWindow
UpdateWindow
Il cui compito è bene illustrato dal loro nome(se qualcosa non ti è chiaro, chiedi pure).
Nella WinMain, infine, viene avviato il loop dei messaggi che consente al sistema operativo di inviare i messaggi alla nostra finestra/applicazione:
codice:
...
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg) ;
DispatchMessage(&msg) ;
}
...
Nella Window Procedure:
codice:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Scriviamo il codice per la gestione dei messaggi che ci interessano(nel nostro caso siamo particolarmente interessati al messaggio WM_PAINT).
Come vedi, per ottenere un HDC all'interno del messaggio WM_PAINT non si usa la funzione GetDC ma BeginPaint. Per rilasciare l'HDC al termine delle operazioni di disegno, si utilizza invece la funzione EndPaint.
GetDC e ReleaseDC si utilizzano invece se si vuole ottenere un HDC all'esterno del messaggio WM_PAINT.
Per disegnare il testo si utilizza la funzione DrawText(ma ne esistono, nella API, anche altre con svariati compiti/finalità).
Per disegnare la linea, il codice è il seguente:
codice:
...
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
...
Le coordinate dell'area client delle finestra, cyClient e cxClient, vanno prese durante l'eleborazione del messaggio WM_SIZE in modo che vengano aggiornate quando l'utente ridimensiona la finestra.
P.S.
Ripeto, chiedi pure in caso di dubbi.