start

WinApi 32 - Einleitung
Das einfachste Windows Programm

Anstelle eines langen theoretischen Einleitungstextes soll dieses Beispiel als kleine Einführung dienen. Die Anwendung selbst ist ohne ein eigenes Fenster und ohne Message-Loop. Es wird ein Standart-API-Dialog geöffnet der den Text Goodbye, cruel world! mit der Überschrift Note ausgibt.
#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 MessageBox(NULL, "Goodbye, cruel world!", "Note", MB_OK);
 return 0;
}

example01.c

An dieser Stelle ein paar Tipps für LCC32-Neueinsteiger (alle anderen Compiler funktionieren auf ähnliche Art).
  • WEDIT starten und Project - Create auswählen, dann den Namen eingeben (firstwin)
  • Das Arbeitsverzeichnis mit Browse festlegen, Single User, Windows Executable auswählen und Create
  • Die Nächte Frage mit NEIN beantworten (keine Erzeugung des Programmskelets vom Wizard)
  • Die Qelldatei wählen und im Nächten Dialog Validate drücken.

Schon ist ein neues Projekt erstellt. Mit F9 wird des Programm übersetzt und CTRL-F5 lässt das übersetzte Programm ablaufen. Mögliche Fehler während der Übersetzung werden im untersten Frame angezeigt, mit einem Doppelklick auf eine der Fehlermeldungen springt der Cursor auf die Entsprechende Fehlerstele. Weitere Informationen zu LCC32 siehe LCC32-Tutorial (noch nicht online verfügbar).

Wenn das Programm nicht läuft oder Fehler beim Erzeugen auftreten sollte nochmals überprüft werden ob es sich um ein WIN32 GUI Projekt handelt. Auf keinen Fall darf es ein Console Projekt sein. Weitere Hilft zu möglichen Fehler findet man in einer C Sprachbeschreibung oder in der Hilfe zum jeweils verwendeten Compiler.

Wie bei jedem anderen Programm beginnt die Abarbeitung mit einer bestimmten festgelegten Funktion, bei C ist das WinMain(). Dabei bedeuten die verwendeten Parameter :
HINSTANCE hInstance
ein HANDLE auf das Programm (die .exe) selbst im Arbeitsspeicher. hInstance wird vor allem für das dynamische Laden von Resorcen und Modulen verwendet. Ein solches Modul kann eine .exe oder .dll Datei sein. In den meisten Fällen wird es nur ein einziges Modul, die .exe Datei selbst.
HINSTANCE hPrevInstance
ist immer NULL bei WIN32 Programmen. hPrevInstance wurde unter WIN16 verwendet um eine zuvor gestartete Instance des Programms zu identifizieren. Unter WIN32 ist dies nicht länger notwendig.
LPSTR lpCmdLine
alle Kommandozeilenparameter als ein STRING, ohne den Programmnamen.
int nCmdShow
Soll das Fenster von Anfang an gezeigt werden oder nicht ? Dieser Wert kann an die Funktion ShowWindow() übergeben werden.
WIN32 Datentypen

Windows (wie auch viele andere Betriebsysteme) verwendet eigene Definitionen für bestimmte Datentypen. (z.B. UINT steht für unsigned int oder LPSTR für char* usw.) Dabei ist es dem jeweiligen Programmierer überlassen welche "Schreibweise" er verwenden möchte. Die Verwendung von char* an stelle von LPSTR ist manchmal übersichtlicher. Jedoch sollte der Programmierer immer sicher sein was sich hinter einem Datentyp verbirgt, bevoer er diesen ersetzt. Hier ein paar Hinweise:

Ein LP prefix steht immer für Long Pointer. Zwar ist in WIN32 der LONG Teil obsolete, aber die Bezeichnung ist immer noch die gleiche seit WIN16.

Wird das LP von einem C gefolgt ist das ein Zeichen für einen CONST POINTER, z.B. LPCSTR steht für einen Pointer auf einen const string (dieser kann nicht modifiziert werden ;-).

Mit unter kommt es auch vor, dass ein T in den Namen eingefügt ist, dabei handelt es sich um eine Typdefinition.

