Win32

6. Betriebssysteme und
Windows-Fenster/Grafikprogrammierung
Inhalt:
A. Rechnerhardware, Betriebssystem und Programme
B. Win32 – Programmierung mit Fenstern und
Grafikausgabe
Peter Sobe
1
Rechnerhardware, Betriebssystem und Programme
Das C-Programm wird als Prozess ausgeführt, z.B. als:




Win32-Konsolenanwendung in einem Textfenster
CLR-Konsolenanwendung
Win32 – Fensteranwendung (mit Haupt-Window)
als UNIX/LINUX-Programm mit/ohne grafische
Benutzeroberfläche
Das Betriebssystem (Windows, UNIX/LINUX und änhliche)
stellt dem Programm eine Ausführungsumgebung bereit.
Nur in ganz besonderen Systemen läuft das Programm
ohne Betriebssystem direkt auf der Hardware.
Peter Sobe
2
Aufgaben des Betriebssystems (1)
Das Betriebssystem (engl. Operating System) virtualisiert die
Hardware für die laufenden Programme.
Speicherverwaltung:
Jedes Programm kann einen eigenen Adressraum benutzen, der für
jedes Programm einen gleichartigen Adressbereich bedeutet. Das
Betriebssystem regelt, dass die Programmadressräume auf getrennte
physikalische Speicheradressen „geschaltet“ werden.
Die MMU (Memory Management Unit) ist eine Funktionseinheit, die
die Adressumsetzung vornimmt. Die dazu benötigten Tabellen werden
durch das Betriebssystem mit Inhalt gefüllt.
Speicherschutz: Ein Anwendungsprogramm kann seine eigenen
Speicherbereiche verändern – aber nicht auf den Speicher
anderer Programme und des Betriebssystem zugreifen (Ausnahmen
für gemeinsamen Speicher sind möglich).
Peter Sobe
3
Aufgaben des Betriebssystems (2)
Prozessverwaltung:
Jedes laufende Programm (Prozeß) wird wie auf einem eigenen
Prozessor ausgeführt, obwohl i.d.R. mehrere Prozesse auf
einem oder einigen wenigen Prozessoren ausgeführt werden.
Das Betriebssystem regelt die Zuteilung von Prozessoren und
Zeitscheiben an die Prozesse.
Scheduling (Planung der Zeitzuteilung):
 Prozesse, die auf Eingaben oder Nachrichten aus dem Netz
warten, werde solange deaktiviert. Andere Prozesse können
arbeiten (laufen bzw. rechnen).
 Mehrere nicht-wartende Prozesse bekommen die
Prozessoren im kurzen Zeitscheiben zugeteilt (einige ms).
Die Verteilung kann durch Prioritäten beeinflusst werden.
Peter Sobe
4
Aufgaben des Betriebssystems (3)
Ein- und Ausgabe (E/A):
Die verschiedenen E/A-Klassen werden durch das
Betriebssystem virtualisiert.
 Tastatur und Bildschirm – stdin, stdout, stderr
 Festplatte(n), Speichermedien – Darstellung als Dateisystem
mit Verzeichnissen, Dateien und zusätzlichen Informationen
(Erstellungsdatum, Zugriffsrechte, u. ä.)
 Netzwerk und entfernte Rechner – das lokal laufende
