STS Homepage
3D VIRTUAL DEVELOPMENT SERVICES:
http://homepages.internet.lu/absolute3d/default.htm
Einführung in die Win32-API unter C/C++
Win32-API Tutorial in C/C++
copyright 2013: Claude Jacobs
from original site:
http://homepages.internet.lu/absolute3/tronic/default.htm


Die unüberschaubare Befehls- und Parametervielfalt, sowie die teils sehr unterschiedlichen Schreibweisen und Strukturierungen bilden häufig die ersten Hürden, wenn man sich einen Einblick in die Win32-Programmierung verschaffen möchte. Daher sind die folgenden Beispiele absichtlich auf das Wesentliche reduziert, um den Einstieg zu erleichtern und möglichst schnell zu ersten Erfolgen zu führen. Ebenso entsprechen die hier verwendeten Befehle weitgehend dem typischen C-Standard, und so dürften die Codes ohne allzugroßen Aufwand zumindest auch auf einigen anderen Programmieroberflächen nutzbar sein. Die vorwiegend deutschsprachigen Bezeichnungen der Variablen, Prozeduren usw. sollten es zudem erleichtern, zwischen den zugeordneten Namen und den feststehenden englischen Befehlen zu unterscheiden. Detailliertere Beschreibungen zu den komplexen Anweisungen und Parametern sollte man aber unbedingt entsprechender Literatur (z.B. win32.hlp) entnehmen.

INDEX NEXT

Ein Fenster erzeugen:
Die Hauptfunktion WinMain erstellt zunächst aufgrund der definierten und registrierten Klassenparameter (WNDCLASS- bzw. WNDCLASSEX-Struktur) ein normales Anwendungsfenster mit den üblichen Eigenschaften und verweilt anschließend in einer Dauerschleife, welche die auftretenden Ereignisse des Fensters als "Befehle" ("messages") an die vordefinierte Fensterprozedur weiterleitet. Dort können die empfangenen Befehle (z.B. der Schaltflächen, der Maus, usw.) ausgewertet und verarbeitet werden. In diesem ersten Programm -ein leeres Fenster ohne sonstige Funktion- berücksichtigt die Prozedur beispielsweise nur den Befehl WM_DESTROY, der das Programm mit PostQuitMessage (0); beenden soll. Die folgenden Listings können entweder mit Copy/Paste in Dateien (*.c oder *.cpp) gespeichert bzw. in ein Compilerprojekt eingefügt werden, oder Sie laden gleich alle Beispiele als Zip-Datei beisp.zip herunter. (Den Projekten muß zumindest die Bibliothek-Datei user32.lib beigefügt werden. Bei anderen Anwendungen können z.B. kernel32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib delayimp.lib erforderlich sein. Für Dev-C++: unter "Projektoptionen" Win32-GUI wählen. Für DigitalMax-Kommandozeile: dmc test.c -mn -WA -L/SU:windows .)

// Win32-API: Simple Window (Author: Claude Jacobs, 2013)
#include <windows.h>
//============== Globale Variablen deklarieren =====================
HWND hFenster ; // Handle des Fensters deklarieren

//============== Prozedur des Fensters =============================
LRESULT CALLBACK FensterProzedur (HWND hFenster, UINT Befehle, WPARAM wParam, LPARAM lParam)
 { switch (Befehle) // Befehle unterscheiden
  {case WM_DESTROY: {PostQuitMessage (0); break;} // Programm beenden
   default: {return DefWindowProc (hFenster, Befehle, wParam, lParam);}
  }
return 0; }

//============== HAUPTFUNKTION (und das Fenster erzeugen) ===========
int WINAPI WinMain (HINSTANCE hInstanz, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFensterStil)
 { MSG Befehle; // eine Message-Variable deklarieren

WNDCLASSEX Klasse; // eine Fensterklassen-Variable deklarieren (für wichtige Parameter des Fensters)
  Klasse.lpszClassName = "Hauptfenster" ; // Klassenname
  Klasse.lpfnWndProc = FensterProzedur ; // Name der Prozedur dieses Fensters
  Klasse.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
  Klasse.hCursor = LoadCursor (NULL, IDC_ARROW);
    Klasse.cbSize = sizeof (WNDCLASSEX);
    Klasse.hInstance = hInstanz;
    Klasse.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    Klasse.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.lpszMenuName = NULL; // Fenster hat kein Menü
    Klasse.cbClsExtra = 0;
    Klasse.cbWndExtra = 0;

if ( ! RegisterClassEx (&Klasse)) // Klasse registrieren (oder Fehler anzeigen)
   {MessageBox(hFenster,"Fensterklasse konnte\n nicht registriert werden","Fehler", MB_OK); return 0;}

hFenster = CreateWindow ("Hauptfenster", "Titel des Fensters", WS_OVERLAPPEDWINDOW, // Hauptfenster erzeugen :
   40, 20, 400, 300, HWND_DESKTOP, NULL, hInstanz, NULL);
ShowWindow (hFenster, nFensterStil); // ... und sichtbar machen

while (GetMessage (&Befehle, NULL, 0, 0)) // Dauerschleife (sendet Befehle an obige Fensterprozedur)
  {TranslateMessage(&Befehle); DispatchMessage(&Befehle);}

return Befehle.wParam; }