LPSTRLONG POINTER CHAR
LPCSTRLONG POINTER CONST CHAR
Ein einfaches Fenster
[images/simple_window.gif] Die Zentrale Frage in der Windows-Programmierung ist : "Wie öffne ich ein Fenster?". Genau darum soll es in diesem ersten einfachen Beispiel gehen. Wie bei allen Dingen ist auch das nicht schwer, solange man nur weiß wie es geht und was beachtet werden muss.

Ich ziehe es immer vor die Dinge erst auszuprobieren und dann zu lernen wie sie funktionieren. Hier ist der CODE für ein einfaches Fenster ...

#include <windows.h>
const char g_szClassName[] = "myWindowClass";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
 case WM_CLOSE:
 DestroyWindow(hwnd);
 break;
 case WM_DESTROY:
 PostQuitMessage(0);
 break;
 default:
 return DefWindowProc(hwnd, msg, wParam, lParam);
 }
 return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPSTR lpCmdLine, int nCmdShow)
{
 WNDCLASSEX wc;
 HWND hwnd;
 MSG Msg;

 //Step 1: Registering the Window Class
 wc.cbSize = sizeof(WNDCLASSEX);
 wc.style = 0;
 wc.lpfnWndProc = WndProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 wc.lpszMenuName = NULL;
 wc.lpszClassName = g_szClassName;
 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

 if(!RegisterClassEx(&wc))
 {
 MessageBox(NULL, "Window Registration Failed!", "Error!",
 MB_ICONEXCLAMATION | MB_OK);
 return 0;
 }

 // Step 2: Creating the Window
 hwnd = CreateWindowEx(
 WS_EX_CLIENTEDGE,
 g_szClassName,
 "The title of my window",
 WS_OVERLAPPEDWINDOW,
 CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
 NULL, NULL, hInstance, NULL);

 if(hwnd == NULL)
 {
 MessageBox(NULL, "Window Creation Failed!", "Error!",
 MB_ICONEXCLAMATION | MB_OK);
 return 0;
 }

 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);

 // Step 3: The Message Loop
 while(GetMessage(&Msg, NULL, 0, 0) > 0)
 {
 TranslateMessage(&Msg);
 DispatchMessage(&Msg);
 }
 return Msg.wParam;
}

Schritt 1: Registrierung der Fenster-Klasse

Window Class speichert alle Informationen zu einem bestimmten Fenster, einschließlich der zugehörigen Window Procedure. (Diese steuert das Fenster.) Ferner werden die Icons für das Fenster sowie die Hinteergrundfarbe gespeichert. Auf diese Art kann man einmal eine Fenster-Klasse registrieren (die Fenster-Klasse wird mit allen ihren Eigenschaften beim System angemeldet und bekannt gemacht) und so viele Fenster davon erzeugen wie man möchte, ohne alle diese Eigenschaften wieder und wieder eingeben zu müssen. Die meisten Eigenschaften eines Fenster lassen sich vor der in dieser Weise vor der Erzeugung festlegen.

Eine Fenster-Klasse hat absolut nichts mit einer C++ Klasse zu tun.

const char g_szClassName[] = "myWindowClass";
Die Variable oberhalb speichert den Namen der Fenster-Klasse in einer konstanten Zeichenketten-Variablen. Diese kann später verwendet werden um eine Instanz der gewünschten Fenster-Klasse zu erzeugen.
 WNDCLASSEX wc;
 wc.cbSize = sizeof(WNDCLASSEX);
 wc.style = 0;
 wc.lpfnWndProc = WndProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 wc.lpszMenuName = NULL;
 wc.lpszClassName = g_szClassName;
 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

 if(!RegisterClassEx(&wc))
 {
 MessageBox(NULL, "Window Registration Failed!", "Error!",
 MB_ICONEXCLAMATION | MB_OK);
 return 0;
 }

Mit diesem CODE wird die Fenster-Klasse in WinMain() registriert. Die Member-Variablen der WNDCLASSEX structure werden ausgefüllt mit den entsprechenden gewünschten Eigenschaften und RegisterClassEx() wird gerufen. Jetzt ist unsere eigene Fensterklasse in System bekannt und kann verwendet werden als Template.

