Pre DirectX Tutorial: Teil 2 - Windows Klassen I
Hallo Halli!
Ich sehe schon, diese Tutorial wird zu einer Ausrede...jedenfalls setze ich
mich immer daran, wenn ich nix mehr "gescheites" machen will. ;)
Egal, das letzte Mal sind wir zum Planeten X aufgebrochen. Zur Zeit durchqueren
wir unser Universum namens Windows und nähern uns langsam aber sicher.
Wir hatten einen ersten Einblick in dieses Universum und nun steigen wir richtig
ein: mit Windows Klassen.
Jedes Fenster egal ob Dialog Box, Message Box oder Vollbild benötigt eine
Windows Klasse. Eine Klasse definiert das Fenster und seine Attribute. Also
das Aussehen, das Verhalten und sonst alles Mögliche. Natürlich gibt
es (wie bei fast allem in Windows) Standard-Klassen, aber im wirklichen Leben
werdet ihr wohl für jede Applikation eine eigene Klasse definieren.
Ich will jetzt nicht lang und breit über Windows Klassen und deren Möglichkeiten
reden. Erstens Mal ist das Thema sehr umfangreich und zweitens Mal braucht ihr
nicht wirklich alles über sie zu wissen. Im Grunde werden wir nur zwei
bestimmte Fälle besprechen: DirectX Fenster auf Desktop und DirectX Fenster
Vollbild.
Also Leute: DAS ist eine Windows Klasse:
--------------------------------------------------------------------------------
typedef struct _WINDCLASSEX
{
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX;
--------------------------------------------------------------------------------
Tataa! Schick, oder? Das ist die Struktur einer neuen Windows Klasse. Eine
von diesen Dingern müsst ihr erzeugen und dann die Werte eintragen - dann
habt ihr eure eigene Windows Klasse. Schritt für Schritt:
WNDCLASSEX winclass; So, hier gehen wir es an. So nebenbei: Es gibt außer
WNDCLASSEX noch WNDCLASS, aber jene ist die ältere Datenstruktur von beiden
(daher auch das EX - für Extended). Über WNDCLASS solltet ihr euch
wenig Gedanken machen, ist so gut wie überholt und vergessen.
cbSize: Sehr wichtiges gleich zum Einstieg. Hier wird die Größe
unserer WNDCLASSEX Struktur eingetragen. Ich sehe es anhand eurer Fragezeichen:
wozu sollte man da die Größe eintragen, immerhin muß eine Struktur
doch nicht ihre eigene Größe wissen!? Mr Petzhold findet dieses Feld
unwichtig aber Mr. LaMothe begründet sie so: wenn diese Struktur als Pointer
übergeben wird kann der Empfänger anhand dieses Feldes die Größe
leichter bestimmen. Deshalb sollte man sie folgendermaßen setzen: winclass.cbSize
= sizeof(WNDCLASSEX);.
style: Dieses Feld hat Tonnen von Flags, die durch ein OR verbunden werden
können. Ein paar Beispiele: CS_REDRAW (zeichnet das Fenster neu, wenn es
der Nutzer bewegt); CS_VREDRAW / CS_HREDRAW (zeichnet das Fenster neu, wenn
der Nutzer seine Größe verändert hat); CS_OWNDC (wichtig, bindet
einen eigenen Device Context an unser Fenster - mehr dazu später); CS_NOCLOSE
(deaktiviert das "schließen" Feld am Fenster); CS_DBLCLKS (sendet
eine Nachricht wenn der User in unserem Fenster doppelklickt). Das sind nur
einige, wenn ihr mehr wollt: nachschlagen ;). Wir nutzen erst einmal folgende
Flags: winclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLICKS;
lpfnWndProc: Das ist ein Pointer zu unserer WndProc Routine. Erinnert ihr euch
noch? Im ersten Teil sagte ich Windows sei Event Driven und jene Nachrichten
würden auch an euer Programm geschickt und ihr bräuchtet eine Schnittstelle?
Nun, diese Schnittstelle ist WndProc. Dort werdet ihr auf jene Events reagieren,
doch jene Prozedur nehmen wir uns irgendwann vor ;) Im Moment genügt es
zu wissen, daß man hier folgendes einträgt: winclass.lpfnWndProc
= WinProc;
cbClsExtra und cbWndExtra: brauchen wir nicht, setzen wir auf 0: winclass.cbClsExtra
= 0; und winclass.cbWndExtra = 0;.
hInstance: siehe erster Teil. winclass.hInstance = hInstance;
hIcon: Juchu, unser Icon ;) Wir nehmen erst mal das 0815 Icon: winclass.hIcon
= LoadIcon(NULL, IDI_APPLICATION);
hCursor: Unser Cursor. Auch hier Standart winclass.hCursor = LoadCursor(NULL,
IDC_ARROW);
hbrBackground: Das ist die Hintergrundfarbe eurer Applikation. Wäre aber
zu einfach nur eine Farbe zu definieren, nein, da das GDI (Graphics Device Interfae)
kompliziert ist, müssen wir auch die Art eintragen mit der wir sie haben
wollen. winclass.hbrBackground = GetStockObject(WHITE_BRUSH);
lpszMenuName: Das ist der Name unseres Menus (falls wir eins wollen). Im Moment
nicht, also: winclass.lpszMenuName = NULL;
lpszClassName: So, jetzt benennen wir unsere soeben definierte Klasse. winclass.lpszClassName
= "WINCLASS1";. Und damit taufe ich dich auf den Namen "Winclass1"...oder
so ;)
hIconSmDas ist nichts anderes als ein Handle zu dem Icon in der Titelleiste
und der Startleiste. Nett, gell? winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Und das ist es! Das ist unsere Windows Klasse! Hier noch einmal im ganzen:
--------------------------------------------------------------------------------
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
--------------------------------------------------------------------------------
Jaja, schon klar, das ist trockenes Material, man kann nicht damit herumspielen
und wenn es alleine da steht kompiliert es sich nicht, aber das ist wichtig
zu wissen! Kein Windows Programm ohne diesen Kram! Also, zieht euch eine Fanta
'rein und versucht zumindest zu erahnen worum es hier geht. Das nächste
Mal öffnen wir dann endlich mal unser Fenster, dann wird euch sicher einiges
klar.
Manche von euch werden sich sicher fragen "Wozu zur Hölle machen
wir den Windows Quatsch per Hand und lassen das nicht den Visual Compiler übernehmen?".
All diejenigen, die sich diese Frage gestellt haben bitte dort drüben an
die Wand...fertig? Schießt Männer! Aber mal ernsthaft: bei DirectX
Programmen geht es doch immer um Zeitkritischen Kram. Also warum zur Hölle
wollt ihr 0815 Code nehmen anstatt eigenen Code von dem ihr wißt, daß
er clean ist? Oder nehmt ihr auch HTML Editoren für eure Homepage? (nein,
bitte nicht antworten, ich wäre von der Antwort nur deprimiert...).
Egal! Wir sind echte Coder! Wir packen das! ;)
Bis denne!
Delax
[delax@sundancerinc.de]