Erklärung: Die Headerdatei <windows.h> stellt die Funktionsprototypen der typischen Fensteranwendungen bereit. In diesem Bereich des Listings sollten auch globale Variablen deklariert werden (also Variablen, die überall gelten, im Gegensatz zu lokalen, die z.B. nur innerhalb einer Prozedur verwendet werden dürfen). Anschließend folgt hier sogleich die Definition der Fensterprozedur, die verfügbar sein muß, bevor die Hauptfunktion (WinMain) sie aufruft.

Hinweis:
Prozeduren -ebenso wie Variablen- müssen bereits vor ihrer Verwendung deklariert sein. Zur besseren Überschaubarkeit können sie dennoch später im Listing geschrieben werden, wenn sie zuvor vordeklariert wurden :

#include <windows.h>
LRESULT CALLBACK FensterProzedur (HWND, UINT, WPARAM, LPARAM) // Vordeklarieren der untenstehenden Prozedur
//============== Globale Variablen deklarieren =====================
HWND hFenster ;

//============== HAUPTFUNKTION und das Fenster erzeugen ==============
int WINAPI WinMain (HINSTANCE hInstanz, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFensterStil)
  // ... wie oben ...
return Befehle.wParam;}

//============== Prozedur des Fensters =============================
LRESULT CALLBACK FensterProzedur (HWND hFenster, UINT Befehle, WPARAM wParam, LPARAM lParam)
 {switch (Befehle)
   {case WM_DESTROY: {PostQuitMessage (0); break;}
   default: {return DefWindowProc (hFenster, Befehle, wParam, lParam);}
  }
return 0; }

Ein Fenster mit Schaltflächen (Buttons), Textanzeigen (Labels) etc. :
Auf den ersten Blick scheint es etwas verwirrend, daß alle Elemente mit dem gleichen Begriff "Window" -also Fenster- bezeichnet werden. Doch Fenster, Buttons, Labels, CheckBoxes usw. haben weitgehend ähnliche Eigenschaften und können teilweise sogar die Funktionen anderer übernehmen. Sie alle werden mit der Anweisung CreateWindow (bzw. CreateWindowEx mit einigen zusätzlichen Parametern) erzeugt. In diesem Beispiel befinden sie sich im Hauptfenster (Parent), sind diesem also untergeordnet (Child) und ihre Aktivitäten lassen sich in der Prozedur dieses Hauptfensters auswerten. Auf die gleiche Weise können auch die Elemente eines Childfensters in dessen Child-Prozedur abgearbeitet werden (siehe ChildFensterProzedur im letzten Beispiel dieser Seite).

Zum Umwandeln von Zahlen in Strings benötigt man die Header-Datei stdio.h (enthält die Funktion sprintf) und um die Beschriftung von Titelleiste, Buttons, Labels usw. verändern zu können, eventuell winuser.h (erlaubt den Parameter WM_SETTEXT in der SendMessage-Anweisung).

// Win32-API: Simple Window, Buttons, Labels (Author: Claude Jacobs, 2013)
#include <windows.h>
#include <winuser.h> // um WM_SETTEXT zu nutzen
#include <stdio.h> // um sprintf zu nutzen
//============== Globale Variablen deklarieren =====================
HWND hFenster ; // Handle des Fensters deklarieren

HWND hTaster01, hTaster02, hTextFeld01, hTextFeld02; // Handles der Buttons u. Labels deklarieren
#define idTaster01 100 // Taster-Ident.-Nr. festlegen (hier z.B.: 100)
#define idTaster02 101 // Taster-Ident.-Nr.
#define idTextFeld01 200 // Label-Ident.-Nr.
#define idTextFeld02 201 // Label-Ident.-Nr.

