Systemschnittstellen - online
Transcrição
Systemschnittstellen - online
Systemschnittstellen Stand: 16.10.03 Skript Systemschnittstellen Thomas Kowarsch Stand: 16.10.03 © Thomas Kowarsch Seite 1/101 Systemschnittstellen Stand: 16.10.03 Inhaltsverzeichnis 1.Allgemeines........................................................................................5 1.1.Übungen...................................................................................... 5 1.2.Literatur....................................................................................... 6 1.3.Inhalt........................................................................................... 7 1.4.Systeme....................................................................................... 7 1.4.1.Plattform................................................................................ 7 1.4.2.Softwareumgebung.................................................................. 7 1.4.3.Begriff System........................................................................ 7 1.4.4.Statisches System................................................................... 8 1.4.5.Stationäre Systeme................................................................. 8 1.4.6.Dynamische Systeme............................................................... 8 1.4.7.Geschlossene Systeme............................................................. 8 1.4.8.Offene Systeme....................................................................... 8 2.Betriebssysteme.................................................................................9 2.1.Allgemeines.................................................................................. 9 2.1.1.Abstraktion............................................................................. 9 2.1.2.Gründe für den Erfolg des PCs................................................... 9 2.2.UNIX.......................................................................................... 10 2.3.Windows 2000/NT/XP................................................................... 10 2.3.1.Windows Versionen................................................................ 10 2.3.2.NT Charakteristika................................................................. 11 2.3.3.Dateisysteme........................................................................ 11 2.4.Chronologisches........................................................................... 12 3.WinDOS............................................................................................13 3.1.GUI............................................................................................ 13 3.1.1.Anwendungsprogrammierung unter MS-DOS.............................. 13 3.1.2.Windows-Programmierung...................................................... 13 3.1.3.GUI - Grafic user interface...................................................... 14 3.1.4.Ziel der GUI.......................................................................... 14 3.1.5.Tendenz............................................................................... 15 3.1.6.Konsequenzen....................................................................... 15 3.2.Herkömmliche Programmierung..................................................... 15 3.3.Callback..................................................................................... 16 3.3.1.Einrichtung einer Plattform-Routine zur Aufnahme eines Zeigers auf eine C-Funktion............................................................................. 16 3.4.Events........................................................................................ 17 3.4.1.Definition.............................................................................. 17 3.5.WinDos....................................................................................... 18 3.5.1.Feedback.............................................................................. 19 4.OpenGL und GLUT............................................................................ 20 4.1.Fensterumgebung........................................................................ 20 © Thomas Kowarsch Seite 2/101 Systemschnittstellen Stand: 16.10.03 4.2.GLUT.......................................................................................... 20 4.3.Design – Philosophie..................................................................... 21 4.4.Funktionalitäten........................................................................... 22 4.5.Programmierung.......................................................................... 23 4.5.1.Visual Studio......................................................................... 23 4.5.2.Initialisierung........................................................................ 23 4.5.3.Start der Ereignisverarbeitung................................................. 23 4.5.4.Fenster Verwaltung................................................................ 24 4.6.Zusatztools für GLUT.................................................................... 24 4.6.1.GLUI.................................................................................... 24 4.6.2.PLIB.................................................................................... 25 4.6.3.MUI..................................................................................... 25 4.7.GLUT Befehle.............................................................................. 25 5.Win32...............................................................................................26 5.1.Datentypen................................................................................. 26 5.2.Ungarische Notation..................................................................... 33 5.3.Librarys...................................................................................... 36 5.4.Resourcen................................................................................... 36 5.5.Übersetzung................................................................................ 37 6.Betriebssystem - Kern......................................................................37 6.1.Hauptfunktion.............................................................................. 48 6.2.Registrierung............................................................................... 49 6.2.1.WNDCLASSEX-Struktur........................................................... 49 6.2.2.RegisterClassEx..................................................................... 50 6.3.Initialisierung.............................................................................. 51 6.3.1.CreateWindowEx.................................................................... 51 6.3.2.ShowWindow........................................................................ 52 6.3.3.UpdateWindow...................................................................... 54 6.4.Hauptnachrichtenschleife............................................................... 54 6.4.1.GetMessage.......................................................................... 54 6.4.2.TranslateMessage.................................................................. 55 6.4.3.DispatchMessage................................................................... 55 6.5.CALLBACK - Funktion.................................................................... 56 6.5.1.WM_PAINT - Nachricht........................................................... 56 6.5.2.Bildschirmausgabe................................................................. 57 6.5.2.a)Device Kontext.......................................................................................... 57 6.5.2.b)BeginPaint(), EndPaint()............................................................................ 62 6.5.3.Schliessen von Fenstern/Applikation......................................... 65 6.5.4.Tastatur - Nachrichten............................................................ 66 6.5.4.a)Wie kann eine gedrücke SHIFT - Taste abgefragt werden?..................... 71 6.5.4.b)Wie kann eine Berechnung abgebrochen werden?.................................. 71 6.5.4.c)Wie kann eine gedrückte CTRL - Taste ( VK_CONTROL ) per Programm simuliert werden?................................................................................................... 72 6.5.4.d)Wie kann die CAPS - LOCK - Taste ( VK_CAPITAL ) invertiert werden?. 72 © Thomas Kowarsch Seite 3/101 Systemschnittstellen Stand: 16.10.03 6.5.4.e)Wie kann ein "floating - pop - up - menu" nach der Anzeige sichtbar bleiben?................................................................................................................. 72 6.5.5.Maus - Nachrichten................................................................ 73 6.5.6.DefWindowProc..................................................................... 77 6.6.Dialoge....................................................................................... 78 6.6.1.Modale Dialoge...................................................................... 78 6.6.1.a)Beispiel: DialogBox als Hauptprogramm................................................... 81 6.6.1.b)About-Dialog.............................................................................................. 84 6.6.1.c)Aufruf des About-Dialogs:.......................................................................... 84 6.6.2.Modless Dialoge..................................................................... 85 6.6.2.a)CreateDialog() - Aufruf.............................................................................. 86 6.6.3.Controls............................................................................... 86 7.Dynamic-Link Library's.................................................................... 88 7.0.1.Wie löst der Linker die DLL_Einsprünge auf?.............................. 89 7.0.2.Wie wird diese DLL benutzt?.................................................... 93 8.Daemon............................................................................................94 8.1.Schreiben von Daemon ................................................................ 95 8.2.Beispiel...................................................................................... 97 8.3.Fehlermeldungen......................................................................... 97 8.4.Prozessgruppen und Sessions........................................................ 98 8.5.WebServer.................................................................................. 99 © Thomas Kowarsch Seite 4/101 Systemschnittstellen Stand: 16.10.03 1.Allgemeines 1.1.Übungen Die Gesamtpunktezahl wird mit maximal 15% auf die Klausur angerechnet. Es gelten hierfür alle Übungen ausser Zeiger und WinDOS. Alle Übungen sind selbst oder in Gruppen zu erarbeiten. Jede Datei (*.cpp;*.h) muss oben im Dokument den/die Namen des/der Autoren mit Matrikelnummer enthalten. Es gibt max 3 Punkte für jede vollständig richtig abgegebe Übung; 2 Punkte, falls kleinere Fehler vorhanden sind; 1 Punkt, falls die Aufgabe nur teilweise/ansatzweise erfüllt wurde. Für besondere Features wird ein Bonus in Form eines + vergeben. Abgabe: Die Abgabe wird mündlich in der Übungsstunde vorgenommen. Die Übungen müssen an dem Stichtag (wird vorher in der Vorlesung und auf der Webseite bekannt gegeben) in der von Ihnen eingetragenen Übungsstunde abgegeben werden. Für jede Folgestunde, in der die Übungen nach den Stichtag abgegeben werden, wird die Punktzahl incrementiert. (z.B. wird die Übung eine Woche später abgegeben, können nur noch max. 2 Punkte erreicht werden) © Thomas Kowarsch Seite 5/101 Systemschnittstellen Stand: 16.10.03 1.2.Literatur • Charles Petzhold: „Windows Programmierung“, Microsoft Press, 2000, 1300+ S. (59,90 €, inkl. CD mit Original, in der Bibliothek) • „Die Programmiersprache C. Ein Nachschlagewerk“, RRZN 1995 • B.W.Kernighan, D.M.Ritchie: „Programmieren in C“ (2.Ausgabe, ANSIC), Carl Hanser Verlag 1990 • M.A.Ellis, B.Stroustrup: „The Annotated C++ Reference Manual“ (ANSIBase Document), Addison-Wesley Publishing Company 1991 • Andrew S. Tanenbaum: „Betriebssysteme - Entwurf und Realisierung“ Carl Hanser Verlag 1990 Weitere Skripte: – Prof. Dr. Bachmann: http://homepages.fh-giessen.de/~hg54/ – Prof. Dr. Christidis: http://homepages.fh-giessen.de/~hg11237/ *Hier muss der eigene Name und Matrikelnummer stehen © Thomas Kowarsch Seite 6/101 Systemschnittstellen Stand: 16.10.03 1.3.Inhalt Ausgewählte Plattformen und Softwareumgebungen, sowie deren Strunktur, Funktionsweisen und Softwareimplementierungen unter ihnen. Schwerpunkt: C, Windowsprogrammierung 1.4.Systeme 1.4.1.Plattform Unter einer Plattform versteht man die tiefste Hardwarenächste genutzte Schicht. In der Regel handelt es sich hierbei um das Betriebsystem. 1.4.2.Softwareumgebung Eine Softwareumgebung ist eine Sammlung von Programmen oder Programmteilen, die zur bestimmten Nutzung die Kommunikation mit der Plattform übernehmen. (vgl. Sw-Paket, -Bibliothek, -Entwicklungsumgebung, 4DOS, OpenGL, Windows95) 1.4.3.Begriff System Ein System ist eine Menge von Komponenten, (Gegenständen, Individuen, Größen, Prozessen, Ideen), die untereinander in einer kausalen Wechselwirkung stehen und von ihrer Umwelt entweder als abgeschlossen oder als in einer wohldefinierten Beziehung stehend betrachtet werden können sowie die Gesamtheit der unter ihnen herrschenden Beziehungen. Die Existenz von Systemen ist meist mit der Erfüllung eines Zweckes verbunden (vgl. technische, politische, soziale, Regal-, Gleichungsoder Planetensysteme). Im Sinne dieser Definition kann jedes System in beliebig viele Teil- oder Subsysteme zerlegt werden, sofern dies sinnvoll erscheint. Der Begriff “System” ist ein Idealtypus (erzeugt durch gedanklich einseitige Steigerung bestimmter Elemente der Wirklichkeit): Komponenten sind selten abgeschlossen, nicht immer unterscheidbar, Beziehungen selten eindeutig; z.B.: Verkehrssysteme, philosophische, mathematische (Gleichungs-) Systeme Software-Systeme lassen sich in sehr guter Näherung durch Idealtypus beschreiben (trotz Digitalisierungsfehler, Fremdeinflüsse durch Betriebssystem u.ä.) © Thomas Kowarsch Seite 7/101 Systemschnittstellen Stand: 16.10.03 1.4.4.Statisches System Ein statisches System verändert sich nicht mit der Zeit. Beispiel: Kartenhaus 1.4.5.Stationäre Systeme Stationäre Systeme haben ein gleichbleibendes Zeitverhalten. Beispiel: Stromgenerator im Dauerbetrieb 1.4.6.Dynamische Systeme In dynamischen Systemen können sich im Laufe der Zeit die Komponenten und Beziehungen ändern. Beispiel: Straßenverkehr 1.4.7.Geschlossene Systeme Geschlossene Systeme haben keinen Austausch mit der SystemUmgebung (u. gehen langfristig in den Zustand max. Entropie über). Beispiel: U-Boot, Raumschiff, mechanische Uhr 1.4.8.Offene Systeme Offene Systeme ist sind durch den Austausch von Materie, Energie, Information mit der System-Umgebung gekennzeichnet. Beispiel: EU © Thomas Kowarsch Seite 8/101 Systemschnittstellen Stand: 16.10.03 2.Betriebssysteme 2.1.Allgemeines Programme, deren Zusammenwirken eine ‚wohldefinierte‘ Beziehung zwischen Rechner-Hw und Nutzer/in (bzw.: Applikation) herstellen, bilden das Betriebssystem. Übernahme der (schwierigen) Programmierung einzelner HwKomponenten und deren Zusammenspiels. Für den Anwender verhält sich das Betriebssystem wie eine Virtuelle Maschine. Wichtig: Information hiding (Einf. v. Abstraktionsstufen) 2.1.1.Abstraktion Bei mehrfacher gleichzeitiger Nutzung (Programme, Menschen): Regelung des Zugriffs auf Hw-Komponenten, Daten, Rechenzeit: Ressourcen-Verwaltung. Bestrebungen zur Hw-Abstraktion (theoretisch) ab 1941 Vorstellung des ersten -verdrahteten- programmierbaren Rechners Z3 (K.Zuse) Heute: ca. ein Dutzend Betriebssysteme z.B. OS/2 (IBM), VMS (DEC), System 7.5 (Apple), BeOS (Be Inc.), MSDOS und Windows (Microsoft), UNIX (...) 2.1.2.Gründe für den Erfolg des PCs • Mächtiger Anbieter (IBM) • Gewähr für Fortbestand trotz Einsatzes v. Fremdprodukten • PC-Anbindung an Großrechner möglich Modulares Bau-Konzept: • Nach Bedarf aufrüstbar • Günstige Nachbauten Dritter • Orientierung am Massenmarkt: • Preis erschwinglich (Institutionen / Heimbedarf) • Kurze Einarbeitung ( “ / “ ) © Thomas Kowarsch Seite 9/101 Systemschnittstellen Stand: 16.10.03 2.2.UNIX • Multi-User Multi-Tasking • Multi-Threading • Virtueller Speicher (Swapping, Paging) • Skalierbarkeit • Multi-Prozessor-Fähigkeit • Scheduling über Prioritäten u. Zeitscheiben (Time slicing) • Kern-Schale-Architektur u. C/S-Untertützung: Hintergrund-prozesse „Dämonen“(Spooler-Dämon lpd etc.) 2.3.Windows 2000/NT/XP • Multi-User • Multi-Tasking • Multi-Threading • Virtueller Speicher (Paging) • Skalierbarkeit • Multi-Prozessor-Fähigkeit • Scheduling über Prioritäten u. Zeitscheiben (Time sharing) • Grafische Benutzungsoberfläche 2.3.1.Windows Versionen • Windows 9x / ME / XP Home: Heimmarkt (Small Office / Home Office) Fokus: Minimaler Ressourcen-Bedarf. • WindowsNT / 2000 / XP Prof. Workstation: Client-Betriebssystem Fokus: Sicherheit, Skalierbarkeit, Erweiterbarkeit, Stabilität; gut zentral zu verwalten. • WindowsNT / 2000 Server: Server-Betriebssystem Fokus: Domäne-Verwaltung (inkl. Service für Macintosh, Gateway zu Netware 3.x, DHCP u.a.) - in Konkurrenz zu Novell, Banyan oder UNIX. © Thomas Kowarsch Seite 10/101 Systemschnittstellen Stand: 16.10.03 2.3.2.NT Charakteristika • Kompatibilität: Durch Submodule Applikationen von Windows 3.x, Windows 95, MS-DOS, OS/2 und POSIX betreibbar • Portierbarkeit: nur zeitkritische Teile des Hardware Abstraction Layer (HAL) in Assembler, sonst in ANSI-C geschrieben • Modularität: Benötigte DLL's nach Bedarf geladen/entfernt • Erweiterbarkeit: Modularer Aufbau ermöglicht Modul-Zusätze • Skalierbarkeit: Windows NT unterstützt das symmetrische Multiprocessing (baugleiche Prozessoren). • Sicherheit: Erfüllung der Sicherheitsanforderungen des USVerteidungsministeriums (C2). * • Verteilte Systeme: Vorbereitet für vert. Prozesse • Zuverlässigkeit und Stabilität: Unterscheidung zw. User- und Kernel-Prozessen (Sicherheit vor Fehlern in Applikation) 2.3.3.Dateisysteme • FAT (File Allocation Table): DOS-Dateisystem und NTDiskettenformat. Max. Dateigröße: 4 GB • HPFS (High Performance File System): OS/2-Dateisystem. Max. Dateigröße: 4 bis 8 GB (nicht mehr bei Windows NT 4.0). • NTFS (New Technology File System): 64-Bit-Dateisystem von NT mit Fokus auf Sicherheit. Max. Dateigröße: 17 Milliarden GB © Thomas Kowarsch Seite 11/101 Systemschnittstellen Stand: 16.10.03 2.4.Chronologisches 1941 Zuse Z3 In den 60ern Verstärkte Anstrengungen in den 60ern - insb. zur Einf. von Dialogbetrieb (vs. Stapelbetrieb mit Operator) Mitte der 60er Ken Thompson, Dennis Ritchie (Bell Labs, AT&T) u. MIT-Forscher entwickelten MULTICS, ein MehrbenutzerBetriebssystem für General Electric (Mainframe GE645) Trotz Nicht-Einsatzes von MULTICS (techn. Mängel) Weiter-Entwicklung durch Thompson („Space Travel“, 2 Benutzer) Verballhornung durch Brian Kernighan „UNICS“ 1969 Betriebssystem UNICS, ab 1970: Unix (Assembler). Gleichzeitig: Thompson u. Ritchie entwickeln Sprache A (BCPL-* basiert), verbesserte Version B, Weiterentwicklung zu C. 1973 Unix erstes BS größtenteils in einer Hochsprache (kaum 1000 Zeilen Maschinencode) ? Portierbarkeit! Keine Vermarktung von Unix wg. US-Kartell-Bestimmungen 1975 Abgabe zum Selbstkostenpreis an Univers.: Univ. of California Berkeley Software Distribution (BSD) Erweiterungen 1980-1990 Xenix (Microsoft, ab Mitte 80er: Santa Cruz Operation) 1981 PC-Vorstellung durch IBM mit MS-DOS 1983 Apple-Computer Lisa mit grafischer Oberfläche 1984 Apple-Computer Macintosh mit graf. Oberfläche 1984 IEEE / POSIX (Portable Operating System Interface for uniX) ? Standardisierungsvorgabe der US-Regierung. 1985 MS präsentiert Windows 1.01 1987 OS/2 v. IBM / MS, zeichenorientiert 1988 OS/2 v. IBM / MS mit grafischer Oberfläche 1988 Normung zu ANSI-C (Komitee X3J11). 1990 Trennung IBM – MS 1991 Linux 0.02 (Linus Torvalds, FIN) 1993 Windows NT 1995 Windows 95 1998 Windows 98 2000 Windows 2000 2001 Windows ME 2002 Windows XP © Thomas Kowarsch Seite 12/101 Systemschnittstellen Stand: 16.10.03 3.WinDOS 3.1.GUI 3.1.1.Anwendungsprogrammierung unter MS-DOS “Standard-I/O” und standardisierte Rechenzeit-Zuweisung; abweichende Handhabung durch Programmierer/in 3.1.2.Windows-Programmierung Kommunikation mit Peripherie ins System integriert: Geräte werden wie “unter Windows” angesprochen. © Thomas Kowarsch Seite 13/101 Systemschnittstellen Stand: 16.10.03 3.1.3.GUI - Grafic user interface Zur Verdeutlichung: Word for DOS wurde auf 20 Disketten ausgeliefert - davon 2 für Programm (Rest für diverseTreiber) Früherer Anspruch an Rechner (bis in die 80er): Erzeugung v. Ergebnissen u. Darstellung auf Drucker Heutiger Anspruch: Ständiger intuitiver Dialog Ergebnisse in div. Formen/Medien Wichtig für die Realisierung: Forschung am Xerox PARC (Palo Alto Research Center) Mitte 70er (? Konzept für graf. Benutzungsschnittstelle: GUI) 3.1.4.Ziel der GUI Verlagerung des Schreibtisches in den PC „Desktop“: - Rechner auf dem Tisch, oder aber: - Tisch-Oberfläche! Zugrundeliegende Vorstellung: zeilenorientierte Arbeitsweise: . . Papier-Stapel (Batch) Fensterumgebung: . . . . . . . . . . . Lose Papierblätter ungeordnete, quasi-parallele Bearbeitung inhaltlich verwandter Arbeits-Abläufe („P“C) Anforderungen • Intuitive Handhabung --> Minimierung d. Voraussetzungen (z.B.: Brief-/Mail-Schreiben nach Klick statt Befehl-Eingabe) • Quasi-parallele Bearbeitung --> Präemptives Multitasking (z.B.: Erstellung einer Präsentation während Internet-Suche) • Arbeits-Abläufe einer Person --> Prozeß-Kommunikation (z.B.: Löschen v.Datei in allen betroffenen Fenstern anzeigen) Plattform / Betriebssystem • Einheitliches „Look & Feel“ --> Kapselung d. Ein-/Ausgabe (z.B.: Programm-übergreifende Realisierung v. „Drag&Drop“) Applikationen / Bibliotheken Weitere Steigerung d. Hw-Abstraktion durch zusätzl. SW © Thomas Kowarsch Seite 14/101 Systemschnittstellen Stand: 16.10.03 3.1.5.Tendenz Dialog-Komponenten immer komplexer / differenzierter (z.B.: gezielte Warn-Meldungen mit Fallunterscheidungen) Dialog (quasi-)unabhängig vom Programm (z.B.: Menüleisten mit: „Datei - Bearbeiten - Ansicht -...“) --> Loslösung der eigentlichen Applikation von Ein-/Ausgabe --> Abgabe d. Ablaufkontrolle an GUI-Umgebung/-Plattform 3.1.6.Konsequenzen Konsequenzen für die Applikations-Entwicklung: für die Ergonomie: sehr groß für das DV-Ergebnis: keine für die Sw-Konzeption: gering für die Codierung: deutlich (v.a. f. kleine Sw-Projekte) Zusätzlicher Codierungsaufwand durch Berücksichtigung der Plattform-Aufrufe (z.B.: Ausgabe im Fenster) - aber auch der plattform-eigenen Erfordernisse (Plattform-‘Eigenleben‘) (z.B.: Änderung der Fenstergröße, Löschung des Fensters) 3.2.Herkömmliche Programmierung Bei der herkömmlichen Methode wartet z.B. das Nachfolgende Programm auf eine Eingabe des Benutzers, indem er wartet bis der Tastaturpuffer Daten erhalten hat. Danach wird meist eine Berechnung durchgeführt und das Ergebnis auf dem Bildschirm ausgegeben. #include <stdio.h> #include <conio.h> int main () { char ch; int num = 0; while ((ch = getch()) != 27) { num++; printf ("%d\n", ch); } return num; } © Thomas Kowarsch Seite 15/101 Systemschnittstellen Stand: 16.10.03 3.3.Callback Zentraler Begriff bei Errichtung o. Nutzung v. Sw-Plattformen: --> Callback: Funktion des Anwendungsprogramms, die in vorgegebenen Situationen von der Sw-Umgebung aufgerufen wird (z.B. zum Auffrischen des Fensterinhalts) Hintergrund: Multitasking --> Teilen von Ressourcen mit anderen (I/O, Rechenzeit etc.) I/O-Koordination nur durch Plattform möglich (Info über laufende Programme u. Ressourcen-Bedarf) Maßnahmen nach Wiederzuweisung von Ressourcen nur durch Plattform einzuleiten Aber: --> Code nur als Bestandteil der Applikation sinnvoll: (Info über Wiederherstellungs-Maßnahmen) Uhr: . . . . . . . . . . Weiterlaufen Bild: . . . . . . . . . . Neuladen Wie kann die (neue) Applikation der (älteren) Plattform mitteilen, welche Funktion aufzurufen ist? 3.3.1.Einrichtung einer Plattform-Routine zur Aufnahme eines Zeigers auf eine C-Funktion #include <stdio.h> #include <conio.h> /* Callback-Registrierung: */ int init (int (*callback)()) { return (*callback) (); } /* Callback: */ int myfunction () { printf ("In myfunction! \n"); getchar(); return 0; } int main () { init (myfunction); return 0 ; } © Thomas Kowarsch Seite 16/101 Systemschnittstellen Stand: 16.10.03 3.4.Events Verstärkter Einsatz von Callbacks in modernen Plattformen u. Umgebungen führt zum weiteren Paradigmenwechsel: Klassisch: Programm fordert vom Betriebss. Ressourcen u. Aktionen an (prozedurorientierte Arbeitsweise - z.B.: Single Task) Nunmehr meist: BS gibt Programm Bescheid, wann es und mit welcher Funktion „an der Reihe ist” (ereignisgesteuerte Arbeitsweise ) 3.4.1.Definition Als Ereignis (engl. event) bezeichnen wir jedes Vorkommnis (occurence), das eine nicht-sequentielle Bearbeitung eines Programms bewirkt. * Ein Vorkommnis kann eine Zustandsänderung (Meßwert) oder die Erfüllung einer Bedingung (x == y) sein. Ein dazugehöriges Ereignis kann die Abarbeitung einer if-Abfrage im Programm sein. Synchrone Ereignisse treten zu vorhersagbaren Zeitpunkten, asynchrone zu nicht-vorhersagbaren ein. Synchrone Ereignisse sind z.B. if-Abfragen im prozedur-orientierten Programm: sie treten vorhersagbar ein (ab Programmbeginn). Asynchrone Ereignisse sind z.B. Tasten- u. Maus-Aktionen (Zeit oft nicht-vorhersagbar: „OK“ vs. „Anhalten“). © Thomas Kowarsch Seite 17/101 Systemschnittstellen Stand: 16.10.03 3.5.WinDos Bei der herkömmlichen Programmierung hat unser Programm auf die Eingabe des Benutzers gewartet und diese Schnittstelle erst dann wieder freigegeben, bis das Programm dies erlaubte. Weiterhin wurde die Ausgabe direkt und ohne Umwege auf dem Bildschirm erzeugt. Um u.a. Portierbarkeit auf andere Plattformen und deren Unabhängigkeit, sowie Multitasking zu realisieren, muss die Entscheidungsgewalt über Ausgabe und Eingabe der Plattform (WinDos) überlassen werden. Dieses löst Ereignisse (Events) in unserer Applikation aus. Ereignisse finden in Form eines Funktionsaufrufes (Callback) statt. Das WinDos ruft, wenn ein Ereignis stattfindet die entsprechende CallbackFunktion mit geeigneten Parametern in unserer Applikation auf. Die Applikation muss dann auf das Ereignis reagieren und so schnell wie möglich die Callback Funktion wieder beenden, um die Kontrolle an WinDos wieder zurückzugeben. D.h.: Das WinDos wartet nun auf eine Eingabe des Benutzers. Schritt 1: Beim Starten von WinDos wird bei uns die Applikation gestartet (Dies kann auch später zB durch Druck auf z.B. F4 usw geschehen). Bei der Initialisierung/Start der Applikation muss diese dem WinDos mitteilen, wie seine Callback Funktionen für das Neuzeichnen und dem Tastendruck heissen. Dazu liefter das WinDos zwei Funktionen initkeypressed und initrepaint. Schritt 2: Drückt dieser eine Taste, entscheidet WinDos darüber an welche Applikation (in unserem Beispiel gibt es nur eine) die Nachricht weitergeleitet wird. WinDos ruft dann die Funktion Callback Funktion für das Event Tastendruck in der Applikation auf. Diese wurde bei der Initialisierung der Applikation (Dem Starten) per initkeypressed dem WinDos zuvor mitgeteilt. Schritt 3: Das WinDos entscheidet nun darüber, wann der Bildschirm aufgefrischt werden soll. Hat der Benutzer nun eine Taste gedrückt soll in unserem Beispiel danach sofort eine Auffrischung des Bildschirms geschehen. WinDos löscht den Bildschirm und teilt der Applikation mit, dass es neu zeichnen soll, indem es die entsprechende Callback Funktion aufruft. Die Callback Funktion der Applikation zeichnet neu, indem sie die Ausgabefunktion von WinDos (wdprintf) verwendet. © Thomas Kowarsch Seite 18/101 Systemschnittstellen Stand: 16.10.03 3.5.1.Feedback Vorteile: • Durch Austausch der Plattform kann jede Applikation auf jede Hardware übertragen werden. • Die Programmierung der Applikation bedarf nun keiner komplizierten Funktionsaufrufe. • Durch Erweiterung der Plattform kann Multitasking implementiert werden • Durch Erweiterung von Schnittstellenfunktionen für andere Ausgabemedien (Drucker, usw) bedarf es keinerlei grossen Aufwand in der Applikation. © Thomas Kowarsch Seite 19/101 Systemschnittstellen Stand: 16.10.03 4.OpenGL und GLUT 4.1.Fensterumgebung Die Unabhängigkeit der OpenGL von Fenstersystemen erfordert für Grafik-SW-Projekte die Adoption entweder eines ‚nativen‘ Fenstersystems oder einer Programmierschnittstelle (Application Programming Interface, API), die die Anbindung an Fenstersysteme übernimmt. Eine solche Programmierschnittstelle ist GLUT (OpenGL Utility Toolkit vgl. glutttony).* Aktuelle Version: 3.7 Literatur: M.J.Kilgard: „OpenGL Programming for the X Window System“ Addison-Wesley 1996 E.Angel: „Interactive Computer Graphics: A top-down approach with OpenGL“ Addison-Wesley 1996 4.2.GLUT HTML-Online-Dokumentation zu GLUT: Links zu Quellen und Dokumentation: http://www.opengl.org/developers/documentation/glut.html darunter erreichbar: Benutzungshandbuch: http://www.opengl.org/developers/documentation/glut/spec3/spec3.ht ml Quellen u. Dokumentation für MS-Windows zu GLUT: http://www.xmission.com/~nate/glut.html © Thomas Kowarsch Seite 20/101 Systemschnittstellen Stand: 16.10.03 4.3.Design – Philosophie Fenster-Einrichtung u. -Verwaltung mit wenigen Aufrufen (für EinFenster-Applikationen genügt Callback +Start) : --> Schnelle Erlernbarkeit, Augenmerk auf Fenster-Inhalt Aufrufe mit möglichst knappen Parameterlisten, Zeiger nur bei Eingabe von Zeichenketten, keine Zeiger-Rückgabe durch GLUT: -->Leichte Handhabung, Fehlerrobustheit Keine Verwendung v. Daten des nativen Fenstersystems (FensterHandler, Schriftarten): --> Unabhängigkeit vom Fenstersystem Übernahme der Ereignisverarbeitung, Überlassung von OpenGLDisplaylisten der Applikation: --> Einschränkung gleichzeitiger Verwendung weiterer Ereignisverarbeitung, keine Einschränkung des OpenGL-Einsatzes Zustandshaftes (stateful) API: --> Einfache Applikationen durch Voreinstellungen (current window/ menu), Vermeidung wiederholten Datentransfers Tendenz: Mehrere, differenziert aufgerufene Callbacks --> Vermeidung unnötigen Codes je nach Art der Applikation © Thomas Kowarsch Seite 21/101 Systemschnittstellen Stand: 16.10.03 4.4.Funktionalitäten Einrichtung und Handhabung mehrerer Grafik-Fenster Ereignisverarbeitung durch Callbacks (event processing) Unterstützung vielfältiger Eingabegeräte Routinen zur Einhaltung von Zeitvorgaben (timer) Ausnutzung nicht-rechenintensiver ("idle”) Zeitintervalle Erzeugung von Pop-Up-Menü-Kaskaden Unterprogramme zur Generierung geometrischer Körper Mehrere Bitmap- und Vektor-Schriftarten (stroke fonts) Diverse Funktionen zur Fenster- und Overlayverwaltung bietet ein komplettes API für das native Fenstersystem --> Sw-Entwicklung ohne Einarbeitung in Fenstersystem überläßt Fenster-Einrichtung dem nativen Fenstersystem --> Erhaltung des plattformeigenen Look & Feel wird regelmäßig aktualisiert --> Befolgung von Trends, Beseitigung von Bugs ist kostenlos erhältlich inkl. Source-Code --> Verwendbarkeit in Ausbildung --> Anpassung an individuelle Sw-Entwicklung möglich © Thomas Kowarsch Seite 22/101 Systemschnittstellen Stand: 16.10.03 4.5.Programmierung 4.5.1.Visual Studio Um ein Glut Programm zu erstellen müssen Sie zuerst ein Projekt vom Typ Win32 Konsolenapplikation anlegen. Erstellen Sie dann zu diesem Projekt eine C++ Quellcode Datei. 4.5.2.Initialisierung Initialisierung des Fenstersystems, Überprüfung der main-Parameter, Setzen der Voreinstellungen für Fenster-Position, Größe, Darstellungsmodus (Single/ Double Buffer) 4 Routinen: int main() { void glutInit(int *argc, char **argv); void glutInitWindowSize(int width, int height); /* def.: (400,400) */ void glutInitWindowPosition(int x, int y); /* def.: (-1,-1)*/ void glutInitDisplayMode(unsigned int mode); /* def.: (GLUT_RGB | GLUT_SINGLE)*/ } 4.5.3.Start der Ereignisverarbeitung Letzte Anweisung in main() vor Überlassung der Programmsteuerung an GLUT und den dort registrierten Callbacks der Anwendung (kein return!) 1 Routine: void glutMainLoop(void); © Thomas Kowarsch Seite 23/101 Systemschnittstellen Stand: 16.10.03 4.5.4.Fenster Verwaltung Fenster-Generierung und -Steuerung 18 Routinen: int glutCreateWindow(char *name); int glutCreateSubWindow(int win,int x,int y,int wid,int hig); void glutSetWindow(int win); int glutGetWindow(void); void glutDestroyWindow(int win); void glutPostRedisplay(void); void glutSwapBuffers(void); void glutPositionWindow(int x, int y); void glutReshapeWindow(int width, int height); void glutFullScreen(void);/* may vary by window system */ void glutPopWindow(void); void glutPushWindow(void); /* execution upon return to GLUT*/ void glutShowWindow(void); void glutHideWindow(void); void glutIconifyWindow(void); ); void glutSetWindowTitle(char *name); void glutSetIconTitle(char *name); void glutSetCursor(int cursor); /* 23 GLUT_CURSOR_xxx */ 4.6.Zusatztools für GLUT 4.6.1.GLUI GLUI 2.1: GLUT-based C++ User Interface (Paul Rademacher, Univ. of North Carolina) http://www.cs.unc.edu/~rademach/glui/ © Thomas Kowarsch Seite 24/101 Systemschnittstellen Stand: 16.10.03 4.6.2.PLIB PLIB 1.4.2: A Portable Games Library / SDK (Steve J. Baker) http://plib.sourceforge.net/ PUI: A Picoscopic User Interface (part of PLIB) http://plib.sourceforge.net/pui/index.html 4.6.3.MUI MUI: Micro User Interface (Tom Davis, Silicon Graphics Inc.) http://www.opengl.org/developers/code/mjktips/mui/mui.html ..übernimmt von GLUT Ereignisse und Callbacks ..ist ältere GLUT-Benutzungsschnittstelle (seit GLUT 3.5, 1997) ..hat einen überschaubaren Umfang ..besitzt als einzige Dokumentation -neben dem veröffent-lichten Quellcode- die persönlichen Notizen von Steve J. Baker (PLIB) ..Fensterdarstellung wie Pulldown, Menüs, Buttons, usw. 4.7.GLUT Befehle Dokumentation zu GLUT unter glut-3.spec.pdf. © Thomas Kowarsch Seite 25/101 Systemschnittstellen Stand: 16.10.03 5.Win32 5.1.Datentypen Beim Übergang von Win16 nach Win32 haben sich die int - Typen von 2 Byte auf 4 Byte erweitert. Die anderen Grundtypen bleiben ungeändert. Datentyp Win16 Modell T,S,M,C,L,V&Z Win32 Modell X,P,F char signed 8 Bit signed 8 Bit signed char signed 8 Bit signed 8 Bit unsigned char unsigned 8 Bit unsigned 8 Bit signed short signed 16 Bit signed 16 Bit unsigned short unsigned 16 Bit unsigned 16 Bit int signed 16 Bit signed 32 Bit unsigned int unsigned 16 Bit unsigned 32 Bit long signed 32 Bit signed 32 Bit unsigned long unsigned 32 Bit unsigned 32 Bit float 32-Bit floating 32-Bit floating double 64-Bit floating 64-Bit floating Daten - Typen sind in Header - Files definiert und bestimmen den Speicherbedarf eines Bitmusters in Byte und die Bedeutung dieses Bitmusters. Diese Typen werden u.a. für Funktions - Parameter, Funktions Rückgabe - Werte, und für Nachrichten benötigt. Handles werden benutzt, um mit einer Deskriptor - Tabelle auf geladenen Resourcen oder einen benötigten globalen Kontext zuzugreifen. Ein Handle entspricht dem Index der Deskriptor - Tabelle. Ein 8 - Byte Deskriptor - Eintrag enthält die Ziel - Byte - Adresse, den Byte - Umfang, die Zugriffsrechte. In der folgenden Tabelle sind Daten - Typen für Character, Integer, Boolean, Pointer und Handles enthalten. Die meisten Pointer - Typen beginnen mit dem Prefix P oder LP. ATOM Atom (a reference to a character string in an atom table) BOOL Boolean variable (should be TRUE or FALSE) BOOLEAN Boolean variable (should be TRUE or FALSE) BYTE Byte (8 bits) © Thomas Kowarsch Seite 26/101 Systemschnittstellen Stand: 16.10.03 CCHAR Windows character CHAR Windows character COLORREF Red, green, blue (RGB) color value (32 bits) CONST Variable whose value is to remain constant during execution CRITICAL_SECTION Critical-section object CTRYID Country identifier DLGPROC Pointer to an application-defined dialog box callback procedure. DWORD Doubleword (32 bits) EDITWORDBREAKPROC Pointer to an application-defined callback function that the operating system calls when a multiline edit control needs to break a line of text. See EditWordBreakProc for information on functions of this type. ENHMFENUMPROC Pointer to an application-defined callback function that enumerates enhanced-metafile records ENUMRESLANGPROC Pointer to an application-defined callback function that enumerates resource languages ENUMRESNAMEPROC Pointer to an application-defined callback function that enumerates resource names ENUMRESTYPEPROC Pointer to an application-defined callback function that enumerates resource types FARPROC Pointer to a callback function FLOAT Floating-point variable FONTENUMPROC Pointer to an application-defined callback function that enumerates fonts GOBJENUMPROC Pointer to an application-defined callback function that enumerates graphics device interface (GDI) objects GRAYSTRINGPROC Pointer to an application-defined callback function that draws gray text HACCEL Handle of an accelerator table HANDLE Handle of an object HBITMAP Handle of a bitmap HBRUSH Handle of a brush HCONV Handle of a dynamic data exchange (DDE) conversation © Thomas Kowarsch Seite 27/101 Systemschnittstellen Stand: 16.10.03 HCONVLIST Handle of a DDE conversation list HCURSOR Handle of a cursor HDC Handle of a device context (DC) HDDEDATA Handle of DDE data HDWP Handle of a deferred window position structure HENHMETAFILE Handle of an enhanced metafile HFILE Handle of a file HFONT Handle of a font HGDIOBJ Handle of a GDI object HGLOBAL Handle of a global memory block HHOOK Handle of a hook HICON Handle of an icon HINSTANCE Handle of an instance HKEY Handle of a registry key HLOCAL Handle of a local memory block HMENU Handle of a menu HMETAFILE Handle of a metafile HOOKPROC Pointer to an application-defined hook function HPALETTE Handle of a palette HPEN Handle of a pen HRGN Handle of a region HRSRC Handle of a resource HSZ Handle of a DDE string HWINSTA Handle of a workstation HWND Handle of a window INT Signed integer LANGID Language identifier LCID Locale identifier LCTYPE Locale type LINEDDAPROC Pointer to a callback function that processes line coordinates LONG 32-bit signed value © Thomas Kowarsch Seite 28/101 Systemschnittstellen Stand: 16.10.03 LP Pointer to a null-terminated Unicode™ string LPARAM 32-bit message parameter LPBOOL Pointer to a Boolean variable LPBYTE Pointer to a byte LPCCH Pointer to a constant Windows character LPCCHOOKPROC Pointer to an application-defined hook function LPCFHOOKPROC Pointer to an application-defined hook function LPCH Pointer to a Windows character LPCOLORREF Pointer to a COLORREF value LPCRITICAL_SECTION Pointer to a critical-section object LPCSTR Pointer to a constant null-terminated Windows character string LPCTSTR Pointer to a constant null-terminated Unicode or Windows character string LPCWCH Pointer to a constant null-terminated Unicode character LPCWSTR Pointer to a constant null-terminated Unicode character string LPDWORD Pointer to an unsigned doubleword (32 bits) LPFRHOOKPROC Pointer to an application-defined hook function LPHANDLE Pointer to a handle LPHANDLER_FUNCTION Pointer to a handler function LPINT Pointer to a signed integer LPLONG Pointer to a signed long (32 bits) LPOFNHOOKPROC Pointer to an application-defined hook function LPPRINTHOOKPROC Pointer to an application-defined hook function LPSETUPHOOKPROC Pointer to an application-defined hook function LPSTR Pointer to a null-terminated Windows character string LPTCH Pointer to a Unicode character or a Windows character LPTSTR Pointer to a null-terminated Windows or Unicode character string LRESULT Signed result of message processing LPVOID Pointer to any type © Thomas Kowarsch Seite 29/101 Systemschnittstellen Stand: 16.10.03 LPWCH Pointer to a Unicode character LPWORD Pointer to an unsigned word (16 bits) LPWSTR Pointer to a null-terminated Unicode character string LUID Locally unique identifier MFENUMPROC Pointer to an application-defined callback function that enumerates metafile records NPSTR Pointer to a null-terminated Windows character string NWPSTR Pointer to a null-terminated Unicode string PBOOL Pointer to a Boolean variable PBOOLEAN Pointer to a Boolean variable PBYTE Pointer to a byte PCCH Pointer to a constant Windows character PCH Pointer to a Windows character PCHAR Pointer to a Windows character PCRITICAL_SECTION Pointer to a critical-section object PCSTR Pointer to a constant null-terminated Windows character string PCWCH Pointer to a constant Unicode character PCWSTR Pointer to a constant null-terminated Unicode character string PDWORD Pointer to an unsigned doubleword (32 bits) PFLOAT Pointer to a floating-point variable PFNCALLBACK Pointer to a callback function PHANDLE Pointer to a handle PHANDLER_ ROUTINE Pointer to a handler routine PHKEY Pointer to a registry key PINT Pointer to a signed integer PLONG Pointer to a signed long (32 bits) PLUID Pointer to a locally unique identifier (LUID) PROPENUMPROC Pointer to an application-defined callback function that enumerates window properties. See PropEnumProc for information on functions of this type. © Thomas Kowarsch Seite 30/101 Systemschnittstellen Stand: 16.10.03 PROPENUMPROCEX Pointer to an application-defined callback function that enumerates window properties. See PropEnumProcEx for information on functions of this type. PSHORT Pointer to a signed short (16 bits) PSID Pointer to a security identifier (SID) PSTR Pointer to a null-terminated Windows character string PSZ Pointer to a null-terminated Windows character string PTCH Pointer to a Windows or Unicode character PTCHAR Pointer to a Windows or Unicode character PTSTR Pointer to a null-terminated Windows or Unicode character string PUCHAR Pointer to an unsigned Windows character PUINT Pointer to an unsigned integer PULONG Pointer to an unsigned long (32 bits) PUSHORT Pointer to an unsigned short (16 bits) PVOID Pointer to any type PWCH Pointer to a Unicode character PWCHAR Pointer to a Unicode character PWORD Pointer to an unsigned word (16 bits) PWSTR Pointer to a null-terminated Unicode character string REGSAM Security access mask for registry key SC_HANDLE Handle of a service SENDASYNCPROC Pointer to an application-defined callback function that the operating system calls when the SendMessageCallback function is called. The system passes the message to the callback function after passing the message to the destination window procedure. See SendAsyncProc for information on functions of this type. SERVICE_STATUS_ HANDLE Handle of a service status value SHORT Short integer SPHANDLE Pointer to a handle © Thomas Kowarsch Seite 31/101 Systemschnittstellen Stand: 16.10.03 TCHAR Unicode character or Windows character TIMERPROC Pointer to an application-defined timer callback function UCHAR Unsigned Windows character UINT Unsigned integer ULONG Unsigned long integer (32 bits) USHORT Unsigned short integer (16 bits) VOID Any type WCHAR Unicode character WNDENUMPROC Pointer to an application-defined callback function that enumerates windows WNDPROC Pointer to an application-defined window procedure WORD Unsigned word (16 bits) WPARAM 32-bit message parameter YIELDPROC Pointer to a yield callback function © Thomas Kowarsch Seite 32/101 Systemschnittstellen Stand: 16.10.03 5.2.Ungarische Notation In Ungarn wird ( anstelle von "Hans Müller" ) der Familien - Name zuerst genannt ( "Müllers Hans" ). Bei Win16 existierten viele verschiedene Speicher - Modelle. Damit bei größeren Programmen an der Window - Variablen der zughörige Typ erkennbar ist, wurden dem Variablen - Namen Prä - Character voran gestellt. Z.B. steht "lp" für "long Pointer", "lpsz" für "long Pointer auf \0 begrenzten String", "dw" für "Doppel Wort", "h" für "Handle", "n" für "Anzahl", "f" für "Flag", usw. Ein Beispiel ist der Aufruf von CreateWindowEx(). HWND CreateWindowEx( DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, identifier // handle to menu, or child-window HINSTANCE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data ); © Thomas Kowarsch Seite 33/101 Systemschnittstellen Stand: 16.10.03 Prefix Naming Conventions Prefix Type Description Example ch char 8-bit character chGrade ch TCHAR 16-bit character if _UNICODE is defined chName b BOOL Boolean value bEnabled n int Integer (size dependent on operating system) nLength n UINT Unsigned value (size dependent on operating system) nLength w WORD 16-bit unsigned value wPos l LONG 32-bit signed integer lOffset dw DWORD 32-bit unsigned integer dwRange p * Pointer pDoc lp FAR* Far pointer lpDoc lpsz LPSTR 32-bit pointer to character string lpszName lpsz LPCSTR 32-bit pointer to constant character string lpszName lpsz LPCTSTR 32-bit pointer to constant character string if _UNICODE is defined lpszName h handle Handle to Windows object hWnd lpfn callback Far pointer to CALLBACK function © Thomas Kowarsch lpfnAbort Seite 34/101 Systemschnittstellen Stand: 16.10.03 Windows verwendet für Nachrichten-, Style-, ControlKonstanten die folgenden Gruppen: BM_ Button Control Messages BN_ User Button Notification Codes BS_ Button Control Styles CBS_ Combo Box styles CCS_ LVS_ TVS_ TCS_ ACS_ COMMON CONTROL STYLES CS_ Class styles CF_ Predefined Clipboard Formats DS_ Dialog Styles ES_ Edit Control Styles HELP_ Commands to pass to WinHelp() HT WM_NCHITTEST, MOUSEHOOKSTRUCT Mouse Pos ID Dialog Box Command IDs IDI_ Standard Icon IDs LANG_ language IDs. LBS_ Listbox Styles MA_ WM_MOUSEACTIVATE Return Codes MF_ Menu flags for Add/Check/EnableMenuItem() MFS_ Menu flags for Add/Check/EnableMenuIt em() MK_ Key State Masks for Mouse Messages OBM_ OEM Resource Ordinal Numbers PWR_ wParam for WM_POWER SBS_ Scroll Bar Styles SC_ System Menu Command Values SIZE_ WM_SIZE message wParam values SORT_ Sorting IDs. SS_ Static Control Constants SW_ ShowWindow() Commands TBS_ Tab style VK_ Virtual Keys, Standard Set WA_ WM_ACTIVATE state values WM_ Window Messages WM_DDE_ DDE - Mesages WS_ Window Styles WS_EX_ Extended Window Styles WVR_ WM_NCCALCSIZE return values © Thomas Kowarsch Seite 35/101 Systemschnittstellen Stand: 16.10.03 5.3.Librarys Windows.h enthält die Funktions - Prototypen. Dadurch kann der Compiler die Schreibweise ( Syntax ) in dem eigenen Programm überprüfen. Damit der Linker die zugeordneten DLL - Einsprünge einbinden kann, sind außerdem z.B. die folgenden Bibliotheken • kernel32.lib • user32.lib • gdi32.lib • coredll.lib • msvcrt.lib in das Projekt aufzunehmen. Soll zusätzlich die "messaging functionality" in das eigene Programm aufgenommen werden, so ist #include Msgstore.h erforderlich. Soll zusätzlich die "e-mail functionality" in das eigene Programm aufgenommen werden, so ist #include Addrstor.h erforderlich. Natürlich sind auch die zugehörigen *.lib - Files in die Entwicklungs - Umgebung aufzunehmen. Oft werden die folgenden ( voreingstellten ) *.lib - Files verwerdet: kernel32.lib user32.lib winspool.lib comdlg32.lib shell32.lib uuid.lib ole32.lib odbc32.lib gdi32.lib advapi32.lib oleaut32.lib odbccp32.lib 5.4.Resourcen Windows - Applikationen benötigen viele statische Daten ( Fenstergröße, Farbe, Controls, ... ). In den meisten Fällen werden die Geometrie - Resourcen mit Hilfe visueller, interaktiver Tools ( z.B. Resourcen Workshop ) erstellt. Diese Resourcen können im *.RC - ASCII - File ( oder in einem binären *.RCT - Template - File ) gespeichert werden. Ein RC - Compiler übersetzt diesen *.RC - ASCII - File in einen binären *.RES - File, der durch den Linker dem *.EXE - File hinzugefügt wird. Weil eine standardisierte Binärform benutzt wird, ist es mit dem Resourcen Workshop auch möglich, aus einem *.EXE - Programm den *.RC - ASCII - File zu erhalten. © Thomas Kowarsch Seite 36/101 Systemschnittstellen Stand: 16.10.03 5.5.Übersetzung 6.Betriebssystem - Kern Der eigentliche Betriebssystem - Kern besteht aus den drei Dateien • KRNL386.EXE ( 85 kB, 377 kB ), • USER.EXE ( 47 kB, 321 kB ), • GDI.EXE ( 21 kB, 162 kB ) Bei diesen Dateien handelt es sich um sogenannte DLL’s ( Dynamic Link Libarys ). Dies sind binäre Funktionsbibliotheken. Zum Betriebssystem gehören noch weitere Komponenten, wie z.B. • COMMDLG: Common Dialog Boxen, • DDEML: Dynamic Datat Exchange Management Library, • DIB.DRV: Device independent bitmap driver, • OLECLI.DLL, OLESVR.DLL: Objekt linking and embedding, • SHELL.DLL: Drag-drop-feature, Registrations-Basis, • LZEXPAND.DLL: Daten decompression, • TOOLHELP.DLL: Tool help, • VER.DLL, VER.LIB: File Installation and versions checking, usw. • Installable drivers, • True Type fonts, DLL’s sind binäre Instanzen von Objekte und enthalten Daten ( Properties ) und Methoden ( Funktionen ). Benötigt eine Applikation eine DLL, so wird diese geladen und die benötigte Funktion ausgeführt. Falls die Dateiendung nicht *.DLL ist ( z.B. *.EXE ), so muß die Datei explizit geladen/freigegeben werden. Ist die DLL bereits geladen, so wird in der DLL lediglich ein Zähler hochgezählt. Ein DLL darf bei Bedarf aus dem Speicher entfernt werden, wenn dieser Zäher 0 ist. Eine DLL wird nur einmal geladen, auch wenn diese DLL von mehreren Anwendungen benutzt wird. Der Zugriff auf eine Funktion und deren Ausführung kann über die ASCII Namen - Tabelle ( langsamer ) oder den Index der Funktions Adress - Tabelle ( schneller ) erfolgen. Der hinterlegte Wert in der Funktions - Tabelle zeigt auf den Anfang der eigentlichen Funktion. Diese Zugriffsart ist schneller, als der Zugriff über die ASCII - Namen Tabelle. Die DOS - Interrupttabelle ist grob mit der DLL - Funktionstabelle vergleichbar (die Zuordnung von Interruptzeiger zu Interruptserviceroutinen) © Thomas Kowarsch Seite 37/101 Systemschnittstellen Stand: 16.10.03 Bei interoperablen Systemen ( UNIX - WINDOWS ) wird der Zugriff über die ASCII - Namen - Tabelle benutzt. Bevor eine DLL - Funktion ausgeführt wird, werden die Funktionsparameter auf den Stack des aurufenden Programmes gelegt. DLL’s arbeiten immer auf dem Benutzerstack. Die Funktions - Adress - Tabelle bedingt, daß das aurufende Programm ( Applikation ) den gewünschten Index der DLL - Funktions - Adress Tabelle kennt. Die Namen - Index - Zuordnungen sind in LIB Dateien ( Libary ) enthalten. Beim Erstellen eines Programmes werden diese Indizes der DLL - Funktions - Adress - Tabelle in den Maschinencode eingefügt. Der Linker trägt den Index in das Maschinenprogramm ein. Der DLL - Name wird nur einmal in das Applikationsprogramm eingetragen. KRNL386.EXE Die Dateien KRNL386.EXE ist eine DLL ( Dynamic Link Libarys ). KRNL386.EXE • kontrolliert und verwaltet den Speicher, • lädt Applikationen, • verteilt die Resourcen an Programme und Tasks. In KRNL386.EXE sind binäre Funktionen enthalten. Die wesentlichen Funktionen sind in der folgende Tabelle zusammengefaßt. Object Creator function Destroyer function Change notification Communications FindFirstChangeNotification FindCloseChangeNotific ation device GetStdHandle CloseHandle Event CreateEvent, OpenEvent CloseHandle Event log OpenEventLog, RegisterEventSource, OpenBackupEventLog CloseEventLog File CreateFile CloseHandle, DeleteFile File mapping CreateFileMapping, OpenFileMapping CloseHandle Find file FindFirstFile FindClose Heap HeapCreate HeapDestroy Mailslot CreateMailslot CloseHandle © Thomas Kowarsch Seite 38/101 Systemschnittstellen Stand: 16.10.03 Module LoadLibrary, GetModuleHandle FreeLibrary Mutex CreateMutex, OpenMutex CloseHandle Pipe CreateNamedPipe, CreatePipe CloseHandle, DisconnectNamedPipe Process CreateProcess, OpenProcess, GetCurrentProcess CloseHandle, TerminateProcess Semaphore CreateSemaphore, OpenSemaphore CloseHandle Thread CreateThread, CreateRemoteThread, GetCurrentThread CloseHandle, TerminateThread Timer CreateWaitableTimer, OpenWaitableTimer CloseHandle Update resource BeginUpdateResource EndUpdateResource USER.EXE Der File USER.EXE ist eine DLL, die die auf dem Bildschirm die Fenster erzeugt und manipuliert ( create, move, size, remove), die Icons und andere Komponenten des Benutzer-Interface behandelt, die Eingaben ( dispatch ) von Keyboard, Mause und anderen Eingabe-Geräten an die zugehörige Applikation verteilt. Mit den Funktionen von USER.EXE können interaktive Fenster ( desktop - shell ) erstellt werden. Die User Interface Services • erzeugen und manipulieren Bildschirm - Fenster ( Screen Windows ), • behandeln Icons und andere Komponenten des Benutzerinterfaces, • verteilen die Eingabe von Keyboard, Maus und anderen Geräten an die zugehörigen Applikationen USER.EXE enthält Funktionen für die folgenden Aufgaben: • Dialogelemente ( Controls ) Auslöseknöpfe ( Buttons ), Textboxen ( List Boxes ), aufklappbare Textboxen ( Combo Boxes ), Text - Editor ( Edit Controls ), RTF - Text - Bearbeitung ( Rich Edit Controls ), Rollbalken ( Scroll Bars ), feste Texte ( Static Controls ) • lesbare Daten ( Resources ) © Thomas Kowarsch Seite 39/101 Systemschnittstellen Stand: 16.10.03 Textcursor ( Carets ), Mauscursor ( Cursors ), kleines Symbolbild ( Icons ), Menus, benutzerdefinierte Daten ( Resources ) • Programmierschnittstelle ( Shell and Common Controls ) Windows Shell API, standardisierter Dialogelemente ( Common Controls ), Wizard97 Specifications • Benutzereingaben ( User Input ) Nachrichtenzugriff ( Accessibility ), Mauseingaben ( Mouse Input ), Tasten - Code der Tastatur ( Keyboard Input ), standardisierter Tastencode ( Virtual-Key Codes ), Alt-Tasten ( Keyboard Accelerators ), fertige Dialoge ( Common Dialog Box Library ) • Fensternhirachie ( Windowing ) Fensterbehandlung ( Windows ) Datenzuordnung zu Fenstern ( Window Properties ), mehrere Fenster mit gleichen Eigenschhaften ( Queues Window Classes ), Nachrichtenbearbeitung ( Message and Message ), ereignisgesteuerter Funktionsaufruf ( Callback, Window Procedures ), Behandlung von Dialogen ( Dialog Boxes ), alle Fenster innerhalb des Eltern Fenster ( Multiple Document Interface ) Die folgenden Funktionen werden zum Erzeugen und Manipulieren von Fenstern benutzt. © Thomas Kowarsch Seite 40/101 Systemschnittstellen Stand: 16.10.03 AdjustWindowRect AdjustWindowRectEx AnimateWindow ArrangeIconicWindows BeginDeferWindowPos BringWindowToTop CascadeWindows ChildWindowFromPoint ChildWindowFromPointEx CloseWindow CreateWindow CreateWindowEx DeferWindowPos DestroyWindow EnableWindow EndDeferWindowPos EnumChildProc EnumChildWindows EnumThreadWindows EnumThreadWndProc EnumWindows EnumWindowsProc FindWindow FindWindowEx GetClientRect GetDesktopWindow GetForegroundWindow GetLastActivePopup GetNextWindow GetParent GetTopWindow GetWindow GetWindowPlacement GetWindowRect GetWindowText GetWindowTextLength GetWindowThreadProcessId IsChild IsIconic IsWindow IsWindowUnicode IsWindowVisible IsZoomed MoveWindow OpenIcon SetForegroundWindow SetParent SetWindowLong SetWindowPlacement SetWindowPos SetWindowText ShowOwnedPopups ShowWindow ShowWindowAsync TileWindows WindowFromPoint WinMain GDI.EXE GDI ist eine Abkürzung für (G)raphic (D)evice (I)nterface. Der File GDI.EXE ist eine DLL, die das Graphics Device Interface ( GDI ) mit den Funktionen zur Bild - Erzeugung und Bild - Anzeige ( nicht nur Screen ) enthält. Hierher gehören z.B. auch Fonts und Device Kontext. • Bilderzeugung und Bildanzeige ( nicht nur auf dem Bildschirm, auch auf z.B. Druckern ). • Fonts • Device - Kontext Den Device Kontext benutzen die folgenden Funktionen. CancelDC ChangeDisplaySettings CreateCompatibleDC CreateDC CreateIC DeleteDC DeleteObject DeviceCapabilities DrawEscape EnumDisplayDevices GetDC EnumDisplaySettings EnumObjects EnumObjectsProc GetCurrentObject GetDCBrushColor GetDCEx GetDCOrgEx GetDCPenColor GetDeviceCaps GetGraphicsMode GetObject GetObjectType GetStockObject ReleaseDC ResetDC RestoreDC SaveDC SelectObject SetDCBrushColor SetDCPenColor © Thomas Kowarsch Seite 41/101 Systemschnittstellen Stand: 16.10.03 Mit Fonts und Texten werden die folgenden Funktionen benutzt: AddFontResource CreateFont CreateFontIndirect CreateScalableFontResource DrawText DrawTextEx EnumFontFamiliesEx EnumFontFamExProc ExtTextOut GetAspectRatioFilterEx GetCharABCWidths GetCharABCWidthsFloat GetCharacterPlacement GetCharWidth32 GetCharWidthFloat GetFontData GetFontLanguageInfo GetFontUnicodeRanges GetGlyphIndices GetGlyphOutline GetKerningPairs GetOutlineTextMetrics GetRasterizerCaps GetTabbedTextExtent GetTextAlign GetTextCharacterExtra GetTextColor GetTextExtentExPoint GetTextExtentPoint32 GetTextFace GetTextMetrics PolyTextOut RemoveFontResource SetMapperFlags SetTextAlign SetTextCharacterExtra SetTextColor SetTextJustification TabbedTextOut TextOut Nicht mehr benutzt werden sollten: EnumFontFamilies EnumFontFamProc EnumFonts EnumFontsProc GetCharWidth GetTextExtentPoint Im Zusammenhang mit der Paint - Nachricht werden die folgenden Funktionen benutzt: BeginPaint DrawAnimatedRects DrawCaption DrawEdge DrawFocusRect DrawFrameControl DrawState DrawStateProc DrawTextEx EndPaint ExcludeUpdateRgn GdiFlush GdiGetBatchLimit GdiSetBatchLimit GetBkColor GetBkMode GetBoundsRect GetROP2 GetUpdateRect GetUpdateRgn GetWindowDC GetWindowRgn GrayString InvalidateRect InvalidateRgn LockWindowUpdate OutputProc PaintDesktop RedrawWindow SetBkColor SetBkMode SetBoundsRect SetRectRgn SetROP2 SetWindowRgn UpdateWindow ValidateRect ValidateRgn WindowFromDC GetDeviceCaps() Als ein Beispiel wird GetDeviceCaps() gewählt. GetDeviceCaps() gibt Informationen zum Device Kontext zurück. int GetDeviceCaps( HDC hDC, // device-context handle int nIndex // index of capability to query ); © Thomas Kowarsch Seite 42/101 Systemschnittstellen Stand: 16.10.03 nIndex kann eine der folgenden Zahlen sein. Die eingerückten Konstanten kennzeichnen die zugehörigen Rückgabeweerte. DRIVERVERSION The device driver version. TECHNOLOGY Device technology: DT_PLOTTER Vector plotter, DT_RASDISPLAY Raster display, DT_RASPRINTER Raster printer, DT_RASCAMERA Raster camera, DT_CHARSTREAM Character stream, DT_METAFILE Metafile und GetObjectType(), DT_DISPFILE Display file HORZSIZE Width, in millimeters, of the physical screen. VERTSIZE Height, in millimeters, of the physical screen. HORZRES Width, in pixels, of the screen. VERTRES Height, in raster lines, of the screen. LOGPIXELSX Number of pixels per logical inch along the screen width. LOGPIXELSY Number of pixels per logical inch along the screen height. BITSPIXEL Number of adjacent color bits for each pixel. PLANES Number of color planes. NUMBRUSHES Number of device-specific brushes. NUMPENS Number of device-specific pens. NUMFONTS Number of device-specific fonts. NUMCOLORS Number of entries in the device's color table, ASPECTX Relative width of a device pixel used for line drawing. ASPECTY Relative height of a device pixel used for line drawing. ASPECTXY Diagonal width of the device pixel used for line drawing. PDEVICESIZE Reserved. CLIPCAPS Flag that indicates the clipping capabilities of the device. SIZEPALETTE Number of entries in the system palette. NUMRESERVED Number of reserved entries in the system palette. COLORRES Actual color resolution of the device, in bits per pixel. PHYSICALWIDTH For printing devices: the width of the physical page, in device units. © Thomas Kowarsch Seite 43/101 Systemschnittstellen Stand: 16.10.03 PHYSICALHEIGHT For printing devices: the height of the physical page, in device units. PHYSICALOFFSETX For printing devices: the distance from the left edge of the physical page to the left edge of the printable area, in device units. PHYSICALOFFSETY For printing devices: the distance from the top edge of the physical page to the top edge of the printable area, in device units. VREFRESH Windows NT only: For display devices: the current vertical refresh rate of the device, in cycles per second (Hz). DESKTOPHORZRES Windows NT only: Width, in pixels, of the virtual desktop. DESKTOPVERTRES Windows NT only: Height, in pixels, of the virtual desktop. BLTALIGNMENT Windows NT only: Preferred horizontal drawing alignment, expressed as a multiple of pixels. RASTERCAPS Value that indicates the raster capabilities of the device: RC_BANDING Requires banding support. RC_BITBLT Capable of transferring bitmaps. RC_BITMAP64 Capable of supporting bitmaps larger than 64K. RC_DI_BITMAP Capable of supporting the SetDIBits and GetDIBits functions. RC_DIBTODEV Capable of supporting the SetDIBitsToDevice function. RC_FLOODFILL Capable of performing flood fills. RC_GDI20_OUTPUT Capable of supporting features of Windows 2.0. RC_PALETTE Specifies a palette-based device. RC_SCALING Capable of scaling. RC_STRETCHBLT Capable of performing the StretchBlt function. RC_STRETCHDIB Capable of performing the StretchDIBits function. CURVECAPS Value that indicates the curve capabilities of the device: CC_NONE Device does not support curves. CC_CHORD Device can draw chord arcs. CC_CIRCLES Device can draw circles. CC_ELLIPSES Device can draw ellipses. CC_INTERIORS Device can draw interiors. CC_PIE Device can draw pie wedges. CC_ROUNDRECT Device can draw rounded rectangles. © Thomas Kowarsch Seite 44/101 Systemschnittstellen Stand: 16.10.03 CC_STYLED Device can draw styled borders. CC_WIDE Device can draw wide borders. CC_WIDESTYLED Device can draw borders that are wide and styled. LINECAPS Value that indicates the line capabilities of the device: LC_NONE Device does not support lines. LC_INTERIORS Device can draw interiors. LC_MARKER Device can draw a marker. LC_POLYLINE Device can draw a polyline. LC_POLYMARKER Device can draw multiple markers. LC_STYLED Device can draw styled lines. LC_WIDE Device can draw wide lines. LC_WIDESTYLED Device can draw lines that are wide and styled. POLYGONALCAPS Value that indicates the polygon capabilities of the device: PC_NONE Device does not support polygons. PC_INTERIORS Device can draw interiors. PC_POLYGON Device can draw alternate-fill polygons. PC_RECTANGLE Device can draw rectangles. PC_SCANLINE Device can draw a single scanline. PC_STYLED Device can draw styled borders. PC_WIDE Device can draw wide borders. PC_WIDESTYLED Device can draw borders that are wide and styled. PC_WINDPOLYGON Device can draw winding-fill polygons. TEXTCAPS Value that indicates the text capabilities of the device: TC_OP_CHARACTER Device is capable of character output precision. TC_OP_STROKE Device is capable of stroke output precision. TC_CP_STROKE Device is capable of stroke clip precision. TC_CR_90 Device is capable of 90-degree character rotation. TC_CR_ANY Device is capable of any character rotation. TC_SF_X_YINDEP Device can scale independently in the x- and y-directions. TC_SA_DOUBLE Device is capable of doubled character for scaling. TC_SA_INTEGER Device uses integer multiples only for character scaling. TC_SA_CONTIN Device uses any multiples for exact character scaling. TC_EA_DOUBLE Device can draw double-weight characters. TC_IA_ABLE Device can italicize. TC_UA_ABLE Device can underline. TC_SO_ABLE Device can draw strikeouts. TC_RA_ABLE Device can draw raster fonts. TC_VA_ABLE Device can draw vector fonts. TC_RESERVED Reserved; must be zero. TC_SCROLLBLT Device cannot scroll using a bit-block transfer. © Thomas Kowarsch Seite 45/101 Systemschnittstellen Stand: 16.10.03 GetSystemMetrics Mit der Funktion GetSystemMetrics köennen ( geometrische ) Fenster - und Screen - Werte abgefragt werden. Durch RECT rc ; //Dialog mittig zentrieren GetWindowRect ( hWnd , & rc ) ; rc.left = ( GetSystemMetrics ( SM_CXSCREEN ) - rc.right + rc.left ) / 2 ; rc.top = ( GetSystemMetrics ( SM_CYSCREEN ) - rc.bottom + rc.top ) / 2 ; SetWindowPos ( hWnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER ) ; kann ein Fenster zentriert werden. Windows - Objekte Windows kennt Objekte. Mit den Funktionen CreateWindow(), DestroyWindow() soll die Nutzung dieser Objekte erklärt werden. Eine Applikation führe z.B. CreateWindow() aus. CreateWindow() erzeugt im Speicher ein Window - Objekt und lieferte ein gültiges Handle. Nach dem Create... kann das Objekt verwendet werden. Durch DestroyWindow() wird das Objekt vernichtet. Der reservierten Speicher wird frei gegeben. Das Fenster - Handle wird ungültig und darf nicht mehr verwendet werden. • Ein Objekt hat nur ein Handle. • Ein Duplizieren eines Handles ist nicht sinnvoll. • Handles sind public für alle Prozesse. © Thomas Kowarsch Seite 46/101 Systemschnittstellen • Stand: 16.10.03 Ein Benutzer kann maximal 65536 Handles verwenden. Die folgende Tabelle enthält die Benutzer - Objekte. User Objects Creator function Destroyer function Accelerator table CreateAcceleratorTable DestroyAcceleratorTable Cursor CreateCursor LoadCursor, GetCursor, SetCursor DestroyCursor DDE conversation DdeConnect, DdeConnectList, DdeQueryNextServer, DdeReconnect DdeDisconnect, DdeDisconnectList Desktop GetThreadDesktop Applications cannot delete this object. Hook SetWindowsHook, SetWindowsHookEx UnhookWindowsHook, UnhookWindowsHookEx Menu CreateMenu, CreatePopupMenu, GetMenu, GetSubMenu, GetSystemMenu, LoadMenu, LoadMenuIndirect DestroyMenu Window CreateWindow, CreateWindowEx, CreateDialogParam, CreateDialogIndirectParam, CreateMDIWindow, FindWindow, GetWindow, GetClipboardOwner, GetDesktopWindow, GetDlgItem, GetForegroundWindow, GetLastActivePopup, GetOpenClipboardWindow, GetTopWindow, WindowFromDC, WindowFromPoint, and others DestroyWindow Window position BeginDeferWindowPos EndDeferWindowPos Window station GetProcessWindowStation Applications cannot delete this object. Lebensdauer von Objekten Applikationen können Objekte erzeugen und verwenden. Ein Objekt kann auch von mehreren Applikationen benutzt werden ( shared ). Das Betriessystem erzeugt und nutzt ( Stock - ) Objekte, die vielfach von Applikationen genutzt werden. © Thomas Kowarsch Seite 47/101 Systemschnittstellen Stand: 16.10.03 Typ belegt durch Sichtbarkeit Lebensdauer Overhead Static C-Compiler Programm Programm 0 (Allignment) Automatic C-Compiler Funktion Funktion 0 (Stackwort) Heap System allokiert Programm Programm, System bei shared 32 Byte Resourcen RCCompiler Programm, System bei shared Owner ca. 32 Byte User Objekte GDIFunktionen System System ca. 30-50 Byte GDI Objekte UserFunktionen System Owner ca. 30-50 Byte Bei Win16 gibt es den lokalen Heap ( schnell, klein, gehört dem Programm, 6 Byte Overhead ) und den globalen Heap ( groß, gehört dem Programm/System, 24 Byte Overhead ) 6.1.Hauptfunktion int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // Registrierung der Windowsklasse ... // Initialisierung der Anwendung durchführen: ... // Accelerators und Hauptnachrichtenschleife ... } © Thomas Kowarsch Seite 48/101 Systemschnittstellen Stand: 16.10.03 6.2.Registrierung 6.2.1.WNDCLASSEX-Struktur Hat eine Applikation mehrere Fenster, so gibt es Daten, die von allen Fenstern benötigt werden. Diese Daten werden in der WNDCLASSEX Struktur gespeichert. The WNDCLASSEX structure is similar to the WNDCLASS structure. There are two differences. WNDCLASSEX includes the cbSize member, which specifies the size of the structure, and the hIconSm member, which contains a handle to a small icon associated with the window class. typedef struct _WNDCLASSEX { UINT cbSize; // sizeof( WNDCLASSEX ) ; UINT style; // CS_HREDRAW,CS_VREDRAW,CS_DBLCLKS,CS_CLASSDC,CS_OWNDC, // CS_PARENTDC,CS_BYTEALIGNWINDOW,CS_BYTEALIGNCLIENT, // CS_NOCLOSE,CS_GLOBALCLASS,CS_SAVEBITS WNDPROC lpfnWndProc; // CALLBACK-Funktion int cbClsExtra; // < 40 Byte int cbWndExtra; // < 40 Byte HANDLE hInstance; // von WinMain() HICON hIcon; IDI_APPLICATION ); // LoadIcon HCURSOR hCursor; IDC_ARROW ); // LoadCursor( NULL, HBRUSH hbrBackground; ( WHITE_BRUSH ); // ( HBRUSH ) GetStockObject LPCTSTR lpszMenuName; ( NULL, // NULL LPCTSTR lpszClassName; "HelloWin" ; // static char szAppName[] = HICON hIconSm; IDI_APPLICATION ); // LoadIcon( NULL, } WNDCLASSEX; © Thomas Kowarsch Seite 49/101 Systemschnittstellen Stand: 16.10.03 Damit später mit ( CreateWindow oder CreateWindowEx ) spezielle Fenster angelegt werden können, müssen vorher der Speicherbereich für die gemeinsamen Daten angelegt und initialisiert werden. WNDCLASSEX wndclass wndclass.cbSize wndclass.style wndclass.lpfnWndProc ... wndclass.lpszClassName = = = = { 0 }; sizeof( WNDCLASSEX ) ; ... ... = ... 6.2.2.RegisterClassEx if ( ! RegisterClass( & wndclass ) ) Fehler; Die hinterlegten Daten können mit GetClassInfoEx() erhalten werden. Damit bei einem Aufruf von RegisterClassEx() ( oder RegisterClass() ) nicht 13 Parameter übergeben werden müssen, werden die Eingabewerte in eine WNDCLASSEX - Struktur geschrieben, die dann an die Funktion ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx ); übergeben wird. Wenn kein Speicher für die Daten angelegt werden konnte und diese Funktion erfolglos war, wird 0 zurück gegeben. In diesem Fall kann der Fehler mit GetLastError() näher untersucht werden. Achtung! Ist RegisterClassEx() in einer NT - DLL, so wird beim unloaden der Speicher nicht automatisch freigegeben. Es ist unRegisterClassEx() erforderlich. Das System kennt bereits die Klassen BUTTON, COMBOBOX, EDIT, LISTBOX, MDICLIENT, SCROLLBAR, STATIC. © Thomas Kowarsch Seite 50/101 Systemschnittstellen Stand: 16.10.03 6.3.Initialisierung 6.3.1.CreateWindowEx Bis auf dwExStyle ist CreateWindowEx() identisch mit CreateWindow(). CreateWindowEx() kann ein Overlapped -, Pop - Up -, oder Child Window erstellen. CreateWindowEx() sendet die WM_NCCREATE-, WM_NCCALCSIZE-, WM_CREATE-Nachrichten zu dem angelegten Fenster. Der Rückgabewert ist das Handle des neuen Fensters. Das Fenster ist nicht sichtbar, obwohl das Handle != NULL den allokierten Speicher referenziert und Fenster-Daten eingetragen wurden. HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, identifier HINSTANCE hInstance, LPVOID lpParam ); // // // // // // // // // // extended window style pointer to registered class name pointer to window name window style horizontal position of window vertical position of window window width window height handle to parent or owner window handle to menu, or child-window // handle to application instance // pointer to window-creation data dwExStyle spezifiziert erweiterte Styles: WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_CLIENTEDGE, WS_EX_CONTEXTHELP, WS_EX_CONTEXTHELP, WS_EX_CONTROLPARENT, WS_EX_DLGMODALFRAME (double border), WS_CAPTION, WS_EX_LEFT, WS_EX_LEFTSCROLLBAR, WS_EX_LTRREADING, WS_EX_MDICHILD, WS_EX_NOPARENTNOTIFY, WS_EX_OVERLAPPEDWINDOW, WS_EX_PALETTEWINDOW, WS_EX_RIGHT, WS_EX_RIGHTSCROLLBAR, WS_EX_RTLREADING, WS_EX_STATICEDGE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_EX_WINDOWEDGE lpClassName zeigt auf einen "null-terminated string" der den Window Class - Namen spezifiziert oder ist ein integer atom ( GlobalAddAtom ). lpClassName zeigt auf einen "null-terminated string" der den Window Namen spezifiziert ( Titelzeile, Text eines Controls ). © Thomas Kowarsch Seite 51/101 Systemschnittstellen Stand: 16.10.03 dwStyle spezifiziert den Style des Fensters und Funktionalität: WS_BORDER, WS_CAPTION, WS_CHILD, WS_CHILDWINDOW, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_DISABLED, WS_DLGFRAME, WS_GROUP, WS_HSCROLL, WS_ICONIC, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_POPUPWINDOW, WS_SIZEBOX, WS_SYSMENU, WS_TABSTOP, WS_THICKFRAME, WS_TILED, WS_TILEDWINDOW, WS_VISIBLE, WS_VSCROLL Alle Fenster haben bereits die WS_CLIPSIBLINGS und WS_CLIPCHILDREN Styles. lpParam kann in der CREATESTRUCT - Struktur unter WM_CREATE an die CALLBACK - Funktion weitergereicht werden. In CreateWindowEx() können für die horizontale/vertikale Fenster Position anstelle von festen int x-, y-, nWidth-, nHeight- Werten auch Bildschirm - bezogene Werte ( z.B. GetSystemMetrics(SM_CXSCREEN) *1/8, GetSystemMetrics(SM_CYSCREEN)*1/5, GetSystemMetrics (SM_CXSCREEN)*6/8, GetSystemMetrics(SM_CYSCREEN)*6/5 ) verwendet werden. 6.3.2.ShowWindow Mit ShowWindow wird definiert wie das Fenster angezeigt wird. BOOL ShowWindow( HWND hWnd, // handle to window int nCmdShow // show state of window ); Parameter: hWnd - Handle to the window. nCmdShow - definiert wie das Fenster angezeigt wird. Folgende Werte sind erlaubt: SW_FORCEMINIMIZE Windows NT 5.0 oder später: Minimiert das Fenster, wenn der Thread des Fensters, sich aufgehängt hat. Dieses Flag Sollte nur benutzt werden, um das Fenster von einem anderen Thread zu minimieren. SW_HIDE Versteckt das Fenster und aktiviert ein anderes. SW_MAXIMIZE Maximiert das Fenster SW_MINIMIZE Minimiert das Fenster und aktiviert ein anderes. SW_RESTORE Aktiviert und zeigt das Fenster. Wenn das Fenster zuvor © Thomas Kowarsch Seite 52/101 Systemschnittstellen Stand: 16.10.03 minimiert oder maximiert gewesen ist, wird das Fenster in die Original Größe und Position zurückgesetzt. Dieses Flag sollte nur dann verwendet werden, dann das Fenster zuvor minimiert gewesen war. SW_SHOW Aktiviert das Fenster und setzt es auf die momentane Größe und Position. SW_SHOWDEFAULT Sets the show state based on the SW_ flag specified in theSTARTUPINFO structure passed to theCreateProcess function by the program that started the application. SW_SHOWMAXIMIZED Aktiviert und maximiert das Fenster . SW_SHOWMINIMIZED Aktiviert und minimiert das Fenster . SW_SHOWMINNOACTIVE Minimiert das Fenster, das letzte aktive Fenster bleibt aktiv. SW_SHOWNA Setzt das Fenster auf die momentane Größe und Position, das letzte aktive Fenster bleibt aktiv. SW_SHOWNOACTIVATE gleiche wie SW_SHOWNOACTIVATE SW_SHOWNORMAL gleiche wie SW_RESTORE. Dieses Flag sollte nur dann verwendet werden, dann das Fenster zum ersten Mal angezeigt wird. Rückgabewerte: <> 0 : Wenn das Fenster sichtbar war 0 : Wenn das Fenster nicht sichtbar war Unter Windows CE werden nur folgende Flags unterstützt: SW_MAXIMIZE SW_MINIMIZE SW_RESTORE SW_SHOWDEFAULT SW_SHOWMAXIMIZED SW_SHOWMINIMIZED SW_SHOWMINNOACTIVE Benötigte Headerfile: winuser.h. Benötigte Library: user32.lib. © Thomas Kowarsch Seite 53/101 Systemschnittstellen Stand: 16.10.03 6.3.3.UpdateWindow Die UpdateWindow Funktion aktuallisiert den Clientbereich des Fensters durch das Senden der WM_PAINT Nachricht. Die Nachricht wird direkt gesendet und nicht zuvor in den Puffer geschrieben. Wenn die Region leer ist, so wird keine Nachricht gesendet. BOOL UpdateWindow( HWND hWnd // handle of window ); Parameter: hWnd - Handle to the window Rückgabewert 0 : Bei Erfolg <> 0 : Fehler Benötigte Headerfile: winuser.h. Benötigte Library: user32.lib. 6.4.Hauptnachrichtenschleife Die Nachrichtenschleife enthält while ( GetMessage( & msg, NULL, 0, 0 ) ) { TranslateMessage( & msg ) ; DispatchMessage( & msg ) ; } 6.4.1.GetMessage GetMessage() holt aus dem Applikations - Buffer ( thread's message queue ) die nächste Nachricht und stellt diese in der MSG - Struktur zur Verfügung. GetMessage() erhält keine Nachrichten von einer anderen Applikation. Entnimmt GetMessage() dem Buffer die WM_QUIT - Nachricht, so ist der Rückgabewert 0, sonst != 0. Ein ungültiges Window-Handle liefert den Rückgabewert -1. Mit GetLastError() kann der Fehler analysiert werden. BOOL GetMessage( LPMSG lpMsg, // address of structure with message HWND hWnd, // handle of window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message ); © Thomas Kowarsch Seite 54/101 Systemschnittstellen Stand: 16.10.03 Wenn mit PostThreadMessage() per Programm eine Nachricht versendet wird, so ist hWnd == NULL, sonst identifiziert hWnd das Fenster. wMsgFilterMin, wMsgFilterMax werden zum Eingrenzen der Nachrichten verwendet ( z.B. WM_KEYFIRST, WM_KEYLAST, WM_MOUSEFIRST, WM_MOUSELAST ). 6.4.2.TranslateMessage Die Funktion BOOL TranslateMessage( CONST MSG *lpMsg ); wandelt eine Virtual - Key - Nachricht in eine Zeichen - Nachricht um ( WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP ). WM_KEYDOWN und WM_KEYUP Kombinationen ergeben WM_CHAR oder WM_DEADCHAR - Nachrichten. WM_SYSKEYDOWN und WM_SYSKEYUP Kombinationen ergeben WM_SYSCHAR oder WM_SYSDEADCHAR - Nachrichten. Die Zeichen - Nachricht wird in die Applikations - Nachrichten - Buffer gestellt. Mit GetMessage() oder PeekMessage() wird diese Nachricht geholt. 6.4.3.DispatchMessage Aus dem Handle der Nachricht kann das Fenster ersehen werden. DispatchMessage() bestimmt das Fenster und leitet eine gültige Nachricht an die CALLBACK - Funktion des Fensters. LONG DispatchMessage( CONST MSG *lpmsg ); Wenn lpmsg auf eine WM_TIMER - Nachricht zeigt wird anstelle der Window - CALLBACK - Funktion die Funktion lParam() != NULL aufgerufen. © Thomas Kowarsch Seite 55/101 Systemschnittstellen Stand: 16.10.03 6.5.CALLBACK - Funktion Das System verwaltet die Tastatur, die Maus und den Bildschirm. Wenn z.B. eine Taste gedrückt wird, so tritt ein Ereignis ein. Dieses Ereignis ruft die CALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) des Fensters auf. Aus dem Handle der Tasten - Nachricht kann das Fenster ersehen werden. DispatchMessage() bestimmt das Fenster und ruft die CALLBACK - Funktion des Fenster auf, d.h. die Tasten - Nachricht wird an das Fenster geschickt. Vor dem Aufruf der Fensters - CALLBACK - Funktion werden ( durch das Windows - System ) die Parameter der Nachricht auf den Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. Nachrichten rufen dieFenster CALLBACK - Funktion auf. Innerhalb der CALLBACK - Funktion können die Nachrichten bearbeitet werden. 6.5.1.WM_PAINT - Nachricht Ist z.B. ein Teilbereich des Bildschirm - Fensters verdeckt und wird die Überdeckung beseitigt, so entsteht ein "weißes Rechteck". Das Windows - System legt die WM_PAINT - Nachricht in den Applikations Message - Buffer. In der Hauptnachrichten - Schleife wird durch DispatchMessage() die CALLBACK - Funktion aufgerufen. Wenn Windows oder eine andere Applikation ein Neuzeichnen wünscht, so wird eine WM_PAINT - Nachricht gesendet. In der CALLBACK - Funktion kann iMsg = WM_PAINT hdc = (HDC) wParam; benutzt werden. Wenn z.B. das Fenster vergrößert wird, so wird automatisch die WM_PAINT - Nachricht durch das Windows - System gesendet. Die WM_PAINT - Nachricht ist eine nachrangige Nachricht. Sind neben WM_PAINT weitere Nachrichten im Applikations Nachrichten - Buffer, so werden diese zuerst abgearbeitet. © Thomas Kowarsch Seite 56/101 Systemschnittstellen Stand: 16.10.03 Die WM_PAINT - Nachricht wird auch durch die Funktionen UpdateWindow(), RedrawWindow() ausgelöst. Eine WM_PAINT Nachricht steht in Zusammenhang mit den WM_ERAEBKGND -, WM_NCPAINT - Nachrichten und den Funktionen DispatchMessage(), DefWindowProc(), BeginPaint(), EndPaint(), GetUpdateRect(), UpdateWindow(), RedrawWindow() Wann wird WM_PAINT ausgelöst? Eine Applikation zeichnet und aktualisiert ein Fenster nachdem die Fenster - Daten allokiert und initialisiert wurden ( WM_CREATE ), nachdem sich die Fenstergröße ändert ( WM_SIZE ), nachdem Fenster - Anteile in den Vordergrund erscheinen, nachdem das Fenster zum Icon wird ( WM_MINIMIZED ), nachdem das Fenster zur Vollbild - Größe wird ( WM_MAXIMIZED ), nachdem das Fenster gescrollt wurde ( WM_ ), nachdem dar Fenster - Inhalt geändert wurde. 6.5.2.Bildschirmausgabe 6.5.2.a)Device Kontext benutzen die folgenden Funktionen. CancelDC ChangeDisplaySettings CreateCompatibleDC CreateDC CreateIC DeleteDC DeleteObject DeviceCapabilities DrawEscape EnumDisplayDevices EnumDisplaySettings EnumObjects EnumObjectsProc GetCurrentObject GetDC GetDCBrushColor GetDCEx GetDCOrgEx GetDCPenColor GetDeviceCaps GetGraphicsMode GetObject GetObjectType GetStockObject ReleaseDC ResetDC RestoreDC SaveDC SelectObject SetDCBrushColor SetDCPenColor Mit Fonts und Texten werden die folgenden Funktionen benutzt: AddFontResource CreateFont CreateFontIndirect CreateScalableFontResource DrawText DrawTextEx EnumFontFamiliesEx EnumFontFamExProc ExtTextOut GetAspectRatioFilterEx GetCharABCWidths GetCharABCWidthsFloat GetCharacterPlacement GetCharWidth32 GetCharWidthFloat GetFontData GetFontLanguageInfo GetFontUnicodeRanges GetGlyphIndices GetGlyphOutline GetKerningPairs GetOutlineTextMetrics GetRasterizerCaps GetTabbedTextExtent GetTextAlign GetTextCharacterExtra GetTextColor GetTextExtentExPoint GetTextExtentPoint32 GetTextFace © Thomas Kowarsch Seite 57/101 Systemschnittstellen Stand: 16.10.03 GetTextMetrics PolyTextOut RemoveFontResource SetMapperFlags SetTextAlign SetTextCharacterExtra SetTextColor SetTextJustification TabbedTextOut TextOut Nicht mehr benutzt werden sollten: EnumFontFamilies EnumFontFamProc EnumFonts EnumFontsProc GetCharWidth GetTextExtentPoint Im Zusammenhang mit der Paint - Nachricht werden die folgenden Funktionen benutzt: BeginPaint DrawAnimatedRects DrawCaption DrawEdge DrawFocusRect DrawFrameControl DrawState DrawStateProc DrawTextEx EndPaint ExcludeUpdateRgn GdiFlush GdiGetBatchLimit GdiSetBatchLimit GetBkColor GetBkMode GetBoundsRect GetROP2 GetUpdateRect GetUpdateRgn GetWindowDC GetWindowRgn GrayString InvalidateRect InvalidateRgn LockWindowUpdate OutputProc PaintDesktop RedrawWindow SetBkColor SetBkMode SetBoundsRect SetRectRgn SetROP2 SetWindowRgn UpdateWindow ValidateRect ValidateRgn WindowFromDC GetDeviceCaps() Als ein Beispiel wird GetDeviceCaps() gewählt. GetDeviceCaps() gibt Informationen zum Device Kontext zurück. int GetDeviceCaps( HDC hDC, // device-context handle int nIndex // index of capability to query ); nIndex kann eine der folgenden Zahlen sein. Die eingerückten Konstanten kennzeichnen die zugehörigen Rückgabeweerte. DRIVERVERSION The device driver version. TECHNOLOGY Device technology: DT_PLOTTER Vector plotter, DT_RASDISPLAY Raster display, DT_RASPRINTER Raster printer, DT_RASCAMERA Raster camera, DT_CHARSTREAM Character stream, DT_METAFILE Metafile und GetObjectType(), DT_DISPFILE Display file © Thomas Kowarsch Seite 58/101 Systemschnittstellen Stand: 16.10.03 HORZSIZE Width, in millimeters, of the physical screen. VERTSIZE Height, in millimeters, of the physical screen. HORZRES Width, in pixels, of the screen. VERTRES Height, in raster lines, of the screen. LOGPIXELSX Number of pixels per logical inch along the screen width. LOGPIXELSY Number of pixels per logical inch along the screen height. BITSPIXEL Number of adjacent color bits for each pixel. PLANES Number of color planes. NUMBRUSHES Number of device-specific brushes. NUMPENS Number of device-specific pens. NUMFONTS Number of device-specific fonts. NUMCOLORS Number of entries in the device's color table, ASPECTX Relative width of a device pixel used for line drawing. ASPECTY Relative height of a device pixel used for line drawing. ASPECTXY Diagonal width of the device pixel used for line drawing. PDEVICESIZE Reserved. CLIPCAPS Flag that indicates the clipping capabilities of the device. SIZEPALETTE Number of entries in the system palette. NUMRESERVED Number of reserved entries in the system palette. COLORRES Actual color resolution of the device, in bits per pixel. PHYSICALWIDTH For printing devices: the width of the physical page, in device units. PHYSICALHEIGHT For printing devices: the height of the physical page, in device units. PHYSICALOFFSETX For printing devices: the distance from the left edge of the physical page to the left edge of the printable area, in device units. PHYSICALOFFSETY For printing devices: the distance from the top edge of the physical page to the top edge of the printable area, in device units. VREFRESH Windows NT only: For display devices: the current vertical refresh rate of the device, in cycles per second (Hz). DESKTOPHORZRES Windows NT only: Width, in pixels, of the virtual desktop. DESKTOPVERTRES Windows NT only: Height, in pixels, of the virtual desktop. BLTALIGNMENT Windows NT only: Preferred horizontal drawing alignment, expressed as a multiple of pixels. RASTERCAPS Value that indicates the raster capabilities of the device: RC_BANDING Requires banding support. RC_BITBLT Capable of transferring bitmaps. RC_BITMAP64 Capable of supporting bitmaps larger than 64K. RC_DI_BITMAP Capable of supporting the SetDIBits and GetDIBits functions. RC_DIBTODEV Capable of supporting the SetDIBitsToDevice function. RC_FLOODFILL Capable of performing flood fills. RC_GDI20_OUTPUT Capable of supporting features of Windows 2.0. © Thomas Kowarsch Seite 59/101 Systemschnittstellen Stand: 16.10.03 RC_PALETTE Specifies a palette-based device. RC_SCALING Capable of scaling. RC_STRETCHBLT Capable of performing the StretchBlt function. RC_STRETCHDIB Capable of performing the StretchDIBits function. CURVECAPS Value that indicates the curve capabilities of the device: CC_NONE Device does not support curves. CC_CHORD Device can draw chord arcs. CC_CIRCLES Device can draw circles. CC_ELLIPSES Device can draw ellipses. CC_INTERIORS Device can draw interiors. CC_PIE Device can draw pie wedges. CC_ROUNDRECT Device can draw rounded rectangles. CC_STYLED Device can draw styled borders. CC_WIDE Device can draw wide borders. CC_WIDESTYLED Device can draw borders that are wide and styled. LINECAPS Value that indicates the line capabilities of the device: LC_NONE Device does not support lines. LC_INTERIORS Device can draw interiors. LC_MARKER Device can draw a marker. LC_POLYLINE Device can draw a polyline. LC_POLYMARKER Device can draw multiple markers. LC_STYLED Device can draw styled lines. LC_WIDE Device can draw wide lines. LC_WIDESTYLED Device can draw lines that are wide and styled. POLYGONALCAPS Value that indicates the polygon capabilities of the device: PC_NONE Device does not support polygons. PC_INTERIORS Device can draw interiors. PC_POLYGON Device can draw alternate-fill polygons. PC_RECTANGLE Device can draw rectangles. PC_SCANLINE Device can draw a single scanline. PC_STYLED Device can draw styled borders. PC_WIDE Device can draw wide borders. PC_WIDESTYLED Device can draw borders that are wide and styled. PC_WINDPOLYGON Device can draw winding-fill polygons. TEXTCAPS Value that indicates the text capabilities of the device: TC_OP_CHARACTER Device is capable of character output precision. TC_OP_STROKE Device is capable of stroke output precision. TC_CP_STROKE Device is capable of stroke clip precision. © Thomas Kowarsch Seite 60/101 Systemschnittstellen Stand: 16.10.03 TC_CR_90 Device is capable of 90-degree character rotation. TC_CR_ANY Device is capable of any character rotation. TC_SF_X_YINDEP Device can scale independently in the x- and ydirections. TC_SA_DOUBLE Device is capable of doubled character for scaling. TC_SA_INTEGER Device uses integer multiples only for character scaling. TC_SA_CONTIN Device uses any multiples for exact character scaling. TC_EA_DOUBLE Device can draw double-weight characters. TC_IA_ABLE Device can italicize. TC_UA_ABLE Device can underline. TC_SO_ABLE Device can draw strikeouts. TC_RA_ABLE Device can draw raster fonts. TC_VA_ABLE Device can draw vector fonts. TC_RESERVED Reserved; must be zero. TC_SCROLLBLT Device cannot scroll using a bit-block transfer. GetSystemMetrics Mit der Funktion GetSystemMetrics köennen ( geometrische ) Fenster und Screen - Werte abgefragt werden. Durch RECT rc ; //Dialog mittig zentrieren GetWindowRect ( hWnd , & rc ) ; rc.left = ( GetSystemMetrics( SM_CXSCREEN ) - rc.right + rc.left ) / 2 ; rc.top = ( GetSystemMetrics ( SM_CYSCREEN ) - rc.bottom + rc.top ) / 2 ; SetWindowPos ( hWnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER ) ; kann ein Fenster zentriert werden. © Thomas Kowarsch Seite 61/101 Systemschnittstellen Stand: 16.10.03 6.5.2.b)BeginPaint(), EndPaint() In der obigen CALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) wird die WM_PAINT - Nachricht durch case WM_PAINT : hDC = BeginPaint( hWnd, & ps ) ; GetClientRect( hWnd, & rect ) ; DrawText ( hDC, "Hallo, Win32!",1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint ( hWnd, & ps ) ; break ; //return 0; behandelt. Der Hintergrund wird gelöscht und der Text wird erneut durch DrawText() zentriert ausgegeben. Die BeginPaint() - Funktion wird benutzt, um gemäß hDC = BeginPaint ( hWnd, & ps ) ; den Text - Cursor ( Caret ) zu verbergen, das Updating - Clipping - Rechteck in PAINTSTRUCT.rcPaint zu setzen, den Device - Kontext zu ermitteln und falls erforderlich WM_NCPAINT und WM_ERASEBKGND ( Title Bar, System Menu, Scroll Bars ) auszulösen. Der Device - Kontext enthält globale Daten, die von vielen GDI Funktionen zum Zeichnen gebraucht werden. Praktisch alle GDI - Funktionen benötigen den Device - Kontext. Durch EndPaint ( hWnd, & ps ) wird das Update - Rechteck auf NULL gesetzt ( keine WM_PAINT Rekursion ), wird der Device - Kontext wieder frei gegeben, wird das Caret wieder angezeigt. BeginPaint() und EndPaint() benutzen PAINTSTRUCT. typedef struct tagPAINTSTRUCT { // ps HDC hdc; BOOL fErase; // TRUE: erase background with hbrBackground of WNDCLASSEX RECT rcPaint; // painting rectangle BOOL fRestore; // Reserved; used internally BOOL fIncUpdate; // Reserved; used internally BYTE rgbReserved[32]; // Reserved; used internally © Thomas Kowarsch Seite 62/101 Systemschnittstellen Stand: 16.10.03 } PAINTSTRUCT; Das Update - Rechteck wird in einer RECT - Struktur gespeichert. RECT hat die folgenden Komponenten: typedef struct _RECT { // rc LONG left; LONG top; LONG right; LONG bottom; } RECT; Durch hDC = GetDC( hWnd ) ; ... ReleaseDC( hWnd, hDC ) ; wird ein hDC erhalten, das zum gesamten Client - Bereich gehört. Auch die DefWindowProc() löscht das Update - Recheck ( validates ). Falls erforderlich, versendet die DefWindowProc() die WM_NCPAINT, WM_ERASEBKGND - Nachrichten. Dies entspricht dem Code case WM_PAINT : BeginPaint( hWnd, & ps ) ; ... EndPaint ( hWnd, & ps ) ; return 0; in der DefWindowProc() - Funktion. InvalidateRect(), ValidateRect(), GetUpdateRect() Mit der GetUpdateRect() kann untersucht werden, ob eine Update Rechteck vorhanden ist. Falls GetUpdateRect den wert 0 zurück gibt, so ist kein BeginPaint() ... EndPaint() erforderlich. Wenn die Update Rechteck nicht leer ist, so sendet Windows eine WM_PAINT - Nachricht zu dem Fenster. Durch die InvalidateRect() kann ein Rechteck zu dem Update - Fenster - Rechteck hinzugefügt werden. Durch InvalidateRect( hWnd, NULL, TRUE ) wird der gesamte Fenster Client - Bereich zur Update - Rechteck hinzugefügt, d.h. mit WM_PAINT - Nachricht soll der Fenster - Hintergrund gelöscht und das gesamte Fenster neu gezeichnet werden. Durch BeginPaint(), ValidateRect()/ValidateRgn() wird das Update - Rechteck/Region gelöscht. © Thomas Kowarsch Seite 63/101 Systemschnittstellen Stand: 16.10.03 BOOL InvalidateRect( HWND hWnd, // handle of window with changed update Rect CONST RECT *lpRect, // address of rectangle coordinates BOOL bErase // TRUE: BeginPaint() erased background ); Mit der GetUpdateRect() kann untersucht werden, ob eine Update Rechteck vorhanden ist. Falls GetUpdateRect den wert 0 zurück gibt, so ist kein BeginPaint() ... EndPaint() erforderlich. Falls ein Update Rechteck vorhanden ist, so sendet die UpdateWindow( hWndMain ) eine synchrone WM_PAINT - Nachricht. Ebenso die RedrawWindow( hWndMain ) Funktion, die eine erweiterte Kontrolle ( not Client, BackGround ) erlaubt. © Thomas Kowarsch Seite 64/101 Systemschnittstellen Stand: 16.10.03 6.5.3.Schliessen von Fenstern/Applikation WM_CLOSE - Nachricht Wird durch einen x - Mausklick die iMsg = WM_CLOSE - Nachricht ausgelöst, so wird die CALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) mit iMsg = WM_CLOSE aufgerufen. Um mit Hilfe eines Anzeige - Fensters ( MessageBox ) eine Rückfrage zu ermöglichen wird unter WM_CLOSE case WM_CLOSE: if ( GetParent( hWnd ) != NULL ) break; char buf[256]; GetWindowText( hWnd, buf, 256 ) ; // Text der Titelzeile wird nach buf kopiert if ( MessageBox ( hWnd, "Do you want to Exit?", buf, MB_ICONQUESTION | MB_YESNO) == IDYES ) { DestroyWindow( hWnd ); //sendet WM_DESTROY } return 0; case WM_DESTROY: // Hauptfenster schliessen, zerstoert automatisch die Child-Windows. PostQuitMessage( 0 ); return 0; ausgeführt. Falls der MessageBox - Rückgabewert TRUE ist, so wurde der "YES" - Button gedrück. Dann wird durch DestroyWindow( hWnd ) die WM_DESTROY - Nachricht gesendet, d.h. die LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) Funktion wird mit iMsg = WM_DESTROY aufgerufen. Infolge von PostQuitMessage( 0 ) wird das Fenster geschlossen. Klick: Zeigt iMsg = WM_...- Nachrichten an © Thomas Kowarsch Seite 65/101 Systemschnittstellen Stand: 16.10.03 6.5.4.Tastatur - Nachrichten Wenn Prozessen mit unterschiedlicher Ausführungs - Geschwindigkeit synchronisiert werden müssen, so werden Warteschlangen ( Buffer ) benötigt. Der schreibende Prozeß hinterlegt die unregelmäßig eintreffenden Ereignisse in einem Buffer. Der lesende Prozeß holt sich die Nachrichten und verarbeitet diese mit der eigenen Geschwindigkeit. Bei dem Windows - System - Tastatur - Buffer handelt es sich um einen Ring - Buffer. Bei DOS enthält der Tastatur - Buffer 32 Worte ( 64 Byte ). • Tastaturereignis ==> int 9h ==> Zeichen in Puffer ==> int 16h ==> Buffer auslesen #include <stdio.h> extern key_read( int*, int* ); void main( ) { int *ascii_ptr, *scan_ptr, num, num1; num = 0; num1 = 0; ascii_ptr = # scan_ptr = &num1; // initialize pointers to zero key_read( ascii_ptr, scan_ptr ); // call assembly routine // print the high byte - ASCII code, and the low byte - extended code // of the character placed in the keyboard buffer printf( "ASCII Code hex %x or decimal %d\n", *ascii_ptr," " *ascii_ptr); printf( "EXTENDED Code hex %x " "or decimal %d\n", *scan_ptr, *scan_ptr); } ****************************************************** .model small,c .data .code PUBLIC key_read key_read PROC PUSH bp ;save the base pointer MOV bp, sp ; Invoke Int 21h Function Ch to clear the keyboard buffer before ; ; accepting a keystroke. MOV ah, 0CH MOV al, 0 INT 21h ; Invoke Int 16h Function 0h to place the character code in the AX ; register. MOV ah, 0H INT 16H MOV MOV bx, [bp+4] ;ASCII returned [bx], al MOV MOV bx, [bp+6] ;Extended code returned [bx], ah POP bp RET key_read ENDP END © Thomas Kowarsch Seite 66/101 Systemschnittstellen Stand: 16.10.03 Tasten - Scan - Code Bei Windows kann der System - Tastatur - Buffer 60 Zeichen aufnehmen. Im System - Nachrichten - Buffer kommt der Tasten - Scan - Code. Die Tasten - Nachricht wird aufbereitet ( einheitliches MSG - Format ) und in den Applikations - Nachrichten - Buffer gestellt. Bei Windows hat ein Fenster den Focus. Dieses Fenster ist i.a. an der blauen Titel - Zeile erkennbar. Die Tasten - Nachrichten werden in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die CALLBACK - Funktion des Fensters wird mit der Tasten - Nachricht ( iMsg, wParam, lParam ) aufgerufen, d.h. • die Tasten - Nachrichten werden an das Fenster geschickt. Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster ( genauer: der Speicher für die Fensterdaten ) erreichbar. In iMsg ist die Tasten Nachricht eindeutig identifizierbar. Mit wParam, lParam können die Tasten unterschieden werden. LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { switch ( iMsg ) { ... case WM_CHAR : { switch ( LOWORD(wParam) ) { case ‘\b’ : Rücktaste; break; case ‘\t’ : Tabulatortaste; break; case ‘\n’ : LF-Taste; break; default : //normales Zeichen bearbeiten } } ... } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } In dem obigen Beispiel werden nur einige WM_CHAR - Nachrichten behandelt. Tabelle der WM - Tastatur - Nachrichten Es gibt die folgenden Keyboard - Nachrichten: TastenNachricht wParam, lParam enthalten ... WM_ACTIVATE fActive = LOWORD(wParam); // activation flag fMinimized = (BOOL) HIWORD(wParam); // minimized flag hwndPrevious = (HWND) lParam; // window handle © Thomas Kowarsch Seite 67/101 Systemschnittstellen Stand: 16.10.03 WM_SETFOCUS // handle of window losing focus hwndLoseFocus = (HWND) wParam; WM_KILLFOCUS // handle of window receiving focus hwndGetFocus = (HWND) wParam; WM_KEYDOWN WM_KEYUP nVirtKey = (int) wParam; // virtual-key code lKeyData = lParam; // key data WM_CHAR WM_SYSCHAR chCharCode = (TCHAR) wParam; // character code lKeyData = lParam; // key data WM_HOTKEY idHotKey = (int) wParam; // identifier of hot key fuModifiers = (UINT) LOWORD(lParam); // key-modifier flags uVirtKey = (UINT) HIWORD(lParam); // virtual-key code WM_GETHOTKEY wParam = 0; // not used; must be zero lParam = 0; // not used; must be zero WM_SETHOTKEY // virtual-key code and modifiers of hot key wParam = (WPARAM) MAKEWORD(vkey, modifiers) lParam = 0; // not used; must be zero WM_DEADCHAR chCharCode = (TCHAR) wParam; // character code lKeyData = lParam; // key data WM_SYSDEADCHAR chCharCode = (TCHAR) wParam; // character code lKeyData = lParam; // key data WM_SYSKEYDOWN WM_SYSKEYUP nVirtKey = (int) wParam; // virtual-key code lKeyData = lParam; // key data Virtual - Tasten - Code • Je Taste werden mehr als eine Nachricht generiert. Wird z.B. der Klein - Buchstabe a auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden die folgenden 3 Nachrichten generiert: • WM_KEYDOWN ( virtuelle Taste ), • WM_CHAR ( wParam enthält ASCII von a ), • WM_KEYUP ( virtuelle Taste ) Wird z.B. der Groß - Buchstabe A auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden die folgenden 5 Nachrichten generiert: • WM_KEYDOWN ( virtuelle Taste VK_SHIFT ), • WM_KEYDOWN ( virtuelle Taste a ), • WM_CHAR ( wParam enthält ASCII von A ), • WM_KEYUP ( virtuelle Taste a ), • WM_KEYUP ( virtuelle Taste VK_SHIFT ) Die (V)irtuellen (K)ey - Nachrichten ( VK_... ) können in der © Thomas Kowarsch Seite 68/101 Systemschnittstellen Stand: 16.10.03 CALLBACK WndProc - Funktion etwa wie folgt benutzt werden. LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { switch ( iMsg ) { ... case WM_KEYDOWN : { switch ( LOWORD(wParam) ) { ... case VK_LEFT: //die Caret-nach-links-Taste ( Pfeilchen-Taste ) //wurde gedrückt, jetzt soll ... break ; case VK_F1: //die F1 - Taste wurde gedrückt, jetzt soll ... break ; } } ... } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } Die RETURN - Tasten können unterschieden werden durch das 24. Bit von lParam. switch ( iMsg ) { case WM_KEYDOWN : { switch ( LOWORD(wParam) ) { ... case VK_RETURN: if ( lParam & 0x01000000L ) { // Enter-Taste ( numeric keypad ) } else { // Enter-Taste ( standard keypad ) } break ; ... } } } Tabelle der Virtual - Tasten - Codes Bei einer WM_KEYDOWN - Nachricht wird in LOWORD(wParam) der ( standardisierte ) Virtual - Key - Code übergeben. Die folgende Tabelle enthält die #define`s. VK_LBUTTON 0x01 VK_RBUTTON 0x02 VK_CANCEL 0x03 VK_MBUTTON 0x04 VK_BACK 0x08 VK_TAB 0x09 VK_CLEAR 0x0C VK_RETURN 0x0D VK_SHIFT 0x10 VK_CONTROL 0x11 VK_MENU 0x12 VK_PAUSE 0x13 VK_CAPITAL 0x14 VK_ESCAPE 0x1B VK_SPACE 0x20 VK_PRIOR 0x21 VK_NEXT 0x22 VK_END 0x23 © Thomas Kowarsch Seite 69/101 Systemschnittstellen Stand: 16.10.03 VK_HOME 0x24 VK_LEFT 0x25 VK_UP 0x26 VK_RIGHT 0x27 VK_DOWN 0x28 VK_SELECT 0x29 VK_PRINT 0x2A VK_EXECUTE 0x2B VK_SNAPSHOT 0x2C VK_INSERT 0x2D VK_DELETE 0x2E VK_HELP 0x2F VK_0...VK_9 0x30... 0x39 VK_A...VK_Z 0x41... 0x5A VK_LWIN 0x5B VK_RWIN 0x5C VK_APPS 0x5D VK_NUMPAD0 0x60 VK_NUMPAD1 0x61 VK_NUMPAD2 0x62 VK_NUMPAD3 0x63 VK_NUMPAD4 0x64 VK_NUMPAD5 0x65 VK_NUMPAD6 0x66 VK_NUMPAD7 0x67 VK_NUMPAD8 0x68 VK_NUMPAD9 0x69 VK_MULTIPLY 0x6A VK_ADD 0x6B VK_SEPARATOR 0x6C VK_SUBTRACT 0x6D VK_DECIMAL 0x6E VK_DIVIDE 0x6F VK_F1 0x70 VK_F2 0x71 VK_F3 0x72 VK_F4 0x73 VK_F5 0x74 VK_F6 0x75 VK_F7 0x76 VK_F8 0x77 VK_F9 0x78 VK_F10 0x79 VK_F11 0x7A VK_F12 0x7B VK_F13 0x7C VK_F14 0x7D VK_F15 0x7E VK_F16 0x7F VK_F17 0x80 VK_F18 0x81 VK_F19 0x82 VK_F20 0x83 VK_F21 0x84 VK_F22 0x85 VK_F23 0x86 VK_F24 0x87 VK_NUMLOCK 0x90 VK_SCROLL 0x91 VK_LSHIFT 0xA0 VK_RSHIFT 0xA1 VK_LCONTROL 0xA2 VK_RCONTROL 0xA3 VK_LMENU 0xA4 VK_RMENU 0xA5 VK_PROCESSKEY 0xE5 WINVER <=0x04 00 VK_ATTN 0xF6 VK_CRSEL 0xF7 VK_EXSEL 0xF8 VK_EREOF 0xF9 VK_PLAY 0xFA VK_ZOOM 0xFB VK_NONAME 0xFC VK_PA1 0xFD VK_OEM_CLEAR 0xFE Z.B. wird durch die Alt - Taste die wParam = VK_MENU Nachricht generiert. VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() - Funktionen benutzt. Tasten - Zustand - Flags © Thomas Kowarsch Seite 70/101 Systemschnittstellen Stand: 16.10.03 Der aktuelle Zustand aller Tasten wird in einem Buffer protokolliert. Auch die Applikation kann diese Einträge lesen/schreiben, wobei zwischen synchron/asynchron unterschieden wird. Wird eine neue Tasten - Nachricht in den Applikations - Nachrichten - Warteschlange ( Applikations - Buffer ) eingetragen, so ändert sich der asynchron Keyboard - Zustand. Der synchron Keyboard - Zustand entspricht dem momentanen Zustand der Tastatur. 6.5.4.a)Wie kann eine gedrücke SHIFT - Taste abgefragt werden? if ( GetKeyState ( VK_SHIFT ) & 0x80000000L ) { // SHIFT - Taste gedrückt } GetKeyState() ( imGegensatz zu GetAsyncKeyState ) liefert den Zustand ohne Verzögerung zurück. Durch GetKeyState ( VK_LBUTTON ) wird z.B. der aktuelle Zustand der linken Maustaste abgefragt. 6.5.4.b)Wie kann eine Berechnung abgebrochen werden? Dauert z.B. eine Berechnung zu lange und soll diese Berechnung durch • die Escape - Taste oder • die linke Maus - Taste abgebrochen werden, so kann dies mit der ( asynchronen ) GetAsyncKeyState() - Funktion if ( ( GetAsyncKeyState ( VK_LBUTTON ) < 0 ) // linke Maus - Taste down || ( GetAsyncKeyState ( VK_ESCAPE ) < 0 ) // Escape Taste ){ ... z.B. ... exit ( -1 ); oder ... SendMessage ( hWnd, WM_CLOSE, 0, 0 ) } erfolgen. Um den Zustand von mehreren Tasten zu untersuchen, wie z.B. die • Shift - Taste ( VK_SHIFT, VK_LSHIFT, VK_RSHIFT ), • Ctrl - Taste ( VK_CONTROL, VK_LCONTROL, VK_RCONTROL ), • Alt - Taste ( VK_MENU, VK_LMENU, VK_RMENU ) können alle 256 Virtual Keys in einen Buffer buf kopiert werden. Die Funktionen GetKeyboardState(), SetKeyboardState(), GetAsyncKeyState(), GetKeyState(), MapVirtualKey() werden benutzt. Es kann dann z.B. zwischen linken und rechten SHIFT Tasten unterschieden werden. Die GetKeyboardState( buf ) - Funktion kopiert alle 256 Virtual Keys in einen Buffer buf. Eine Taste ist gerade gedrückt, wenn das 7. Bit gesetzt ist ( sonst 0 ). Der Gedrückt/Losgelassen - Zustand hat © Thomas Kowarsch Seite 71/101 Systemschnittstellen Stand: 16.10.03 gewechselt, wenn das 0. Bit gleich 1 ist ( tggled ). Normalerweise ist eine Taste nicht gedrückt, dann ist das 0. Bit gleich 1. 6.5.4.c)Wie kann eine gedrückte CTRL - Taste ( VK_CONTROL ) per Programm simuliert werden? BYTE buf[256]; GetKeyboardState( buf ); // hole VK_ - Keys buf[VK_CONTROL] |= 0x80; // setze "gedrückt" bei VK_CONTROL - Taste SetKeyboardState( buf ); // schreibe VK_ - Keys zurück 6.5.4.d)Wie kann die CAPS - LOCK - Taste ( VK_CAPITAL ) invertiert werden? BYTE buf[256]; GetKeyboardState( buf ); if ( buf[VK_CAPITAL] & 1 ) buf[VK_CAPITAL] &= 0xFE; else buf[VK_CAPITAL] |= 0x01; SetKeyboardState( buf ); VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() - Funktionen benutzt. 6.5.4.e)Wie kann ein "floating - pop - up - menu" nach der Anzeige sichtbar bleiben? case WM_RBUTTONDOWN: BYTE buf[256]; GetKeyboardState( buf ); // hole VK_ - Keys buf[VK_RBUTTON] = 0x00; // setze "losgelassen" bei VK_RBUTTON - Maus - Taste SetKeyboardState( buf ); // schreibe VK_ - Keys zurück ... create - pop - up - Menu ... ... call TrackPopUp ... break; lParam - Tastenflags TranslateMessage() benutzt die Funktion ToAsciiEx() um den virtuellen Key - Code ( z.B. für die WM_KEYDOWN - Nachricht ) zu erzeugen. Eine Nachricht enthält in LOWORD( lParam ) die Anzahl von automatischen Tasten - Wiederholungen. Durch diesen Anschlag Wiederholungs - Zähler werden Überflutungen von Nachrichten vermieden. In HIWORD( lParam ) sind interessante Tasten - Flags, die im folgenden erklärt werden. Eine Nachricht enthält in HIWORD( lParam ) interessante Tasten - Flags, die im folgenden erklärt werden. Bit HIWORD( lParam ) - Bits 15 1 if the key is up; 0 if the key is down. © Thomas Kowarsch Seite 72/101 Systemschnittstellen 14 1 if the key was previously up; 0 if the key was previously down. 13 1 if the ALT key is down. 12 1 if Windows displays a menu. 11 1 if Windows displays a dialog box. 10 Not used. 9 Not used. 8 1 if the key is extended; 0 if it is not. 7 generally 0. 6..0 hardware-scan code (used mainly in the translation of ALT+number-pad character code input). Stand: 16.10.03 6.5.5.Maus - Nachrichten Die Maus - Nachrichten werden in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die CALLBACK - Funktion des Fensters wird mit der Maus - Nachricht ( iMsg, wParam, lParam ) aufgerufen, d.h. • die Maus - Nachrichten werden an das Fenster geschickt. Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster ( genauer: der Speicher für die Fensterdaten ) erreichbar. In iMsg ist die Maus Nachricht eindeutig identifizierbar. Typische iMsg sind: WM_LBUTTONDOWN, WM_RBOTTOMDOWN, WM_MOUSEMOVE, WM_NCLBUTTONDBLCLICK. Die Behandlung von Maus - Ereignisses geschieht vielfach in der CALLBACK - Funktion. In lParam wird die aktuelle Maus - Position an die CALLBACK - Funktion übergeben. © Thomas Kowarsch Seite 73/101 Systemschnittstellen Stand: 16.10.03 LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { switch ( iMsg ) { ... case WM_LBUTTONDOWN : x = LOWORD(lparam); // 16 BIT y = HIWORD(lparam) // pt = MAKEPOINT(lparam); // 32 BIT, pt vom Typ Point break; ... } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } Für einen Doppel - Klick muß nach WM_LBUTTONDOWN ein Zähler gestartet werden. Deshalb ist für einen Doppelklick ein Eintrag WNDCLASSEX wndclass={ 0 }; wndclass.cbSize=sizeof(WNDCLASSEX); ... wndclass.style = ... | CS_DBLCLKS; // Zeitgeber ½ sec. RegisterClass( & wndclass ); erforderlich. WM - Maus - Nachrichten Ein Fenster besteht aus dem Fenster - Inneren ( Client - Bereich ) und dem Nicht Client - Bereich ( NC ). Auch der Fenster - Rand gehört zu NC. Maus-Nachricht wParam, lParam enthalten ... weitere Spezifizierun g ... WM_CAPTUR ECHANGED hwndNewCap ture = (HWND) lParam; // handle of window to gain mouse capture © Thomas Kowarsch Seite 74/101 Systemschnittstellen WM_MOUSE MOVE WM_LBUTTO NDOWN WM_LBUTTO NUP WM_RBUTTO NDOWN WM_RBUTTO NUP WM_MBUTTO NDOWN WM_MBUTTO NUP WM_LBUTTO NDBLCLK WM_MBUTTO NDBLCLK WM_RBUTTO NDBLCLK WM_MOUSEA CTIVATE Stand: 16.10.03 fwKeys = wParam; // key flags xPos = LOWORD (lParam); // horizontal position of cursor yPos = HIWORD (lParam); // vertical position of cursor hwndTopLev el = (HWND) wParam; // handle of top-level parent nHittest = (INT) LOWORD (lParam); // hit-test value uMsg = (UINT) HIWORD (lParam); // mouse message © Thomas Kowarsch fwKeys: MK_CONTROL Set if the CTRL key is down. MK_LBUTTON Set if the left mouse button is down. MK_MBUTTON Set if the middle mouse button is down. MK_RBUTTON Set if the right mouse button is down. MK_SHIFT Set if the SHIFT key is down. nHittest is the return value of DefWindowProc: MA_ACTIVATE Activates the window, and does not discard the mouse message. MA_ACTIVATEANDEAT Activates the window, and discards the mouse message. MA_NOACTIVATE Does not activate the window, and does not discard the mouse message. MA_NOACTIVATEANDEAT Does not activate the window, but discards the mouse message Seite 75/101 Systemschnittstellen WM_MOUSE WHEEL © Thomas Kowarsch Stand: 16.10.03 fwKeys = LOWORD (wParam); // key flags zDelta = (short) HIWORD (wParam); // wheel rotation xPos = (short) LOWORD (lParam); // horizontal position of pointer yPos = (short) HIWORD (lParam); // vertical position of pointer fwKeys: MK_CONTROL Set if the CTRL key is down. MK_LBUTTON Set if the left mouse button is down. MK_MBUTTON Set if the middle mouse button is down. MK_RBUTTON Set if the right mouse button is down. MK_SHIFT Set if the SHIFT key is down. Seite 76/101 Systemschnittstellen WM_NCHITT EST © Thomas Kowarsch Stand: 16.10.03 xPos = LOWORD (lParam); // horizontal screen position of cursor yPos = HIWORD (lParam); // vertical screen position of cursor Value Location of hot spot is the return value of DefWindowProc: HTBORDER In the border of a window that does not have a sizing border HTBOTTOM In the lower horizontal border of a window HTBOTTOMLEFT In the lower-left corner of a window border HTBOTTOMRIGHT In the lower-right corner of a window border HTCAPTION In a title bar HTCLIENT In a client area HTCLOSE In a close button HTERROR On the screen background or on a dividing line between windows (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error) HTGROWBOX In a size box (same as HTSIZE) HTHELP In a Help button HTHSCROLL In a horizontal scroll bar HTLEFT In the left border of a window HTMENU In a menu HTMAXBUTTON In Maximize button HTMINBUTTON In Minimize button HTNOWHERE On the screen background or on a dividing line between windows HTREDUCE In a Minimize button HTRIGHT In the right border of a window HTSIZE In a size box (same as HTGROWBOX) HTSYSMENU In a System menu or in a Close button in a child window HTTOP In the upper horizontal border of a window HTTOPLEFT In the upper-left corner of a window border HTTOPRIGHT In the upper right corner of a window border HTTRANSPARENT In a window currently covered by another window HTVSCROLL In the vertical scroll bar HTZOOM In a Maximize button Seite 77/101 Systemschnittstellen WM_NCLBUT TONDBLCLK WM_NCLBUT TONDBLCLK WM_NCLBUT TONDOWN WM_NCLBUT TONUP WM_NCMBU TTONDBLCLK WM_NCMBU TTONDOWN WM_NCMBU TTONUP WM_NCMOU SEMOVE WM_NCRBUT TONDBLCLK WM_NCRBUT TONDOWN WM_NCRBUT TONUP Stand: 16.10.03 nHittest = (INT) wParam; // hit-test value pts = MAKEPOINTS (lParam); // position of cursor nHittest see WM_NCHITTEST Das Maus - Rad ( WM_MOUSEWHEEL ) kann z.B. zur Steuerung von Scroll - Bars eingesetzt werden 6.5.6.DefWindowProc Einige Nachrichten werden in der eigenen CALL-Klassen-CALBACKFunktionen behandelt. Alle anderen Nachrichten werden an die "default - Windows - CALLBACK - Funktion" DefWindowProc() übergeben. DefWindowProc() ist wie eine Applikations - CALLBACK - Funktion aufgebaut. DefWindowProc() behandelt die folgenden Nachrichten: WM_NCCREATE, WM_NCCALCSIZE, WM_NCHITTEST, WM_NCPAINT, WM_NCACTIVATE, WM_CANCELMODE, WM_SETTEXT, WM_GETTEXT, WM_GETTEXTLENGTH, WM_PAINT, WM_PAINTICON, WM_ERASEBKGND, WM_ICONERASEBKGND, WM_SYNCPAINT,WM_SYSCOMMAND, WM_ACTIVATE, WM_SETREDRAW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED,WM_CTLCOLOR, WM_SETCURSOR, WM_MOUSEACTIVATE, WM_SHOWWINDOW, WM_NCLBUTTONDOWN, WM_NCLBUTTONUP, WM_NCLBUTTONDBLCLK, WM_NCMOUSEMOVE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP, WM_SYSCHAR, WM_CLOSE, WM_QUERYOPEN, WM_QUERYENDSESSION, WM_ISACTIVEICON, WM_CHARTOITEM, WM_VKEYTOITEM, WM_DRAWITEM, WM_GETHOTKEY, WM_SETHOTKEY, WM_QUERYDRAGICON, WM_QUERYDROPOBJECT, WM_DROPOBJECT, © Thomas Kowarsch Seite 78/101 Systemschnittstellen Stand: 16.10.03 © Thomas Kowarsch Seite 79/101 Systemschnittstellen Stand: 16.10.03 6.6.Dialoge Es gibt zahlreiche Funktionen, die zum Erzeugen und Manipulieren von modalen/modeless Dialogen und deren Unterfenster ( Controls ) dienen: CreateDialog CreateDialogIndirect CreateDialogIndirectParam CreateDialogParam DefDlgProc DialogBox DialogBoxIndirect DialogBoxIndirectParam DialogBoxParam DialogProc EndDialog GetDialogBaseUnits GetDlgCtrlID GetDlgItem GetDlgItemInt GetDlgItemText GetNextDlgGroupItem GetNextDlgTabItem IsDialogMessage MapDialogRect MessageBox MessageBoxEx SendDlgItemMessage SetDlgItemInt SetDlgItemText MessageBoxIndirect 6.6.1.Modale Dialoge Ein modaler Dialog enthält eine eigene Nachrichten-Schleife. Erscheint ein ( Applikations-)modale Dialog - Box auf dem Bildschirm so wird in dieser Nachrichten-Schleife "gewartet", bis der Benutzer reagieren und den Dialog beendet. Messagebox Eine MessageBox() entspricht einem modalen Dialog. Z.B. wird die Applikation blockiert, bis der Benutzer den "OK" - Button gedrückt hat. Eine MessageBox() erzeugt die Anzeige - Box für Ausgabe-Text ohne externe Resourcen. Eine eingebaute ( intern verfügbare ) CALLBACK Funktion behandelt die Nachrichten. Es gibt eine Anzahl von verwendbaren Icons und Push-Buttons. int MessageBoxEx( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType, // style of message box WORD wLanguageId // language identifier ); MessageBoxEx() hat gegenüber MessageBox() einen zusätlichen WORD wLanguageId - Parameter. Falls hWnd = NULL verwendet wird, so gehört die Message - Box zu keinem speziellen Fenster. lpCaption zeigt auf den auszugebenden Text. Für lpszTitle = NULL ist, wird in der Titel - Zeile "Error" angezeigt. Im Fehlerfall gibt die MessageBoxEx() den Wert 0 zurück. Im Erfolgsfall gibt die MessageBoxEx() eine © Thomas Kowarsch Seite 80/101 Systemschnittstellen Stand: 16.10.03 positiven Wert zurück. Der Rückgabe - Wert entspricht dem gedrückten Button. IDABORT Abort button was selected. IDCANCEL Cancel button or ESC key was selected. IDIGNORE Ignore button was selected. IDNO No button was selected. IDOK OK button was selected. IDRETRY Retry button was selected. IDYES Yes button was selected. Für uType kann verwendet werden: MB_ABORTRETRYIGNORE three push buttons: Abort, Retry, and Ignore. MB_OK one push button: OK. This is the default. MB_OKCANCEL two push buttons: OK and Cancel. MB_RETRYCANCEL two push buttons: Retry and Cancel. MB_YESNO two push buttons: Yes and No. MB_YESNOCANCEL three push buttons: Yes, No, and Cancel. -------------------------------------------------------------MB_ICONEXCLAMATION, MB_ICONWARNING icon ( exclamationpoint ) MB_ICONINFORMATION, MB_ICONASTERISK icon ( i in a circle ) MB_ICONQUESTION icon ( question-mark ) MB_ICONSTOP, MB_ICONERROR, MB_ICONHAND icon ( stop -sign ) -------------------------------------------------------------MB_DEFBUTTON1 MB_DEFBUTTON2 MB_DEFBUTTON3 MB_DEFBUTTON4 The The The The first button is the default button. second button is the default button. third button is the default button. fourth button is the default button. -------------------------------------------------------------more: MB_APPLMODAL, MB_SYSTEMMODAL, MB_TASKMODAL, MB_DEFAULT_DESKTOP_ONLY, MB_HELP, MB_RIGHT, MB_RTLREADING, MB_SETFOREGROUND, MB_TOPMOST, MB_SERVICE_NOTIFICATION, MB_SERVICE_NOTIFICATION_NT3X © Thomas Kowarsch Seite 81/101 Systemschnittstellen Stand: 16.10.03 Beispiele: MessageBox( 0,"Client-Bereich",0, MB_OK ); MessageBox(hwnd,"MB_ICONINFORMATION","Titel", MB_OK|MB_ICONINFORMATION); Der einfache Aufruf einer MessageBox()-Funktion begrenzt die optische Ausgestaltung, die Anzeigeposition und - Form, die enthaltenen Buttons ( Controls ), usw, auf das notwendigste. Eine erweiternde Gestaltung ist nicht möglich. Eine MessageBox() gehört zu den modalen Dialogen ( Benutzer muß reagieren ). Eine ( allgemeine ) Dialog - Box kann mit der DialogBox()-Funktion aufgerufen werden. Die DialogBox()-Funktion braucht eine Dialog-CALLBACK-Funktion und ein Ressourcen-Script ( flexible optische Gestaltung ). Die DialogBox() kann Controls enthalten, die Informationen angezeigen und Benutzereingaben erlauben ( Texteingaben, Auswahlaktionen, usw. ). Diese Unter - Fenster ( Child - Windows == Controls ) einer DialogBox () werden Controls genannt. Die "DialogBox() - Funktion" ist ein Macro, das gemäß #define DialogBoxA( lpDialogFunc) \ hInstance, lpTemplate, hWndParent, DialogBoxParamA( hInstance, lpTemplate, hWndParent, lpDialogFunc, 0L) definiert ist. Die Funktion WINUSERAPI int WINAPI DialogBoxParamA( HINSTANCE hInstance, // handle to application instance LPCTSTR lpTemplate, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc // pointer to dialog box procedure LPARAM dwInitParam //wird bei WM_INITDIALOG in lParam an CALLBACK weitergereicht ); © Thomas Kowarsch Seite 82/101 Systemschnittstellen Stand: 16.10.03 hInstance kann durch GetModuleHandle( NULL) oder unter WM_CREATE durch static HINSTANCE hInstance = ( LPCREATESTRUCT ) lParam-> hInstance ermittelt werden. 6.6.1.a)Beispiel: DialogBox als Hauptprogramm Existiert eine IDD_DIALOG-Dialog-Ressource und die dlg-CALLBACKFunktion dlgProc), so kann das Hauptprogramm etwa wie folgt aussehen: //Hauptprogramm int APIENTRY WinMain( HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain) { return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)dlgProc); } Die DialogBox() - Funktion verwendet intern die CreateWindowEx() Funktion. Es wird i.a. eine interne vorhandene ( Dialog - ) Klassen Registrierung benutzt ( DefDlgProg, default dialog class ). Für die DialogBox() wird eine eigener, zusätzlicher Nachrichten Buffer und eine eigene Nachrichten - Loop - Behandlung eingerichtet. Bevor die Dialog - Box sichtbar wird, sendet DialogBox() die WM_INITDIALOG - Nachricht an die lpDialogFunc - Funktion. In der CALLBACK - Funktion wird WM_INITDIALOG im Normalfall mit return FALSE beendet. Falls die Dialog - Box den DS_SETFONT - Style hat, so wird die WM_SETFONT - Nachricht an die lpDialogFunc - Funktion gesendet. Wenn der WS_VISIBLE - Style spezifiziert wurde, so erscheint die Dialog - Box. Durch EndDialog ( hWnd, wParam ) wird der Dialog beendet, der allokierte Speicher wird freigegeben. DialogBox() gibt wParam zurück. Eine private Dialog - Klasse muß WNDCLASS - Struktur besetzten ( cbWndExtra = DLGWINDOWEXTRA ) und RegisterClass() aufrufen. Das Dialog - Template muß dann das CLASS - Statement enthalten. © Thomas Kowarsch Seite 83/101 Systemschnittstellen Stand: 16.10.03 Gegenüber einer MessageBox() ist der Programmier - Aufwand bei Verwendung von DialogBox() größer. int DialogBox( HINSTANCE hInstance, // handle to application instance LPCTSTR lpTemplate, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc // pointer to dialog box procedure ); DialogBox() erzeugt mit lpTemplate = MAKEINTRESOURCE( idRes ) aus der *.RC - Template Resource idRes die DialogBox, indem automatisch die Resourcen - Daten in den Speicher geladen werden und die DialogBox angezeigt wird. Durch eine System - Klassen CALLBACK - Funktion werden bestimmte Ereignisse ( Tab, ... ) ( vor - ) behandelt. Ein typischer Aufruf hat die Form: int rval = DialogBox ( hInstance, MAKEINTRESOURCE( idRes ), hWnd, ( DLGPROC )dlgProc ) ; Zur Behandlung der Ereignisse muß eine DIALOG - CALLBACK Funktion geschrieben werden. Diese Funktion wird mit DLGPROC lpDialogFunc an DialogBox() übergeben. Der modale Dialog wird erst beendet, wenn in der eigenen CALLBACK - Funktion EndDialog() ausgeführt wird. Der Dialog wird meisten unter WM_CLOSE durch EndDialog ( hWnd, rval ) beendet. Der Rückgabe - Wert von int DialogBox() ist hier rval. Bei einem Fehler wird -1 zurück gegeben. © Thomas Kowarsch Seite 84/101 Systemschnittstellen Stand: 16.10.03 Steht im *.RC - FIle unter IDD_DIALOG_ABOUT die Resourcen Beschreibung der Dialog - Box, so wird z.B. in der Fenster - CALLBACK - Funktion WndProc() ( unter dem Menu - Punkt ID_MAIN_MENU_1 ) diese modale Dialog - Box erscheinen, wenn LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { case WM_CREATE : ... break ;//return 0; case WM_PAINT : ... break ; //return 0; case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0; case WM_COMMAND: int wmId = LOWORD( wParam ); int wmEvent = HIWORD( wParam ); switch ( wmId ) { case ID_MAIN_MENU_1: //Aufruf der Dialog – Box Dialog_Box( hWnd, IDD_DIALOG_ABOUT,myDlgBox ) ; break ; } } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } eingetragen wird. Die Dialog - CALLBACK - Funktion myDlgBox ( muß BOLL zurück geben ) ist zu schreiben. In myDlgBox ( muß BOLL zurück geben ) sind die Buttons, Texteingaben, Radiobuttons, usw. zu behandeln. BOOL myDlgBox( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { switch ( iMsg ) { case WM_INITDIALOG : break; case WM_COMMAND: switch ( LOWORD( wParam ) ) { case IDOK : case IDCANCEL : SendMessage( hWnd , WM_CLOSE, LOWORD( wParam ), 0 ); return TRUE; } case WM_CLOSE : EndDialog ( hWnd, wParam ); //beendet den modalen Dialog break; //return TRUE; } return FALSE; } © Thomas Kowarsch Seite 85/101 Systemschnittstellen Stand: 16.10.03 Beim Initialisieren des Dialoges ( vor dem Sichtbarwerden ) wird die WM_INITDIALOG - Nachricht gesendet ( sonst WM_CREATE ). Diese Nachricht kommt, bevor das Fenster erscheint. Unter WM_INITDIALOG können Anpassungen von Controls vorgenommen werden. Soll z.B. der Dialog ( bezüglich des Fensters hWnd ) mittig zentriert erscheinen, so kann unter WM_INITDIALOG die Position ermittelt und gesetzt werden. 6.6.1.b)About-Dialog Die Resourcen werden mit Hilfe eines Identifizierers angesprochen. Für das gesamte About - Template wird Die Konstante IDOK ist verfügbar und wird für den OK-Button verwendet. Das Icon ist bereits unter IDI_MAIN_ICON vorhanden und kann in das About - Template eingefügt werden. Das MENUITEM "&About", ID_MENUITEM_ABOUT wird für den Aufruf des About - Dialoges verwendet. Die Konstante IDC_STATIC entspricht der Zahl -1. 6.6.1.c)Aufruf des About-Dialogs: Der *.CPP - File enthält die Dialog - CALLBACK - Funktion dlgAboutProc und die Fenster - CALLBACK - Funktion WndProc, in der der Dialog durch Dialog_Box( hWnd, IDD_DIALOG_ABOUT, dlgAboutProc ) ; aufgerufen wird. BOOL CALLBACK dlgAboutProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { case WM_INITDIALOG: ... break; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: case IDCANCEL: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; } break; case WM_CLOSE: EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ); break; } return FALSE; } © Thomas Kowarsch Seite 86/101 Systemschnittstellen Stand: 16.10.03 LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { case WM_CREATE: ... break ;//return 0; case WM_PAINT: ... break ; //return 0; ... case WM_COMMAND: switch ( LOWORD( wParam ) ) { case ID_MENUITEM_ABOUT: //Aufruf der About – Box Dialog_Box( hWnd, IDD_DIALOG_ABOUT, dlgAboutProc ) ; break ; } case WM_DESTROY: PostQuitMessage(0); break; //return 0; ... } return DefWindowProc( hWnd,iMsg,wParam,lParam ) ; } 6.6.2.Modless Dialoge Mit der Funktion IsDialogMessage() können Nachrichten der Nachrichten-Schleife an das hDlgModeless-Fenster verteilt werden. Die Modless - Dialog - Nachrichten müssen durch Erweiterung der Haupt Nachrichten - Schleife "verschickt" werden. Es können mehrere Modeless - Dialoge gleichzeitig geöffnet sein. Für die Erweiterung der Haupt - Nachrichten - Schleife kann eine globale Variable HWND hDlgModeless verwendet werden. Ist das globale Handle hDlgModeless != NULL, so ist kein Modless - Fenster "offen". Wird ein Modless Fenster aktiviert ( WM_ACTIVATE ), so wird das globale Handle hDlgModeless mit dem Handle des aktiven Fensters überschrieben. Weil nur ein Fenster aktiv ist und den Focus hat, können beliebig viele Modless - Fenster "gleichzeitig offen" sein. für Modeless: Haupnachrichten-Schleife while ( GetMessage( & msg, NULL, 0, 0 ) ) { if ( NULL == hDlgModeless || ! IsDialogMessage ( hDlgModeless, & msg ) ) { TranslateMessage( & msg ); DispatchMessage ( & msg ); } } © Thomas Kowarsch Seite 87/101 Systemschnittstellen Stand: 16.10.03 6.6.2.a)CreateDialog() - Aufruf LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { ... case WM_COMMAND: switch ( LOWORD( wParam ) ) { case ID_MENUITEM_MODELESS: //Aufruf der About – Box Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) ; break ; } } ... return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } Die Funktion Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) benötigt die Resource IDD_DIALOG_MODELESS und die CALLBACK - Funktion dlgModelessProc(). 6.6.3.Controls Ein Dialog enthält untergeordnete Fenster ( Controls ). Zu einem Control gehört i.a. eine eingebauten Klasse. Die Klasse enthält eine eingebaute CALLBACK - Funktion, die die Ereignisse behandelt. Zu einer ein/mehr - zeiligen Texteingabe gehört die Klasse "Edit". Zu einem Button gehört die Klasse "Button". Mit der Kenntnis dieser Control - Ereignisse können die Controls genutzt werden. Als Beispiel werden die Combo - Box - Ereignisse angefügt. Die Combo - Box ( Edit - Zeile mit List - Box ) kann die folgenden Nachrichten senden/empfangen/behandeln: Combo Box Messages CB_ADDSTRING CB_DELETESTRING CB_DIR CB_FINDSTRING CB_FINDSTRINGEXACT CB_GETCOUNT CB_GETCURSEL CB_GETDROPPEDCONTROLRECT CB_GETDROPPEDSTATE CB_GETDROPPEDWIDTH CB_GETEDITSEL CB_GETEXTENDEDUI CB_GETHORIZONTALEXTENT CB_GETITEMDATA © Thomas Kowarsch Seite 88/101 Systemschnittstellen Stand: 16.10.03 CB_GETITEMHEIGHT CB_GETLBTEXT CB_GETLBTEXTLEN CB_GETLOCALE CB_GETTOPINDEX CB_INITSTORAGE CB_INSERTSTRING CB_LIMITTEXT CB_RESETCONTENT CB_SELECTSTRING CB_SETCURSEL CB_SETDROPPEDWIDTH CB_SETEDITSEL CB_SETEXTENDEDUI CB_SETHORIZONTALEXTENT CB_SETITEMDATA CB_SETITEMHEIGHT CB_SETLOCALE CB_SETTOPINDEX CB_SHOWDROPDOWN CBN_CLOSEUP CBN_DBLCLK CBN_DROPDOWN CBN_EDITCHANGE CBN_EDITUPDATE CBN_ERRSPACE CBN_KILLFOCUS CBN_SELCHANGE CBN_SELENDCANCEL CBN_SELENDOK CBN_SETFOCUS WM_COMPAREITEM WM_DRAWITEM WM_MEASUREITEM Um einem Control eine Nachricht zu schicken wird anstelle von HWND hCtl = GetDlgItem ( HWND hDlg, int idRes ); LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam); oft LONG SendDlgItemMessage ( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam, LPARAM lParam); benutzt. © Thomas Kowarsch Seite 89/101 Systemschnittstellen Stand: 16.10.03 7.Dynamic-Link Library's Das Windows - Betriebssystem besteht aus Dynamic-Link Libraries ( DLL's ). DLL's sind z.B. kernel32.dll, user32.dll, gdi32.dll, ). Mit pview.exe können die geladenen DLLs angezeigt werden. Der Compiler übersetzt jeden *.asm-, *.c-, *.cpp-FIle in einen *.obj-File. Eine Static-Link-Library ( herkömmliche *.lib-Bibliothek ) entspricht einer solchen der Code-, Daten-Sammlung ( z.B. libc.libObjektbibliothek, normale C-Laufzeitbibliothek ). Beim Erstellungsvorgang ( "statisches Binden" ) wird in jede Applikation der LIB-Code und die LIB-Daten kopiert. Dadurch entsteht ein einheitlicher Adressraum. Weil viele Applikationen den gleichen Bibliotheks-Code enthalten verschwendet dieses statische Verfahren Speicherplatz. Applikation1 DLL Applikation2 Code der App @dllFunc Code der App call dllFunc() ... call strlen() Code der Dll dllFunc-Code call strlen() call dllFunc() ... call strlen() Static-Libary -Code strlen() Static-Libary -Code strlen() Static-Libary -Code strlen() Resourcen Resourcen Resourcen Daten Daten Daten Stack Stack Applikation1 DLL Applikation2 Code der App @dllFunc Code der App call dllFunc() ... call strlen() Code der Dll dllFunc-Code call strlen() call dllFunc() ... call strlen() Static-Libary -Code strlen() Static-Libary -Code strlen() Static-Libary -Code strlen() Resourcen Resourcen Resourcen Daten Daten Daten Stack Stack Applikation1 und Applikation2 nutzen die DLL © Thomas Kowarsch Seite 90/101 Systemschnittstellen Stand: 16.10.03 7.0.1.Wie löst der Linker die DLL_Einsprünge auf? CQuelltext func1(); ASMQuelltext call func1 ASM-Quelltext ohne __declspec (dllimport) call 0x4000000; 0x4000000 ist die Adresse von func1 ASM-Quelltext mit __declspec(dllimport) 0x40000000: jmp DWORD PTR __imp_func1 __imp_func1 ist die Adresse der .exe-Importadreßtabelle Eine Dynamic-Link Library ( DLL ) entspricht ( grob ) einem ausführbaren File ( ausführbarer Code, allgemeine Daten, Resourcen ) der zur Laufzeit in den Arbeitsspeicher geladen und von mehreren Applikationen genutzt wird. Eine DLL kann eine beliebige File-Endung ( z.B. *.fon ) haben. Dann muss die DLL explizit mit LoadLibrary() in den Arbeitsspeicher geladen werden ( Explicit dynamic linking ). System-DLLs sind z.B. user.exe, gdi.exe, krnl286.exe, krnl386.exe, mouse.drv, keyboard.drv. //Beispiel für explizites Laden der DLL: typedef int ( * LPFUNC1) ( int ); typedef double ( * LPFUNC2) ( int, double ); LPFUNC1 lpFunc1a, lpFunc1b; LPFUNC2 lpFunc2; HINSTANCE hLib = GetModuleHandle("myDll.dll"); if ( hLib == NULL ) hLib = LoadLibrary("myDll.dll"); // Load the DLL now if ( hLib == NULL ) error ... lpFunc1a = (LPFUNC1) GetProcAddress( hLib, "myFunc" ); if ( lpFunc1a != NULL) int i1a = ((lpFunc1a)(4711)); else error ... lpFunc1b = (LPFUNC1) GetProcAddress( hLib, MAKEINTRESOURCE(1) ); if (lpFunc1b != NULL) int i1b = ((lpFunc1b)(4711)); else error ... lpFunc2 = (LPFUNC2) GetProcAddress( hLib, MAKEINTRESOURCE(2) ); if (lpFunc2 != NULL) double x = ((lpFunc2)( 1.23, 47.11 )); else error ... FreeLibrary(hLib); // Unload DLL from memory Mit der DLL-Schnellansicht kann die Ordinal Number der exportierten Funktion ( 4 Byte-Index aus der DLL-Einsprung-Tabelle ) erhalten werden. @2 wird als MAKEINTRESOURCE(2) verwendet. Falls gewünscht kann beim Erstellen der DLL die Ordinal Number der Funktion im *.def-File explizit festgelegt werden. Sind die FunktionsParameter bekannt, so wird ( im obigen Beispiel ) keine dynamische *.lib benötigt. Hat die DLL die File-Endung *.dll, so kann diese DLL bei ProgrammAusführung automatisch in den Arbeitsspeicher geladen werden ( Implicit dynamic linking ). Beim Programmstart wird die DLL © Thomas Kowarsch Seite 91/101 Systemschnittstellen • im aktuellen Verzeichnis, • im Systemverzeichnis • im Windows eigenem Verzeichnis und • im Pfad der Umgebungsvariable Stand: 16.10.03 gesucht und ( falls gefunden ) geladen. Wird die benötigte DLL nicht gefunden, so wird eine Fehlermeldung ausgegeben. Eine Multithreaded DLL Version benötigt die C run-time library ( libcmt [D].lib ) oder die C run-time library( msvcrt[D].lib ). [D] steht für die Debug Version. Linker-Schalter: /MT /MD /ML Multithread-aware library (default for DLLs) MSVCRT40.DLL, dynamic-link library that is multithread aware Single-thread-aware library (default for applications) Verwendet wird z.B. void _endthread( void ); unsigned long _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void *arglist ); //Multithreaded DLL-Beispiel: HINSTANCE hLib = LoadLibrary("myDll.dll"); // Load the DLL now if ( hLib == NULL ) error ... ... _beginthread( firstThread, 0, NULL); // Start a thread Sleep(10000L); cout << "Exit Main Process" << endl; FreeLibrary(hLibrary); void firstThread(void* dummy) { HINSTANCE hLibrary = LoadLibrary("myDll.dll"); ... FreeLibrary(hLibrary); } Erstellen einer DLL Beim Erstellungsvorgang der DLL wird ein Header-File ( z.B. myDll.h ) und der DLL-Quellcode ( z.B. myDll.c ) benutzt. Daraus wird myDll.dll und die ( Adressen- ) Import-Bibliothek myDll.lib erzeugt. Der Erstellungsvorgang der Applikation ( z.B. myApp.c ) benutzt der Compiler für die Prüfung der Funktionsprototypen ( z.B. myDll.h ). Der Linker holt aus myDll.lib die "dynamischen DLLEinsprungpunkte" und erstellt ( z.B. myExe.exe ). Wird myExe.exe ausgeführt, so wird die myDll.dll aktuellen Verzeichnis, Systemverzeichnis und ggf. im Pfad gesucht und geladen. Zur Laufzeit benutzt myExe.exe die dynamisch gebundenen Funktionen ausmyDll.dll. Im Header-File wird verwendet: • Win32: __declspec(dllimport), __declspec(dllexport) • Win16: __export © Thomas Kowarsch Seite 92/101 Systemschnittstellen Stand: 16.10.03 Tritt beim Linken ein Fehler auf, wie etwa *.obj:error LNK2001: unresolved external symbol "?myFunc@@YAXPAD@Z (void __cdecl myFunc(char *))" so ist es vielfach günstig, die DLL-Erstellung mit "reinem C" durchzuführen. Dann wird die folgende Klammerung verwendet: #ifdef __cplusplus //in windows.h enthalten #define EXTERN_C extern "C" #else #define EXTERN_C extern #endif oder z.B. #if defined(__cplusplus) #define C_BEGIN extern "C" { //////////////////////////////// #define C_END } //////////////////////////////// #else #define C_BEGIN ///////////////////////////////////////////// #define C_END ///////////////////////////////////////////// #endif ////////////////////////////////////////////////////////// In window.h ist WINAPI, PASCAL, CALLBACK als __stdcall definiert. Die alten Win16-Bezeichner wie z.B. PASCAL, __far __pascal sollten in Win32 durch WINAPI ersetzt werden. Win32-API-Funktionen benutzen die "__stdcall calling convention". Dadurch erfolg automatisch ein __cdecl-Aufruf mit Stackbereinigung bei variablen Argumentlisten. Für __cdecl und __stdcall werden die Funktions-Argumente von rechts nach links auf den Applikations-Stack gelegt. Die folgende DLL wird mit myDll.h erstellt. Die DLL soll die Funktion __declspec( dllexport ) int myDllFunc( int i ) exportieren. Die Variable extern __declspec( dllexport ) int myDllInt wird in myDll.cpp definiert. Jede Applikation bekommt dann eine eigene int myDllInt. © Thomas Kowarsch Seite 93/101 Systemschnittstellen Stand: 16.10.03 #ifndef MYDLL_H #define MYDLL_H #include <windows.h> #ifdef _DLL #define DLL_EXPORT __declspec( dllexport ) #else #define DLL_EXPORT __declspec( dllimport ) #endif myDll. h extern DLL_EXPORT int myDllInt; DLL_EXPORT int myDllFunc( int i ); class DLL_EXPORT myDllClass { //exportiere Klasse public: myDllClass(void); //Konstruktor }; /////////////////// #endif //MYDLL_H /////////////////// © Thomas Kowarsch Seite 94/101 Systemschnittstellen Stand: 16.10.03 Quelltext für die DLL: //#define _DLL #include "myDll.h" myDll. c BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // DLL wird in den Adressraum des Prozesses eingeblendet. // Bei einem Fehler return FALSE case DLL_THREAD_ATTACH: // Ein Thread wird erstellt. // Hier können notwendige Initialisierungen durchgeführt werden // Serialisieren: // DisableThreadLibraryCalls( hModule ); // hThread = CreateThread( NULL, 0, SomeFunc, NULL, 0, &dwThreadId ); // WaitForSingleObject( hThread, INFINITE ); // CloseHandle ( hThread ); case DLL_THREAD_DETACH: // Ein Thread wird ordnungsgemäss verlassen. // Hier können notwendige Aufräumarbeiten durchgeführt werden case DLL_PROCESS_DETACH: // Die DLL wird aus dem Prozess-Adressraum ausgeblendet // Hier können notwendige Aufräumarbeiten durchgeführt werden // Auctung! // TerminateProzess() führt NICHT immer DLL_PROCESS_DETACH aus! // if ( pHeap != NULL ) HeapFree( GetProcessHeap(), 0, pHeap ); break; } return TRUE; } DLL_EXPORT int myDllInt=1; //exportierte Variable DLL_EXPORT int myDllFunc(int i) { //exportierte Funktion. char buf[256]; int j = i+myDllInt; wsprintf( buf, "i+myDllInt=%d", j ); MessageBox(0,buf,0,MB_OK); return j; } myDllClass::myDllClass() { //Konstruktor return; } 7.0.2.Wie wird diese DLL benutzt? //myDll.lib in das Applikations-Projekt aufnehmen! myApp.c © Thomas Kowarsch #include "myDll.h" ... myDllInt++; int i = myDllFunc( 3 + myDllInt ); ... Seite 95/101 Systemschnittstellen Stand: 16.10.03 8.Daemon Als Daemonen werden unter Linux die verschiedenen dienstbaren Geister bezeichnet. Sie sind in etwa vergleichbar mit den speicherresidenten Programmen unter DOS (TSR: terminate and stay resident). Sie warten unauffällig im Hintergrund, ob es etwas für sie zu tun gibt. Wenn ja, wird das erledigt, dann gehen sie wieder in Wartestellung. Ein typisches Beispiel ist der lpd, der line printer daemon. Er wartet, ob ein Druckauftrag gegeben wurde, wenn ja, wird er von ihm abgearbeitet. Der lpd kann Druckjobs entgegennehmen, auch wenn der Drucker nicht betriebsbereit oder sogar nicht einmal angeschlossen ist, die Dateien werden eben solange zwischengespeichert. Daemonen können z.B. gleich beim Systemstart aus den Startdateien heraus gestartet werden, z.B. aus /etc/rc.d/rc.local heraus. Daemonen im Leerlauf verbrauchen zwar nur wenig Systemleistung, bei einem gut ausgebauten Server sind aber recht viele Daemonen am Werk, die dann eben doch eine nennenswerte Grundlast erzeugen. Daher existiert noch eine weitere Startmöglichkeit über den Metadaemon inetd. Aufgrund von Konfigurationsdateien, deren Besprechung gleich folgt, achtet er permanent darauf, ob vom System die Dienste eines Dämonen benötigt werden. Wenn ja, startet er den entsprechenden Dämon, der sich nach Abarbeitung des Auftrages dann wieder beendet. Im Idealfall ist dann nur dieser Metadaemon permanent am Laufen, alle anderen laufen nur, wenn sie auch gerade benötigt werden. Der Metadaemon inetd wird bei uns aus der Datei / etc/rc.d/rc.inet2 heraus gestartet. Wann er welchen Daemon starten soll, erfährt inetd aus der Konfigurationsdatei /etc/inetd.conf heraus. Beispielsweise wird der POP-Server (Post Office Protocol, wird bei EMail genauer behandelt) bei Bedarf mit folgender Zeile gestartet: pop3 stream tcp nowait root /usr/sbin/tcpd /usr/sbin/in.pop3d Dabei steht ganz am Ende das eigentliche auszuführende Programm, das aber über den TCP-Wrapper tcpd, der nur berechtige Zugriffe zuläßt, aufgerufen wird. Der Name pop3 wird in der Datei /etc/services einer Portnummer zugeordnet, in diesem Fall: pop3110/tcp pop3110/udp © Thomas Kowarsch Seite 96/101 Systemschnittstellen Stand: 16.10.03 inetd lauscht nun u.a. am Port 110, ob dort eine Anfrage vorliegt. Wenn ja, wird der über den Namen pop3 zugeordnete Dämon in.pop3d gestartet. Dabei kann noch unterschieden werden zwischen TCPAnfragen (Transmission Control Protocol) und UDP-Anfragen 8.1.Schreiben von Daemon Beim Schreiben von Daemons sind folgende Regeln zu beachten: 1. Aufruf von fork und anschließendes Beenden des Elternprozesses Als erstes muß fork aufgerufen werde, und dann muss der Elternprozess sich mit exit beenden. So erreicht man beim Aufruf des Daemons in einer Shell, dass diese Shelle annimmt, das Kommando habe such beendet, und sie so den Benutzer mit der Ausgabe des Promptzeichens weitere Kommandos eingeben läßt. 2. Da der Kindprozess die Prozessgruppen-ID vom Elternprozess erbt, seinerseits abr eine neue Prozeß-ID erhält, ist sichergestellt, daß der Kindprozeß nicht ein Prozeßgruppenführer ist, was die Voraussetzung für den nächsten Schritt (Aufruf von setsid) ist. Aufrufen von setsid Mit einem setsid-Aufruf wird eine neue Session kreiert, was folgende Konsequenzen hat: - Der Prozeß wird Sessionführer der neuen Session - Der Prozeß wird Prozessgruppenführer der neuen Prozeßgruppe - Der Prozeß hat kein Kontrollterminal 3. Wechseln ins Root-Directory oder in ein spezielles Directory Da das von Elternprozeß geerbte Directory eventuell ein montiertes Filesystem sein könnte, empfielt es sich, ins Root-Directory zu wechseln. Der Grund dafür liegt in der Tatsache, daß beim Hochfahren eines Systems ein Filesystem, auf dem noch ein Prozeß (in diesem Fall der Daemon) läuft, nicht demontiert werden kann. Manche Daemonprozesse wechseln in ein spezielles Directory, in dem sie ihre Aktionen durchführen, wie z.B. der lpd-Daemon, der meist in Spool-Directory wechselt. © Thomas Kowarsch Seite 97/101 Systemschnittstellen Stand: 16.10.03 4. Setzen der Dateikreierungsmarke auf 0 Der Kindprozeß (Daemon) erbt die Dateikreierungsmarke vin seinem Elternprozeß. Damit der Daemin für seine kreierten Dateien auch genau die Zugriffsrechte erhält, die er fordert, ohne daß diese durch die geerbte Dateikreierungsmarke umgeändert werden, sollt er die Dateikreierungsmarke löschen (auf 0 setzen) 5. Schließen von nicht mehr benötigten Filedeskriptoren Der Daemon sollte die vom Elternprozeß geerbten offenen, aber nicht benötigten Filedeskriptoren schließen. Es hängt natürlich von den jeweiligen Daemons ab, welche Filedeskriptoren zu schließen sind. Wenn ein Daemon alle geerbten Filedeskriptoren schließen möchte, kann er mit sysconfig(_SC_OPEN_MAX) die Nummer des höchsten Filedeskriptor ermitteln und dann entsprechend alle Filedescriptoren schließen. © Thomas Kowarsch Seite 98/101 Systemschnittstellen Stand: 16.10.03 8.2.Beispiel #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int daemonisieren() { pid_t pid; if ( (pid = fork()) < 0) return -1; else if (pid != 0) exit (0); /* Elternprozess beendet sich */ /* Ab hier wird nur vom Kindprozess ausgeführt */ setsid(); /* Kind wird Sessionführer */ chdir("/"); /* Ins Root Directory wechseln */ umask(0); /* Dateikreierungsmaske loeschen */ } return 0; int main() { if (daemonisieren() != 0) { printf("FEHLER: Daemonisierung nicht moeglich.\n"); return -1; } printf("... ich bin jetzt ein Daemon...\n"); sleep(20); } printf("... Ich verabschide mich nun als Daemon ...\n"); return 1; 8.3.Fehlermeldungen Da Daemons kein Kontrollterminal haben, können sie Ihre Meldungen nicht einfach auf die Standarfehlerausgabe ausgeben. Auch ist es sicher nicht erwünscht, daß alle Daemons ihre Fehlermeldungen an der Systemkonsole ausgeben, was sehr störend für den Systemadministrator wäre. Ebenso ist es nicht klug, daß jeder Daemin seine Fehlermeldung in eine eigene Log-Datei schreibt. Die Überprüfung der einzelnen Dateien durch den Systemadministrator würde dann sehr aufwendig. © Thomas Kowarsch Seite 99/101 Systemschnittstellen Stand: 16.10.03 Was man braucht, ist eine zentrale Einrichtung, die für Meldungen von Daemons verantwortlich ist. Hierzu werden wir syslog verwenden. syslog ist ebenfalls ein Daemon, der die Nachrichten (beschrieben in / etc/syslog.conf) in die entsprechenden Dateien einträgt. Beschreibung hierzu siehe man syslog, bzw. man 3 syslog 8.4.Prozessgruppen und Sessions Jeder Prozesse unter Unix gehört zu einer Prozessgruppe. Jede Prozessgruppe besteht aus einem oder mehreren Prozessen. Jede Prozessgruppe kann einen Prozessgruppenführer haben, den man daran erkennt, dass seine Prozess-ID gleich wie seine ProzessgruppenID ist. Eine Prozessgruppe hört auf zu existieren,wenn sie keine Mitglieder mehr hat. Ein Prozess kann die Prozessgruppe wechseln (Details dazu in bei Herold, [1]). Eine weitere Gruppierung sind sogenannte Sessions. Zu einer Session können eine oder mehrere Prozessgruppen gehören. Eine Session kann genau ein Kontrollterminal besitzen. Der Prozess, der die Verbindung zum Kontrollterminal eingerichtet hat, wird Kontrollprozess genannt (und ist Sessionführer). In einer Session gibt es maximal eine Vordergrund-Prozessgruppe, alle anderen Prozessgruppen sind Hintergrund-Prozessgruppen. Die Vordergrund-Prozessgruppe existiert genau dann, wenn die Session ein Kontrollterminal hat. Nur die Prozesse der VordergrundProzessgruppe können mit dem Kontrollterminal kommunizieren, deshalb können auch nur diese Prozess mit CTRL-C (Signal SIGINT) abgebrochen werden. © Thomas Kowarsch Seite 100/101 Systemschnittstellen Stand: 16.10.03 8.5.WebServer Ein Webserver sollte immer als Deamon (Hintergrund) laufen. Auf Anfrage vom Webbrowser sendet der WebServer die entsprechend angeforderten Dateien. Der Webbrowser stellt eine Anfrage an dem entsprechenden Port (Standartport ist 80, HTTPS: 443) . Es wird dann eine Socketverbindung aufgebaut. (1) Der Browser nimmt eine Verbindung an den Server zu Port 80 auf. (2) Der Server erstellt einen neuen Channel (Neuer Port) und übergibt den Handle an diesen. (3) Es können Daten von Client zum Server und umgekehrt gesendet werden, bis einer von beiden die Verbindung abbricht. © Thomas Kowarsch Seite 101/101