Win32 API
Hantera fönster
Sök…
Skapa ett fönster
#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);
}
Det första man ser är de två UNICODE
, UNICODE
och _UNICODE
. Dessa makron gör att vårt program förstår breda teckensträngar ( wchar_t[n]
), inte vanliga smala strängar ( char[n]
). Som ett resultat måste alla strängbokstäver vara lindade i en TEXT(
makro. Den generiska karaktärstypen för Win32-strängar är TCHAR
, vars definition beror på om UNICODE
är definierad eller inte. En ny rubrik ingår: <tchar.h>
innehåller förklaring av TCHAR
.
Ett fönster består av det som kallas fönsterklass . Detta beskriver information om ett fönster som ska delas mellan instanser av det, som ikonen, markören och andra. En fönsterklass identifieras med ett fönsterklassnamn, som anges i den globala variabeln CLSNAME
i detta exempel. Den första akten av WinMain
är att fylla i fönsterklassstrukturen, WNDCLASSEX wc
. Medlemmarna är:
- cbSize: Storleken, i byte, på strukturen
- stil: Fönsterklassens stilar. Detta är 0 för nu.
- lpfnWndProc: Detta är ett av de viktigare fälten. Den lagrar adressen till fönsterproceduren . Fönsterproceduren är en funktion som hanterar händelser för alla fönster som är fall i denna fönsterklass.
- cbClsExtra: Antalet extra byte som ska tilldelas för fönsterklassen. För de flesta situationer är denna medlem 0.
- cbWndExtra: Antalet extra byte som ska tilldelas för varje enskilt fönster. Förväxla inte detta med
cbClsExtra
, vilket är vanligt i alla fall. Detta är ofta 0. - hInstance: Instanshandtaget.
hInst
argumentet iWinMain
till det här fältet. - hIcon: Ikonhandtaget för fönsterklassen.
LoadIcon(NULL, IDI_APPLICATION)
laddar standardprogramikonen. - h Markör: Markörhandtaget för fönsterklassen.
LoadCursor(NULL, IDC_ARROW)
laddar standardmarkören. - hbrBackground: Ett handtag till bakgrundsborsten.
GetStockObject (WHITE_BRUSH)
ger ett handtag till en vit borste.GetStockObject
måste kastas eftersomGetStockObject
returnerar ett generiskt objekt. - lpszMenuName: Resursnamnet på menyfältet som ska användas. Om ingen menyfält behövs kan detta fält vara NULL.
- lpszClassName: Klassnamnet som identifierar denna fönsterklassstruktur. I det här exemplet
CLSNAME
globala variabelnCLSNAME
fönsterklassens namn. - hIconSm: Ett handtag till den lilla klassikonen.
När denna struktur har initialiserats kallas funktionen RegisterClassEx
. Detta gör att fönsterklassen registreras med Windows, vilket gör det känt för applikationen. Det returnerar 0 vid misslyckande.
Nu när fönsterklassen har registrerats kan vi visa fönstret med CreateWindowEx
. Argumenten är:
- stylesex: De utökade fönsterstilarna. Standardvärdet är WS_EX_LEFT.
- clsname: Klassnamnet
- cap: Fönstertitel eller bildtext. I det här fallet är det bildtexten som visas i fönstrets titelfält.
- stilar: Fönsterstilarna. Om du vill skapa ett toppfönster (förälder) som det här är flaggan som ska passeras WS_OVERLAPPEDWINDOW.
- x: X-koordinaten i det övre vänstra hörnet av fönstret.
- y: Y-koordinaten i det övre vänstra hörnet av fönstret
- cx: Fönsterbredden
- cy: Höjden på fönstret
- hwndParent: Handtaget till moderfönstret. Eftersom detta fönster i sig är ett överordnat fönster, är detta argument NULL.
- hMenuOrID: Om fönstret som skapas är ett överordnat fönster, är detta argument ett handtag till fönstermenyn. Förväxla inte detta med klassmenyn, som är
WNDCLASSEX::lpszClassName
. Klassmenyn är gemensam för alla instanser av fönster med samma klassnamn. Detta argument är dock specifikt för just det här fallet. Om fönstret som skapas är ett barnfönster är detta ID för barnfönstret. I det här fallet skapar vi ett överordnat fönster utan meny, så NULL passeras. - hInst: Handtaget till applikationens instans.
- etc: Den extra informationen som skickas till fönstret i fönstret. Om ingen extra information ska överföras, skicka NULL.
Om x
eller y
eller cx
eller cy
är CW_USEDEFAULT
, kommer det argumentets värde att bestämmas av Windows. Det är vad som görs i detta exempel.
CreateWindowEx
returnerar handtaget till det nyskapade fönstret. Om skapandet av fönster misslyckades returnerade det NULL
.
Vi visar sedan fönstret genom att ringa ShowWindow
. Det första argumentet för denna funktion är handtaget till fönstret. Det andra argumentet är showstilen, som indikerar hur fönstret ska visas. De flesta applikationer passerar bara cmdshow
argumentet som gick i WinMain
. När fönstret visas måste det uppdateras genom ett samtal till UpdateWindow
. Det gör att ett uppdateringsmeddelande skickas till fönstret. Vi kommer att lära oss vad det betyder i en annan handledning.
Nu kommer applikationens hjärta: Meddelandepumpen. Den pumpar meddelanden som skickas till denna applikation av operativsystemet och skickar meddelandena till fönsterproceduren. GetMessage
samtalet returnerar icke-noll tills applikationen tar emot ett meddelande som får det att sluta, i vilket fall det returnerar 0. Det enda argumentet som berör oss är pekaren till en MSG
struktur som kommer att fyllas i med information om meddelandet. De andra argumenten är alla 0.
Inuti meddelandeslingan TranslateMessage
TranslateMessage virtuella nyckelmeddelanden till teckenmeddelanden. Betydelsen av detta, återigen, är obetydlig för oss. Det tar en pekare till en MSG
struktur. Samtalet som direkt följer det, DispatchMessage
, skickar meddelandet som påpekas med dess argument till fönstret i fönstret. Det sista WinMain
måste göra är att returnera en statuskod. wParam
medlemmen i MSG
strukturen innehåller detta returvärde, så det returneras.
Men det är bara för WinMain
funktionen. Den andra funktionen är winproc
, fönsterproceduren. Det kommer att hantera meddelanden för fönstret som skickas till det av Windows. Signaturen för winproc
är:
- hwnd: Ett handtag till fönstret vars meddelanden behandlas.
- wm: Fönstermeddelandets identifierare
- wp: Ett av meddelanden informationsargument. Detta beror på
wm
argumentet - lp: Ett av meddelanden informationsargument. Detta beror på
wm
argumentet. Detta argument används vanligtvis för att sända pekare eller handtag
I detta enkla program hanterar vi inga meddelanden själv. Men det betyder inte att Windows inte gör det heller. Därför måste man ringa DefWindowProc
, som innehåller standardfönsterhanteringskod. Denna funktion måste anropas i slutet av varje fönsterprocedur.
Vad är ett handtag?
Ett handtag är en datatyp som representerar ett unikt objekt. De är pekare, men till hemliga datastrukturer som upprätthålls av operativsystemet. Detaljerna i dessa strukturer behöver inte beröra oss. Allt som en användare behöver göra är att helt enkelt skapa / hämta ett handtag igenom ett API-samtal och skicka det till andra API-samtal som tar den typen av handtag. Den enda typen av handtag som vi använde varHWND
returnerades av CreateWindowEx
. Konstanter anter~~POS=HEADCOMP
I det här exemplet stöter vi på en handfull konstanter, som finns i alla-kepsar och börjar med ett prefix med två eller tre bokstäver. (Windows-typerna finns också i all-caps)- IDI_APPLICATION: Resursnamnet som innehåller standardprogramikonen. Detta används antingen med
LoadIcon
ellerLoadImage
(LoadIcon i detta exempel). - IDC_ARROW: Resursnamnet som innehåller standardprogrammarkören. Detta används antingen med
LoadIcon
ellerLoadImage
(LoadIcon i detta exempel). - WHITE_BRUSH: Namnet på ett lagerobjekt. Detta lagerobjekt är den vita borsten.
- MB_ICONERROR: En flagga som används med
MessageBox
att visa en felikon. - WS_EX_LEFT: Standardutvidgad fönsterstil. Detta gör att fönstret har vänsterjusterade egenskaper.
- WS_OVERLAPPEDWINDOW: En fönsterstil som indikerar att fönstret ska vara ett överordnat fönster med en titelrad, storleksrutan och andra element som är typiska för toppnivåfönster.
- CW_USEDEFAULT: Används med
CreateWindowEx
x
,y
,cx
ellercy
argument. Gör att Windows väljer ett giltigt värde för det argument somCW_USEDEFAULT
överfördes för.
Windows-typer
När du programmerar för Windows måste du vänja dig med Win32-typerna, som är alias för inbyggda typer. Dessa typer finns i alla mössor. Aliastyperna som används i detta program är:- TCHAR: Den generiska karaktärstypen. Om
UNICODE
är definierat är detta enwchar_t
. I övrigt är det enchar
. - UINT: Ett osignerat heltal. Används för att representera meddelandets identifierare i fönsterprocedurer och andra syften.
- WPARAM: I Win16 var detta ett WORD-argument (därav
W
prefixet). Med introduktionen av Win32 är detta emellertid nu enUINT_PTR
. Detta illustrerar poängen med dessa Windows-alias; de är där för att skydda program från förändringar. - LPARAM: Detta är ett
LONG
argument (LONG_PTR
i Win64). - PTSTR:
P
betyder pekaren.T
betyder generiskt tecken, ochSTR
betyder sträng. Således är detta en pekare till enTCHAR
sträng. Andra strängtyper inkluderar:- LPTSTR: Samma som
PTSTR
- LPCTSTR: betyder
const TCHAR *
- PCTSTR: Samma som
LPCTSTR
- LPWSTR: Bred sträng (
wchar_t *
) - LPCWSTR: betyder
const wchar_t *
- PWSTR: Samma som
LPWSTR
- och mycket mer Som ni kan se, kan Win32-typerna vara ett besvär att förstå, särskilt med så många olika typer, som är en artefakt från Win16.
- LPTSTR: Samma som
- LRESULT: Denna typ används för att representera returvärdet för fönsterprocedurer. Det är vanligtvis en LÅNG (därav
L
).