int Zahl=3274;
//============== Prozedur des Fensters =============================
LRESULT CALLBACK FensterProzedur (HWND hFenster, UINT Befehle, WPARAM wParam, LPARAM lParam)
 { switch (Befehle) // Befehle unterscheiden
  {case WM_DESTROY: {PostQuitMessage (0); break;} // Programm beenden
  //----------------
  case WM_COMMAND:
   {switch LOWORD(wParam)
   {
   case idTaster01:
    {SendMessage(hTextFeld01, WM_SETTEXT, 0, (LPARAM)"abcd");
    SendMessage(hTaster01, WM_SETTEXT, 0, (LPARAM)"xyz");
   break;}

   case idTaster02:
    {char STR[]=""; sprintf(STR,"%d",Zahl); Zahl++;
    SendMessage(hTextFeld02, WM_SETTEXT, 0, (LPARAM)&STR);
    SendMessage(hTaster02, WM_SETTEXT, 0, (LPARAM)&STR);
   break;}
  }
  break;}
  //----------------
   default: {return DefWindowProc (hFenster, Befehle, wParam, lParam);}
  }
return 0; }

//============== HAUPTFUNKTION (und das Fenster erzeugen) ===========
int WINAPI WinMain (HINSTANCE hInstanz, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFensterStil)
 { MSG Befehle; // eine Message-Variable deklarieren

WNDCLASSEX Klasse; // eine Fensterklassen-Variable deklarieren (für wichtige Parameter des Fensters)
  Klasse.lpszClassName = "Hauptfenster" ; // Klassenname
  Klasse.lpfnWndProc = FensterProzedur ; // Name der Prozedur dieses Fensters
  Klasse.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
  Klasse.hCursor = LoadCursor (NULL, IDC_ARROW);
    Klasse.cbSize = sizeof (WNDCLASSEX);
    Klasse.hInstance = hInstanz;
    Klasse.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    Klasse.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.lpszMenuName = NULL; // Fenster hat kein Menü
    Klasse.cbClsExtra = 0;
    Klasse.cbWndExtra = 0;

if ( ! RegisterClassEx (&Klasse)) // Klasse registrieren (oder Fehler anzeigen)
   {MessageBox(hFenster,"Fensterklasse konnte\n nicht registriert werden","Fehler", MB_OK); return 0;}

hFenster = CreateWindow ("Hauptfenster", "Titel des Fensters", WS_OVERLAPPEDWINDOW, // Hauptfenster erzeugen :
  40, 20, 400, 300, HWND_DESKTOP, NULL, hInstanz, NULL);
//-------------------------- Weitere Elemente des Fensters erzeugen:
hTaster01 = CreateWindow ("BUTTON", "Test 1", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_CENTER,
  10, 10, 50, 18, hFenster, (HMENU)idTaster01, (HINSTANCE) GetWindowLong(hFenster, GWL_HINSTANCE), NULL);

hTaster02 = CreateWindow ("BUTTON", "Test 2", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_CENTER,
  10, 30, 50, 18, hFenster, (HMENU)idTaster02, (HINSTANCE) GetWindowLong(hFenster, GWL_HINSTANCE), NULL);

hTextFeld01 = CreateWindow ("STATIC", "Textfeld 1", WS_VISIBLE|WS_CHILD|BS_CENTER,
  65, 10, 70, 18, hFenster, (HMENU)hTextFeld01, (HINSTANCE) GetWindowLong(hFenster, GWL_HINSTANCE), NULL);

hTextFeld02 = CreateWindow ("STATIC", "Textfeld 2", WS_VISIBLE|WS_CHILD|BS_CENTER,
  65, 30, 70, 18, hFenster, (HMENU)hTextFeld02, (HINSTANCE) GetWindowLong(hFenster, GWL_HINSTANCE), NULL);
//---------------------------------
ShowWindow (hFenster, nFensterStil); // ... und sichtbar machen

while (GetMessage (&Befehle, NULL, 0, 0)) // Dauerschleife (sendet Befehle an obige Fensterprozedur)
  {TranslateMessage(&Befehle); DispatchMessage(&Befehle);}

return Befehle.wParam; }

Ein zusätzliches Child-Fenster erzeugen :
Als Child ("Kind") bezeichnet man ein Element, das einem anderen untergeordnet ist, also auch ein sekundäres Fenster. Da im vorigen Beispiel die meisten Klassen-Parameter des Hauptfensters auch für das neue Childfenster gültig sind und übernommen werden können, brauchen nur einige davon verändert und die Klasse erneut registriert zu werden. Dem neuen Fenster ordnet man ebenfalls eine eigene Prozedur zu -hier ChildFensterProzedur genannt-, welche die Aktivitäten dieses Fensters verwaltet. (Die Anweisung zum Beenden des Programms PostQuitMessage(0); sollte verständlicherweise eher nur vom Hauptfenster ausgehen.)

