Zunächst muss in MS Visual C++ 6.0 ein neues Projekt erstellt werden. Dazu wählen sie im Menü <Datei> den Menüpunkt <Neu...> und wählen dann auf der Registerkarte <Projekte> den Eintrag <Win32-Anwendung>, geben sie dem Projekt den Namen "Prog1" und bestätigen sie mit <Ok>. Im nächsten Dialog wählen Sie <Ein leeres Projekt> und bestätigen erneut. Als nächstes fügen Sie dem Projekt eine neue C++-Quellcodedatei hinzu und nennen sie main.cpp.
Zunächst muss sie Funktionalität der Windows-API mithilfe des Eintrags '#include <windows.h>' in das Projekt eingebunden werden. Anschließend fügen Sie die Deklaration der Fensterprozedur und den Funktionsrumpf der WinMain-Methode hinzu. Zuletzt fügen sie dann noch die in der letzten Lektion geschriebene Implementierung der Fensterprozedur hinzu:
<Prog1/main.cpp>
//Windows-API #include <windows.h> //Deklaration der Fensterprozedur LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //WinMain int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { return 0; } //Implementierung der Fensterprozedur LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { switch (uiMessage) { case WM_CLOSE: DestroyWindow(hWnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uiMessage, wParam, lParam); }
Das Programm sollte jetzt schon kompilierbar sein. Das Ausführen ergäbe aber wenig Sinn, da 'WinMain(...)' praktisch leer ist.
Als erstes sollten wir nun eine Zeichenkette deklarieren, welche den Namen der Anwendung trägt. Wir nennen die Variable 'szAppName' mit dem Datentyp 'LPCTSTR':
//Name der Anwendung LPCTSTR szAppName = TEXT("Prog1");
Anschließend bilden wir eine Instanz der WNDCLASS-Struktur, füllen diese wie folgt aus und registrieren diese anschließend:
//Fensterklasse erstellen... WNDCLASS wc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hInstance; wc.lpfnWndProc = WndProc; wc.lpszClassName = szAppName; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW; //Fensterklasse registrieren RegisterClass(&wc);
Neu dürfte die Methode 'GetStockObject(...)' und die Konstanten 'CS_VREDRAW' und 'CS_HREDRAW' erscheinen. Mit der Anweisung 'GetStockObject(...)' lassen sich gewisse Standard-GDI-Objekte von Windows erstellen (Erklärung folgt in weiteren Lektionen). In diesem Beispiel legt die Anweisung lediglich fest, dass der Fensterhintergrund mit einem weißen Pinsel ('WHITE_BRUSH') ausgefüllt werden soll. Die Konstante 'CS_HREDRAW' legt fest, dass der Fensterinhalt immer dann neu gezeichnet wird, wenn die Breite des Anwendungsbereiches geändert wird. Entsprechendes gilt für die Konstante 'CS_VREDRAW', welche dafür sorgt, dass das Fenster immer dann neu gezeichnet wird, wenn die Höhe geändert wird. Die Buchstaben 'H' und 'V' innerhalb der Konstanten stehen dabei jeweils für horizontal (Breite) und vertikal (Höhe). Alles weitere sollte bekannt sein. Nun sollte das Fenster erstellt werden:
HWND hWnd = CreateWindow(szAppName, szAppName, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
Die Funktion wurde zuvor bereits besprochen. Der Fensterstil wird hier durch eine Kombination aus fünf verschiedenen Eigenschaften festgelegt:
Fensterstil | Bedeutung |
---|---|
WS_CAPTION | - Fenster besitzt eine Titelleiste |
WS_SYSMENU | - Fenster besitzt ein Systemmenü inkl. der Schließen-Schaltfläche |
WS_THICKFRAME | - Fenster erhält einen dickeren Rahmen - Fenstergröße lässt sich ändern |
WS_MAXIMIZEBOX | - Schaltfläche zum minimieren |
WS_MINIMIZEBOX | - Schaltfläche maximieren |
Alternativ kann auch der Fensterstil 'WS_OVERLAPPEDWINDOW' gewählt werden. Dieser Fensterstil kombiniert all diese Eigenschaften und verleiht dem Fenster ein wahres Windows-Aussehen. Der Aufruf von 'CreateWindow(...)' sähe dann wie folgt aus:
//Fenster erstellen HWND hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
Zuletzt sollte das Fenster noch angezeigt und der Anwendungsbereich noch aktualisiert werden. Die dafür notwendigen Anweisungen wurden bereits zuvor besprochen:
//Fenster anzeigen und Anwendungsbereich aktualisieren ShowWindow(hWnd, nShowCmd); UpdateWindow(hWnd);
Dann schließlich folgt schließlich und endlich die Nachrichtenschleife:
//Nachrichtenschleife MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
Als letztes ist das Programm mit einer 'return-Anweisung' zu beenden. Ausreichend wäre '0' zurückzugeben. Normalerweise führt man allerdings folgende Anweisung aus:
//Programmende return msg.wParam;
Da die Instanz 'msg' zu diesem Zeitpunkt die Informationen der von 'PostQuitMessage(...)' gesendeten 'WM_QUIT'-Nachricht enthält, besitzt der Parameter 'wParam' den Wert, welcher beim Aufruf von 'PostQuitMessage(...)' übergeben wurde. Meist ist dies genau '0' (wie auch in diesem Falle). Der Wert '0' informiert Windows über ein erfolgreiches Programmende. Mit dem bevorzugten Aufruf wird immer der Wert von 'PostQuitMessage(...)' zurückgegeben und der kann innerhalb der Fensterprozedur angegeben werden.
Die vollständige Datei <main.cpp> sollte nun wie folgt aussehen:
//Windows-API #include <windows.h> //Deklaration der Fensterprozedur LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //WinMain int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { //Name der Anwendung LPCTSTR szAppName = TEXT("Prog1"); //Fensterklasse erstellen... WNDCLASS wc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hInstance; wc.lpfnWndProc = WndProc; wc.lpszClassName = szAppName; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW; //Fensterklasse registrieren RegisterClass(&wc); //Fenster erstellen HWND hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //Fenster anzeigen und Anwendungsbereich aktualisieren ShowWindow(hWnd, nShowCmd); UpdateWindow(hWnd); //Nachrichtenschleife MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //Programmende return msg.wParam; } //Implementierung der Fensterprozedur LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { switch (uiMessage) { case WM_CLOSE: DestroyWindow(hWnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uiMessage, wParam, lParam); }
Das Programm sollte nun kompilierfähig und ausführbar sein. Es sollte in etwa folgende Ausgabe entstehen (nach Verminderung der Fenstergröße) :
Trotz seiner Schlichtheit und seiner mangelnden Funktionalität enthält es bereits alle typischen Fenstereigenschaften. So lassen sich zumindest schon einmal Fenstergröße und Position verändern. So sieht der Rohbau einer jeden Windowsanwendung aus. Für weitere Programme können Sie diesen Quelltext komplett übernehmen und müssen ihn nur noch erweitern und selbstverständlich gewünschte Änderungen editieren.
In den nächsten Lektionen soll das Programm mit Leben gefüllt werden, indem wir uns vornehmlich mit Ausgaben beschäftigen.