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
© Copyright 2024 ExpyDoc