// Win32-API: Simple Child-Window (Author: Claude Jacobs, 2013)
#include <windows.h>
//============== Globale Variablen deklarieren =====================
HWND hFenster, hChildFenster ; // Handles der Fenster deklarieren

//============== Prozeduren der einzelnen Fenster ==================
LRESULT CALLBACK FensterProzedur (HWND hFenster, UINT Befehle, WPARAM wParam, LPARAM lParam)
 { switch (Befehle) // Befehle unterscheiden
  {case WM_DESTROY: {PostQuitMessage (0); break;} // Programm beenden
   default: {return DefWindowProc (hFenster, Befehle, wParam, lParam);}
  }
return 0; }

LRESULT CALLBACK ChildFensterProzedur (HWND hChildFenster, UINT Befehle, WPARAM wParam, LPARAM lParam)
 { switch (Befehle)
// Befehle unterscheiden
    {
    default: {return DefWindowProc (hChildFenster, Befehle, wParam, lParam);}
    }
return 0; }


//========== HAUPTFUNKTION (und die beiden Fenster erzeugen) =======
int WINAPI WinMain (HINSTANCE hInstanz, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFensterStil)
 { MSG Befehle; // eine Message-Variable deklarieren

WNDCLASSEX Klasse; // eine Fensterklassen-Variable deklarieren (für wichtige Parameter des Fensters)
  Klasse.lpszClassName = "Hauptfenster" ; // Klassenname
  Klasse.lpfnWndProc = FensterProzedur ; // Name der Prozedur des Hauptfensters
  Klasse.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
  Klasse.hCursor = LoadCursor (NULL, IDC_ARROW);
    Klasse.cbSize = sizeof (WNDCLASSEX);
    Klasse.hInstance = hInstanz;
    Klasse.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    Klasse.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    Klasse.lpszMenuName = NULL; // Fenster hat kein Menü
    Klasse.cbClsExtra = 0;
    Klasse.cbWndExtra = 0;

if ( ! RegisterClassEx (&Klasse)) // Klasse registrieren (oder Fehler anzeigen)
   {MessageBox(hFenster,"Fensterklasse konnte\n nicht registriert werden","Fehler", MB_OK); return 0;}

hFenster = CreateWindow ("Hauptfenster", "Titel des Fensters", WS_OVERLAPPEDWINDOW, // Hauptfenster erzeugen :
   40, 20, 400, 300, HWND_DESKTOP, NULL, hInstanz, NULL);

//-------- Child-Fenster:
  Klasse.lpszClassName = "Childfenster" ; // Klassenname
  Klasse.lpfnWndProc = (WNDPROC)ChildFensterProzedur; // Name der Prozedur dieses Fensters
  Klasse.hCursor = LoadCursor(NULL, IDC_CROSS); // Cursor als Kreuz
  Klasse.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;

if ( ! RegisterClassEx (&Klasse)) // Klasse registrieren (oder Fehler anzeigen)
  {MessageBox(hFenster,"ChildFensterklasse konnte\n nicht registriert werden","Fehler", MB_OK); return 0;}

hChildFenster = CreateWindowEx (0, "Childfenster", "Titel des Child-Fensters",
   WS_OVERLAPPEDWINDOW | WS_VISIBLE |WS_CLIPSIBLINGS,
   300, 250, 250, 200, hChildFenster, NULL, hInstanz, NULL);

//--------

ShowWindow (hFenster, nFensterStil); // ... und sichtbar machen

while (GetMessage (&Befehle, NULL, 0, 0)) // Dauerschleife (sendet Befehle an die Fensterprozeduren)
  {TranslateMessage(&Befehle); DispatchMessage(&Befehle);}

return Befehle.wParam; }
INDEX NEXT
© 2013 by Claude Jacobs URL: http://homepages.internet.lu/absolute3/tronic/default.htm

Weiterführende Links:
http://cplus.kompf.de/links.html (Umfangreiche Linksammlung: C/C++ in versch. Bereiche untergliedert)
http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html (Bücher zum Download: C u. C++)
http://openbook.galileocomputing.de/c_von_a_bis_z/ ("C von A bis Z")
http://www.cplusplus.com/ (C/C++, allgemein)
http://www.carabez.com/downloads.html (u.a. versch. win32api Help-Dateien)
http://www.cs.virginia.edu/~lcc-win32/ download: Windows API documentation (win32api Help-Datei)
http://win32asm.rxsp.com/download.html (Win32.hlp, including graphics)

DISCLAIMER: THIS SITE CONTAINS LINKS TO THIRD-PARTY WEBSITES, WHICH ARE NOT UNDER THE CONTROL OF STS.
THESE LINKS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
© 2013: STS Selected Technology Sites, all rights reserved.