Die 1. Windows-Anwendung

Einführung

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.

Erstellen eines Fensters

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);

Die Nachrichtenschleife

Dann schließlich folgt schließlich und endlich die Nachrichtenschleife:

//Nachrichtenschleife
MSG msg;

while (GetMessage(&msg, NULL, 0, 0))
{
	TranslateMessage(&msg);
	DispatchMessage(&msg);
}

Programmende

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.

Das fertige Programm

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) : 

Zum Programm

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.

Die nächsten Lektionen

In den nächsten Lektionen soll das Programm mit Leben gefüllt werden, indem wir uns vornehmlich mit Ausgaben beschäftigen.

Zurück Nach oben Weiter