Die WinAPI Plattform

Tutorials

(01.) Das erste Windows Programm

In dem ersten Tutorial zeige ich dir, wie man eine ganz einfache Ausgabe in Form eines Nachrichtenfensters macht. Hierfür benutzen wir die MessageBox Funktion, die genau dafür konzipiert wurde.

Zu aller erst musst du ein neues Projekt (wichtig: Windows Anwendung bzw. -tW Compiler Flag beim Borland C++ Compiler) erstellen (Anleitung für Visual C++ 6). Damit wir von einer verbesserten Typsicherheit profitieren, müssen wir vor dem Einbinden der Windows Headerdatei einen Bezeichner definieren.

#define STRICT

Dann muss die haupt Windows API Headerdatei eingebunden werden. In diese Datei werden wiederum andere Dateien eingebunden, sodass man schließlich alle Prototypen und Konstanten deklariert hat. Diese Zeile muss in jedem Programm, dass Teile der Windows API benutzt, vorhanden sein.

#include <windows.h>

Die nächste Anweisung speichert unseren Witz, der nachher ausgegeben werden soll, unter dem Namen szWitz als konstante Zeichenkette ab.

const char  szWitz[] = "\"Ich steh' schwer auf Umweltschutz\", sagt Peter.\n"
                       "\"Ich werfe zum Beispiel alte U-Bahn-Fahrscheine nie weg,\n"
                       "sondern benutze sie mehrmals.\"";

In jedem Programm braucht man eine Funktion, die als Einstiegspunkt dient. Diese Funktion wird praktisch vom Betriebssystem aufgerufen und bekommt meistens Daten als Parameter überliefert. Wenn die Hauptfunktion beendet ist, dann ist auch das Programm beendet. In Dos war dies die main Funktion. Da man Windows und Dos Programme klar von einander trennen wollte, heißt die Hauptfunktion in Windows WinMain. Rückgabetyp ist wie auch in Dos Zeiten ein int Wert. WINAPI steht vor allen Windows API Funktionen und legt die Aufrufkonvention fest. In MS Visual C++ 6 steht WINAPI für __stdcall. Das bedeutet, dass die Parameter von Rechts nach Links übergeben werden, dass die Werte per Value übergeben werden, also eine Kopie erzeugt wird, und einiges mehr (im MSND: The __stdcall Keyword). Die Parameter der WinMain Funktion erkläre ich dir im nächsten Tutorial, da wir die Parameter in diesem Tutorial noch nicht benötigen.

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{

Dir ist sicher aufgefallen, dass alle Variablennamen mit einem Präfix beginnen. Man schreibt vor eine Variable vom Typ int ein i, damit man später noch weiß, welchen Typ diese Variable hat. Diese Art der Namensgebung nennt man 'ungarische Notation' zu Ehren des Microsoft Programmierers Charles Simonyi, der Ungarischer Staatsbürger ist. Ich habe eine Liste aller Präfixe zusammengestellt.

Die MessageBox Funktion (im MSDN: MessageBox) gibt in einem separaten Fenster eine Nachricht aus. Der erste Parameter soll normalerweise ein Handle auf ein Fenster sein, zu dem die Nachricht gehören soll (und das die Funktion solange lahm legen soll), aber da wir kein Fenster besitzen, geben wir Null an. Dies bedeutet, dass die Nachricht als eigenständiges Fenster dargestellt wird. Was ein Handle ist und wie man ein Fenster erzeugt, lernst du im zweiten Tutorial. Der zweite Parameter ist ein Zeiger auf eine C-Zeichenkette, die als Text im Nachrichtenfenster ausgegeben werden soll. Der dritte Parameter ist auch ein Zeiger auf eine Zeichenkette. Dieser Text wird in der Titelleiste des Fensters angezeigt. Mit dem vierten Parameter kann man das äußerliche Erscheinungsbild der Nachricht beeinflussen. So bekommt ein Nachrichtenfenster ein bestimmtes Icon und die Art und Anzahl der Buttons wird festgelegt. In unserem Fall bekommt das Fenster ein "Information" Icon und die Buttons "Ok" und "Abbrechen" von denen der erste der standard Button ist. Im Rückgabewert wird gespeichert, welcher Button nun gedrückt wurde. Diese Information speichern wir in der Variablen iAntwort.

   int iAntwort = MessageBox(NULL, szWitz, "Ha, ha, ha, ha...",
                                   MB_ICONINFORMATION | MB_OKCANCEL | MB_DEFBUTTON1);

In der nächsten Anweisung prüfen wir, ob der Benutzer in dem vorherigen Nachrichtenfenster auf "Ok" gedrückt hat. Wenn dies der Fall war, dann geben wir noch eine Nachricht aus, in der genau dies steht. Wir geben wieder MB_ICONINFORMATION an, aber diesmal MB_OK. Die Konstante MB_DEFBUTTON1 behalten wir bei.

   if (IDOK == iAntwort)
   {
      MessageBox(NULL, "Ja, ich finde den Witz auch Ok...",
                       "Sie haben auf Ok gedrückt",
                       MB_ICONINFORMATION | MB_OK | MB_DEFBUTTON1);
   }

Wenn der Benutzer jedoch den "Abbrechen" Button gedrückt hat, geben wir eine andere Nachricht aus. Wir können hier nicht einfach else statt else if schreiben, da die MessageBox Funktion bei einem Fehler Null zurückgibt und wir dann den Fehler als Abbrechen interpretieren würden.

   else if (IDCANCEL == iAntwort)
   {
      MessageBox(NULL, "Ja, warum haben sie denn auf Abbrechen gedrückt?\n"
                       "Hat ihnen der Witz etwa nicht gefallen?",
                       "Sie haben auf Abbrechen gedrückt",
                       MB_ICONINFORMATION  | MB_OK | MB_DEFBUTTON1);
   }

Da die WinMain Funktion einen Rückgabetyp angegeben hat, müssen wir nun auch einen zurückgeben. Man darf die WinMain Deklaration natürlich nicht ändern, so darf man in ISO-C auch kein void als Rückgabetyp der Hauptfunktion angeben. Null als Rückgabewert steht für erfolgreich beendet und alles ungleich Null deutet auf einen Fehler hin.

    return 0;
}

Dies musst du dann noch mit einem Windows fähigen Compiler compilieren (Anleitung für Visual C++ 6). Nach dem Ausführen des Programms müsste das erste Nachrichtenfenster erscheinen.

Wer eine IDE benutzt, die Eingabehilfen anbietet (wie Visual C++ 6), wird merken, dass ich ein paar Variablen und Typen anders geschrieben habe, als dort vielleicht angegeben. Dies ist unter Umständen im dritten Parameter der WinMain Funktion der Fall. Dort schreibe ich PSTR szCmdLine und andere werden vielleicht LPSTR lpCmdLine schreiben. Der Typ LPSTR bedeutet "Long Pointer to a String" und ist veraltet, da es in Windows 32 Systemen keine Long (far) Pointer mehr gibt. Der Präfix sz ("String terminated by Zero") beschreibt den Typ viel besser, als lp ("Long Pointer"). Für den Compiler sind natürlich beide Varianten identisch, da der Unterschied durch den Präprozessor eleminiert wird. Und da wir gerade bei der Namensgebung sind: MB_* steht für MessageBox. Dies findet man in der Windows API häufig, dass die Konstanten im Zusammenhang mit einer Funktion ein Kürzel des Funktionsnamen als Präfix tragen.

webmaster@win-api.de