|
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.
|
|
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; }
|
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.
|
|