cbSize
Die Größe der Struktur.
style
Hier ist ein Class Style (CS_*) gemeint, nicht zu verwechseln mit einem Window Style (WS_*). Dieser Wert ist Normalerweise immer 0.
lpfnWndProc
Ein pointer auf die window procedure für diese Fenster Klasse.
cbClsExtra
Größe der extra Daten die dieser Klasse im Speicher zugewiesen wurden. Normalerweise 0.
cbWndExtra
Größe der extra Daten die der Klasse jeweiligem Fester im Speicher zugewiesen wurden. Normalerweise 0.
hInstance
Das Handle der Anwendungsinstanz (entspricht dem ersten Parameter von WinMain()).
hIcon
Das große ICON (normalerweise 32x32) wird gezeigt wenn Alt+Tab gedrückt wird.
hCursor
Mauszeiger der über diesem Fenster angezeigt werden soll.
hbrBackground
Hintergrund Brush (Pinsel) legt die Farbe des Fensters fest.
lpszMenuName
Name einer menu resource die mit einem Fenster dieser Klasse benutzt werden soll.
lpszClassName
Name um die Klasse zu identifizieren.
hIconSm
Das kleine ICON (normalerweise 16x16) wird in der Taskbar und in der linken oberen Ecke gezeigt.
Wer an dieser Stelle nicht alles genau verstanden hat kann getrost weiter lesen, die wichtigen Zusammenhänge werden später noch in Detail erklärt. Ich werde keine structs, oder Funktionsparameter niederschreiben, das ist in diesem Zusammenhang eine Verschendung von Kraft und Zeit. Dise finden sich in den entsprechenden Hilfe-Dateien. Wer keine Hilfe-Dateien hat sollte sich diese besorgen, denn ohne ist man bei der WINAPI Programmierung verloren.

Als nächstes wird RegisterClassEx() ausgeführt und auf Fehler geprüft, im Fehlerfall wird dieser ausgegeben und das Programm beendet durch ein RETURN in der Funktion WinMain().

Schritt 2: Erzeugen eines Fensters

Wenn die Fenster-Klasse erst einmal registriert ist kann ein Fenster erzeugt werden mit CreateWindowEx(). Die einzelnen Parameter dieser Funktion, wie auch jeder anderen API-Funktion, sollte jeder wenigstens einmal in der WINAPI-Hilfe nachgeschlagen haben.

 HWND hwnd;
 hwnd = CreateWindowEx(
 WS_EX_CLIENTEDGE,
 g_szClassName,
 "The title of my window",
 WS_OVERLAPPEDWINDOW,
 CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
 NULL, NULL, hInstance, NULL);

Der erste Parameter (WS_EX_CLIENTEDGE) ist der Erweiterte Fenster Stiel (extended windows style), in diesem Beispiel ist das eine abgesenkte Innenkante um das Fenster. Weitere Möglichkeiten sind :