Betriebssystem erlaubt, einzelne Nachrichten (s.g. Pakete)
an andere Prozesse zu senden oder Ströme zu anderen
Prozessen aufzubauen.
Gerätetreiber zur Anbindung von speziellen Geräten
(Grafikkarten, Netzwerkkarten, Drucker, etc.) an die
Betriebssystem-Schnittstellen.
Peter Sobe
5
Aufgaben des Betriebssystems (4)
Auch die grafische Benutzeroberfläche ist zumindest bei MSWindows ein Teil des Betriebssystems.
Prozesse können dabei mehrere Fenster öffnen, Elemente
(Knöpfe, Auswahlboxen, Textboxen, Grafikbereiche,
Schiebebalken u.ä.) darstellen und durch eigene Funktionen
programmieren.
Bei unixartigen Betriebssystemen ist die grafische
Benutzeroberfläche ein eigenständiger Prozess, der wie die
Anwendungen unter Steuerung des Betriebssystems ausgeführt
wird. Die Anwendungen benutzen Bibliotheken zur Gestaltung
ihrer Benutzeroberfläche, die mit dem Prozess für die
Benutzeroberfläche kommunizieren.
Peter Sobe
6
Gesamtbild des Betriebssystems
Befehlsausführung
(für Anweisungen)
AnwendungsAnwendungsprozeß
Anwendungsprozeß
prozeß
Speicherzugriff
(z.B. Variable, Felder)
Ein- und Ausgabe
Rechnerhardware
Betriebssystem
ProzessVerwaltung
Speicherverwaltung:
Tabellen zu
Adressumsetzung
Dateisystem
und Gerätetreiber
Prozessor-Befehle
und Register
Peter Sobe
MMU
Physikalischer Speicher
7
Abgrenzung vom Betriebssystem
Keine Teile des Betriebssystems sind:
 Texteditoren, Media-Player und sonstige ZubehörProgramme (obwohl diese für den „Konsumenten“ oft als
Bestandteile des Betriebssystems dargestellt werden.)
 Entwicklungsumgebungen, Übersetzer, u.ä.
 Kommandointerpreter, Web-Browser
Das sind typischerweise auch Anwendungsprogramme.
Peter Sobe
8
Win32-Fenster-Programmierung
Fensterbasierte Anwendungen können durch Benutzung der
Win32-Anwendungsschnittstelle (API) oder durch Verwendung
der MFC (C++ Microsoft Foundation Classes) erstellt werden.
Win32: durch Auswahl Projekttyp „Win32“ innerhalb
Visual Studio wird beim Erstellen ein Codegerüst für eine
Fensteranwendung mit minimaler Grundfunktionalität erstellt.
Hauptfenster – zum Aufnehmen von Text und Grafik
Menu – mit Standardeinträgen “Datei/Beenden“
und “Hilfe/Info…“
Peter Sobe
9
Die Windows-API (Win32)
Um Windows-Programme mit einer Fensteroberfläche zu erzeugen,
benötigen Nicht-Microsoft-Programmierer einen Zugriff auf Windowsinterne Funktionen – ein Application Programming Interface (API)
Die Windows-API fasst eine große Anzahl von Windowsfunktionen in einer Schnittstelle zusammen
•
die erste Windows-API basierte noch auf einer reinen CProgrammierung und bot nur reine C-Funktionen an
•
später wurde eine objektorientierte Schicht darüber gesetzt - die
Microsoft Foundation Classes MFC (C++)
-
Es gibt auch noch weitere objektorientierte Windows/GUIProgrammierschnittstellen (z.B. Qt)
R. Grossmann / P.Sobe
10
allgemeine Architektur einer Windowsanwendung
•
•
Anstelle des main() gibt es eine Funktion WinMain(). Diese Funktion wird
nach dem Start der Anwendung aufgerufen.
In WinMain() wird in der Regel das erste Fenster oder eine andere
Dialogform generiert.
• Die allgemeine Anwendungsfensterklasse wird zusammen mit einer
sogenannten CALLBACK-Routine bei Windows registriert (bekannt
gemacht in der windowsinternen Verwaltung)
• Nach dem Definieren der Fensterparameter wird das Fenster sichtbar
gemacht
• abschließend wird eine Schleife zur Abfrage und Verarbeitung von
Windows-Nachrichten gestartet, welche erst bei einem angeforderten
Beenden der Applikation verlassen wird
• Windows ruft von sich aus die CALLBACK-Routine auf, falls für das
zugehörige Fenster Nachrichten vorliegen
• Unter Fenster sind auch alle Bedienelemente wie Tasten, Eingabefelder
und Boxen zu verstehen, welche hierarchisch verknüpft sind.
R. Grossmann / P.Sobe
11
Das Nachrichtensystem von WINDOWS
Windows-Applikation
Fenster mit Callbackfunc.
WndProc zur Reaktion
auf Ereignisse
WinMain ( )
Fenstererzeugung/Registrierung
while (getmessage)
{ dispatchmessage }
2.
3.
0.
Start
Nachrichtenwarteschlange
Kodierung und
Windows-Betriebssystem Ablage als Nachricht
Fensterverwaltung
(Sichtbarkeit / Ereigniszuordn.)
1. Hardwareereignis (z.B. Mausklick)
12
Hardware
( Bildschirm, Tastatur, Maus, Massenspeicher, Drucker, ...)
Die WinMain-Funktion
Funktionskopf der WinMain-Funktion:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow);
Erläuterungen:
 HINSTANCE- Handle auf Anwendungsinstanz - ermöglicht dem System
