Win32 API
Umgang mit Fenstern
Suche…
Fenster erstellen
#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);
}
Als erstes sieht man die beiden Makrodefinitionen UNICODE
und _UNICODE
. Diese Makros bewirken, dass unser Programm breite Zeichenketten ( wchar_t[n]
) und keine einfachen schmalen Zeichenfolgen ( char[n]
) versteht. Als Folge müssen alle Stringliterale in einem gewickelt werden TEXT(
Makro Der generische Zeichentyp für Win32 - Strings ist. TCHAR
, Definition dessen hängt davon ab , ob oder ob nicht UNICODE
definiert ist ein neuer Header enthalten ist. <tchar.h>
enthält die Erklärung von TCHAR
.
Ein Fenster besteht aus einer sogenannten Fensterklasse . Hier werden Informationen zu einem Fenster beschrieben, das von Instanzen, z. B. dem Symbol, dem Cursor und anderen, gemeinsam genutzt werden soll. Eine Fensterklasse wird durch einen Fensterklassennamen identifiziert, der in diesem Beispiel in der globalen Variablen CLSNAME
angegeben ist. Der erste Vorgang von WinMain
ist das Ausfüllen der Fensterklassenstruktur WNDCLASSEX wc
. Die Mitglieder sind:
- cbSize: Die Größe der Struktur in Bytes
- style: Die Fensterklassenstile. Dies ist momentan 0.
- lpfnWndProc: Dies ist eines der wichtigeren Felder. Es speichert die Adresse der Fensterprozedur . Die Fensterprozedur ist eine Funktion, die Ereignisse für alle Fenster behandelt, die Instanzen dieser Fensterklasse sind.
- cbClsExtra: Die Anzahl der zusätzlichen Bytes, die für die Fensterklasse zugewiesen werden sollen. In den meisten Situationen ist dieses Mitglied 0.
- cbWndExtra: Die Anzahl der zusätzlichen Bytes, die für jedes einzelne Fenster zugewiesen werden sollen. Verwechseln Sie dies nicht mit
cbClsExtra
, das allen Instanzen gemeinsam ist. Dies ist oft 0. - hInstance: Das Instanzhandle.
hInst
WinMain
diesem Feld einfach das ArgumentWinMain
inWinMain
zu. - hIcon: Das Icon-Handle für die Fensterklasse.
LoadIcon(NULL, IDI_APPLICATION)
lädt das Standardanwendungssymbol. - hCursor: Das Cursor-Handle für die Fensterklasse.
LoadCursor(NULL, IDC_ARROW)
lädt den Standardcursor. - hbrBackground: Ein Griff zum Hintergrundpinsel.
GetStockObject (WHITE_BRUSH)
gibt einem weißen Pinsel einen Griff. Der Rückgabewert muss umgewandelt werden, daGetStockObject
ein generisches Objekt zurückgibt. - lpszMenuName: Der Ressourcenname der zu verwendenden Menüleiste. Wenn keine Menüleiste benötigt wird, kann dieses Feld NULL sein.
- lpszClassName: Der Klassenname, der diese Fensterklassenstruktur identifiziert. In diesem Beispiel speichert die globale Variable
CLSNAME
denCLSNAME
des Fensters. - hIconSm: Ein Handle für das kleine Klassensymbol.
Nachdem diese Struktur initialisiert wurde, wird die RegisterClassEx
Funktion aufgerufen. Dadurch wird die Fensterklasse bei Windows registriert und der Anwendung bekannt gemacht. Bei einem Fehler wird 0 zurückgegeben.
CreateWindowEx
die Fensterklasse registriert wurde, können Sie das Fenster mit CreateWindowEx
. Die Argumente sind:
- stylesex: Die erweiterten Fensterstile. Der Standardwert ist WS_EX_LEFT.
- clsname: Der Klassenname
- cap: Der Fenstertitel oder die Bildunterschrift. In diesem Fall wird die Beschriftung in der Titelleiste eines Fensters angezeigt.
- Stile: Die Fensterstile. Wenn Sie ein (übergeordnetes) Fenster der obersten Ebene wie dieses erstellen möchten, ist WS_OVERLAPPEDWINDOW das zu übergebende Flag.
- x: Die x-Koordinate der oberen linken Ecke des Fensters.
- y: Die y-Koordinate der oberen linken Ecke des Fensters
- cx: Die Breite des Fensters
- cy: Die Höhe des Fensters
- hwndParent: Das Handle für das übergeordnete Fenster. Da dieses Fenster selbst ein übergeordnetes Fenster ist, ist dieses Argument NULL.
- hMenuOrID: Wenn das erstellte Fenster ein übergeordnetes Fenster ist, ist dieses Argument ein Handle für das Fenstermenü. Verwechseln Sie dies nicht mit dem Klassenmenü
WNDCLASSEX::lpszClassName
. Das Klassenmenü gilt für alle Instanzen von Fenstern mit demselben Klassennamen. Dieses Argument ist jedoch nur für diesen Fall spezifisch. Wenn das erstellte Fenster ein untergeordnetes Fenster ist, ist dies die ID des untergeordneten Fensters. In diesem Fall erstellen wir ein übergeordnetes Fenster ohne Menü, sodass NULL übergeben wird. - hInst: Das Handle für die Instanz der Anwendung.
- etc: Die zusätzlichen Informationen, die an die Fensterprozedur des Fensters übergeben werden. Wenn keine zusätzlichen Informationen übertragen werden sollen, übergeben Sie NULL.
Wenn x
oder y
oder cx
oder cy
CW_USEDEFAULT
ist, wird der Wert dieses Arguments von Windows bestimmt. Das ist, was in diesem Beispiel gemacht wird.
CreateWindowEx
gibt das Handle an das neu erstellte Fenster zurück. Wenn die Fenstererstellung fehlgeschlagen ist, wurde NULL
.
Wir zeigen dann das Fenster, indem ShowWindow
aufrufen. Das erste Argument für diese Funktion ist das Handle für das Fenster. Das zweite Argument ist der Showstil, der angibt, wie das Fenster angezeigt werden soll. Die meisten Anwendungen übergeben nur das in cmdshow
Argument WinMain
. Nachdem das Fenster angezeigt wird, muss es durch einen Aufruf von UpdateWindow
aktualisiert werden. Dadurch wird eine Aktualisierungsnachricht an das Fenster gesendet. Was das bedeutet, erfahren Sie in einem anderen Tutorial.
Nun kommt das Herz der Anwendung: Die Nachrichtenpumpe. Es pumpt Meldungen, die vom Betriebssystem an diese Anwendung gesendet werden, und sendet die Meldungen an die Fensterprozedur. Der GetMessage
Aufruf gibt nicht null zurück, bis die Anwendung eine Nachricht erhält, die dazu führt, dass sie beendet wird. In diesem Fall wird 0 zurückgegeben. Das einzige Argument, das uns betrifft, ist der Zeiger auf eine MSG
Struktur, die mit Informationen zur Nachricht gefüllt wird. Die anderen Argumente sind alle 0.
Innerhalb der Nachrichtenschleife TranslateMessage
TranslateMessage Nachrichten mit virtuellen Schlüsseln in Zeichennachrichten. Die Bedeutung davon ist uns wiederum unwichtig. Es benötigt einen Zeiger auf eine MSG
Struktur. Der direkt darauf folgende Aufruf, DispatchMessage
, sendet die Nachricht, auf die sein Argument zeigt, an die Fensterprozedur des Fensters. Das letzte, was WinMain
tun muss, ist einen Statuscode zurückzugeben. Das wParam
Member der MSG
Struktur enthält diesen Rückgabewert und wird daher zurückgegeben.
Das ist aber nur für die WinMain
Funktion. Die andere Funktion ist winproc
, die Fensterprozedur. Es verarbeitet Nachrichten für das Fenster, die von Windows an dieses Fenster gesendet werden. Die Unterschrift für winproc
lautet:
- hwnd: Ein Handle für das Fenster, dessen Nachrichten verarbeitet werden.
- wm: Die Fensternachrichtenkennung
- wp: Eines der Nachrichteninformationsargumente. Dies hängt vom Argument
wm
- lp: Eines der Nachrichteninformationsargumente. Dies hängt vom Argument
wm
. Dieses Argument wird normalerweise verwendet, um Zeiger oder Handles zu übertragen
In diesem einfachen Programm behandeln wir selbst keine Nachrichten. Das heißt aber auch nicht, dass Windows dies nicht tut. Aus diesem Grund muss DefWindowProc
, das den Standardcode für die Fensterbehandlung enthält. Diese Funktion muss am Ende jeder Fensterprozedur aufgerufen werden.
Was ist ein Griff?
Ein Handle ist ein Datentyp, der ein eindeutiges Objekt darstellt. Sie sind Zeiger, aber auf geheime Datenstrukturen, die vom Betriebssystem verwaltet werden. Die Details dieser Strukturen brauchen uns nicht zu interessieren. Ein Benutzer muss lediglich einen Handle mithilfe eines API-Aufrufs erstellen / abrufen und ihn an andere API-Aufrufe weiterleiten, die diesen Typ von Handle verwenden. Der einzige Typ von Handle, den wir verwendet haben, war der vonHWND
zurückgegebene CreateWindowEx
. Konstanten
In diesem Beispiel stoßen wir auf eine Handvoll Konstanten, die in Großbuchstaben stehen und mit einem Präfix aus 2 oder 3 Buchstaben beginnen. (Die Windows-Typen sind auch in Großbuchstaben)- IDI_APPLICATION: Der Ressourcenname, der das Standardsymbol der Anwendung enthält. Dies wird entweder mit
LoadIcon
oderLoadImage
(in diesem Beispiel LoadIcon) verwendet. - IDC_ARROW: Der Ressourcenname, der den Standard-Anwendungscursor enthält. Dies wird entweder mit
LoadIcon
oderLoadImage
(in diesem Beispiel LoadIcon) verwendet. - WHITE_BRUSH: Der Name eines Aktienobjekts. Dieses Lagerobjekt ist der weiße Pinsel.
- MB_ICONERROR: Ein Flag, das in
MessageBox
zum Anzeigen eines Fehlersymbols verwendet wird. - WS_EX_LEFT: Der Standardstil für erweiterte Fenster. Dies bewirkt, dass das Fenster links ausgerichtete Eigenschaften hat.
- WS_OVERLAPPEDWINDOW: Ein Fensterstil, der angibt, dass das Fenster ein übergeordnetes Fenster mit einer Titelleiste, einem Größenfeld und anderen Elementen sein sollte, die für Fenster der obersten Ebene typisch sind.
- CW_USEDEFAULT: Gebrauchte mit
CreateWindowEx
‚sx
,y
,cx
odercy
Argumente. Bewirkt, dass Windows einen gültigen Wert für das ArgumentCW_USEDEFAULT
für dasCW_USEDEFAULT
wurde.
Windows-Typen
Wenn Sie für Windows programmieren, müssen Sie sich an die Win32-Typen gewöhnen, bei denen es sich um Aliase für eingebaute Typen handelt. Diese Typen sind in allen Kappen. Die in diesem Programm verwendeten Alias-Typen sind:- TCHAR: Der generische Zeichentyp. Wenn
UNICODE
definiert ist, ist dies einwchar_t
. Otheriwse, es ist einchar
. - UINT: Eine vorzeichenlose Ganzzahl. Wird verwendet, um die Nachrichten-ID in Fensterprozeduren und zu anderen Zwecken darzustellen.
- WPARAM: In Win16 war dies ein WORD-Argument (daher das
W
Präfix). Mit der Einführung von Win32 ist dies jedoch jetzt einUINT_PTR
. Dies veranschaulicht den Sinn dieser Windows-Aliase. Sie sind dazu da, Programme vor Veränderungen zu schützen. - LPARAM: Dies ist ein
LONG
Argument (LONG_PTR
in Win64). - PTSTR: Das
P
bedeutet Zeiger. DasT
für ein generisches Zeichen und dasSTR
eine Zeichenfolge. Dies ist also ein Zeiger auf eineTCHAR
Zeichenfolge. Andere Zeichenfolgentypen umfassen:- LPTSTR: Wie
PTSTR
- LPCTSTR: Mittel
const TCHAR *
- PCTSTR: Wie
LPCTSTR
- LPWSTR: Wide String (
wchar_t *
) - LPCWSTR: Bedeutet
const wchar_t *
- PWSTR: Wie
LPWSTR
- und vieles mehr Wie man sieht, lassen sich die Win32-Typen mühelos verstehen, vor allem bei so vielen Typen, die ein Artefakt von Win16 sind.
- LPTSTR: Wie
- LRESULT: Dieser Typ wird verwendet, um den Rückgabewert von Fensterprozeduren darzustellen. Es ist normalerweise ein LANG (daher das
L
).