WS_EX_ACCEPTFILES
Dieses Fenster akzeptiert "drag-drop" Dateien.
WS_EX_APPWINDOW
Erzwingt ein top-level window auf der taskbar während das Fesnter minimiert ist.
WS_EX_CLIENTEDGE
Das Fenster hat einen abgesenkten Rand.
WS_EX_CONTEXTHELP
Erzeugt ein Fragezeichen in der Titelzeile des Fensters. Klickt der Benutzer auf der Fragezeichen, ändert sich der Mauszeiger in ein Fragezeichen. Klickt der Anwender jetzt in ein untergeordnetes Fenster, empfängt dieses eine WM_HELP Nachricht. Das untergeordnete Fenster sollte diese Nachricht durch die Nachrichten-Benadlungs-Routine des Hauptfensters leiten, welches die WinHelp Funktione mit dem HELP_WM_HELP Befehl rufen sollte. Es wird ein POP-UP Fenster mit der Hilfenachricht für das untergeordnete Fenster angezeigt. WS_EX_CONTEXTHELP kann nicht zusammen mit WS_MAXIMIZEBOX oder WS_MINIMIZEBOX verwendet werden.
WS_EX_CONTROLPARENT
Erlaubt dem Benuter zwischen den untergeordneten Fenstern mit Hilfe der TAB Taste zu wechseln.
WS_EX_DLGMODALFRAME
Erzeugt ein Fesnter mit doppeltem Rand.
WS_EX_LEFT
In dem Fesnter wird alles Linksbündig angeordnet. (Diese Eigenschaft ist voreingestellt).
WS_EX_LEFTSCROLLBAR
Für bestimmte Sprachen wie Arabisch oder Hebräisch wird die Scroll-Bar auf der linken Seite dargestellt, für alle anderen Sprachen wird diese Eigenschaft ohne Fehler ignoriert.
WS_EX_LTRREADING
Der Text wird von Links nach Rechts dargestellt. (Diese Eigenschaft ist voreingestellt.)
WS_EX_MDICHILD
Erzeugt ein MDI untergeordnetes Fenster.
WS_EX_NOPARENTNOTIFY
Ein Fenster mit dieser Eigenschaft sendet kein WM_PARENTNOTIFY an das übergeordnete Fenster wenn es erzeugt oder gelöscht wird.
WS_EX_OVERLAPPEDWINDOW
Eine Kombination aus WS_EX_CLIENTEDGE und WS_EX_WINDOWEDGE.
WS_EX_PALETTEWINDOW
Eine Kombination aus WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW, und WS_EX_TOPMOST.
WS_EX_RIGHT
Der Text wird von Rechts nach Links dargestellt. Diese Eigenschaft ist jedoch von der Fensterklasse abhängig und der Shell-Sprache des Rechners.
WS_EX_RIGHTSCROLLBAR
Die Scroll-Bar wird auf der rechten Seite dargestellt.
WS_EX_RTLREADING
Der Text wird von Links nach Rechts dargestellt.
WS_EX_STATICEDGE
Erzeugt ein Fesnter mit 3-D Rand um dem Anwender zu signalisieren, keine Benutzereingaben werden akzeptiert.
WS_EX_TOOLWINDOW
Erzeugt ein Tool-Fenster welches als fliegende Tool-Bar verwendet werden kann. Ein derartiges Fenster hat eine kleinere Titel-Leiste und der Titel wird in einer kleineren Schriftart dargestellt. Ein Tool-Fenster erscheint nicht in der Taskbar oder in dem Dialog welcher erscheint, wenn man ALT+TAB drückt.
WS_EX_TOPMOST
Diese Fenster wird über allen non-topmost Fenstern dargestellt und sollte auch an dieser stelle bleiben, bis ein weiteres Fenster mit dieser Eigenschaft erzeugt wird.
WS_EX_TRANSPARENT
Erzeugt ein durchsichtiges Fenster. Alle darunter liegenden Fenster werden nicht verdeckt. Ein derartiges Fenster empfängt die WM_PAINT Nachricht erst nachdem alle darunterliegenden Fenster aktualisiert wurden.
WS_EX_WINDOWEDGE
Ein Fenster mit erhöhter Kante.

Als nächstes kommt der am Anfang erzeugte Klassenname zum Einsatz. g_szClassName teilt dem System mit, welche Art Fenster erzeugt werden soll. Zuerst wird ein Fenster aus der Klasse mit der Hilfe des Namen erzeugt, dann der Name oder Titel festgelegt. Der Title ist der Text der angezeigt wird die Caption, oder Title Bar eines Fensters.

Der Parameter WS_OVERLAPPEDWINDOW ist der Window Style Parameter. Hiervon gibt es eine ganze Menge, die in der Apidokumentation nachgeschlagen werden können. Später wird darauf noch näher eingegangen.

Die folgenden vier Parameter (CW_USEDEFAULT, CW_USEDEFAULT, 320, 240) sind die X und Y Koordinaten für die obere linke Ecke des Fensters, die Breite sowie Höhe des Fensters. In dem Beispiel sind die X und Y Werte auf CW_USEDEFAULT gesetzt, so dass Windows eine Auswahl treffen kann wo das Fenster auf dem Bildschirm erscheinen soll. Die Linke Bildschirmseite hat einen X Wert von Null und wird nach Rechts größer. Die oberen Bildschirmkante hat den Y-Wert Null und wird nach unten größer. Die Einheit ist ein Pixel (1px). Die Größe des Bildschirms wird von der Auflösung bestimmt. Es ist auch möglich außerhalb des Bildschirm etwas darzustellen, aber diese Elemente können vom Anwender NIE gesehen werden.

