Win32 API
Omgaan met Windows
Zoeken…
Een venster maken
#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);
}
Het eerste wat je ziet zijn de twee _UNICODE
, UNICODE
en _UNICODE
. Deze macro's zorgen ervoor dat ons programma brede tekenreeksen ( wchar_t[n]
) begrijpt, geen gewone smalle tekenreeksen ( char[n]
). Als gevolg hiervan moeten alle tekenreeksliteralen worden ingepakt in een TEXT(
macro. Het generieke TCHAR
voor Win32-tekenreeksen is TCHAR
, waarvan de definitie afhangt of UNICODE
is gedefinieerd. Een nieuwe koptekst is opgenomen: <tchar.h>
bevat de verklaring van TCHAR
.
Een venster bestaat uit een zogenaamde vensterklasse . Dit beschrijft informatie over een venster dat moet worden gedeeld tussen instanties ervan, zoals het pictogram, de cursor en andere. Een vensterklasse wordt geïdentificeerd door een vensterklasse naam, die in dit voorbeeld wordt gegeven in de algemene variabele CLSNAME
. De eerste handeling van WinMain
is het invullen van de vensterklasse-structuur, WNDCLASSEX wc
. De leden zijn:
- cbSize: de grootte, in bytes, van de structuur
- stijl: de stijlen van de vensterklasse. Dit is nu 0.
- lpfnWndProc: Dit is een van de belangrijkste velden. Het slaat het adres van de vensterprocedure op . De vensterprocedure is een functie die gebeurtenissen afhandelt voor alle vensters die instanties zijn van deze vensterklasse.
- cbClsExtra: het aantal extra bytes dat moet worden toegewezen voor de vensterklasse. Voor de meeste situaties is dit lid 0.
- cbWndExtra: het aantal extra bytes dat moet worden toegewezen voor elk afzonderlijk venster. Verwar dit niet met
cbClsExtra
, wat in alle instanties gebruikelijk is. Dit is vaak 0. - hInstance: de exemplaarhandle. Wijs
hInst
argumentWinMain
inWinMain
aan dit veld. - hIcon: de pictogramgreep voor de vensterklasse.
LoadIcon(NULL, IDI_APPLICATION)
laadt het standaard toepassingspictogram. - hCursor: de cursorhandgreep voor de vensterklasse.
LoadCursor(NULL, IDC_ARROW)
laadt de standaardcursor. - hbrBackground: een handvat voor het achtergrondpenseel.
GetStockObject (WHITE_BRUSH)
geeft een handvat aan een witte borstel. De retourwaarde moet worden gecast omdatGetStockObject
een generiek object retourneert. - lpszMenuName: de bronnaam van de te gebruiken menubalk. Als er geen menubalk nodig is, kan dit veld NULL zijn.
- lpszClassName: de klassenaam die deze structuur van de vensterklasse identificeert. In dit voorbeeld slaat de algemene variabele
CLSNAME
de naam van de vensterklasse op. - hIconSm: een handvat voor het pictogram van de kleine klasse.
Nadat deze structuur is geïnitialiseerd, wordt de functie RegisterClassEx
aangeroepen. Hierdoor wordt de vensterklasse geregistreerd bij Windows, waardoor deze bekend wordt bij de toepassing. Het geeft 0 terug bij mislukking.
Nu de vensterklasse is geregistreerd, kunnen we het venster weergeven met CreateWindowEx
. De argumenten zijn:
- stylesex: de uitgebreide vensterstijlen. De standaardwaarde is WS_EX_LEFT.
- clsname: de klassenaam
- cap: de venstertitel of het bijschrift. In dit geval is het het bijschrift dat wordt weergegeven in de titelbalk van een venster.
- stijlen: de vensterstijlen. Als u een hoofdvenster (bovenliggend) zoals deze wilt maken, is de vlag die moet worden doorgegeven WS_OVERLAPPEDWINDOW.
- x: de x-coördinaat van de linkerbovenhoek van het venster.
- y: de y-coördinaat van de linkerbovenhoek van het venster
- cx: de breedte van het venster
- cy: de hoogte van het venster
- hwndParent: de greep naar het bovenliggende venster. Aangezien dit venster op zichzelf een bovenliggend venster is, is dit argument NULL.
- hMenuOrID: Als het venster dat wordt gemaakt een bovenliggend venster is, is dit argument een handvat voor het venstermenu. Verwar dit niet met het klassenmenu, namelijk
WNDCLASSEX::lpszClassName
. Het klassenmenu is gemeenschappelijk voor alle exemplaren van vensters met dezelfde klassenaam. Dit argument is echter specifiek voor alleen deze instantie. Als het venster dat wordt gemaakt een onderliggend venster is, is dit de ID van het onderliggende venster. In dit geval maken we een bovenliggend venster zonder menu, dus wordt NULL doorgegeven. - hInst: de ingang van het exemplaar van de toepassing.
- enz.: De extra informatie die wordt doorgegeven aan de vensterprocedure van het venster. Als u geen extra informatie wilt verzenden, geeft u NULL door.
Als x
of y
of cx
of cy
CW_USEDEFAULT
, wordt de waarde van dat argument bepaald door Windows. Dat is wat er in dit voorbeeld wordt gedaan.
CreateWindowEx
retourneert de handle naar het nieuw gemaakte venster. Als het maken van vensters is mislukt, is NULL
geretourneerd.
We tonen het venster vervolgens door ShowWindow
bellen. Het eerste argument voor deze functie is de greep naar het venster. Het tweede argument is de showstijl, die aangeeft hoe het venster moet worden weergegeven. De meeste toepassingen passeren gewoon het cmdshow
argument dat is doorgegeven in WinMain
. Nadat het venster is weergegeven, moet het worden bijgewerkt door een aanroep van UpdateWindow
. Hierdoor wordt een updatebericht naar het venster verzonden. We zullen leren wat dit betekent in een andere zelfstudie.
Nu komt het hart van de applicatie: de berichtenpomp. Het pompt berichten verzonden naar deze toepassing door het besturingssysteem en verzendt de berichten naar de vensterprocedure. De GetMessage
retourneert niet-nul totdat de toepassing berichten GetMessage
waardoor deze wordt afgesloten, in welk geval deze 0 retourneert. Het enige argument dat ons bezighoudt, is de aanwijzer naar een MSG
structuur die wordt ingevuld met informatie over het bericht. De andere argumenten zijn allemaal 0.
Binnen de berichtenlus vertaalt TranslateMessage
berichten met virtuele sleutels naar berichten met tekens. De betekenis hiervan is wederom onbelangrijk voor ons. Het neemt een pointer naar een MSG
structuur. De aanroep die er direct op volgt, DispatchMessage
, verzendt het bericht waarnaar het argument verwijst, naar de vensterprocedure van het venster. Het laatste wat WinMain
moet doen, is een statuscode retourneren. Het wParam
lid van de MSG
structuur bevat deze retourwaarde, dus wordt deze geretourneerd.
Maar dat is alleen voor de WinMain
functie. De andere functie is winproc
, de vensterprocedure. Het zal berichten voor het venster afhandelen die het door Windows worden verzonden. De handtekening voor winproc
is:
- hwnd: een ingang naar het venster waarvan de berichten worden verwerkt.
- wm: de identificatie van het vensterbericht
- wp: een van de berichtinformatieargumenten. Dit hangt af van het
wm
argument - lp: een van de berichtinformatieargumenten. Dit hangt af van het
wm
argument. Dit argument wordt meestal gebruikt om pointers of handvatten te verzenden
In dit eenvoudige programma verwerken we zelf geen berichten. Maar dat betekent niet dat Windows dat ook niet is. Dit is de reden waarom men DefWindowProc
moet aanroepen, die de standaard afhandelingscode voor vensters bevat. Deze functie moet worden opgeroepen aan het einde van elke vensterprocedure.
Wat is een handvat?
Een handle is een gegevenstype dat een uniek object vertegenwoordigt. Het zijn verwijzingen, maar dan naar geheime datastructuren die door het besturingssysteem worden onderhouden. De details van deze structuren hoeven ons geen zorgen te maken. Het enige dat een gebruiker hoeft te doen, is eenvoudig een handle maken / terughalen met behulp van een API-aanroep en deze doorgeven aan andere API-aanroepen met dat type handle. Het enige type handvat we gebruikten was deHWND
geretourneerd door CreateWindowEx
. constanten
In dit voorbeeld komen we een handvol constanten tegen, die allemaal in hoofdletters staan en beginnen met een voorvoegsel van 2 of 3 letters. (De Windows-typen staan ook in hoofdletters)- IDI_APPLICATION: de bronnaam die het standaardtoepassingspictogram bevat. Dit wordt gebruikt met
LoadIcon
ofLoadImage
(LoadIcon in dit voorbeeld). - IDC_ARROW: de bronnaam die de standaardcursor van de toepassing bevat. Dit wordt gebruikt met
LoadIcon
ofLoadImage
(LoadIcon in dit voorbeeld). - WHITE_BRUSH: de naam van een stockobject. Dit stockobject is de witte borstel.
- MB_ICONERROR: een vlag die wordt gebruikt met
MessageBox
om een foutpictogram weer te geven. - WS_EX_LEFT: De standaard uitgebreide vensterstijl. Hierdoor heeft het venster links uitgelijnde eigenschappen.
- WS_OVERLAPPEDWINDOW: Een vensterstijl die aangeeft dat het venster een bovenliggend venster moet zijn met een titelbalk, groottevak en andere elementen die typisch zijn voor vensters op het hoogste niveau.
- CW_USEDEFAULT: Gebruikt met
CreateWindowEx
'sx
,y
,cx
, ofcy
argumenten.CW_USEDEFAULT
ervoor dat Windows een geldige waarde kiest voor het argument waarvoorCW_USEDEFAULT
is doorgegeven.
Windows-typen
Bij het programmeren voor Windows moet je wennen aan de Win32-typen, aliassen voor ingebouwde typen. Deze types hebben allemaal hoofdletters. De alias-typen die in dit programma worden gebruikt, zijn:- TCHAR: het generieke karaktertype. Als
UNICODE
is gedefinieerd, is dit eenwchar_t
. Anders is het eenchar
. - UINT: een geheel getal zonder teken. Wordt gebruikt om de berichtidentificatie weer te geven in vensterprocedures en andere doeleinden.
- WPARAM: In Win16 was dit een WORD-argument (vandaar het
W
voorvoegsel). Met de introductie van Win32 is dit nu eenUINT_PTR
. Dit illustreert het punt van deze Windows-aliassen; ze zijn er om programma's tegen verandering te beschermen. - LPARAM: Dit is een
LONG
argument (LONG_PTR
in Win64). - PTSTR: De
P
betekent aanwijzer. DeT
betekent generiek teken en deSTR
betekent tekenreeks. Dit is dus een verwijzing naar eenTCHAR
tekenreeks. Andere stringtypen zijn onder meer:- LPTSTR: Hetzelfde als
PTSTR
- LPCTSTR: Betekent
const TCHAR *
- PCTSTR: Hetzelfde als
LPCTSTR
- LPWSTR: brede string (
wchar_t *
) - LPCWSTR: betekent
const wchar_t *
- PWSTR: Hetzelfde als
LPWSTR
- en veel meer Zoals je kunt zien, kunnen de Win32-typen een probleem zijn om te begrijpen, vooral met zoveel synonieme typen, wat een artefact is van Win16.
- LPTSTR: Hetzelfde als
- LRESULT: Dit type wordt gebruikt om de retourwaarde van vensterprocedures weer te geven. Het is meestal een LANG (vandaar de
L
).