- MainWin, das Hauptprogramm einer Windows-Applikation
- MyRegisterClass
- InitMainWindow
- Die Fensterfunktion
- Das Menü
- Der Fensterinhalt
- Beenden einer Windows-Anwendung
- Der Quelltext
- Die Ressourcen
- Die Headerdatei der Ressourcen
MainWin, das Hauptprogramm einer Windows-Applikation
MainWin heißt das Hauptprogramm unter Windows. Per Parameter erhält es seine Instanz, auf der es seine Initialisierung aufsetzt. Es registriert die Fensterklasse, erzeugt das Hauptfenster und läuft in eine Schleife, in der es alle Messages verteilt, bis die Message WM_QUIT zu einem Rückgabewert 0 der Funktion GetMessage führt und damit die Schleife beendet. Dies führt dann zum Ende des Programms. GetMessage kann im Fehlerfall auch -1 zurückgeben. Auch dann ist ein Verlassen der Schleife angebracht.Die Instanz
Per Parameter erhält MainWin die Instanz von Windows. Diese Variable wird bei Aufrufen von diversen Funktionen benötigt, die an Windows gehen. An dieser Variablen erkennt Windows die Applikation wieder, auch dann, wenn sie kein Fenster geöffnet hat. Aus diesem Grund wird sie von den meisten Windowsprogrammen in einer globalen Variable gespeichert und direkt zugegriffen.MyRegisterClass
Das Hauptfenster wird registriert und bei Windows angemeldet. Die Registrierung ist die Anmeldung einer Fensterklasse. Es können also auch mehrere Fenster der gleichen Klasse angemeldet werden.Der RegisterClass-String
Welches Fenster zu welcher Klasse gehört, wird nicht durch ein Handle, sondern durch eine Zeichenkette beschrieben. Da diese Zeichenkette exakt identisch sein muß, wird dieser String zu Anfang in einem define-Statement festgelegt oder sogar in den Ressourcen abgelegt. Wichtig ist, daß er das Fenster im laufenden System eindeutig bezeichnet. Er wird einmal bei der Registrierung der Klasse und dann noch einmal beim Erzeugen des Fensters verwendet.Festlegen der Eigenschaften
Das Registrieren der Klasse gibt Windows bekannt, welche Eigenschaften die Fenster dieser Klasse haben werden. Die wichtigste Information ist dabei die Adresse der Fensterfunktion WndProc. Da die Fensterklasse auf alle Ereignisse reagiert, bestimmt sie maßgeblich das Verhalten des Fensters.Der Hintergrund des Fensters wird durch die Elementvariable hbrBackground festgelegt. Wird dieser Wert - wie im Listing - mit (HBRUSH)(COLOR_WINDOW+1) festgelegt, ist der Fensterhintergrund weiß, was sich besonders für das Zeichnen eignet. Wird stattdessen (HBRUSH)(COLOR_WINDOW) verwendet, hat das Fenster einen grauen Hintergrund, der geeigneter ist, wenn Kontrollelemente in das Fenster gesetzt werden.
InitMainWindow
In InitMainWindow wird das Fenster erzeugt (create) und angezeigt. In vielen Beispielen wird diese Funktion als InitInstance benannt.Das Fenster wird durch den RegisterClass-String als zu der registrierten Klasse gehöriges Fenster erzeugt.
Als zweiten String hat das Fenster szTitle. Das ist der Text, der im blauen Balken zu sehen ist. Er hat nur informellen Charakter und könnte auch leer sein. Da dieser String oft sprachenabhängig ist, würde es Sinn machen, ihn in der Ressource abzulegen.
Die Fensterfunktion
Die Fensterfunktion WndProc behandelt diejenigen Ereignisse, die auf das Fenster einstürmen. Die Funktion wird von Windows gerufen, wenn immer ein Ereignis für dieses Fenster vorliegt.Windows liefert vier Parameter.
- Der erste Parameter ist das Handle (HWND) des Fensters. Dies ist besonders wichtig, wenn es mehrere Fenster gleichen Typs gibt.
- Der zweite Parameter ist eine ganze Zahl ohne Vorzeichen (UINT). Sie enthält die Information, welche Nachricht eingetroffen ist. Typischerweise besteht eine Fensterfunktion in erster Linie aus einer großend Fallunterscheidung über diese Variable.
- Die beiden Parameter wParam und lParam enthalten weitere Daten der Nachricht. So liefert WM_SIZE in LOWORD(lParam) und HIWORD(lParam) die neue Ausdehnung des Fensters und in wParam den Grund für die Fenstergrößenveränderung.
Die Default-Fensterfunktion DefWindowProc
Werden Nachrichten nicht behandelt oder werden nur Teilaspekte des Ereignisses verarbeitet, so ruft die Fensterfunktion die Funktion DefWindowProc und übergibt ihr die Parameter, die sie von Windows erhalten hat. DefWindowProc ist die Default-Fensterfunktion und behandelt alle Ereignisse mit der Standardreaktion. So wird beispielsweise das Fenster vergrößert oder mit der Hintergrundfarbe weiß versehen.Mausereignisse
Ein Mausklick mit der linken Taste führt zu einer Nachrich WM_LBUTTONDOWN beim Herunterdrück und WM_LBUTTONUP beim Loslassen der Maustaste. Diese Nachrichten müssen in einem case in der Fensterfunktion abgefangen werden.- WM_LBUTTONDOWN: Der linke Button wurde heruntergedrück.
- WM_LBUTTONUP: Der linke Button wurde losgelassen.
- WM_MBUTTONDOWN: Der mittlere Button wurde heruntergedrückt.
- WM_MBUTTONUP: Der mittlere Button wurde losgelassen.
- WM_RBUTTONDOWN: Der rechte Button wurde heruntergedrückt.
- WM_RBUTTONUP: Der rechte Button wurde losgelassen.
int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam);In den meisten Fällen wird ein Mausereignis dazu führen, dass das Fenster neu gezeichnet wird. Durch den Aufruf von
RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE);wird das Fenster sofort neu gezeichnet. Dagegen wird mit dem Aufruf von
InvalidateRect(hWnd, 0, 0);die Meldung in die Warteschlange gestellt, dass das Rechteck im zweiten Parameter ungültig geworden ist und bei Gelegenheit neu gezeichnet werden sollte. Ist der zweite Parameter wie hier 0, wird das ganze Fenster neu gezeichnet.
Das Menü
Definition
In der Ressource wird das Menü beschriebenAnmeldung
Das Menü wird beim Registrieren der Fensterklasse dem Fenster zugeordnet. Dazu wird dem Element lpszMenuName der Fensterklassenstruktur der in der Ressource definierte Namen des Menüs zugewiesen.Ereignis der Menüauswahl
Das Anklicken eines Menüpunktes löst eine Nachricht WM_COMMAND aus, die in der Fensterfunktion verarbeitet wird. Welcher Menüpunkt ausgewählt wurde, ist im niedrigeren Teil des ersten Parameters wParam kodiert. Für das Extrahieren stellt Windows das Makro LOWORD zur Verfügung.Der Fensterinhalt
Alles, was im Fenster gezeichnet oder angezeigt werden soll, wird nicht direkt auf das Fenster gezeichnet. Das hätte den Nachteil, daß alles verschwunden ist, wenn das Fenster kurzzeitig überdeckt wurde. Ein Fenster erhält in dem Falle, daß der Inhalt neu zu zeichnen ist, die Nachricht WM_PAINT. Hier muß es seinen Inhalt neu darstellen. Den gleichen Mechanismus benutzt man, wenn man im Fenster zeichnen will. Man manipuliert die Daten, aus denen die Fensterfunktion das Fenster rekonstruiert und ruft die Funktion Invalidate auf, und täuscht so dem Fenster vor, daß eine Neuzeichnung notwendig sei.InvalidateRect(hWnd, 0, 0);Die Parameter:
- Der erste Parameter ist das Window-Handle des Fensters, das betroffen ist.
- Der zweite Parameter gibt in einer RECT-Struktur das betroffene Rechteck an. Wird hier 0 übergeben, betrifft es das ganze Fenster.
- Der dritte Parameter gibt an, ob der Bereich vor dem Neuzeichen gelöscht werden soll (TRUE) oder ob einfach darüber gezeichnet werden soll (0 oder FALSE).
Beenden einer Windows-Anwendung
Der Menüpunkt für das Ende der Applikation ruft WindowDestroy auf. Dies erzeugt wiederum die Nachricht WM_DESTROY an das eigene Fenster. Hier erst setzt die Anwendung den Befehl PostQuitMessage(0); ab, das wiederum eine Nachricht absetzt. Das "Post" führt aber im Gegensatz zu "Send" dazu, daß an dieser Stelle nicht auf die Abarbeitung gewartet wird.Die Quit-Nachricht wird nicht in der Fensterfunktion bearbeitet, sondern bewirkt ein Unterbrechen der Main-Loop und führt so zum Ende der Applikation.
Der scheinbare Umweg über das Nachrichtensystem führt dazu, daß alle beteiligten Komponenten informiert sind, daß dieses Programm sich abbaut.
Der Quelltext
#include <windows.h> #include "resource.h" HINSTANCE hInst; #define szTitle "Fenstertitel" #define szWindowClass "MyWindowClass" LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_EXIT: DestroyWindow(hWnd); break; } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // do the painting of the window EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, message, wParam, lParam); } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex = {0}; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_RAHMEN); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCSTR)IDC_RAHMEN; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex); } BOOL InitMainWindow(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HACCEL hAccelTable; MyRegisterClass(hInstance); hInst = hInstance; if (!InitMainWindow (hInstance, nCmdShow)) return FALSE; hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_RAHMEN); while (GetMessage(&msg, NULL, 0, 0) > 0) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } |
Die Ressourcen
Die Headerdatei der Ressourcen
#define IDR_MAINFRAME 128 #define IDD_RAHMEN_DIALOG 102 #define IDS_APP_TITLE 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDS_HELLO 106 #define IDI_RAHMEN 107 #define IDI_SMALL 108 #define IDC_RAHMEN 109 #define IDC_MYICON 2 #define IDC_STATIC -1 |