Weiter geht es mit (NULL, NULL, g_hInst, NULL), das sind ein Parent Window handle, ein Menu handle, das application instance handle, und eine pointer auf die window creation daten. In windows werden die Fenster auf dem Bildschirm in einer Hierarchie von über- und untergeordneten Fenstern angeordnet. Jeder Button ist wiederum ein untergeordnetes (Child-Window) des Fenstern in dem dieser enthalten ist und er enthält wiederum einen Verweis auf das übergeordnete Fenster(Parent-Window). Im Folgenden werden diese auch kurz Child und Parent genannt. In dem Beispiel ist das parent handle gleich NULL, weil es kein parent gibt. Das Fenster ist das Top Level Fenster der Anwendung. Das menu handle ist auch gleich NULL, denn in diesem Beispiel gibt es kein Menu. Das instance handle wird auf den ersten Parameter von WinMain() gesetzt. Die creation data (welche ich noch persönlich noch nie benutzt habe), zusätzliche Daten in das Fenster reinzureichen während der Erzeugung ist auch NULL.

Anmernkung : Wer sich fragt was es mit dem magic NULL auf sich hat sollte hier weiter lesen, wer das weiß kann diesen Absatz getrost überspringen. Dabei geht es um nichts weiter als ein DEFINE NULL ((void*)0). Am Anfang war es einfach nur ein DEFINE NULL 0. Mit der Zeit wurde dieses Define aber auch in Verbindung mit Pointern verwendet, und so entstand die neue Definition. Aus diesem Grund wird der Compiler auch Warnungen auswerfen, wenn NULL in Verbindung mit einem integer Wert verwendet wird. Man kann diese Warnungen entwerder ignorieren oder einfach eine 0 anstelle von NULL verwenden.

Einer der Hauptgründe, warum viele Programmierer nicht wissen, was eigentlich in ihren Programmen schief geht, ist, dass sie die Rückgabe Werte der Funktionen nicht abfragen und auswerten. Diese geben Auskunft über den Erfolg der Aktion(en) und mögliche Fehlerursachen. CreateWindow() kann immer schief gehen (auch wenn man ein erfahrener Programmierer ist), einfach schon aus dem Grund das es jede Menge Möglichkeiten für die verschiedensten Fehler gibt. Während man lernt Fehler zu vermeiden, sollte man sich zuerst mal die Chance geben diese zu erkennen. Ein weitere Vorteil des sofortigen Einbaues (auch in einen schnellen Hack) ist, dass der Programmierer diese Fehlerbehandlungen nicht erst dann einbauen muss wenn der Fehler auftritt, sonder diese dann schon von Anfang an drin sind. In jedem Fall sollten die Rückgabe Werte mindestens wie folgt geprüft werden.

 if(hwnd == NULL)
 {
 MessageBox(NULL, "Window Creation Failed!", "Error!",
 MB_ICONEXCLAMATION | MB_OK);
 return 0;
 }

Nachdem wir jetzt ein Fenster erzeugt haben, und sicher sind, dass das HANDLE gültig ist, können wir das Fenster zum ersten mal anzeigen lassen unter Verwendung des letzten Parameters der Funktion WinMain(). Zu guter letzt wird noch mit einem UpdateWindow() sichergestellt, dass alle Änderungen auch korrekt dargestellt werden.

 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);

Der Parameter nCmdShow optional und kann auch einfach durch SW_SHOWNORMAL ersetzt werden. Wird der Wert aus WinMain() eingesetzt hat der Anwender der das Programm startet die Möglichkeit mittels eines entsprechendenAufrufes des Programms, Einfluss auf die InitialeSichtbarkeit zu nehmen. Denkbar wäre "Maximiert", "Minimiert" usw.

Schritt 3: Die Nachrichten-Schleife (Message-Loop)

Sie ist das Herz des gesamten Programms, so ziemlich alles was das Programm macht wird von hier aus gesteuert. Alle eintreffenden Ereignisse werden hier verarbeitet.

 while(GetMessage(&Msg, NULL, 0, 0) > 0)
 {
 TranslateMessage(&Msg);
 DispatchMessage(&Msg);
 }
 return Msg.wParam;

GetMessage() bekommt eine Nachricht vom System aus der message queue (dt.: Nachrichten Warteschlange) der Anwendung. Wann immer der Anwender die Maus bewegt, eine Taste drückt oder auf das Fenster klickt, oder irgend eine andere beliebige Eingabe macht, werden entsprechende Nachrichten vom System erzeugt und in die eigene message queue des Programms eingefügt. Durch Aufruf der Funktion GetMessage() wird die nächste Nachricht aus der Warteschlange geholt und zur Verarbeitung bereit gestellt. Sollte gerade keine Nachricht auf ihre Verarbeitung warten blockiert diese Funktion, d.h. es wird mit der weiteren Ausführung gewartet bis eine Nachricht vorliegt.