die eindeutige Zuordnung einer gestarteten Anwendung
 PrevInstance- Handle der vorherigen Instanz, bedeutungslos ab WIN32
(immer NULL)
 LPSTR lpCmdLine- Komandozeile (Zeichenkette) (entspricht: char*)
 nCmdShow- legt fest wie die Anwendung gestartet wird (maximiert,
minimiert etc.)
R. Grossmann / P.Sobe
13
Die Nachrichtenschleife von WinMain
Windows setzt jede Aktion des Benutzers in eine Nachricht um
und speichert diese in einer Nachrichtenwarteschlange
Jede Anwendung muss diese Nachrichtenwarteschlange
zyklisch abfragen.
while (GetMessage(&msg, NULL, 0, 0))
{ TranslateMessage(&msg); // Umsetzen von Tastatureingaben
DispatchMessage(&msg);
// Verteilung an die Fenster
}
R. Grossmann / P.Sobe
14
Die Callback-Fensterprozedur
•
Windows ermittelt für jede Nachricht den zugehörigen Empfänger in
Abhängigkeit von der Sichtbarkeit
•
An das Fenster (auch eine Taste oder Eingabeelement) wird über einen
Callback eine bereits etwas entschlüsselte Nachricht gesendet:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage,
WPARAM wParam, LPARAM lParam)
Erläuterung:
hWnd- Fensterhandle des entsprechenden Fensters (= FensterID)
uiMessage- Nachrichtenkonstante in der Form WM_x (WM: Window Message)
-> ganze Zahl / vordefinierte Konstanten in Windows
wParam- 1. Parameter (Bedeutung abhängig vom uiMessage-Wert)
lParam - 2. Parameter (beide Parameter sind 32bit integer)
LRESULT – 32bit ganzzahliger Rückgabewert (normalerweise 0)
R. Grossmann / P.Sobe
15
Die Bearbeitung von Windows-Nachrichten
Für jedes Fenster wird eine Fensterfunktion angegeben, die die einzelnen
an das Fenster gerichteten Nachrichten verarbeitet.
Das erfolgt meist mit einer CASE-Selektion.
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);
}
Falls ein Nachrichtentyp nicht bearbeitet wird, erfolgt mit DefWindowProc
eine Übergabe zur Standardbearbeitung an Windows. Die dargestellte
case-Mehrfachselektion kann als Vorlage für das Schließen und Beenden
16
einer Windows-Anwendung übernommen werden.
Vordefinierte Fensterklassen
•
Auf der graphischen Oberfläche können beliebig konfigurierte Fenster
platziert werden. Jedes Dialogfeld, jedes Eingabefeld, jede Schaltfläche und
auch jedes Textfeld ist ein Fenster.
•
Jedes Fenster besitzt eine Fensterklasse, welche in einer Struktur die
grundsätzlichen Einstellungen des Fenster speichert. Sie enthält u.a. einen
eindeutigen Namen, Informationen über Hintergrundfarbe, Menü, Verhalten
beim Ändern der Größe etc. Anhand des Namens können beliebig viele
Fenster ein und derselben Fensterklasse erstellt werden.
•
Die Windows-API stellt einige vordefinierte Fensterklassen bereit, die
wichtigsten davon sind:
edit
button
static
combobox
listbox
R. Grossmann / P.Sobe
Eingabefeld
Schaltfläche (auch Radio-feld)
für Textfelder
Auswahlbox (z.B. bei Auswahl von Schriftarten)
Listenfeld
17
Eintragungen in der Fensterklassen-Struktur
Bekanntmachen der Fensterklasse im Hauptprogramm:
WNDCLASS wndclass;
wndclass.style
= CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = fenst;
wndclass.hIcon
= LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor
= LoadCursor(NULL, IDC_CROSS);
wndclass.hbrBackground= (HBRUSH)
GetStockObject(LTGRAY_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName= szAppName;
RegisterClassEx(&wndclass);
R. Grossmann / P.Sobe
18
Erzeugen eines Fensters
f= CreateWindow(szAppName,
//Name der Fensterklasse
"Fenster mit Sinus-Kurve",
//Fenstertitel
WS_OVERLAPPEDWINDOW |
//Fensterstil
WS_VISIBLE,
100,
//x-Wert linke obere Ecke
200,
//y-Wert linke obere Ecke
300,
//Fensterbreite
300,
//Fensterhöhe
NULL,
//Vaterfenster
NULL,
//Menü
fenst,
//Programmzähler
NULL);
//zusätzliche Parameter
// Display the window to the user
ShowWindow(f, SW_SHOWNORMAL);
UpdateWindow(f);
R. Grossmann / P.Sobe
19
Mausnachrichten
Alle Mausbewegungen werden als Nachrichten kodiert:
•
WM_MOUSEMOVE- Maus wird bewegt
WM_LBUTTONDOWN- Linke Maustaste wird gedrückt
WM_LBUTTONUP- Linke Maustaste wird losgelassen
WM_RBUTTONDOWN- Rechte Maustaste wird gedrückt
WM_RBUTTONUP- Rechte Maustaste wird losgelassen
WM_MBUTTONDOWN- Mittlere Maustaste wird gedrückt
WM_MBUTTONUP- Mittlere Maustaste wird losgelassen
•
Die Nachrichtenparameter enthalten die Koordinaten und weitere Infos.
•
Die Koordinaten sind relativ zum Fensterursprung (linke obere Ecke).
•
Der Parameter 'wParam' besteht aus einer Kombination von Konstanten,
die jeweils angeben ob eine weitere Taste gedrückt ist oder nicht.
signed int xPos = LOWORD(lParam); //X-Koordinate
signed int yPos = HIWORD(lParam); //Y-Koordinate
R. Grossmann / P. Sobe
20
MessageBox-Funktion
Die Funktion MessageBox hat vier Parameter. Als Rückkehrwert wird
der int Wert der Taste gesendet, die gedrückt wurde. Die Tastencodes
sind definiert über IDOK , IDYES, IDNO, IDCANCEL usw.
Beispiel:
if (MessageBox(hwnd,"Fenster schliessen","Nachricht",
MB_YESNOCANCEL|MB_DEFBUTTON2|
MB_ICONQUESTION)==IDYES) { … }
Der 1.Parameter ist ein Fensterhandle (zu welchem Fenster gehört die
MB). Der 2.Parameter stellt den Text der MB dar. Der 3.Parameter stellt
den MB-Titel dar. Der 4.Parameter enthält die Buttons (max. drei
möglich), den Button, der den Fokus erhält und ggf. Symbole zur
Darstellung.
Konstanten: MB_OK, MB_YESNO,MB_YESNOCANCEL,MB_IGNORERETRY
Fokus: MB_DEFBUTTONi
i=1,2,3 (Button i erhält Fokus)
Symbol: MB_ICONQUESTION, MB_ICONINFORMATION,
MB_ICONEXCLAMATION, MB_ICONHAND
21
Das Graphic Device Interface (GDI)
Zum Ausgeben von Text und dem Zeichnen grafischer Elemente steht eine
relativ leistungsfähige Bibliothek bereit – das Graphic Device Interface (GDI).
•
Die GDI ist hardwareunabhängig. Ein Kreis wird sowohl auf dem Bildschirm
als auch auf dem Drucker mit gleichen Befehlen gezeichnet. Die
Unterscheidung erfolgt durch dem sogenannten Gerätekontext (Device
Context – definiert in Datenstruktur HDC -Handle to Device Context) .
•
Der Device Context muss vor dem Zeichen erzeugt und nach dem Zeichnen
wieder freigeben werden (häufiger Fehler mit Ressourcenverbrauch):
HDC hDC = GetDC(hWnd); // Erzeugung des Device Context
/* --- Zeichenoperationen --- ... */
ReleaseDC(hDC); // Freigabe des Device Context
hDC = NULL;
R. Grossmann / P. Sobe
22
Die Zeichenfunktionen der GDI
Die Grundfunktionen für das Zeichnen von Grafik und Text unter Windows sind:
•
Rectangle(hDC, Left, Top, Right, Bottom) - zeichnet ein Rechteck in dem
angegebenen Rechteck
•
Ellipse(hDC, Left, Top, Right, Bottom) - zeichnet eine Ellipse in dem
angegebenen Rechteck
•
MoveToEx(hDC, X, Y, &pt) - setzt die Zeichenposition und speichert die
alte in 'pt'
•
LineTo(hDC, X, Y) - malt eine Linie von der aktuellen Zeichenposition
zu dem angegebenen Punkt
•
TextOut(hDC,X,Y,"text",count) - zeichnet einen Text auf den DC
•
Polyline(hDC, Point, Anzahl) - Polygonzug, Point ist ein Punkt-Vektor,
der die x-y-Koordinaten der Punkte des Polygons enthält; Anzahl gibt die
Anzahl der Punkte im Vektor an
R. Grossmann / P. Sobe
23
Farben und Muster bei Zeichenfunktionen
•
Die Zeichenfunktionen enthalten keine Parameter für Farbe und Stil.
•
Aus Effizienzgründen sind diese Parameter global einzustellen.
•
Die Füllfarbe wird definiert mit einem Pinsel (Brush)
HBRUSH hBrush = CreateSolidBrush(RGB(0,255,0));
// oder einer Farbkonstanten
•
Die Linieneigenschaften werden definiert mit einem Stift (Pen)
HPEN hPen = CreatePen(Style, Width, cl);
mit Style = PS_SOLID oder PS_DASH oder PS_DOT oder Kombinationen
•
Sowohl Pinsel wie Stift müssen dem GDC bekannt gemacht werden und
sollten nach Gebrauch wieder auf den alten Wert rückgesetzt werden:
HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush );
/* --- Zeichenoperationen --- ... */
DeleteObject(SelectObject(hDC, hOldBrush));
hBrush = NULL;
24
Win32-Beispiel (1)
Win32 – Programmskelett, von Visual Studio automatisch erzeugt:
#include "resource.h"
…
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_UHRGRAFIK, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); // hier wird das Hauptfenster angelegt und
// die WndProc()-Funktion angegeben
// Anwendungsinitialisierung ausführen:
if (!InitInstance (hInstance, nCmdShow) ) // hier wird CreateWindow ausgerufen
return FALSE;
…
Peter Sobe
25
Win32-Beispiel (2)
Win32 – Fortsetzung Programmskelett:
// Hauptnachrichtenschleife:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{ TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
Durch GetMessage(), TranslateMessage() und DispatchMessage()
werden Ereignisse (z.B. Auswahl eines Menüpunkts, Mausklick in einen
Fensterbereich) verarbeitet und an die Fensterfunktionen WNDProc
weitergereicht. Für jedes Fenster kann eine solche Funktion
programmiert werden, die dann anwendungsspezifische Aktionen umsetzt.
Peter Sobe
26
Win32-Beispiel (3)
Win32 – Fortsetzung Programmskelett:
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style
= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc
= WndProc; // hier wird Fensterfunktion angegeben
wcex.cbClsExtra
= 0;
wcex.cbWndExtra
= 0;
wcex.hInstance
= hInstance;
wcex.hIcon
= LoadIcon(hInstance, ….
wcex.hCursor
= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground
= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName
= MAKEINTRESOURCE(IDC_WIN32_WIZARD);
wcex.lpszClassName
= szWindowClass;
wcex.hIconSm
= LoadIcon(wcex.hInstance, …
return RegisterClassEx(&wcex);
}
Peter Sobe
27
Win32-Beispiel (4)
Win32 – Fortsetzung Programmskelett:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Peter Sobe
28
Win32-Beispiel (5)
Win32 – Fortsetzung Programmskelett:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{ int wmId, wmEvent;
PAINTSTRUCT ps; HDC hdc;
switch (message)
{
case WM_COMMAND:
// typisch für Menüauswahl-Ereignisse
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) // Menüauswahl bearbeiten:
{ case IDM_ABOUT: DialogBox(hInst, …); break;
case IDM_EXIT: DestroyWindow(hWnd); break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
…
Peter Sobe
29
Win32-Beispiel (6)
Win32 – Fortsetzung Programmskelett:
…
case WM_PAINT: // ausgelöstes Ereignis, wenn Fenster erscheint
hdc = BeginPaint(hWnd, &ps);
// Hier den Zeichnungscode hinzufügen.
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
} // end switch message
return 0;
}
Peter Sobe
30