TranslateMessage() ist für die Nachbearbeitung von Tastaturereignissen zuständig. Diese Funktion erzeugt unter anderem die WM_CHAR Nachricht die immer zusammen mit der WM_KEYDOWN Nachricht verwendet wird. Zu letzt sendet DispatchMessage() die Nachricht an das Fenster, für wleches die Nachricht eigentlich bestimmt war. Das kann das eigene Hauptfenster, ein Control genauso wie ein fremdes Fenster oder Control sein, sogar der Desktop kann das Ziel sein. Die aktive Anwendung erhält immer alle Nachrichten für alle Fenster und verteilt diese dann entsprechend. Darüber brauchen wir uns jedoch nicht dem Kopf zu zerbrechen, alles was wir damit zu tun haben ist, die Nachricht zu bekommen und wieder raus zu senden. Das System sorgt dann schon dafür, dass die Nachricht beim richtigen Fenster ankommt. ;-)

Schritt 4: Die Window Procedure

Wenn also die Nachrichten-Schleife das Herz des Programms ist, dann ist die window procedure das Gehirn. Hier werden alle Nachrichten die ein Fenster bekommt verarbeitet. Jedes Fenster hat eine eigene window procedure.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
 case WM_CLOSE:
 DestroyWindow(hwnd);
 break;
 case WM_DESTROY:
 PostQuitMessage(0);
 break;
 default:
 return DefWindowProc(hwnd, msg, wParam, lParam);
 }
 return 0;
}

Die window procedure wird bei jeder ankommenden Nachricht gerufen, der HWND Parameter ist das HANDLE auf das Fenster, für welches die Nachricht bestimmt war. Das ist wichtig für den Fall, dass man mehrere Fenster der gleichen Klasse gleichzeitig offen hat, denn diese verwenden alle die gleiche window procedure (WndProc()). Der einzige Unterschied ist der Parameter hwnd an dem erkannt werden kann, zu welchem Fenster diese Nachricht gehört. Ein Beispiel: Nach Erhalt der Nachricht WM_CLOSE wird das Fenster zerstört. Wird dabei das empfangene window handle verwendet bleiben alle anderen Fenster unberührt von dieser Nachricht (ausgenommen untergeordnete child Fenster).

Die Nachricht WM_CLOSE wird gesendet wenn der Anwender den Close Button [x] drückt oder Alt-F4 eingibt. Dies führt (wird diese Nachricht nicht explizit behandelt) zur Zerstörung des Fensters, ich zeihe es jedoch vor, diese Nachricht explizit zu behandeln, weil das der beste Punkt und die letzt Chance ist, ungesicherte Daten zu sichern oder belegten Speicher wieder frei zu geben. Dies ist zwar in dem Beispiel nicht nötig aber sollte immer vorhanden sein.

Nach dem Aufruf der Funktion DestroyWindow() sendet das SYSTEM die Nachricht WM_DESTROY an das Fenster, welches zerstört werden soll. In diesem Fall handelt es sich um unsrer Fenster, welches dann auch zerstört wird inklusive aller untergeordneten Fenster und Elemente. Handelt es sich dabei um das Hauptfenster einer Anwendung sollte man unbedingt die Funktion PostQuitMessage() rufen um das Programm zu beenden. Diese sendet die Nachricht WM_QUIT in die nachrichten Schleife, diese Nachricht werden wir niemals erhalten, denn GetMessage() wird ein FALSE zurückgeben, das wiederum führt zum verlassen der Nachrichtenschleife. Ferner wird der Parameter von PostQuitMessage() an wParam übergeben und letzten Endes als Programm-Return-Code zurückgegeben.

Schritt 5: Es gibt keinen Schritt 5 !

Wow. Das war's! Soweit zum Thema "Wie öffne ich ein Fenster?".

spam me: mfischer25@web.de !
 

Weiter mit : Nachrichten - Details zur Nachrichtenverarbeitung zurück : Übersicht


---[ letzte Änderung : 19.04.2002 ]---