SP2-SCRIPT Info Einleitung System Schnittstellen Kybernetik
Transcription
SP2-SCRIPT Info Einleitung System Schnittstellen Kybernetik
SP2-SCRIPT Info Einleitung System Schnittstellen Kybernetik Normen Betriebssysteme Datentypen windowsx.h Entwicklungsumg. Assembler main() Console-App Nachrichten WM-Konstanten def_wnd.c def_dlg.c Win-Objekte Ressourcen Dialoge Dll's MFC SP01 SP01 SP02 SP02 Q02 SP03 SP03 Q03 menu.cpp SP04 SP04 Q04 Menu SP05 SP05 hex1.exe hex1.txt hex2.exe hex2.txt But SP06 SP06 tray butt SP07 SP07 quell test SP08 SP08 SP09 SP09 Info: Systemprogrammierung Hier finden sie Unterlagen zu den Veranstaltungen: ( Grafische Darstellungen und Erkennen nach ) Antoine de Saint-Exupéry: Man sieht nur mit dem Herzen gut. Das Wesentliche ist für die Augen unsichtbar. Einleitung Diese Veranstaltung hat das Ziel, in die Programmierung mit dem aktuellen ( Windows-) Betriebssystem einzuführen. Die unfangreiche Funktionalität eines Betriessystem ( als Virtuelle Maschine und Resourcen-Verwalter ) wird auf den "unteren Ebenen" für die Programmierung genutzt. Wegen der Komplexität und des Umfanges wird diese Einführung nicht vollständig sein. Das Skript kann der Vor- und Nachbereitung der Veranstaltung dienen. Ziel der Veranstaltung In der Veranstaltung werden grundlegende Begriffe erklärt, und in die Programmierung der Betriebssystem-Funktionalität eingeführt. Der Schwerpunkt liegt auf praktischen Anwendungsaspekten. Wegen des Stoff-Umfanges kann nur eine spezielle Auswahl behandelt werden. Kognitive Ziele Verstehen von Sachverhalten bedeutet, dass wir ( innerhalb eines stillschweigend vorausgesetzten Kontext ) in Begriffen, Schlüssen, Urteilen denken und Erkenntnisse in Zusammenhänge einordnen können. ● ● Beschreibungen antworten auf Wie - Fragen, Erklärungen antworten auf Warum - Fragen. Praktische Ziele Im engeren Sinne wird als Grunglage ein aktuelles Betriebssystem ( Windows ) und aktuelle Programmierwerkzeuge verwendet ( Entwicklungsumgebung, Debbuger, Ressourcen-Erstellung, Nachrichtenverfolgung, usw. ). Danke Ich möchte mich ● ● ● ● ● bei meiner Frau für das Verständnis, bei den Kollegen für interessante Diskussionen, bei meinen Diplomanden für die geleistete Arbeit, bei den Tutoren für den aufopfernden Einsatz und bei den Studenten für zahlreiche Fragen bedanken. Ron Kritzfeld: Der Pragmatiker entscheidet Fälle nicht nach Grundsätzen, sondern fallweise. In dem Wort "Systemprogrammierung" steckt "System" und "Programmierung". Diese Begriffe werden unten behandelt. Was ist ein Programm? Das Wort Programm kommt aus dem griechischen und bedeutet "schriftliche Bekanntmachung, Tagesordnung". Das Programmieren möchte ein bestimmtes Verhalten entwickeln, aufschreiben und festlegen um damit Abläufe zu unterstützen, steuern, regeln. Ein Programm kann bedeuten: ● ● ● ● ● ● ● ● ● ● Vorhaben ökonomisches Sortiment, Warenangebot Vorstellungs-, Aufführungs-, Vortrags-, Konzertfolge oder Spielfolge ( Theater, Fernsehen ) Angebot an Sendungen ( Gesamtheit der Sendungen des Tages, Rundfunk, Fernsehen ) Darlegung von Zielen und Grundsätzen ( politische Partei, Staatsführung ) Vorgesehenen Ablauf für eine Reihe von Darbietungen Folge von Tätigkeiten; Arbeitsplan für ein Vorhaben Zeit- od. Terminplan, festlegen der Abfolge von Vorgängen Detailplanung der einzelnen technischen Arbeitsschritte für die Ausführung ( durch ausführende Einheiten ) Folge von Anweisungen an den Computer, mit denen bestimmte Aufgaben von physikalisch-technischen Einheiten ausgeführt werden ( Realisierung mit Algorithmen, Programmiersprache, Hardware, Sensoren, Aktoren ) Beispiel: Im Raum von Ressourcen und Wissen entwickelt der Programmatiker ( z.B. Prof. ) ein Vorlesungsprogramm für eine Veranstaltung. Art und Umfang der Durchführung hängen auch von der Programmatik ( Zielsetzung, Zielvorstellung ) und der programmatischen ( zielsetzend, richtungsweisend, auf dem Programm beruhenden ) Mitarbeit der Studierenden ab, die zum programmgemäßen ( planmäßig, so wie es geplant ist ) Gelingen beitragen. allg. Programmiermodell Das Erstellen einer Schrittfolge ( programmieren ) erfolgt auf einer abstrakten, formalen Ebene ( Projektabwicklungen, militärische Planungen, Arbeitsvorbereitungen, volkswirtschaftliche Verflechtungs- und Vorgehensmodelle, Software/Hardware-Entwicklungszyklen, Entwicklungsmodelle, usw. ). Das erstellte Programm garantiert noch nicht die Fehlerfreiheit ( Verwendbarkeit, Ausführung ). In komplexen Ausführungssystemen ( Organisationen, Computersysteme, Netze, usw. ) können vorausschauenden Beurteilungen schwierig sein ( Funktionstests, Laufzeitverhalten, Skalierung, Fehlerfreiheit, zusichernde Garantien, Verfeinerungen, usw. ). Für ein allgemeines, abstraktes Programmier-Modell gibt es unterschiedliche Ansätze. Ein universelles Modell soll auch für nicht technische Systeme brauchbar sein. Das folgende Modell kann komplexe Prozesse beschreiben und ist einem ComputerSystem nachgebildet. Es besteht aus den Komponenten: Memory, Prozessor, Receptor, Effektor, Enviroment. Memory Prozessor enthält: 1. Nutzdaten, 2. Daten für den Prozessor: Programm - Code, Umschaltungen und Steuerungen führt aus: elementare Verarbeitungsschritte, Verzweigungen, kurzzeitige Speicherung von Zwischenwerten, Prozess - Umschaltung Memory Prozessor Wandler wandelt um: <== Rececptor( Sensor ) Enviroment Übertragungsmedium: Weiterleitung von Signalfolgen ==> Effektor( Aktor ) Wandler Enviroment Bei einem ( biologischen ) lernenden System ist die Trennung von Speichern und Ausführen oft schwierig. Ein technischer Prozessor kann Daten im Speicher ablegen, finden, holen, ändern, überschreibend-speichern. Es gibt ● Daten, die der Prozessor als von aussen kommende Befehle ( OpCode ) erkennt und interpretiert ( fester Befehlssatz ). Solche Befehle sind z.B. ❍ ausführen von elementaren Operationen ❍ internes ( zwischen- ) speichern von aktuellen Ausdrücken ❍ interne Ausführungsverzweigungen durchführen ( Sprung, "bedingter Adressversatz" ) Speichern aller internen Prozessordaten und umschalten auf einen neuen Prozess oder in einen neuen Ausführungsmodus Nutz-Daten, die der Prozessor holt, ändert, geändert speichert Daten, die dem Prozessor äussere Zustände signalisieren ( Steuerbus-Signale ) und sein gesamtes Verhalten beeinflussen. Solche Hardware/Software-Steuerdaten können den Prozessor in einen anderen Zustand ( z.B. wach, schlafend ) umschalten. Im schlafenden Zustand können unbewusste Aufräumungsarbeiten durchgeführt werden. ❍ ● ● Die Folge von Prozessor-Befehlen bilden ein Programm. Ein Programm braucht zur Ausführung eine interpretierende Apparatur. Jeder interpretierende Apparatur kann nur die eigenen Befehle interpretieren ( braucht speziell auf die Apparatur abgestimmte Programm-Sequenzen ). Der Prozessor arbeitet mit dem Effektor und dem Receptor zusammen, die Signalumwandlungen durchführen. Kommunikation ist ein wechselseitiger Prozess von Sender und Empfänger ( feed back, Rückkoppelung zwischen Empfänger und Sender ). Was ist ein System? In der Philosophie ist ein System [ griechisch: "gegliedertes Ganzes"; von griechisch systema: das Zusammengesetzte ], eine Bezeichnung für das geordnete Zusammenstellen von grundlegenden Erkenntnissen zu einem Ganzen, d.h. zu einer Lehre, einer Doktrin oder einem Lehrgebäude. In der Wissenschaftstheorie ist ein System die Gesamtheit der Prinzipien, die einer Theorie zugrunde liegen. Nach Immanuel Kant ( Kritik der reinen Vernunft, 1781 ) ist das System "die Einheit der mannigfaltigen Erkenntnisse unter eine Idee". Beispiel: Fachwerksystem Ein Fachwerk besteht aus einem System von Stäben, die miteinander verbunden sind. Die Stäbe erfüllen erst dann die Funktionen des Fachwerksystems, wenn die Stäbe zu einem "neuen Ganzen" montiert sind. Das Fachwerksystem kann Lasten tragen und damit seine Aufgabe erfüllen, wenn die Lasten über Stäbe und Stabverbindungen ( an die Erde ) abgeleitet werden. "Schnittstellen" sind gedachte Trennstellen, um rechnerisch die innen wirkenden Schnittgrössen ( Kräfte, Momente ) zu ermitteln. Zu einem konkreten Systemen gehören ( meist ) unterteilende Fachbegriffe, die die Vielfalt spezifizieren und das wissenschaftlichen Modell beschreiben. Als strukturbildende Einteilung wird der System-Begriff in allen Wissenschaften verwenden. Hier einige Beispiele: In der Psychologie formulierte Gregory Bateson ( 9.5.1904-11.6.1980 ) die Double-Bind-Theorie zur Rolle der Familie bei der Entstehung von Schizophrenie. Die zunehmende Bevölkerung führte zu Umweltschutz, Grenzen des Wachstums, Populationen, Ökologie, Biozönosen, Nahrungsbeziehungen zwischen den Arten, usw. Die Biologie und Evolutionstheorie führten zu verwobenen ( grossen ) Systemen. Die Ökologie ( zu griechisch oikos: Haus und lógos: Lehre ) beschreibt Systeme undderen Wechselbeziehungen zwischen den Organismen der unbelebten/belebten Umwelt und dem Stoff- und Energiehaushalt Es wird zwischen der unbelebten Umwelt ( abiotische Faktoren wie Klima, Boden ) und der belebte Umwelt ( biotische Faktoren ) unterschieden. ● ● ● ● Die Aut-Ökologie behandelt Beziehungen zwischen Individuum und Umwelt Die Dem-Ökologie ( Populationsökologie ) behandelt Beziehungen zwischen Wechselbeziehungen artgleicher Individuen Die Syn-Ökologie behandelt Wechselbeziehungen verschiedener Populationen Biozönosen kennzeichnet die Gesamtheit aller Lebewesen eines bestimmten Lebensraums. Die System-Ökologie behandelt Ökosysteme untereinander Die Human-Ökologie behandelt Wechselwirkungen zwischen dem Menschen und seiner natürlichen und technischen Umwelt Syllogistik [griechisch] die, Logik: von Aristoteles begründete Lehre vom Schluss als Kernstück der traditionellen Logik. Aus der Verbindung von zwei Vordersätzen (Prämissen) geht dabei der Schlusssatz (Konklusion) als logische Folgerung hervor. Die Syllogistik stellt in der modernen Logik einen Teil der prädikatenlogischen Schlüsse dar ( Prädikat lateinisch: auszeichnende Bewertung ). In der Mathematik ist der von D.Hilbert begründete ( nur aus Axiomen gewonne ) Formalismus als mathematisch erweisbare Widerspruchsfreiheit gescheitert ( Gegenposition zum Intuitionismus ). K.Gödel hat 1931 den Unvollständigkeitssatz bewiesen: Eine mathematische Theorie, die die Arithmetik umfasst, und die widerspruchsfrei ist, kann nicht alle in ihr wahren Aussagen beweisen. Intuitionismus [lateinisch] der, als mathematische Grundlagenforschung die von L.Kronecker, H.Poincaré, H.L. Lebesgue u.a. vertretene Lehre, dass die Gesamtheit der natürlichen Zahlen intuitiv und unableitbar gegeben sei und dass sich die Gesamtheit der reellen Zahlen (Kontinuum) arithmetisch nicht bilden lasse. Einen intuitionistischen Neuaufbau der Mathematik versuchten seit 1907 L.E.J. Brouwer, H.Weyl, A.Heyting u.a. mit der Forderung der effektiven Konstruktion zur Definition mathematischer Objekte und unter Einschränkung des Tertium non datur ( lateinisch: ein Drittes gibt es nicht; Satzes vom ausgeschlossenen Dritten; ein Axiom, das besagt, dass eine Aussage gilt oder nicht gilt; eine dritte Möglichkeit besteht nicht ) auf endliche Mengen. In der Informatik werden in der Systemanalyse Methoden zur Einteilung und Untersuchung von Arbeitsgebieten und Arbeitsabläufe entwickelt ( Automatisierung, Phase der Softwaretechnik, usw. ). Aristoteles: Das Ganze ist mehr als die Summe der Teile. Im allgemeinen Sinne ist ein System eine Sammlung von Komponenten, die zusammenwirken. Das System enthält den ganzheitlichen Zusammenhang von Dingen, Vorgängen, Teilen, ( z.B. ökologische Wechselwirkungen in der Natur; vom Menschen hergestelltes soziologisch-politisches System ) und entspricht einem geordneten, zusammenwirkendem Ganzen. Ein System besteht aus wechselwirkenden Komponenten. Die Wechselwirkungen werden durch Relationen ( Funktionen, Methoden ) ausgedrückt. Die Komponenten ( Elemente, Bausteine, Teile ) haben Eigenschaften, die als Merkmale und Methoden gekennzeichnet werden können. Ein System besteht aus einer Menge von Elementen, welche Eigenschaften besitzen und durch Relationen miteinander verknüpft sind. Ein System ist ein Gebilde ( Gefüge, Komplex, Zusammenstellung ) von bestimmten Objekten ( Komponenten, Bestandteile, Gegenstände ) zwischen denen Beziehungen ( Verbindungen, Kopplungen ) mit bestimmten Eigenschaften bestehen. Ein System ist ein Gefüge von Objekten und Beziehungen mit bestimmten Eigenschaften. Der System - Begriff wird in vielfältiger Weise verwendet. Z.B. sind Programmen, Verfahren, Daten und Methoden zur Informationsverarbeitung in einem. In der Informatik wird der System - Begriff in vielfältiger Weise benutzt. ● ● ● ● ● ● ● Ein Hardware-System besteht z.B. Mikroprozessoren, elektronischen Bausteinen, elektronischen Geräten, weiteren Schaltungen, physikalischen Sensoren und Aktoren Ein Computer besteht aus System-Software, Betriebssystem, Firmware, Middleware, Software-Komponenten, Anwendungssoftware, Hardware-System, Speicher-System, Ein- und Ausgabegeräten, Peripherie, usw. Eingabegeräten ( Tastatur, Maus, Laufwerk ), Ausgabegeräten ( Bildschirm, Laufwerk ) und Peripheriegeräten ( Drucker, Modem ) Datenbanksystem ( Anwendungsprogramm zum Erfassen, Suchen, Sortieren und Verwalten größerer Datenmengen, Daten-, Adressen- und Artikelverwaltung, Buchhaltungssysteme, Rechnungssystem, SQLAbfragen, Recherchen, Suchmaschinen ) CIM ( englisch computer integrated manufacturing, rechnerintegrierte Fertigung ) enthält für die Konstruktion und Fertigung mit Hilfe eines Rechners CAD ( Computer-Aided-Design ) und CAM ( Computer-AidedManufacturing ) Nach DIN 19226 gilt: Ein System ist eine abgegrenzte Anordnung von aufeinander einwirkenden Gebilden. Solche Gebilde können sowohl Gegenstände als auch Denkmethoden und deren Ergebnisse ( z.B. Organisationsformen, mathematische Methoden, Programmiersprachen) sein. Diese Anordnung wird durch eine Hüllfläche von ihrer Umgebung abgegrenzt oder abgegrenzt gedacht. Durch die Hüllfläche werden Verbindungen des Systems mit seiner Umgebung geschnitten. Die mit diesen Verbindungen übertragenen Eigenschaften und Zustände sind die Größen, deren Beziehungen untereinander das dem System eigentümliche Verhalten beschreibt. Durch zweckmäßiges Zusammenfügen und Unterteilen von solchen Systemen können größere und kleinere Systeme entstehen. Objektbezogene Systembezeichnungen: abstrakt: lat. abstrahere: wegziehen, wegschleppen, von den individuellen Merkmalen losgelöst, nicht konkret, sinnlich nicht wahrnehmbar, rein begrifflich, unanschaulich, von der Wirklichkeit abgetrennt; Gegensatz: konkret. Abstrakt wird auch als Bezeichnung für die Erfassung des Wesentlichen verwendet ( z.B. Person – Mensch – Säugetier – Lebewesen – Seiendes etc. ). Aristoteles nannte es aphairesis ( griechisch: Wegnahme ) das methodische Erfassen des Wesentlichen ( Abstraktionsmethode, induktiven Logik, Phänomenologie ). formal Formal meint die äußere Form ( nicht den Inhalt ) und kann ohne Entsprechung in der Wirklichkeit sein, der Form genügend, nur äußerlich, nicht in Wirklichkeit, Axiome werden in Zeichen des Operationssystems ausgedrückt verbal mündlich, mit Worten, mit Hilfe der Sprache konkret: gegenständlich, dinglich, fassbar, wirklich, tatsächlich, anschaulich, sinnlich wahrnehmbar; Gegensatz: abstrakt. konzipiert lat. concipere: zusammenfassen, begreifen, sich vorstellen; von einer bestimmten Vorstellung, Idee ausgehend etwas planen, entwerfen, entwickeln; einen Plan oder ein schriftliches Konzept für etwas machen; real lat., zu res "Sache", wirklich, tatsächlich, nicht nur in der Einbildung, in der Wirklichkeit vorhanden, der Realität entsprechend; Gegensatz: irreal. künstlich: Wer sich künstlich aufregt, regt sich über etwas mehr als nötig auf natürlich: Die lateinische Fügung ( in natura ) entspricht der Bedeutung "in Wirklichkeit; in seiner wirklichen, natürlichen Gestalt". Das Haus sieht in natura ganz anders aus als auf dem Foto. Ein System S besteht aus einer Menge M von Komponenten und damit definierten Relation R, d.h. aus dem Begriffspaar S = ( M, R ). Wird M = { i, s, o } : Eingabe-, System-, Ausgabe - Zustände R = { I, S, O } : Eingabe-, Übergangs-, Ausgabe - Funktionen in S = ( M, R ) : Menge von Komponenten, Relationen eingesetzt, so ergibt sich mit der Zeit t die Darstellung eines Sytems S zu S = ( { i, s, o, t }, { I, S, O } ) Gödel: Jedes formale System ist unvollständig. Die wahre Welt umfasst mehr als das Denken. Das Denken umfasst mehr als die Sprache. Ein diskretes System wird in der Graphentheorie ( Topologie ) dargestellt durch eine Menge von Punkten ( Ecken oder Knoten ), die durch Kanten ( Linien; gerichtete oder ungerichtete ) verbunden sind. Ein statisches System ist unabhängig von der Zeit. Bei einem dynamischen System können sich im Laufe der Zeit die Komponenten und Beziehungen ändern. Ein offenes System ist sind durch den Austausch von Materie, Energie, Information mit der System - Umgebung gekennzeichnet. Bei einem geschlossenes System ist kein Austausch mit der System - Umgebung möglich. Ein geschlossenes System geht langfristig in den Zustand maximaler Entropie über. Bei einem Aufbausystem steht die statische Darstellung der Systemstruktur, d.h. die Verknüpfung der in einem System enthaltenen Komponenten im Vordergrund ( Strukturbäume, Hirarchiestrukturen, Strukturmatrizen, ). Charakteristisch sind die Bezeichnungen für die Verknüpfungen: Relation, Beziehung, Kopplung. Bei einem Ablaufsystem steht die Darstellung der Systemfunktionen als Folgeverknüpfung ( Vorgänger, Nachfolger, Sequenz ) im Vordergrund. Ein modulares System [ engl. modular systems ] nutzen eine funktionale Zerlegung ind kleinere Teilaufgaben. Praktische Anwendungen sind: Netzpläne, Programmablaufpläne, Flußdiagramme. Die Netzplantechnik ( Teilgebiet des Operations-Research ) ist ein Verfahren zur Analyse, Planung und Kontrolle von Großprojekten und zur Gewährleistung eines optimalen Einsatzes von Personal, Betriebs- und Finanzmitteln. Die Projekte werden zunächst gedanklich in Einzeltätigkeiten ( Aktivitäten, Vorgänge ) zerlegt und diese dann gemäß ihren technologisch bedingten Verknüpfungen mit Mitteln der Graphentheorie ( Graph ) dargestellt, im einfachsten Fall mit Pfeilen als Tätigkeiten und Knoten als Ereignissen. Der sich daraus ergebende Netzplan bildet die Grundlage für die Zeitplanung. Dabei werden die frühestmöglichen Zeitpunkte für den Abschluss der Einzeltätigkeiten und damit auch das frühestmögliche Projektende errechnet ( kritischer Pfad ). Aus der Bestimmung der spätestzulässigen, das frühestmögliche Projektende nicht gefährdenden Eintrittszeitpunkten der Einzeltätigkeiten ergeben sich gewisse zeitliche Spielräume ( Pufferzeiten ). Die bekanntesten Methoden der Netzplantechnik sind CPM ( englisch critical path method ) und MPM ( Metra Potenzial-Methode ) für deterministische sowie PERT ( englisch program evaluation and review technique ) für stochastische Vorgänge. Damit grundlegende Wechselwirkungen zwischen diese Komponenten möglich sind, läuft auf diesem Hardwaresystem ein Betriebssystem. Das Betriebssystem ist ein wesentlicher Bestandteil der Systemsoftware. Die Systemsoftware besteht aus einzelnen Teilen und Gruppe von Basisprogrammen, die die Hardware unmittelbar ansprechen und Dateien verwalten. Die Anwendungssysteme ( Applikationen, Programme ) nutzen diese grundlegenden Basisprogramme. Der Begriff Systemtechnik ( System Engineering, auch System Analysis ) entstammt etymologisch dem Griechischen und bedeutet soviel wie "zusammen, stellen, Handwerk". Der Begriff Systemtechnik wird als Verallgemeinerung und Erweiterung der ingenieurwissenschaftlichen Methodik betrachtet. Die Systemtechnik ist auf die Untersuchung und Entwicklung von Systemen als sinnvoll gegliedertes Gebilde ausgerichtet. Strukturiert werden Objekte und Prozesse. Wissenschaftliche Fragen werden in der Systemtheorie behandelt. Beispiele Transport von Informationen: Telefon TAPI Transportsystem PKW: Rolls-Royce ( Typ: Silver Ghost, 6-Zyl.-Luxusauto von 1909, Aluminiumkarosserie, faltbaren Verdeck, Innenausstattung aus Leder Transportsystem Bahn: ICE T der Baureihe 415 mit Neigetechnik, 1999 System Flugzeug: Airbus A 319 Bauelemente-Bauplan; Gesamtlänge/Spannweite/Höhe=33,84/34,10/11,76 m Was sind Schnittstellen? Ein Fachwerksystem besteht aus Stäben, die miteinander verbunden sind. Die "Schnittstellen" sind gedachte Trennstellen, für die innen wirkenden Schnittgrössen ( Kräfte, Momente ). Bei verteilten Aufgaben erfolgt der Informationsaustausch an Übergangspunkten ( Schnittstellen ). Die Kommunikation findet über die Schnittstellen statt. Engpässe an diesen Informations-Schnittstellen ( Mitarbeiter-Abteilungsleiter, Abteilungsleiter-Führungsebene, Schnittstellen zwischen Software-Modulen, Schnittstellen zwischen Hardware-Modulen, Schnittstellen zwischen Software-Hardware, usw. ) können zu Frust führen. Hardware-Schnittstellen haben i.a. eine physische Übertragungsstrecke ( Sender, Kanal, Empfänger ). SoftwareSchnittstellen nutzen für die asynchrone Kommunikation i.a. adressierbare Speicher ( Buffer, LIFO, FIFO, usw. ). Besonders leistungsfähige Computer ( hohe Taktraten, großes Speichervolumen ) können helfen, die Informationen am rechten Ort, zur rechten Zeit, in der rechten Form bereit zu stellen. Software-Schnittstellen regeln semantisch die Nachrichten-Verteilung ( z.B. auf Quelltext-Modul-Ebene, auf Maschinen-Ebene bei DLL's ). Albert Einstein: Fortschritt lebt vom Austausch des Wissen. Software-Ergonomie Die Schnittstelle zwischen dem Menschen und dem Computer ( Mensch-Maschine-Schnittstelle, Man-Machine-Interface MMI, auch Human-Machine-Interface HMI ) ist meistens eine Benutzer-Oberflächen ( Bedienung, Schnittstellen, HMI, MMI ), die visuelle Bildschirm-Fenster-Techniken nutzt SAA ( Mitte der 80er Jahre von IBM entwickelt ) ist eine Abkürzung für System Application Architecture, die einen vereinheitlichter Aufbau der Mensch-Computer-Schnittstelle definiert. Art der Gestaltung von Software, die die Arbeit erleichtert und bereichert sowie den Gesundheitsschutz angemessen berücksichtigt. Zur Software-Ergonomie gehören vor allem Benutzerfreundlichkeit sowie Möglichkeiten der individuellen Einstellung und Anpassung, z.B.: Auswahl, Anordnung und Größe der Bedienungselemente, Farbwahl, Zoomen der Darstellung, Vorgaben für Tastatur und Maus ( etwa Wiederhol- und Klicktempo ), Lautstärke- und Klangregelungen. Zur Software-Ergonomie zählen außerdem Arbeitserleichterungen, die die Bedienung vereinfachen und dem Benutzer Routinetätigkeiten abnehmen, z.B. ● ● ● ● Grafische Benutzeroberflächen Vereinfachte Verfahren wie Drag and Drop Zusammenfassen von Befehls- und Aktionsfolgen in Makros Automatisierte Funktionen ( z.B. kontexsensible Hilfen, intelligente Aktionsunterstützung, Rechtschreibprüfung, Korrektur von "Drehern", usw.) Die Software soll der Aufgabe angemessen, fehlertolerant, lernfördernd sein, und echte Dialoge bieten. Software-Ergonomie ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG von 1990 ( DIN 66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter Dialog zwischen Mensch und Computer erfüllen soll. Arbeitgeber sollen benutzerfreundliche Software einsetzen, die der ausführenden Tätigkeit angepasst ist ( verständliche Format, angemessenes Bearbeitungtempo, Rückmeldungen über Ergebnisse der Abläufe ). Kybernetik Der Name Kybernetik stammt von N.Wiener ( 1948, Cybernetics ), der neben C.E.Shannon, A.N.Kolmogorow, J.von Neumann grundlegende Arbeiten zur Kybernetik lieferte. Kybernetik ist eine interdisziplinäre Wissenschaft, die sich mit Kommunikations- und Steuerungssystemen in lebenden Organismen, Maschinen und Organisationen beschäftigt. Kommunikations- und Steuerungssysteme bei lebenden Organismen und bei Maschinen werden analog betrachtet. Die Kybernetik [von griechisch kybernetike, kybernetes (téchne): Steuermannskunst, Rudergänger, Kommandant ] ist eine fachübergreifende Wissenschaft, die nach Erklärung von dynamischen, komplexen Systemen und formalen Modellen sucht. Die Beschreibung der Modelle nutzt die mathematische Schreibweisen. Oft wird versucht, die funktionalen Zusammenhänge mit Computerprogrammen nachzubilden. Kybernetisches Modell als Regelkreises Die externe Führungsgrösse übermittelt einen gewünschten SollWert xk. Der Regler vergleicht Soll- und Ist-Wert, ermittelt die Abweichung, sucht eine optimale Handlungsstrategie und legt die Stellgrösse y fest, die über das Stellorgan wirkt und zum gewünschten Ergebnis führen soll. Der Fühler misst den ist-Wert x und meldet diesen an den Regler. Eine Blackbox [ englisch schwarzer Kasten ] ist ein grafisches Box-Symbol für Systemkomponenten, wobei der innere Aufbau des Kasten nicht bekannt, aber die äusseren Reaktionen aus Eingangssignale gemessen, untersucht und beschrieben werden können. Wird eine Blackbox unterteilt, so ergeben sich für die inneren Komponenten äussere Reaktionen ( innere Untersuchungen ). Jede Verfeinerung erhöht die Gesamtkomplexität aller möglichen Wechselwirkungen. Kybernetik bezeichnet heute oft interdisziplinäre Foschungsaktivitäten ( z.B. Aufbau von neuralen Netze in Medizin Psychologie, Informatik ) und weniger ein abgetrenntes, eigenständiges Forschungsgebiet. Beispiel: Im menschlichen Körper koordiniert z.B. das Nervensystem ( Gehirn ) die Verarbeitung der Informationen. Natürliche Prozesse ( 2.Hauptsatz der Thermodynamik ) streben einen Zustand der Unordnung oder des Chaos an. Die Auswahl einer bestimmten Botschaft hängt von der Vielfalt der Wahlfreiheit einer Aktion ab ( Entropie ist das Maß der Wahrscheinlichkeit, mehr Chaos führt zur Erhöhung der Entropie ). In diesem Bild kann Leben nur materiell und als Maschine beschrieben werden. Es gibt keine Gefühle, Willen, Geist. Ein zielgerichtetes Verhalten von Menschen bedingt zur Aufrechterhaltung von der Ordnung impizite Steuerungsmechanismen. Vielfach können Eigenschaften und Verhaltensweisen von realer Systeme aus unterschiedlichen Wissenschaftbereichen fachübergreifend aus einer zusammenfassenden Modellvorstellung behandelt und verstanden werden. Bescheibende ModellIdentität entstehen durch Reduktion von Komplexität ( Selektion von Komponenten ) und der Erfassung und Behandlung von Wechselwirkungen zwischen den Komponenten. Wissenschaftliche Untersuchung ( Kybernetik ) umfassen Psychologie, künstlicher Intelligenz, Servomechanismen, Wirtschaft, Neurophysiologie, Systemsteuerung und sozialen Systemen Um die Gleichartigkeit von ähnlichen Erscheinungen in ganz unterschiedlichen Bereichen eines abstrakten kybernetischen Systems zu finden, werden vorrangig die Aufnahme, Übertragung, Rückkopplung von Informationen betrachtet. Zu ihren Hauptmethoden zählen Analogie- und Modellverfahren ( z.B. Blackboxmethode ). Zentrale Begriffe sind System, Information, Steuerung und Regelung. Hauptdisziplinen sind: ● ● ● ● ● ● Steuerungstheorie und Regelungstheorie Systemtheorie Informationstheorie und Automatentheorie Zuverlässigkeitstheorie Algorithmenheorie und Spieltheorie künstliche Intelligenz Beispiele Die spezielle Kybernetik behandelt die Theorie und Konstruktion von lernenden ( sich selbst organisierenden ) Automaten und sich selbst reproduzierenden Maschinen ( lernende Automaten ). Die angewandte Kybernetik versucht empirischer Sachverhalte im kybernetischen Zusammenhang zu erklären ( in Technik, Ökonomie, Biologie, Bionik, Ökologie, Medizin, Soziologie, Pädagogik, Psychologie, Linguistik ). Die politische Kybernetik ( Talcott Parsons, David Eastons, Gabriel A.Almonds und Karl W.Deutschs ) als politikwissenschaftliches Theorie- und Analysekonzept untersucht wechselseitige Rückkopplungen und Steuerungsprozesse ( Umweltproblematik, Globalisierung der Wirtschaft, Bevölkerungswachstum, Migration ) innerhalb eines politischen Systems ( Beziehungsgeflechten ) ( Wie und dem Warum, Theorien des politischen Handelns, politischer Entscheidung und Planung ). Für Niklas Luhmann (1927-1998) ist ein soziales System ein reales System, das durch beobachtung das soziale System selbst bestimmt ( selbstreferentielle Systeme ). Der Mensch gehört zu seiner Umwelt und beide sind Teil des sozialen System. In diesem Sinne sind rigide Ideologien ( als geschlossenes System ohne Austausches mit ihrer Umwelt ) kein Teil eines sozialen System. Nach Luhmann ( Theorie der Gesellschaft ) besitzt die moderne Gesellschaft kein Zentrum ( weder in Politik, noch in Moral oder Wirtschaft ), das alle anderen Gesellschaftsbereiche erklären kann. Eine Gesellschaftstheorie kann nicht auf einige Bereiche eingeschränkt werden ( wie z.B. Religion, Wirtschaft, Recht ). Jedes System arbeitet spezifisch: ● ● ● ● Das Wirtschaftssystem funktioniert über das Medium Geld ( Gewinnoptimierung ) Das Rechtssystem über erlassene Gesetze ( Machtmonopol des Staates ) Die Menschen als psychische Systeme über Bewusstsein Die Religionssysteme über einen bekennenden Glauben Humberto R.Maturana und Francesco J.Varela versuchen die biologische Systemtheorie ( Neurophysiologie ) in den Sozialwissenschaften anzuwenden. Normen Was ist eine normal? Im Alltag verhalten sich die Menschen i.a. "funktional-normal". Der Einzelne versucht seine Verhaltensweisen ( mit seiner kognitiven Kompetenzen ) zu bewerten um sich "angepasst und normal" zu verhalten. Normal ist, was häufig vorkommt ( z.B. Alkohol ). Normal ist, was "im gesellschaftlichen Funktionieren" dem eigenen, wünschenswerten Ideal entspricht. Normal ist, was als gesellschaftliche Idealnormen erkennbar wird ( z.B. Schönheitsideale ). Schulische Leistungskriterien und Anforderungen zeigen die vielen Unterschiede auf von Erzieher, Eltern, Lehrer, Ausbilder ( individuelle Normvorstellungen, Bezugsnormen des Lehrenden, Erwartungsnormen der Gesellschaft, Bedürfnissen und Zielsetzungen des Einzelnen, Idealnormen und das durchschnittliche Verhalten ). Was ist eine Norm? Allgemein beruhen die Wechselwirkungen von System-Komponenten auf Vereinbarungen. Damit z.B. im Fertigungsbau ( Maschinenbau ) unterschiedliche Hersteller Schrauben fertigen können, müssen Durchmesser und Gewindeart ( und vieles mehr ) "genormt" sein. Die Einhaltung der Norm "garantiert" die Verwendbarkeit. Im Informations- und Medienzeitalter braucht auch die Kommunikation zahlreiche vereinbarungen ( einheitliche Buchstaben, Schrift, Sprache, usw. ). Ein Austausch von Informationen ist nur auf der Grundlage von Vereinbarungen möglich. Z.B. macht die Unterhaltung von 2 Betrunkenen ( in unterschiedlichen Sprachen ) wenig Sinn. Genormt wird nur, was in einem Gefüge verwendet und genutzt werden kann. Standards und Normen kennzeichnen einen gewissen Abschluss von Erfahrungen. Neue Erfindungen und inovative Entwicklungen erweitern den möglichen Gestaltungsraum, ( Erweitern und Ergänzen von bestehenden Normen ). Normen für technische Komponenten und Geräte orientieren sich an sachlichen Bezügen. Die meisten nationalen und internationalen Normungsinstitutionen wurden im im 20.Jahrhundert gegründet und dienem dem Zweck die Austauschbarkeit von Komponenten und Erfahrungen zu fördern. Durch Normen wird der Warenverkehr vereinfacht ( bei "Normenchaos" erschwert ). Normung ist mit Rationalisierung der industriellen Massenproduktion und Vereinfachung des Warenverkehrs verknüpft und eine Vorbedingung freie eine frei Wirtschaft ( Globalisierung ). Das Deutsche Institut für Normung ( DIN ) erklärt ( definiert ) den Begriff Normung gemäss: Nach DIN 820-1 ist Normung die planmäßige, durch interessierte Kreise gemeinschaftlich durchgeführte Vereinheitlichung von materiellen und immateriellen Gegenständen zum Nutzen der Allgemeinheit; sie darf nicht zu einem wirtschaftlichen Sondervorteil Einzelner führen. Normung fördert vor allem die Rationalisierung, Regelung, Kommunikationsverbesserung und Qualitätssicherung in Wirtschaft, Technik, Wissenschaft und Verwaltung; sie soll überdies der Sicherheit des Menschen, dem Schutz der Umwelt und der Qualitätsverbesserung in allen Lebensbereichen dienen. Zur Effizienzsteigerung und Kostensenkung durch Normung kommt es etwa durch die Austauschbarkeit oder Vereinbarkeit genormter Produkte, die Verringerung der Typenvielfalt, die Erleichterung der Lagerhaltung und des Warenverkehrs. Normen sind darüber hinaus als Beschreibung technischer Sachverhalte für Gesetzgebung und Rechtsverkehr von Bedeutung. DIN-Normen enthalten in der Hauptsache Angaben, Anweisungen oder Anforderungen für die Herstellung, Wartung oder Handhabung von Gegenständen, Geräten oder Anlagen, den Ablauf oder die Ausführung von Vorgängen oder Dienstleistungen, die Qualität oder Qualitätsprüfung, -sicherung oder -verbesserung technischer Produkte, die Sicherheit oder Gesundheit des Menschen oder den Schutz der Umwelt. Einheiten Für die Objektivierung von vergleichenden Messungen sind Basis-Einheiten definiert. In Industrienationen ist das Internationale bzw. das SI-Einheitensystem ( Système international ) verbindlich. Durch das "Gesetz über Einheiten im Meßwesen" vom 2.7.1969 und der Ausführungsverordnung vom 26.6.1970 wurde das SI-Einheitensystem in der BRD verbindlich eingeführt. Außer seinen 6 Basiseinheiten ( Meter, Kilogramm, Sekunde, Ampere, Kelvin, Mol, candela m, kg, s, A, K mol, und cd werden auch die abgeleiteten Einheiten N, Pa, J, W und Pa s benutzt. 1 t = 1000 kg Masse Volumen 1 l = 103 m3 1 h = 60 min = 3600 s Zeit Temperatur1 °C = 1 K differenz 1 bar = 105 Pa Winkel Druck 1° = PI rad/180 Für die Einheit 1 rad = 1 m/m darf nach DIN 1301 bei Zahlenrechnungen auch 1 stehen. Nach DIN 1301 können Vorsätze für dezimale Vielfache und Teile verwendet werden: Abkürzung: E P T G M k h da d c m µ n p f a Kurzname: Exa Peta Tera Giga Mega Kilo Hekto Deka Dezi Zenti Milli Mikro Nano Piko Femto Atto Wert: 1018 1015 1012 109 106 103 102 101 10-1 10-2 10-3 10-6 10-9 10-12 10-15 10-18 Nach DIN 1314 wird der Druck p meist in der Einheit bar angegeben und zählt vom Nullpunkt aus. Druckdifferenzen werden durch die Formelzeichen, nicht aber durch die Einheit gekennzeichnet. Dies gilt besonders für die Manometerablesung bzw. atmosphärischen Druckdifferenzen. Nationale Normungsinstitutionen 1917 wurde in Deutschland der Normalienausschuß für den Allgemeinen Maschinenbau gegründet 1926 in Deutscher Normenausschuß e.V. ( DNA ) umbenannt wurde. 1936 wurden die Normen staatlich verbindlich. 1975 erfolgte eine Umbenennung in DIN = Deutsches Institut für Normung e.V. und die Anerkennung als nationale Normungsinstitution der Bundesrepublik Deutschland 1990 übernahm das DIN die gesamtdeutsche Normung. DIN hat die Rechtsform eines eingetragenen, gemeinnützigen Vereins mit Sitz in Berlin. Mitglieder ( etwa 6000 ) können Firmen, Verbände, interessierte Körperschaften, Behörden und Organisationen aber keine Einzelpersonen sein. Die Normungsarbeit wird in 4600 Arbeitsausschüssen von etwa 28 500 Fachleuten ( ehrenamtliche Mitarbeiter von Herstellern, Handel, Handwerk, Verbraucher, Behörden, Wissenschaftseinrichtungen ) geleistet und von 1000 hauptamtlichen Mitarbeitern koordiniert. DIN finanziert sich zu etwa 60% aus dem eigenen Beuth-Verlag ( Normen, Normentwürfe und DIN-Taschenbücher ). Die eigene Normungsarbeit ist in DIN 820-4) festgelegt und ausgerichtet an Freiwilligkeit, Öffentlichkeit, Beteiligung aller interessierten Kreise, Konsens, Einheitlichkeit und Widerspruchsfreiheit, Ausrichtung am Stand der Technik, an den wirtschaftlichen Gegebenheiten und am allgemeinen Nutzen sowie Internationalität. Internationale Normungsinstitutionen 1906 Genf: International Electrotechnical Commission ( IEC ) 1926 Genf: International Federation of the National Standardizing Associations ( ISA ) 1947 International Organization for Standardization ( ISO, ersetzte die ISA ). Die ISO besteht aus etwa 120 nationalen Normungsinstitutionen. Die Internationale Fernmelde-Union ( IFU ) ist für Telekommunikation zuständig. 1961 Brüssel: das Europäische Komitee für Normung ( CEN, Comité Européen de Normalisation; nicht staatliche, gemeinnützige Vereinigung; Deutsches Mitglied ist das DIN ) 1961 Brüssel: Europäische Komitee für elektrotechnische Normung ( CENELEC, Comité Européen de Normalisation Electrotechnique; nicht staatliche, gemeinnützige Vereinigung; Deutsche Mitglieder sind die DKE = Deutsche Elektrotechnische Kommission und der VDE = Verband Deutscher Elektrotechniker ) 1982 Zusammenschluss von CEN und CENELEC zur Gemeinsamen Europäischen Normungsinstitution. CEN/CENELECMitglieder übernehmen ( soweit möglich ) die europäischen Normen ( EN ) als nationale Normen. Im Bereich der Telekommunikation sorgt das Europäische Institut für Telekommunikationsnormen ( ETSI, Institut Européen des Normes de Télécommunication, etwa 12000 europäische Normen ) in enger Zusammenarbeit mit CEN/CENELEC für europaweite Normen. DFÜ-Normen schafft die CCITT ( ComitConsultatif International Télégraphique et Téléphonique, Genf, nationalen Behörden, privaten Firmen sowie nationalen und internationalen wissenschaftlichen Organisationen ) ständiges Organ der internationalen Fernmeldeunion ( Abkürzung ITU ). Das CCITT ist 1993 in der ITU aufgegangen. Beispiele für Normen X.400 An international message-handling standard for connecting e-mail networks and for connecting users to email networks. X.400 is published by the International Telegraph and Telephone Consultative Committee ( CCITT standards body, now called the International Telecommunications Union (ITU). The X.400 Application Programming Interface Association XAPIA defines programming interfaces to X.400. MAPI applications are fully interoperable with X.400 messaging applications. X.435 Electronic Data Interchange (EDI): A standard for integrating data with various native formats into a, which has been defined by the International Telegraph and Telephone Consultative Committee standards body, now called the International Telecommunications Union (ITU), and is implemented in the X.435 messagehandling standard. X.435 is an international message-handling standard that is published by the International Telegraph and Telephone Consultative Committee CCITT standards body, now called the International Telecommunications Union (ITU), and that implements the Electronic Data Interchange (EDI) standard for integrating data with various native formats into a message. X.400 Schicker, Pietro, "Message Handling Systems, X.400", Message Handling Systems and Distributed Applications, E. Stefferud, O-j. Jacobsen, and P. Schicker, eds., North-Holland, 1989, pp. 3-41. X.500 An international message-handling standard for directory services, published by the International Telegraph and Telephone Consultative Committee CCITT standards body, now called the Internal Telecommunications Union (ITU). X.509 An international message-handling standard for message authentication and encryption. X.509 is published by the International Telegraph and Telephone Consultative Committee CCITT standards body, now called the Internal Telecommunications Union (ITU). XAPIA The X.400 Application Programming Interface Association, the standards-setting body for programming interfaces to X.400 components. XAPIA also defines the Common Messaging Calls inteface component. US-ASCII Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986. ISO-646 International Standard--Information Processing--ISO 7-bit coded character set for information interchange, ISO 646:1983. ISO-2022 International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension techniques, ISO 2022:1986. ISO-8859 Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990. < ISO 9241-10 Grundsätze der Dialoggestaltung ISO/DIS 9241Richtlinien zur Gebrauchstauglichkeit 11 ISO/DIS 9241Informationsdarstellung 12 ISO/DIS 9241Benutzerführung 13 ISO 9241-14 Dialogführung über Menüs ISO/DIS 9241- Dialogführung über Kommandosprachen. 15 (DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO). ISO/DIS 9241- Dialogführung über direkte Manipulation. 1+ (DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO). ISO/DIS 9241- Dialogführung über Bildschirmformulare 17 (DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO). ISO 9241 1998 verabschiedete die ISO die Ergonomie-Normenreihe. "Ergonomische Anforderungen an Bürotätigkeiten mit Bildschirmgeräten" ISO/IEC 10646 Unicode ISO-Norm 13407 Beschreibt einen benutzerorientierten Entwicklungszyklus ( 1998 verabschiedet ). Unter dem Titel "Benutzer-orientierte Gestaltung interaktiver Systeme" formuliert die Norm für Hard- und Software Kriterien, die die Anpassung interaktive Systeme an den Benutzer ermöglichen sollen. RFC 783 Sollins, K., "TFTP Protocol (revision 2)", RFC 783, MIT, June 1981. RFC-821 Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821, USC/Information Sciences Institute, August 1982. RFC822 Standard of the Format of Internet Text Messages ,D.Crocker,1982: Legt den Aufbau des Kopfes einer EMail-Nachricht fest,z.b. die Codierung von Sender- und Empfaengeradresse. RFC1521 MIME(Multipurpose Internet Mail Extensions)Part One: Definiert ein Schema fuer die Unterbringung verschiedenartigster Daten innerhalb des Hauptteils einer E-Mail-Nachricht. Beispilesweise von Grafiken oder ausfuehrbaren Dateien. Gilt nicht fuer E-Mail ,sondern natuerlich auch fuer das Web. RFC1522 MIME(Multipurpose Internet Mail Extensions)Part Two: Der zweite Teil der MIME-Definition. Definiert den Kodierungsmechanismus fuer Zeichen,die ueber den 7-Bit-Us_ASCII-Zeichensatz hinausgehen,in den Kopffeldern von E-Mail-Nachrichten. RFC 2617 Digest Access Authentication GIF Graphics Interchange Format (Version 89a), Compuserve, Inc., Columbus, Ohio, 1990. MPEG Video Coding Draft Standard ISO 11172 CD, ISO IEC/TJC1/SC2/WG11 (Motion Picture Experts Group), May, 1991. PCM CCITT, Fascicle III.4 - Recommendation G.711, Geneva, 1972, "Pulse Code Modulation (PCM) of Voice Frequencies". POSTSCRIPT Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, 1985. POSTSCRIPT2 Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, Second Edition, 1990. ATK Borenstein, Nathaniel S., Multimedia Applications Development with the Andrew Toolkit, Prentice-Hall, 1990. ECMA-158 December 1997, Standardizing Information and Communication Systems, Portable Common Tool Environment (PCTE) - C Programming Language Binding DIN 1304 Formelzeichen DIN 66234 ( Software-Ergonomie ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG Teil 8) von 1990 ( DIN 66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter Dialog EG ( 90/270/ ) zwischen Mensch und Computer erfüllen soll. Arbeitgeber sollen benutzerfreundliche Software einsetzen, die der ausführenden Tätigkeit angepasst ist ( verständliche Format, angemessenes Bearbeitungtempo, Rückmeldungen über Ergebnisse der Abläufe ). ... Sinnbilder Schaltpläne von Leitungen, Schaltern, Maschinen und Aggregate DIN-Normen oder den Richtlinien entnommen. ECMA Standards ECMA - Standardizing Information and Communication Systems ( ECMA blue cover) Stichwort Kommentar ECMA-6 7-Bit Coded Character Set, 6th edition (December 1991) ECMA-13 File Structure and Labelling of Magnetic Tapes for Information Interchange, 4th edition (December 1985) ECMA-35 Character Code Structure and Extension Techniques, 6th edition (December 1994) ECMA-43 8-Bit Coded Character Set Structure and Rules, 3rd edition(December 1991) ECMA-48 Control Functions for Coded Character Sets, 5th edition(June 1991) ECMA-74 Measurement of Airborne Noise Emitted by Information Technology and Telecommunications Equipment, 6th edition (December 1999) ECMA-94 8-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabets No. 1 to No. 4, 2nd edition (June 1986) ECMA-99 Data Interchange on 130 mm Flexible Disk Cartridges Using MFM Recording at 13 262 ftprad on Both Sides, 3,8 Tracks per mm (September 1985) ECMA-100 Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 7 958 ftprad on 80 Tracks on Each Side - ISO Type 301, 2nd edition (December 1988) ECMA-106 Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point - Circuit Mode Basic Services (SSIG-BC), 3rd edition (December 1993) ECMA-107 Volume and File Structure of Disk Cartridges for Information Interchange, 2nd edition (June 1995) ECMA-108 Measurement of High-Frequency Noise emitted by Information Technology and Telecommunications Equipment, 3rd edition (December 1996) ECMA-109 Declared Noise Emission Values of Information Technology and Telecommunications Equipment, 4th edition (December 1996) ECMA-113 8-Bit Single-Byte Coded Graphic Character Sets - Latin/Cyrillic Alphabet, 3rd edition (December 1999) ECMA-114 8-Bit Single-Byte Coded Graphic Character Sets - Latin/Arabic Alphabet, 2nd edition (December 2000) ECMA-118 8-Bit Single-Byte Coded Graphic Character Sets - Latin/Greek Alphabet (December 1986) ECMA-119 Volume and File Structure of CDROM for Information Interchange, 2nd edition (December 1987) ECMA-120 Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges, 3rd edition (December 1993) ECMA-121 8-Bit Single-Byte Coded Graphic Character Sets - Latin/Hebrew Alphabet, 2nd edition (December 2000) ECMA-125 Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 15 916 ftprad on 80 Tracks on Each Side - ISO Type 302 (December 1987) ECMA-128 8-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabet No. 5, 2nd edition (December 1999) ECMA-130 Data Interchange on Read-only 120 mm Optical Data Disks (CD-ROM), 2nd edition (June 1996) ECMA-133 Private Integrated Services Network (PISN) - Reference Configurations for PISN Exchanges (PINX), 2nd edition (December 1998) ECMA-139 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS Format (June 1990) ECMA-142 Private Integrated Services Network (PISN) - Circuit Mode 64kbit/s Bearer Services - Service Description, Functional Capabilities and Information Flows (BCSD), 2nd edition (June 1997) ECMA-143 Private Integrated Services Network (PISN) - Circuit Mode Bearer Services - Inter-Exchange Signalling Procedures and Protocol (QSIG-BC), 3rd edition (June 1997) ECMA-144 8-Bit Single-Byte Coded Character Sets - Latin Alphabet No. 6, 3rd edition (December 2000) ECMA-145 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording (December 1990) ECMA-146 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording DATA/DAT Format (December 1990) ECMA-147 Data Interchange on 90 mm Flexible Disk Cartridges using MFM Recording at 31 831 ftprad on 80 Tracks on Each Side - ISO Type 303 (December 1990) ECMA-148 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Identification Supplementary Services (ISSD), 3rd edition (June 1997) ECMA-149 Portable Common Tool Environment (PCTE) - Abstract Specification, 4th edition (December 1997) ECMA-150 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDSDC Format using 60 m and 90 m Length Tapes, 2nd edition (June 1992) ECMA-151 Data Compression for Information Interchange - Adaptive Coding with Embedded Dictionary - DCLZ Algorithm (June 1991) ECMA-152 Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges - Extended Format, 2nd edition (December 1993) ECMA-153 Information Interchange on 130 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) Type, using the Magneto-Optical Effect, 2nd edition (June 1994) ECMA-154 Data Interchange on 90 mm Optical Disk Cartridges, Read only and Rewritable, M.O., 2nd edition (June 1994) ECMA-155 Private Integrated Services Networks - Addressing, 2nd edition (June 1997) ECMA-156 Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Keypad Protocol for the Support of Supplementary Services (SSIG-KP), 2nd edition (June 1993) ECMA-157 Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point Identification Supplementary Services (SSIG-ID), 2nd edition (June 1993) ECMA-158 Portable Common Tool Environment (PCTE) - C Programming Language Binding, 4th edition (December 1997) ECMA-159 Data Compression for Information Interchange - Binary Arithmetic Coding Algorithm (December 1991) ECMA-160 Determination of Sound Power Levels of Computer and Business Equipment Using Sound Intensity Measurements; Scanning Method in Controlled Rooms, 2nd edition (December 1992) ECMA-161 Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Feature Key Management Protocol for the Control of Supplementary Services (SSIG-FK), 2nd edition (June 1993) ECMA-162 Portable Common Tool Environment (PCTE) - Ada Programming Language Binding, 4th edition (December 1997) ECMA-163 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Name Identification Supplementary Services (NISD), 3rd edition (September 1997) ECMA-164 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Name Identification Supplementary Services (QSIG-NA), 3rd edition (September 1997) ECMA-165 Private Integrated Services Network (PISN) - Generic Functional Protocol for the Support of Supplementary Services - Inter-Exchange Signalling Procedures and Protocol (QSIG-GF), 4th edition(June 2001) ECMA-167 Volume and File Structure for Write-Once and Rewritable Media using Non-Sequential Recording for Information Interchange, 3rd edition(June 1997) ECMA-168 Volume and File Structure of Read-Only and Write-Once Compact Disk Media for Information Interchange, 2nd edition (December 1994) ECMA-169 8 mm Wide Magnetic Tape Cartridge Dual Azimuth Format for Information Interchange - Helical Scan Recording (June 1992) ECMA-170 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS Format Using 60 m and 90 m Length Tapes (June 1992) ECMA-171 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording DATA/DAT-DC Format Using 60 m and 90 m Length Tapes (June 1992) ECMA-173 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Diversion Supplementary Services (CFSD), 2nd edition (June 1997) ECMA-174 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Diversion Supplementary Services (QSIG-CF), 2nd edition (June 1997) ECMA-175 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Path Replacement Additional Network Feature (ANF-PRSD), 3rd edition (December 1998) ECMA-176 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Path Replacement Additional Network Feature (QSIG-PR), 3rd edition (December 1998) ECMA-177 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Transfer Supplementary Service (CTSD), 2nd edition (September 1997) ECMA-178 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Transfer Supplementary Service (QSIG-CT), 2nd edition (September 1997) ECMA-179 Services for Computer Supported Telecommunications Applications (CSTA) Phase I (June 1992) ECMA-180 Protocol for Computer Supported Telecommunications Applications (CSTA) Phase I (June 1992) ECMA-182 Data Interchange on 12,7 mm 48-Track Magnetic Tape Cartridges - DLT1 Format (December 1992) ECMA-183 Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1 Gigabyte per Cartridge (December 1992) ECMA-184 Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1,3 Gigabytes per Cartridge (December 1992) ECMA-185 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Completion Supplementary Services (CCSD), 2nd edition (June 1997) ECMA-186 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Completion Supplementary Services (QSIG-CC), 3rd edition (February 2000) ECMA-189 Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) Type using the SSF Method (June 1993) ECMA-190 Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) Type using the CCS Method (June 1993) ECMA-191 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Offer Supplementary Service (COSD), 2nd edition (June 1997) ECMA-192 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Offer Supplementary Service (QSIG-CO), 3rd edition (June 1997) ECMA-193 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Do Not Disturb and Do Not Disturb Override Supplementary Services (DND(O)SD), 2nd edition (June 1997) ECMA-194 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Do Not Disturb and Do Not Disturb Override Supplementary Services (QSIG-DND(O)), 3rd edition (June 1997) ECMA-195 Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 2 Gigabytes per Cartridge, 2nd edition (June 1995) ECMA-196 Data Interchange on 12,7 mm 36-Track Magnetic Tape Cartridges (December 1993) ECMA-197 Data Interchange on 12,7 mm 112-Track Magnetic Tape Cartridges - DLT2 Format (December 1993) ECMA-198 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-2 Format using 120 m Length Tapes, 2nd edition (June 1995) ECMA-201 Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 230 Megabytes per Cartridge, 2nd edition (December 1994) ECMA-202 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Intrusion Supplementary Service (CISD), 2nd edition (June 1997) ECMA-203 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Intrusion Supplementary Service (QSIG-CI), 3rd edition (June 1997) ECMA-205 Commercially Oriented Functionality Class for Security Evaluation (COFC) (December 1993) ECMA-206 Association Context Management including Security Context Management (December 1993) ECMA-207 Data Interchange on 90 mm Flexible Disk Cartridges - 326 Data Tracks on each Side - Capacity: 21 Mbytes - ISO Type 305 (June 1994) ECMA-208 System-Independent Data Format - SIDF (December 1994) ECMA-209 Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT3 Format (December 1994) ECMA-210 12,65 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DATAD3-1 Format, 2nd edition (December 1995) ECMA-211 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Advice of Charge Supplementary Services (AOCSD), 2nd edition (June 1997) ECMA-212 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Advice of Charge Supplementary Services (QSIG-AOC), 2nd edition (June 1997) ECMA-213 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Recall Supplementary Service (RESD), 2nd edition (June 1997) ECMA-214 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Recall Supplementary Service (QSIG-RE), 2nd edition (June 1997) ECMA-215 Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Incoming Call Additional Network Feature (QSIG-CTMI), 2nd edition (September 1997) ECMA-216 Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Location Registration Supplementary Service (QSIG-CTLR), 2nd edition (September 1997) ECMA-217 Services for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994) ECMA-218 Protocol for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994) ECMA-219 Authentication and Priviledge Attribute Security Application with Related Key Distribution Functions Part 1, 2 and 3, 2nd edition (March 1996) ECMA-220 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Interception Additional Network Feature (ANF-CINTSD), 2nd edition (June 1997) ECMA-221 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Interception Additional Network Feature (QSIG-CINT), 2nd edition (June 1997) ECMA-222 Adaptive Lossless Data Compression Algorithm(June 1995) ECMA-223 Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 385 Megabytes per Cartridge (June 1995) ECMA-224 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Transit Counter Additional Network Feature (ANF-TCSD), 2nd edition (June 1997) ECMA-225 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Transit Counter Additional Network Feature (QSIG-TC), 2nd edition (June 1997) ECMA-226 Private Integrated Services Network (PISN) - Mapping Functions for the Employment of Dedicated Circuit Mode Connections as Inter-PTNX Connections (MAPPING-CM-STATIC) (June 1995) ECMA-230 Portable Common Tool Environment (PCTE) - IDL Binding (Interface Definition Language), 2nd edition (December 1997) ECMA-231 Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 4 Format (December 1995) ECMA-232 Private Integrated Services Network (PISN) - Profile Standard for the Connection of Radio Paging Equipment (RPE) to a PISN (December 1995) ECMA-233 Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Outgoing Call Additional Network Feature (QSIG-CTMO), 2nd edition (September 1997) ECMA-234 Application Programming Interface for Windows (APIW) (December 1995) ECMA-235 The ECMA GSS-API Mechanism (March 1996) ECMA-236 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-3 Format using 125 m Length Tapes (June 1996) ECMA-238 Data Interchange on 130 mm Optical Disk Cartridge of Type WORM (Write Once Read Many) using Irreversible Effects - Capacity: 2,6 Gbytes per Cartridge (June 1996) ECMA-239 Data Interchange on 90 mm Optical Disk Cartridges - HS-1 Format - Capacity: 650 Megabytes per Cartridge (June 1996) ECMA-240 Data Interchange on 120 mm Optical Disk Cartridges using Phase Change PD Format - Capacity: 650 Mbytes per Cartridge (June 1996) ECMA-241 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Message Waiting Indication Supplementary Service (MWISD), 4th edition (February 2002) ECMA-242 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Message Waiting Indication Supplementary Service (QSIG-MWI), 3rd edition (December 1998) ECMA-243 Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Authentication Supplementary Services (QSIG-CTAU), 2nd edition (September 1997) ECMA-244 Private Integrated Services Network (PISN) - Mapping Functions for the Employment of a Circuit Mode Basic Service and the Supplementary Service User-to-User Signalling as a pair of On-demand InterPINX Connections (Mapping-UUS), 2nd edition (September 2000) ECMA-245 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - PINX Clock Synchronization (SYNC-SIG), 2nd edition (September 1997) ECMA-246 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-1 Format, 2nd edition(June 1998) ECMA-247 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - HH-1 Format, 2nd edition(June 1998) ECMA-248 12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-1 Format, 2nd edition (June 1998) ECMA-249 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DA-2 Format, 2nd edition (June 1998) ECMA-250 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Common Information Additional Network Feature (ANF-CMNSD), 2nd edition (December 1998) ECMA-251 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Common Information Additional Network Feature (QSIG-CMN), 2nd edition (December 1998) ECMA-252 Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Transit Counter Additional Network Feature (B-QSIG-TC) (December 1996) ECMA-253 Private Integrated Services Network (PISN) - Mapping Functions for the Employement of 64 kbit/s Circuit Mode Connection with 16 kbit/s Sub-multiplexing (Mapping/16), 2nd edition (September 2000) ECMA-254 Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Generic Functional Protocol (B-QSIG-GF), 2nd edition (December 1999) ECMA-258 Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 3-XT Format (June 1997) ECMA-259 Data Interchange on 12,7 mm 208-Track Magnetic Tape Cartridges - DLT 5 Format (June 1997) ECMA-260 Data Interchange on 356 mm Optical Disk Cartridges - WORM, using Phase Change Technology Capacity: 14,8 and 25 Gbytes per Cartridge (June 1997) ECMA-261 Broadband Private Integrated Services Network (B-PISN) - Service Description - Broadband Connection Oriented Bearer Services (B-BCSD) (June 1997) ECMA-262 ECMAScript Language Specification, 3rd edition (December 1999) ECMA-263 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Priority Interruption and Call Priority Interruption Protection Supplementary Services (CPI(P)SD), 2nd edition (December 1998) ECMA-264 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Priority Interruption and Call Priority Interruption Protection Supplementary Services (QSIG-CPI(P)), 2nd edition (December 1998) ECMA-265 Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol Signalling ATM Adaptation Layer (B-QSIG-SAAL) (September 1997) ECMA-266 Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Basic Call/Connection Control (B-QSIG-BC) (September 1997) ECMA-267 120 mm DVD - Read-Only Disk, 3rd edition (April 2001) ECMA-268 80 mm DVD - Read-Only Disk, 3rd edition (April 2001) ECMA-269 Services for Computer Supported Telecommunications Applications (CSTA) Phase III, 4th edition (June 2000) ECMA-270 Portable Common Tool Environment (PCTE) - Mapping from CASE Data Interchange Format (CDIF) to PCTE (December 1997) ECMA-271 Extended Commercially Oriented Functionality Class for Security Evaluation (E - COFC), 2nd edition (December 1999) ECMA-272 120 mm DVD Rewritable Disk (DVD-RAM), 2nd edition (June 1999) ECMA-273 Case for 120 mm DVD-RAM Disks (February 1998) ECMA-274 Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes, 2nd edition (June 1999) ECMA-275 Measurement of structure-borne vibration induced by small air moving devices (AMDs) (June 1998) ECMA-276 Private Integrated Services Network (PISN) - Reference Configuration for PINX Extension Lines (June 1998) ECMA-277 Private Integrated Services Network (PISN) - Circuit Emulation Specification - Emulation of Basic Access by ATM Networks (June 1998) ECMA-278 Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridge - Parallel Serpentine Format, 2nd edition (June 2000) ECMA-279 80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) (December 1998) ECMA-280 Data Interchange on 130 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using Irreversible Effects - Capacity: 5,2 Gbytes per Cartridge (December 1998) ECMA-281 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Private User Mobility (PUM) - Registration Supplementary Service (PUMRSD), 2nd edition(June 2000) ECMA-282 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility (PUM) - Registration Supplementary Service (QSIG-PUMR), 2nd edition (June 2000) ECMA-283 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Private User Mobility (PUM) - Call Handling Additional Network Features (PUMCHSD), 2nd edition (June 2000) ECMA-284 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility (PUM) - Call Handling Additional Network Features (QSIG-PUMCH), 2nd edition (June 2000) ECMA-285 Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III, 2nd edition (June 2000) ECMA-286 Data Interchange on 12,7 mm 208-Track Magnetic Tape Cartridges - DLT 6 Format, 2nd edition (June 2000) ECMA-287 Safety of electronic equipment (June 1999) ECMA-288 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-4 Format (June 1999) ECMA-289 Private Integrated Services Network (PISN) - Mapping Functions for the Employment of 64 kbit/s Circuit Mode Connections with 8 kbit/s Sub-Multiplexing (Mapping/8), 2nd edition (September 2000) ECMA-290 ECMAScript Components Specification (June 1999) ECMA-291 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-1 with MIC Format (December 1999) ECMA-292 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-2 with MIC Format (December 1999) ECMA-293 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording MammothTape-2 Format (December 1999) ECMA-294 B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer Control Environment - Part 1: Protocol Specification (December 1999) ECMA-295 B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer Control Environment - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999) ECMA-296 B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 1: Protocol Specification (December 1999) ECMA-297 B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999) ECMA-298 Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol Separated Bearer Control (SBC) (B-QSIG-SBC) (December 1999) ECMA-299 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Single Step Call Transfer Supplementary Service (SSCT-SD) (February 2000) ECMA-300 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Single Step Call Transfer Supplementary Service (QSIG-SSCT) (February 2000) ECMA-301 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Location Registration Supplementary Service and Wireless Terminal Information Exchange Additional Network Feature (WTMLR-SD) (June 2000) ECMA-302 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal Location Registration Supplementary Service and Wireless Terminal Information Exchange Additional Network Feature (QSIG-WTMLR) (June 2000) ECMA-303 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Call Handling Additional Network Features (WTMCH-SD) (June 2000) ECMA-304 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal Call Handling Additional Network Features (QSIG-WTMCH) (June 2000) ECMA-305 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Authentication Supplementary Services (WTMAU-SD) (June 2000) ECMA-306 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal Authentication Supplementary Services (QSIG-WTMAU) (June 2000) ECMA-307 Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Generic Functional Protocol for the Support of Supplementary Services (June 2000) ECMA-308 Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Transfer Supplementary Services, 2nd edition (June 2001) ECMA-309 Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Diversion Supplementary Services, 2nd edition (June 2001) ECMA-310 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Simple Dialog Supplementary Service (SDSD) (June 2000) ECMA-311 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Simple Dialog Supplementary Service (QSIG-SD) (June 2000) ECMA-312 Private Integrated Services Network (PISN) - Profile Standard for the Use of PSS1 (QSIG) in Air Traffic Services Networks, 2nd edition (June 2001) ECMA-313 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Identification and Call Linkage Additional Network Feature (CIDLSD) (September 2000) ECMA-314 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Identification and Call Linkage Additional Network Feature (QSIG-CIDL) (September 2000) ECMA-315 12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-2 (December 2000) ECMA-316 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - VXA-1 Format (December 2000) ECMA-317 Data Interchange on 300 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using Irreversible Effects - Capacity: 30 Gbytes per Cartridge (December 2000) ECMA-318 Private Integrated Services Network (PISN) - Use of QSIG at the C Reference Point between a PINX and an Interconnecting Network (December 2000) ECMA-319 ECMA-320 ECMA-321 ECMA-322 ECMA-323 Data Interchange on 12,7 mm - 384- Track Magnetic Tape Cartridges - Ultrium-1 Format (June 2001) Data Interchange on 12,7 mm - 448-Track Magnetic Tape Cartridges - SDLT1 Format (June 2001) Streaming Lossless Data Compression Algorithm (SLDC) (June 2001) Data Interchange on 130 mm Magneto-Optical Disk Cartridges - Capacity: 9,1 Gbytes per Cartridge (June 2001) XML Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III (June 2001) ECMA-324 Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Short Message Service (SMSSD) (June 2001) ECMA-325 Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Short Message Service (QSIG-SMS) (June 2001) ECMA-326 Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Completion Supplementary Services (June 2001) ECMA-327 ECMA-328 ECMAScript 3rd Edition Compact Profile (June 2001) Detection and measurement of chemical emissions from electronic equipment (August 2001) ECMA-329 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-3 Format (December 2001) ECMA-330 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) (December 2001) ECMA-331 Case for 120 mm and 80 mm DVD-RAM Disks (December 2001) ECMA-332 Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Basic Services (December 2001) ECMA-333 Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through H.323 Networks (December 2001) ECMA-334 ECMA-335 ECMA-336 C# Language Specification (December 2001) Common Language Infrastructure (CLI) (December 2001) Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through IP Networks (Mapping/IP-QSIG) (June 2002) Historisches einige Jahreszahlen 1941 Zuse Z3, ab etwa 1960 Einführung von Dialogbetrieb ( Stapelbetrieb mit Operator ) 1960 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, Weiterentw. zu C. 1973, Unix erstes BS größtenteils in einer Hochsprache ( kaum 1000 Zeilen Maschinencode, portierbar ), Keine Vermarktung von Unix wg. US-Kartell-Bestimmungen 1975, BSD-UNIX: Abkürzung für Berkeley Software Distribution-UNIX. Bezeichnung für eine UNIX-Variante ( entwickelt an der Berkeley-Universität in Kalifornien, Abgabe an Universitäten zum Selbstkostenpreis ) 1980, Xenix ( Microsoft, ab Mitte 80er: Santa Cruz Operation, etwa bis 1990 ) 1981 IBM bringt den ersten PC ( mit MS-DOS ) heraus: 8088-CPU, 4.77 MHz, 64 KByte Speicher, 5.25"Diskettenlaufwerk. Microsoft entwickelt dazu eine erste Version des Betriebssystems MS-DOS. Hayes bringt ein Modem mit 1200 Bit/s heraus. Herwig Feichtinger, heute bei Shamrock, gründet mit "mc" eine der ersten ComputerZeitschriften. Novell stellt ein Netzwerk vor, mit dem mehrere Computer auf eine gemeinsame Festplatte zugreifen können. Hewlett-Packet konstruiert den ersten 32-Bit-Mikroprozessor. 1981 MS-DOS ( Microsoft-Disc Operating System, angelehtn an CP/M 80 für 160 KByte Disketten entwickelt, Version 1.25 ( ab 1982 ) benutzt zweiseitige Disketten ( 320 KByte Kapazität ); ab 1983 MS-DOS 2.11 mit FAT-Festplatten und User-Hardware-Anpassungen durch Treiber ( in der CONFIG.SYS ); ab 1984 MS-DOS 3.2 mit HD-Disketten ( 5.25 Zoll, 720 KByte) und die Einbindung in Netzwerke. ab 1984 MSDOS 3.3 konnten Platten mit mehr als 32 MByte verwaltet werden; ab 1988 gab es das fehlerbehaftete MS-DOS 4.X mit DOS-Shell, Festplatten bis 2 GByte, EMS-Speicher nach dem LIM-Standard; ab 1991 erschien MS-DOS 5.0 mit HMA und UMA ab 1993 MS-DOS 6.X mit Zusatzprogrammen, wie OnlineKomprimierer Doublespace, einem Virenschutz- und einem Backup-Programm, Memmaker-Speicher-Optimierer, ab 6.22 als Drivespace; ) 1983 Apple bringt mit "Lisa" erstmals einen per Maus bedienbaren Computer mit grafischer Oberfläche heraus. Wegen des hohen Preises von rund 75.000 Dollar wird er ein Flop. Microsoft kündigt Windows 1.0 an, es wird erst 1985 verfügbar. Sony kündigt die 3,5"-Diskette an. IBM und Microsoft entwickeln zusammen das Betriebssystem OS/2. Novell bringt die Netware-Software heraus. Microcom erfindet ein fehlerkorrigierendes Modem-Protokoll (MNP). 1984 POSIX ( Portable Operating System Interface for UNIX ). Schnittstellen-Standard der IEEE, der von allen UNIXDerivaten benutzt wird, dementsprechend auch von Programmen, die unter UNIX laufen beziehungsweise Übergänge zu UNIX-Rechnern herstellen. 1988 Normung zu ANSI-C ( Komitee X3J11 ). 1991 Linux 0.02 ( Linus Torvalds entwickelt einen Kern, FIN ) 1985 1985, MS präsentiert Windows 1.01; 1987, Windows 2; 1987, OS/2 von IBM / MS, zeichenorientiert 1988, OS/2 von IBM/MS mit grafischer Oberfläche 1990, Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet die Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste kommerzielle Internet-Provider den Dienst auf. Unter Federführung der Bundespost entsteht der Treiber-Standard CAPI 1.1 für ISDN-Karten. James Gosling und Bill Joy beginnen mit der Entwicklung der Programmiersprache Java; 1992, Windows 3.1; 1993, Windows 3.11; 1993 Windows NT ( Windows New Technology, 32-Bit-Betriebssystem, für Workstations Windows NT 3.1, für Windows NT 3.1 Advanced Server und Netzwerke ); 1996: Windows NT 3.5, und Windows NT 4.0; 1995, Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte Plug-and-Play-Technologie, mitgeliefert wurde der Internet-Browser Internet Explorer ); 1998, Windows 98 ( Update für Windows 95, Active Desktop bindet den Webbrowser Internet Explorer, unterstützt werden: FAT32, DVD- und MMX-Technologie, AGP (siehe Graphikkarte) USB-Anschlüsse ( Universal Serial Bus ), AGP ( Accelerated Graphics Port, 1997 Intel, direkte Verbindung von der Grafikkarte zum Prozessor sowie zum Arbeitsspeicher, Taktfrequenz 66 MHz, AGP 1X = 266 MByte/s, AGP 2X = 533 MByte/s, AGP 4X = 1066 MByte/s, Pipelining, 8 zusätzliche Leitungen, DIME-Auslagerungsmodus für Texturen ); 2000, Windows 2000 wird in 4 Zusammenstellungen ausgeliefert: Windows 2000 Professional ( für PC und Notebook ), Windows 2000 Server ( einfache Netzanwendungen ), Windows 2000 Advanced Server ( Unternehmenskritische und komplexe Netzanwendungen ) Windows 2000 Datacenter Server ( für Rechenzentren, Lagerverwaltungssysteme und Finanzsysteme ); 2001, Windows ME; 2002, Windows XP Betriebssystem Achtung! Hier werden lediglich einige Betriebssystem-Aspekte wiederholt ( vorrangig wird auf die Veranstaltung Betriebssysteme hingewiesen )! Ein Computer-Hardwaresystem besteht aus Mikroprozessoren, Chips, Uhren, Schaltungen, Eingabegeräten, Tastatur, Maus, Laufwerk; Ausgabegeräten, Bildschirm, Plattenlaufwerken; Peripheriegeräten, Drucker, Modem, Netzwerkkomponenten und weiteren Komponenten. Moderne Prozessoren können eine aufwendige Architektur haben: Moderne Prozessoren können verschiedene Speicher-Adressiersarten ( Memory-Management: Segnmentierung, Paging ) haben: Moderne Prozessoren können Descriptoren ( Zugriffstypen, Zugriffrechte, Privilege Level, Call Gates, Interrupt and Exception-Handling, usw. ) haben: Ein Betriebssystem ( Operating System, Systemsoftware, Basisprogramme ) besteht aus Software mit Basisroutinen für die Hardware - Ansteuerung und die Hardware - Resourcen - Verwaltung. Ein Betriebssystem erfüllt 2 Aufgaben: 1. Virtuelle Maschine, 2. Resourcen-Verwalter Die Betriebssystem - Architektur ( Instruktionssatz der zentralen Verarbeitungseinheit, der Speicher- organisation, Ein/Ausgabe auf Platten und Disketten, Bildschirm ) erfordert die (schwierige) Programmierung der Kontrollerbausteine. Diese Maschinen - Programme, wie Unterbrechungen ( interrupt ), Zeitgeber ( timer ) und die Speicherverwaltung ( memory management ) sind in den BIOS enthalten. Für den Anwender ist die Benutzung dieser Programmteile einfacher, als die direkte Programmierung der zugrundeliegende Hardware. Für den Anwender verhaelt sich das Betriebssystem wie eine Virtuelle Maschine. Wenn auf einem Computer mehrere Benutzer gleichzeitig arbeiten wollen, entsteht die Notwendigkeit, Speicher, Ein-/Ausgabegeraete und andere ( teure ) Komponenten zu verwalten und zu sichern. Aus dieser Sicht hat das Betriebssystem die Aufgabe, festzustellen, wer welche Resourcen verwendet, Resourcen auf Anforderung zu gewaehren, Unterbrechungens - Informationen zu sammeln und zwischen den gegenseitig sich überschneidenden Anforderungen mehrerer Benutzer oder Programme zu vermitteln. Die Software - Schichten: 1. Physikalische Geräte 2. Mikroprogrammierung 3. Maschinensprache 4. Betriebssystem 5. Kommando - Interpreter, Editoren, Compiler 6. Anwendungsprogramme Die Punkte 1, 2, 3 werden auch zu einer Hardware - Schicht zusammengefaßt. Die Punkte 4, 5 bilden die Systemprogramme. Zu den Applikationen ( Anwendungsprogrammen 6 ) gehören Datenbanken, CAD, Spiele, Banksystem, Simulatoren, usw. ). MS-DOS Etwa 1980 hat Jim Paterson (ausgehend vom CP/M-80) ein 6 KB umfassendes Betriebssystem QDOS (Quick and Durty Operating System) entwickelt. IBM wollte eine neue 16-Bit-Maschine auf Intel-Basis auf den Markt bringen. Mircosoft übernahm Jim Paterson und entwickelte MS-DOS unter strenger Geheimhaltung die Version 1.0 (1981). 1983 war die Version 2.0 ( hierarchisches Dateisystem mit 9 Sektoren für 360 kB Laufwerke, installierbare Geraetetreiber, Bildschirmtreiber ANSI.SYS, Backgroundprozessing ). 1984 entstand für den PC-AT die Version 3.0 ( Netzwerk, 20 MB Festplatte, 1.2 MB Diskettenlaufwerke, Verbesserungen der Ausführungszeiten ). Der interne Aufbau des DOS - Kerns DOS-BIOS ( : ROM) DOS-Kern ( I/O : IBMDOS.COM) Kommandoprozessor (Shell: COMMAND.COM) Unter DOS ausführbare DOS-Programme sind z.B. *.EXE und *.COM. *.COM-Programme können maximal 64 KB Code enthalten. Beim Laden von *.EXE Programmen werden die absoluten Speicher- bezüge angepasst. Starten von DOS Nach dem Einschalten wird geprüft ob im Laufwerk A: (falls leer dann B:, dann C:, usw.) eine Diskette ist. Der Boot-Sektor wird automatisch geladen, die BootRoutine wird ausgeführt und IBMBIO.COM und IBMDOS.COM geladen. Nun wird die Datei CONFIG.SYS gesucht und die in CONFIG.SYS enthaltenen Treiber werden geladen (DEVICE-Befehl). Dadurch wird der Kern des Betriebssystems zusammengebaut (SYStem CONFIGurieren). Dann wird der Kommandoprozessor (COMMAND.COM) geladen, der automatisch die in Beim Starten von DOS wird zuerst die Datei CONFIG.SYS (Gerätetreiber) und dann die Datei AUTOEXEC.BAT abgearbeitet. Die in AUTOEXEC.BAT enthaltenen *.COM- und *.EXE-Programme der Reihe nach ausführt. *.Bat steht für eine BATch-Job-Stapeldatei. Achtung! Das folgenden Beispiele ( DOS 5.0 ) können nicht kritiklos übernommen werden! Beispiel für CONFIG.SYS Beispiel für AUTOEXEC.BAT shell =c:\dos\command.com c:\dos\ /e:256 /p country=49,,c:\dos\country.sys @ECHO OFF device =c:\dos\himem.sys set comspec=c:\dos\command.com device =c:\dos\emm386.exe 2048 noems path C:\DOS;c:\bc\bin; dos=high,umb append=c:\dos lastdrive = g in not "%prompt%"=="" goto ende files =30 prompt $p$g buffers=15 lh keyb gr dh =c:\dos\smartdrv.sys 2048 1024 lh c:\dos\mouse.com dh =c:\dos\ansi.sys nc dh =c:\dos\ramdrive.sys 1024 /e :ende install=c:\dos\share.exe </td> Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Diese Tabelle beginnt bei der Speicher-Adresse 0 und enthält 256 Adressen. Jeder Adress-Eintrag verwendet 4 Byte. Wird ( durch ein Gerät ) dem Interrupt-Controller-Baustein ein Hardware - Interrupt angezeigt, so legt das Gerät danach den Tabelle-Index auf den Datenbus. Der Tabelle wird dann die Ziel-Adresse entnommen. Ab der Zielstelle wird das unterbrechende Programm ( ähnlich einem Unterprogramm ) ausgeführt. Bei einem Software-Interrupt ( z.B. INT 21h ) enthält der INT-Maschinen-Befehl bereits den Tabellen-Index. Ab der Zielstelle wird das unterbrechende Programm ( ähnlich einem Unterprogramm ) ausgeführt. Speicher-Bild: +----------------------------------+ | | | | Tabellen- |----|----|----| ... |----|----|----| ... |----|-- ... ---------Index 0. 1. 2. 33. 34. 35. 255. Zielstelle Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Dadurch ergeben sich die folgenden Vorteile: Wird das Betriebssystem verbessert oder erweitert, so wird der Maschinencode an der Zielstelle geändert. Die Folge der Adressen an den Zielstellen verschieben sich. Wenn Anwendungsprogramme die direkte Adresse der Zielstelle verwenden würden, so müßten bei jeder Betriebssystemänderung alle Anwendungsprogramme angepaßt werden. Wenn ein Anwendungsprogramm Funktionen des Betriebssystems verwendet, so wird lediglich den Index der Interrupt - Tabelle benutzt ( z.B. INT 21h ). Dadurch funktionieren die alten Anwendungsprogramme auch unter einer neueren Version des Betriebssystems. UNIX UNIX ist ein Mehrprogrammsystem. Die einzigen aktiven Einheiten in einem UNIX-System sind die ( sequeltiellen ) Prozesse. Jeder Prozess hat einen eigenen Programmzähler. Viele Prozesse laufen im Hintergrund ( Dämon, z.B.Terminplanung mit cron ). UNIX und C Nachdem Ken Thomson aus dem MIT - Projekt ( MULTiplexed Information and Computing Service, PL/I ) verlassen hatte, schrieb er auf der PDP-7 ein kleineres Betriebssystem UNICS ( UNiplexed Information and Computing Service, kastriertes MULTICS, späterer Name UNIX ). Die Übertragung des gesamten Assembler - Codes auf PDP-11/20, PDP-11/45, PDP-11/70 war schwierig. Deshalb wurde ein Programmiersprache B ( vereinfachtes BCPL, stark vereinfachtes PL/I ) entwickelt. B hatte keine Strukturen. Dennis Ritchie erweiterte B zu C. Um das Betriessystem auf einen neuen Computer zu übertragen wurde zunächste ( mit mittleren Aufwand ) der C - Compiler portiert. Die meisten Software Anteile konnten dann übernommen werden. Der Quellcode wurde kostenlos an Universitäten abgegeben. C wurde die Sprache der Systemprogrammierung. Ausgehend von der typenlosen Sprache BCPL wurde die Programmiersprache C von Ken Thomson und Dennis Ritchie bei den Bell Laboratories auf einer PDP11 entwickelt. Das Betriebssystem UNIX ist weitgehend in C geschrieben. UNIX Ver. 6 ist zu 95% in C geschrieben. C ist eine einfache und universelle Programmiersprache, die auch bei Mikrocontrollern als Assembler-Ersatz verwendbar ist. C ist heute i.a. die erste hoehere Programmiersprache, die auf einem neuen Computer, Microcomputers, Minicomputers oder Mainframe laeuft. Wir wollen immer zwischen der Programmiersprache C und den Bibliotheken unterscheiden. Bibliotheken enthalten eingebaute Funktionen und Dienstleistungen. Bei Projekten werden solche Bibliotheken mit Hilfe eines C-Compilers oft selbst erstellt (z.B. Window-, Grafik-, Device-Bibliotheken). 1988 wurde ANSI-C X3J11 genormt. C ist für Programmier-Anfaenger wegen der cryptischen-Schreibweise nicht so einfach wie z.B. BASIC. Mit C kann man flexibel bis auf Betriebssystem- und Maschinenebene programmieren. Anders als z.B. bei OBERON gilt: Die Verantwortung beim Programmieren mit C ( C++ ) liegt stets beim Programmierer! UNIX-Standardisierungen Die Universität Kalifornia in Berkeley nutzte den C - Quellcode und entwickelte eigene UNIX-Erweiterungen ( vi, csh, Compiler für Pascal und Lisp, usw. ). Sun baute auf dem Berkeley-Unix auf. Es gab unterschiedliche Unix-Normungsgremien z.B. AT&T SVID ( System V Interface Definition ), BSD ( Berkeley Sooftware Distribution ), IEEE POSIX 1003.1 ( Portaples Operating System ). OSF ( IBM und weitere, Open Software Foundation, starke Erweiterungen X11, MOTIF, DCE, DME ), UI ( AT&T und weitere, Unix International ). Für UNIX hat sich die sogenannte Mach Gruppe schon frühzeitig bemüht, einen Kernel weiter zu entwickeln, der die folgenden Eigenschaften vereint: ● ● ● ● ● Beibehaltung Schnittstelle abstraktes Modell der Speicherverwaltung ( großer und nicht dicht besetzter Adreßraum, memory mapped files, Speicherverwaltungsmodule für den Benutzer, Interprozeßkommunikation ( Transparenz im Netz, Schutzmechanismen, Austauschbare Datenmengen ) Beachtung von neuen Technologien ( Vernetzung, Mehrprozeßortechnik, enge und lose Kopplung, Prozeß in Tasks und Threads abbilden ) Werkzeuge ( im Kern eingebaute Testhilfe, Debugger, transparente Zugriffe auf andere Rechner, remote File access, remote Procedure Call für C, Pascal und Common Lisp ) Windows Windows ist überwiegend in ANSI - C geschrieben. Einige wenige zeitkritische Teile des Betriebssystem - Kerns für die Hardware Abstraktions Layer ( HAL ) sind in Assembler - Code geschrieben. Das Betriebssystem ist modular. Bei Bedarf werden die benötigten Teile ( DLL's ) geladen/entfernt. Es gibt verschiedene Windows-Betriebssysteme: 1985 1987 1987 1988 1990 1992 1993 1993 1996 1995 MS präsentiert Windows 1.01; Windows 2; OS/2 von IBM / MS, zeichenorientiert OS/2 von IBM/MS mit grafischer Oberfläche Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet die Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste kommerzielle Internet-Provider den Dienst auf. Unter Federführung der Bundespost entsteht der Treiber-Standard CAPI 1.1 für ISDN-Karten. James Gosling und Bill Joy beginnen mit der Entwicklung der Programmiersprache Java; Windows 3.1; Windows 3.11; Windows NT ( Windows New Technology, 32-Bit-Betriebssystem, für Workstations Windows NT 3.1, für Windows NT 3.1 Advanced Server und Netzwerke ); Windows NT 3.5, und Windows NT 4.0, Sicherheit, Erweiterbarkeit, Stabilität und Skalierbarkeit, zentrale Administration, NT-Server tritt in Konkurrenz zu Novell, Banyan oder UNIX Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte Plug-and-Play-Technologie, mitgeliefert wurde der Internet-Browser Internet Explorer, für Heimmarkt = Small Office/Home Office; 1998 Windows 98 ( Update für Windows 95, Active Desktop bindet den Webbrowser Internet Explorer, unterstützt werden: FAT32, DVDund MMX-Technologie, AGP (siehe Graphikkarte) USB-Anschlüsse ( Universal Serial Bus ), AGP ( Accelerated Graphics Port, 1997 Intel, direkte Verbindung von der Grafikkarte zum Prozessor sowie zum Arbeitsspeicher, Taktfrequenz 66 MHz, AGP 1X = 266 MByte/s, AGP 2X = 533 MByte/s, AGP 4X = 1066 MByte/s, Pipelining, 8 zusätzliche Leitungen, DIME-Auslagerungsmodus für Texturen ); 2000 Windows 2000 wird in 4 Zusammenstellungen ausgeliefert: Windows 2000 Professional ( für PC und Notebook ), Windows 2000 Server ( einfache Netzanwendungen ), Windows 2000 Advanced Server ( Unternehmenskritische und komplexe Netzanwendungen ) Windows 2000 Datacenter Server ( für Rechenzentren, Lagerverwaltungssysteme und Finanzsysteme ); 2001 Windows ME; 2002 Windows XP ● ● ● ● ● ● NT-Design Ziele Kompatibilität: Durch seine Submodule ist Windows NT in der Lage, Applikationen für die Betriebssyteme Windows 3.x, Windows 95, MSDOS, OS/2 und POSIX zu betreiben. Portierbarkeit: Windows NT ist fast vollständig in C geschrieben. Für eine neue Hardware Architektur muß deswegen lediglich eine neue HAL (Hardware Abstraction Layer) geschrieben werden und ein NTkomformer Compiler verfügbar sein. Skalierbarkeit: Windows NT unterstützt das symmetrische Multiprocessing. Sicherheit: Windows NT beinhaltet ein durchgängiges Sicherheitskonzept, das darauf ausgelegt ist, die Sicherheitsanforderungen des Amerikanischen Verteidungsministeriums zu erfüllen (C2). Verteilte Systeme: Windows NT hat schon im Betriebssystemkern weitreichende Funktionalität, um Prozesse auf anderen Rechnern ablaufen zu lassen. Zuverlässigkeit und Stabilität: Durch sein Konzept unterscheidet ● ● ● ● ● ● ● NT-Server Die Server - Version unterstützt beliebig viele gleichzeitige Dateiund Druckerverbindungen, Datei- und Druckerserver auch für Macintosh, Die Benutzerinformationen stehen allen Servern zur Verfügung (Domänen Konzept), NT-Server ermöglicht eine zentrale Benutzeradministration, Verzeichnis-Replikation, TCP/IP Unterstützung ( DHCP, WINS, DNS, etc.), NetWare Unterstützung ( GSNW, Migration Tool, FPNW kompatibel ), fehlertolerante Plattenkonzepte werden unterstützt ( Parity, RAID 5 ), Multiuser Remote Access Service ● Windows NT zwischen User und Kernel Prozessen. Dadurch ist es normalerweise einer Applikation nicht möglich einen Windows NT Rechner zu blockieren oder abzuschießen. Dadurch kann ein Server auch dann weiter arbeiten wenn in einer Applikation ein Fehler aufgetreten ist. Erweiterbar: Da Windows NT sehr modular aufgebaut ist, ist es einfach möglich neue Module einzuhängen oder zusätzliche hinzuzufügen. Architektur des NT-Betriebssystem Wichtige Teile des Betriebssystems sind im ( privilegierten ) Executive Modus geschützt. ● ● ● ● ● ● ● ● Hardware Abstraction Layer (HAL): Die HAL - Komponenten sind in Assembler geschrieben. Diese HAL - Schicht muß bei der Portierung von Intel-Basis auf MIPS, Alpha, Power-PC und PA/RISC neu geschrieben werden. Kern (Kernel): Dieser Mach-Kernel ist überwiegend in ANSI-C geschrieben. Der Kernel bearbeitet Unterbrechungen und AUsnahmen, Laufzeitfestlegung von Threads, Synchronisation von Prozessoren und stellt Objekte und Schnittstellen bereit. Objekt-Manager: Der Objekt-Manager verwaltet NT-Objekten ( Hardware, Prozesse, Threads, Ereignisse, Dateien, ... ). Prozeß-Manager: Verwaltung der Prozesse. Local Procedure Call-Facility (LPC): Variante der RPCs ( Remote Procedure Call ) zur Interprozeßkommunikation. Virtual Memory Manager: Virtuelle Speicherverwaltung, Verwaltung von Auslagerungsdateien. Sicherheitsmonitor: Überwachung der Sicherheit auf dem lokalen Computer. Ein/Ausgabesystem: Gerätetreiber, Dateisysteme, allgemeine Eingabe/Ausgabe. Struktur des NT 4.x-Betriebssystems Struktur des NT 4.x-Betriebssystems NT-Subsysteme Darüber hinaus stellt Windows NT eine Reihe geschlossener Subsysteme zur Ausführung von Applikationen zur Verfügung. Sie alle kommunizieren mit dem darunterliegenden Betriebssystem und regeln ihre Bildschirmausgaben über die Windows32-Graphikschnittstelle. ● ● ● ● Win32: Ausführung von 32-Bit Windows-Programmen, beinhaltet das WOW-Modul (Windows-on-Windows) zur Ausführung von 16-BitProgrammen. OS/2: OS/2 2.x Subsystem. POSIX: Zeichenorientiertes POSIX-Subsystem. Sicherheit: Subsystem zur Überwachung der Sicherheit der anderen Subsysteme NT-Objekte Resourcen als Objekte: ● ● ● ● Dateien Gemeinsam benutzter Speicher Physikalische Geräte jeder Art Prozesse/Threads NT-Objekte Ein NT-Thread: ● ● ● teilt sich das Code- und DatenSegment eines Prozesses mit anderen Threads, hat seine eigenen CPU-Register, StackRaum und einen eigenen Instruktions Zähler, erhält vom System eine gewisse CPU Zeit, so daß alle Threads des Prozesses gleichzeitig ausgeführt werden. NT-Objekte Unterschiedliche Objekte sind: ● ● ● ● Executive Objects hat bereits Windows NT 3.5 mit Service Pack 3 die C2Zertifizierung für NT-Rechner ohne Netzwerkanbindung erhalten. NT ist für B1-Security ausgelegt. Für jedes Objekt gibt es ein Zugriffstoken Dateisysteme: Die von Windows NT unterstützten Dateisysteme können parallel nebeneinander laufen. ● ● ● NTFS: New Technology File System, das eigentliche 64-Bit-Dateisystem von Windows NT mit starkem Fokus auf Sicherheit. Maximale Dateigröße: 17 Milliarden Gbytes HPFS: High Performance File System, OS/2-Dateisystem. Maximal Dateigröße: 4 bis 8 Gbytes ( wird ab NT 4.0 nicht mehr unterstützt ). FAT: File Allocation Table, DOS Dateisystem und Diskettenformat unter NT. Maximale Dateigröße: 4 Gbytes. Datentypen Alle binär gespeicherten Informationen bestehen aus kleinen, typisierten Einheiten. Jedem Buchstaben ist z.B. ein Bitmuster zugeordnet. Text besteht z.B. aus Buchstaben und diese aus Binärcode. Maschinencode besteht z.B. aus kleinen binären Einheiten ( prozessor-spezifischen OpCode-Befehlen ). Zu einer ganzen Zahl im Speicher gehört z.B. der Umfang von Bits, eine bestimmte Art des Bit-Muster-Aufbaues ( Interpretation dieser Bits ) und die Position, bei der diese Bits im Speicher sind ( Speicheradresse, Zeiger ). Zu jeder vorhandenen Information gehört ein Identifizierer ( physikalische RAM-Adresse, Entität, Ort der Information ) und ein Binärcode ( Bitmuster, Bedeutung, Semantik ). Daten-Typen legen die elementare Bedeutung eines Speicher-Bit-Musters fest. Mit Daten-Typen sind sinnvolle Operationen möglich. Zu einer Programmiersprache gehören Grundtypen, die für Zeichen, Zahlen, Strukturen verwendet werden können. Strukturen und Objekte legen die elementare Bedeutung einer Kombination von Grundtypen fest. Beispiel: Gleitpunktzahlen Zahlen in wissenschaftlicher Notation bestehen aus Vorzeichen ( Sign Bit ) , Mantisse ( Significant ) und Exponent ( Biased Exponent ). Wir müssen daher bei en sehr genau zwischen der Von der Größe einer Gleitpunktzahl ( Wert des Exponenten ) ist die Darstellungsgenauigkeit ( Anzahl der gespeicherten Ziffern ) zu unterscheiden. Das Format von Gleitpunktzahlen ist in IEEE 754 ( Floating Point Standard ) festgelegt. Es gibt die Daten-Formate: ● ● ● ● ● ● ● Word Integer ( Zweierkomplement, Bereich 104, Genauigkeit 16 Bit ), Short Integer ( Zweierkomplement, Bereich 109, Genauigkeit 32 Bit ), Long Integer ( Zweierkomplement, Bereich 1018, Genauigkeit 64 Bit ), Packed BCD ( Bereich 1018, Genauigkeit 18 Digits ), Single Precision ( 8 Bit für Exponenten, Bereich 10+<38; 24 Bits für Mantisse, Genauigkeit 24 Bit ), Double Precision ( 11 Bit für Exponenten, Bereich 10+<308; 53 Bits für Mantisse, Genauigkeit 53 Bit ), Extended Precision ( 16 Bit für Exponenten, Bereich 10+-4932; 64 Bits für Mantisse, Genauigkeit 64 Bit ). Gleitpunktzahlen werden vielfältig benötigt ( naturwissenschaftlichen, technischen Anwendungen, Grafik, numerische Mathematik, usw. ). Wegen des Zeitbedarfes werden Fließkommaoperationen von Gleitpunktzahlen (engl. Floating Point Numbers ) in digitalen Einheiten ( Coprozessor ) ausgeführt. Bitweise Darstellung einer double-Zahl 63 .. 56 55 .. 48 47 .. 40 39 .. 32 31 .. 24 23 .. 16 15 .. 8 7 .. 0 3210987654321008765432109876543210987654321098765432109876543210 s - Wert = (-1)s * 2e-e0 * ( normalisierte Mantisse ) mit e = Exponent ( -1022 ...1023 ), e0 := 1023 und 1 <= normalisierte Mantisse < 2 Beispiel: dez 25678.34 = = dez 2.567834*104 = = bin 0110 0100 0100 1110.0101 0111 = = bin 0110 0100 0100 1110. 0101 0111 = ( . um 14 Positionen verschieben, begrenzen der Mantisse auf 3 Byte: ) = bin 1.1001 0001 0011 1001 0101 11oo * 2dez 14 ( e0+14 = dez 1023 + 14 = dez 1037 = bin 100 0000 1101 ) 010000001101100100010011100101011100............................ 4 6 C 8 9 C A E 0 0 0 0 0 0 0 0 Beispiel: Unicode Eine lesbare Schrift besteht aus Schriftzeichen. Eine Repräsentation von Bildern als Zeichen wird Font genannt. Outline-Typeface ist eine Konturschrift ( Vektoren, Zeichen nur aus Umrisslinien ). TrueType-Fonts wurden von Apple und Microsoft entwickelt ( Zeichen werden als Hüllkurven-Konturen ). BitmappedFonts entsprechen binären Bildern. Ein Font besteht z.B. aus einer "Bildersammlung" aus 256 einzelnen Elementen, die mit 8 Bits eindeutig identifiziert werden können ( Code, z.B. ASCII ). Der Windows-ANSI-Zeichensatz enthält 256 Zeichen. Die ersten 32 Zeichen sind Steuerbefehle. Der ANSI-Zeichensatz ist von Zeichen 32 bis Zeichen 127 mit dem ASCII-Zeichensatz identisch. Unicode benutzt 16 Bits und kann 216 = 65536 verschieden Zeichen adressieren. Zu einem Zeichensatz gehören: ● ● ● ● ● Steuerzeichen ( Silbentrennzeichen, Tabulatorzeichen ) Sonderzeichen und Einzelteile von Zeichen ( z.B. Doppelpunkt, deutsche Umlauten, usw. ) Zeichen für Zahlen ( mathematischer Formeln ) Silbenzeichen oder Wortzeichen für fernöstlicher Schriftkulturen Schreibrichtung ( bei arabischen Zeichen etwa ist die Schreibrichtung von rechts nach links ) Bei der darstellung von Zeichen können diese auch dynamisch kombiniert werden ( z.B."ä" aus "a" und darüber gesetzten Doppelpunkt ). Das Unicode-Konsortium ( gegründet 1991, Linguisten, Fachleute ) koordiniert die weltweiten Schrift-Zeichen-Standardisierungen. Zeichen-Codes sollten systemunabhängig, programmunabhängig, sprachunabhängig sein und dennoch eine Vielfalt der Zeichen-Darstellung unterstützen. ● ● ● ● ● US-ASCII: Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986. ISO-646: International Standard--Information Processing--ISO 7-bit coded character set for information interchange, ISO 646:1983. ISO-2022: International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension techniques, ISO 2022:1986. ISO-8859: Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990. ISO/IEC 10646: Unicode Die vergebenen Codes ( Zahl-Zeichenwert-Zuordnung ) haben verbindlichen Charakter. Das Unicode-System ( Version 2.0 ) ist eine internationale Norm ISO/IEC 10646. Das Unicode-System ist in Zahlenbereiche aufgeteilt ( ASCII, Schriftkultur, Sonderzeichen, auch noch Platz für Zukünftiges ). Windows-Zeichen-Typen Generisch TCHAR LPTSTR ANSI UNICODE ANSI UNICODE Explizit CHAR WCHAR LPSTR LPWSTR Aufgelöst char wchar_t char * wchar_t Unicode Damit die generischen Typen den Unicode-Size verwenden, muß #define UNICODE ( vor den #include ) definiert sein. ANSI-Zeichen werden auf dem Tastatur-Ziffernblock unter Windows erzeugt durch: [Alt]-Taste drücken und die ANSI-Nummer mit vorangestellter [0] eingeben. Beispiel: ø = [Alt]+[0]+[2]+[4]+[8]. C++Grundtypen C++ kennt main() für Program Startup and Termination und die Standard-Streams: cin ( for standard input ), cout ( for standard output ), cerr ( for unbuffered standard error output ), clog ( for buffered standard error output ). C++ kennt die Header-Files ( bzw. subset ) : algorithm, bitset, cassert, cctype, cerrno, cfloat, ciso646, climits, clocale, cmath, complex, csetjmp, csignal, cstdarg, cstddef, cstdio, cstdlib, cstring, ctime, cwchar, cwctype, deque, exception, fstream, functional, iomanip, ios, iosfwd, iostream, istream, iterator, limits, list, locale, map, memory, numeric, ostream, queue, set, sstream, stack, stdexcept, streambuf, string, strstream, utility, valarray, vector Unterschiedliche Maschinen haben unterschiedlich geeignete Darstellungen ( Speicherbedarf, Geschwindigkeit, Vorzeichen, Big/Little Endian, usw. ). Typ C++ garantiert die folgenden Relationen: 1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(float) <= sizeof(double) Beispiel Typen für Integer char entspricht bei vielen Maschinen einem 8-Bit-signed-Wert; char char char char // char // // // // // char // t = c0 = *p = c[5] '\t'; /* 0x09 */ ( char ) 0x61;/* 'a' */ ∓ c0; /* pStr -> c0 */ = {'A', 'B', 'C'}; 0x41 0x42 0x43 0x00 0x00 *ptrs[5] = {"abc","ABC"}; ptrs[0] -> 0x61 0x62 0x63 0x00 0x00 ptrs[1] -> 0x41 0x42 0x43 0x00 0x00 ptrs[2] == NULL ptrs[3] == NULL ptrs[4] == NULL *pStr = "ABC"; pStr -> 0x61 0x62 0x63 0x00 short int entspricht signed short int vorzeichbehaftete Zahl, bei 32 Bit Maschinen meist 2 Byte; int entspricht signed int; all. darf int bei mehrfach Kombinationen weggelassen werden; bei 32 Bit Maschinen meist sizeof(int) = 4; int i1 = 256+255; char ch = i1;/* ch=255 */ int i2 = ch; /* i2 = -1 oder 255 */ long int entspricht signed long int; bei 32 Bit Maschinen meist sizeof(long) = 4 Typen für Fließkommazahlen float bei 32 Bit Maschinen meist sizeof(float) = 4 double bei 32 Bit Maschinen meist sizeof(double) = 8 long double bei 32 Bit Maschinen meist sizeof(double) = 8 Typen für vorzeichenlose Integer, logische Werte, Bitfelder, usw. unsigned char entspricht bei 32 Bit Maschinen meist 1 Byte; unsigned short int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 2 Byte; unsigned short int shorti = -1; liefert ... unsigned int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned int ui = -1; liefert ... unsigned long int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned long l = -1; liefert ... Standard C- Bibliotheks-Header-Files Hier sind einige C-Header-Files ( Funktionsnamen ). Standard C++ Bibliotheks-Header-Files Die C, C++-Prototypen von Funktionen, Macros, Datenstrukturen, usw. werden in Header-Files zusammengefaßt. Die beim Erstellen des Betriebssystems ( *.DLL's ) benutzten Header - Files werden zur Verfügung gestellt. Liegen auch die zugeordneten *.LIB - Files vor, so können die DLL - Funktionen in eigenen Applikationen eingebunden werden. Standard C++ library headers algorithm.h for defining numerous templates that implement useful algorithms for enforcing assertions when functions execute cassert.h for testing error codes reported by library functions cerrno.h ciso646.h for programming in ISO 646 variant character sets for adapting to different cultural conventions clocale.h complex.h for defining a template class that supports complex arithmetic for controlling various exceptional conditions csignal.h cstddef.h for defining several useful types and macros for performing a variety of operations cstdlib.h for converting between various time and date formats ctime.h cwctype.h for classifying wide characters exception.h for defining several functions that control exception handling functional.h for defining several templates that help construct predicates for the templates defined in algorithm.h and numeric.h bitset.h for defining a template class that administers sets of bits cctype.h cfloat.h climits.h cmath.h csetjmp.h cstdarg.h cstdio.h cstring.h cwchar.h deque.h fstream.h for classifying characters for testing floating-point type properties for testing integer type properties for computing common mathematical functions for executing nonlocal goto statements for accessing a varying number of arguments for performing input and output for manipulating several kinds of strings for manipulating wide streams and several kinds of strings for defining a template class that implements a deque container for defining several iostreams template classes that manipulate external files for declaring several iostreams manipulators that take an argument iomanip.h for defining the template class that serves as the base for many iosfwd.h iostreams classes iostream.h for declaring the iostreams objects that manipulate the standard iso646.h.h streams istream.h for defining the template class that performs extractions iterator.h ios.h for testing numeric type properties for defining several classes and templates that control localespecific behavior, as in the iostreams classes memory.h for defining several templates that allocate and free storage for various container classes numeric.h for defining several templates that implement useful numeric functions for defining a template class that implements a queue container queue.h limits.h locale.h list.h map.h for declaring several iostreams template classes before they are necessarily defined for programming in ISO 646 variant character sets for defining several templates that help define and manipulate iterators for defining a template class that implements a list container for defining template classes that implement associative containers new.h for declaring several functions that allocate and free storage ostream.h for defining the template class that performs insertions set.h for defining template classes that implement associative containers with unique elements for defining a template class that implements a stack container for defining several iostreams template classes that manipulate stack.h string containers stdexcept.h for defining several classes useful for reporting exceptions streambuf.h for defining template classes that buffer iostreams operations for defining a template class that implements a string container strstream.h for defining several iostreams classes that manipulate instring.h memory character sequences for defining several templates of general utility typeinfo.h for defining class type_info, the result of the typeid operator utility.h for defining a template class that implements a vector container valarray.h for defining several classes and template classes vector.h that support value-oriented arrays sstream.h Windows-Standard Typen Ein Betriessystem ( im Gegensatz zur C++-Definition ) arbeitet mit ( exakt ) festgelegten Typen, Strukturen und Speicherabbildern. Typ Windows-Standard Typen der RTL ( Run-Time Library ) Beschreibung deklariert in clock_t structure _complex structure _dev_t short or unsigned integer div_t, ldiv_t structures _exception structure FILE structure _finddata_t, _wfinddata_t _wfinddatai64_t structures _FPIEEE_RECORD structure fpos_t (long integer, __int64, or structure, depending on the target platform) _HEAPINFO structure jmp_buf array lconv structure _off_t long integer _onexit_t pointer _PNH pointer to function ptrdiff_t integer sig_atomic_t integer size_t unsigned integer _stat structure time_tlong integer _timeb structure tm structure _utimbuf structure Stores time values; used by clock. Stores real and imaginary parts of complex numbers; used by _cabs. Represents device handles. TIME.H MATH.H SYS\TYPES.H Store values returned by div and ldiv, respectively. Stores error information for _matherr. Stores information about current state of stream; used in all stream I/O operations. _finddata_t stores file-attribute information returned by _findfirst and _findnext. _wfinddata_t stores file-attribute information returned by _wfindfirst and _wfindnext. _wfinddatai64_t stores file-attribute information returned by _wfindfirsti64 and _wfindnexti64. Contains information pertaining to IEEE floating-point exception; passed to user-defined trap handler by _fpieee_flt. Used by fgetpos and fsetpos to record information for uniquely specifying every position within a file. STDLIB.H MATH.H STDIO.H Contains information about next heap entry for _heapwalk. Used by setjmp and longjmp to save and restore program environment. Contains formatting rules for numeric values in different countries. Represents file-offset value. Returned by _onexit. Type of argument to _set_new_handler. Result of subtraction of two pointers. Type of object that can be modified as atomic entity, even in presence of asynchronous interrupts; used with signal. Result of sizeof operator. Contains file-status information returned by _stat and _fstat. Represents time values in mktime and time. Used by _ftime to store current system time. Used by asctime, gmtime, localtime, mktime, and strftime to store and retrieve time information. Stores file access and modification times used by _utime to change filemodification dates. MALLOC.H SETJMP.H LOCALE.H SYS\TYPES.H STDLIB.H NEW.H STDDEF.H SIGNAL.H _finddata_t: IO.H _wfinddata_t: IO.H, WCHAR.H _wfinddatai64_t: IO.H, WCHAR.H FPIEEE.H STDIO.H STDDEF.H and other include files SYS\STAT.H TIME.H SYS\TIMEB.H TIME.H SYS\UTIME.H va_list structure wchar_t internal type of a wide character wctrans_t integer wctype_t integer wint_t integer Used to hold information needed by va_arg and va_end macros. Called function declares variable of type va_list that can be passed as argument to another function. Useful for writing portable programs for international markets. STDARG.H Represents locale-specific character mappings. Can represent all characters of any national character set. Type of data object that can hold any wide character or wide end-of-file value. WCTYPE.H WCHAR.H WCHAR.H STDDEF.H, STDLIB.H Die Typen und Strukturen eines Betriessystems sind vielfältig und umfangreich. Windows-Typen werden u.a. für Funktions - Parameter, Funktions-RückgabeWerte, 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. Windows benötigt viele Typen. Hier eine Auswahl ... ATOM Atom (a reference to a character string in an atom BOOL Boolean variable (should be TRUE or FALSE) table) BOOLEAN Boolean variable (should be TRUE or FALSE) BYTE Byte (8 bits) 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 DWORD Doubleword (32 bits) callback procedure. EDITWORDBREAKPROC Pointer to an application-defined callback function ENHMFENUMPROC Pointer to an application-defined callback function that the operating system calls when a multiline that enumerates enhanced-metafile records edit control needs to break a line of text. See EditWordBreakProc for information on functions of this type. ENUMRESLANGPROC Pointer to an application-defined callback function that enumerates resource languages ENUMRESTYPEPROC Pointer to an application-defined callback function that enumerates resource types FLOAT Floating-point variable GOBJENUMPROC Pointer to an application-defined callback function that enumerates graphics device interface (GDI) objects HACCEL Handle of an accelerator table HBITMAP Handle of a bitmap HCONV Handle of a dynamic data exchange (DDE) conversation HCURSOR Handle of a cursor HDDEDATA Handle of DDE data HENHMETAFILE Handle of an enhanced metafile HFONT Handle of a font HGLOBAL Handle of a global memory block HICON Handle of an icon HKEY Handle of a registry key HMENU Handle of a menu HOOKPROC Pointer to an application-defined hook function HPEN Handle of a pen HRSRC Handle of a resource HWINSTA Handle of a workstation INT Signed integer LCID Locale identifier LINEDDAPROC Pointer to a callback function that processes line coordinates LP Pointer to a null-terminated Unicode™ string LPBOOL Pointer to a Boolean variable LPCCH Pointer to a constant Windows character LPCFHOOKPROC Pointer to an application-defined hook function LPCOLORREF Pointer to a COLORREF value LPCSTR Pointer to a constant null-terminated Windows character string ENUMRESNAMEPROC Pointer to an application-defined callback function that enumerates resource names FARPROC Pointer to a callback function FONTENUMPROC Pointer to an application-defined callback function that enumerates fonts GRAYSTRINGPROC Pointer to an application-defined callback function that draws gray text HANDLE Handle of an object HBRUSH Handle of a brush HCONVLIST Handle of a DDE conversation list HDC Handle of a device context (DC) HDWP Handle of a deferred window position structure HFILE Handle of a file HGDIOBJ Handle of a GDI object HHOOK Handle of a hook HINSTANCE Handle of an instance HLOCAL Handle of a local memory block HMETAFILE Handle of a metafile HPALETTE Handle of a palette HRGN Handle of a region HSZ Handle of a DDE string HWND Handle of a window LANGID Language identifier LCTYPE Locale type LONG 32-bit signed value LPARAM 32-bit message parameter LPBYTE Pointer to a byte LPCCHOOKPROC Pointer to an application-defined hook function LPCH Pointer to a Windows character LPCRITICAL_SECTION Pointer to a critical-section object LPCTSTR Pointer to a constant null-terminated Unicode or Windows character string LPCWCH Pointer to a constant null-terminated Unicode character LPDWORD Pointer to an unsigned doubleword (32 bits) LPHANDLE Pointer to a handle LPINT Pointer to a signed integer LPOFNHOOKPROC Pointer to an application-defined hook function LPSETUPHOOKPROC Pointer to an application-defined hook function LPTCH Pointer to a Unicode character or a Windows character LRESULT Signed result of message processing LPWCH Pointer to a Unicode character LPWSTR Pointer to a null-terminated Unicode character string MFENUMPROC Pointer to an application-defined callback function that enumerates metafile records NWPSTR Pointer to a null-terminated Unicode string PBOOLEAN Pointer to a Boolean variable PCCH Pointer to a constant Windows character PCHAR Pointer to a Windows character PCSTR Pointer to a constant null-terminated Windows character string PCWSTR Pointer to a constant null-terminated Unicode character string PFLOAT Pointer to a floating-point variable PHANDLE Pointer to a handle PHKEY Pointer to a registry key PLONG Pointer to a signed long (32 bits) PROPENUMPROC Pointer to an application-defined callback function that enumerates window properties. See PropEnumProc for information on functions of this type. PSHORT Pointer to a signed short (16 bits) PSTR Pointer to a null-terminated Windows character string LPCWSTR Pointer to a constant null-terminated Unicode character string LPFRHOOKPROC Pointer to an application-defined hook function LPHANDLER_FUNCTION Pointer to a handler function LPLONG Pointer to a signed long (32 bits) LPPRINTHOOKPROC Pointer to an application-defined hook function LPSTR Pointer to a null-terminated Windows character string LPTSTR Pointer to a null-terminated Windows or Unicode character string LPVOID Pointer to any type LPWORD Pointer to an unsigned word (16 bits) LUID Locally unique identifier NPSTR Pointer to a null-terminated Windows character string PBOOL Pointer to a Boolean variable PBYTE Pointer to a byte PCH Pointer to a Windows character PCRITICAL_SECTION Pointer to a critical-section object PCWCH Pointer to a constant Unicode character PDWORD Pointer to an unsigned doubleword (32 bits) PFNCALLBACK Pointer to a callback function PHANDLER_ Pointer to a handler routine ROUTINE PINT Pointer to a signed integer PLUID Pointer to a locally unique identifier (LUID) PROPENUMPROCEX Pointer to an application-defined callback function that enumerates window properties. See PropEnumProcEx for information on functions of this type. PSID Pointer to a security identifier (SID) PSZ Pointer to a null-terminated Windows character string PTCH Pointer to a Windows or Unicode character PTSTR Pointer to a null-terminated Windows or Unicode character string PUINT Pointer to an unsigned integer PUSHORT Pointer to an unsigned short (16 bits) PWCH Pointer to a Unicode character PWORD Pointer to an unsigned word (16 bits) REGSAM Security access mask for registry key 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. SHORT Short integer TCHAR Unicode character or Windows character UCHAR Unsigned Windows character ULONG Unsigned long integer (32 bits) VOID Any type WNDENUMPROC Pointer to an application-defined callback function that enumerates windows WORD Unsigned word (16 bits) YIELDPROC Pointer to a yield callback function PTCHAR Pointer to a Windows or Unicode character PUCHAR Pointer to an unsigned Windows character PULONG Pointer to an unsigned long (32 bits) PVOID Pointer to any type PWCHAR Pointer to a Unicode character PWSTR Pointer to a null-terminated Unicode character string SC_HANDLE Handle of a service SERVICE_STATUS_ Handle of a service status value HANDLE SPHANDLE Pointer to a handle TIMERPROC Pointer to an application-defined timer callback function UINT Unsigned integer USHORT Unsigned short integer (16 bits) WCHAR Unicode character WNDPROC Pointer to an application-defined window procedure WPARAM 32-bit message parameter Windows-Header-Files Das Betriessystem wurde überwiegend mit C/C++ entwickelt. Die System-Funktionen sind als Maschinencode in DLL's enthalten. Für die Entwicklung der System-Funktionen wurden Header-Quelltext-Files benutzt. Diese Header-Files werden auch für die Programm-Entwicklungen verwendet. Es gibt zahlreiche Windows-Header-Files: _dbdao.h _entryid.h a.txt accctrl.h aclapi.h aclcls.h aclsid.h acsmgtc.h acssvcc.h activecf.h activeds.h activex.mak activex.rcv activex.ver activscp.h activscp.idl addrlkup.h admex.h adminext.h adoid.h adoint.h adomd.h adomd.idl adptif.h ads.odl adsdb.h adserr.h adshlp.h adsiid.h adsnms.h adssts.h advpub.h agtctl.h agtctl_i.c agterr.h agtsvr.h agtsvr_i.c algorithm alphaops.h amaudio.h amrtpdmx.h amrtpnet.h amrtpss.h amrtpuid.h amstream.h amstream.idl amvideo.h amvpe.idl ansiapi.h appavcap.h appc_c.h appccfg.h appfftp.h asptlb.h assert.h atalkwsh.h attrname.h austream.h austream.idl avifmt.h aviriff.h axcore.idl axextend.idl basemake.inc basetsd.h basetyps.h bdnapi.h bh.h bh.mak bhcommon.ver bherr.h bherr.inc bhfilter.h bhsupp.h bhtypes.h bhver.h bitset bkoffice.mak blberr.h bpcpri.h bpcreg.h bpcsusp.h bradm.idl brerror.h bridge.h brprop.h brtest.h bttncur.h buffer.h callconv.inc cassert cctype cderr.h cdialog.h cerrno certadm.h certcli.h certenc.h certexit.h certext.h certif.h certpol.h certsrv certsrv.h cfloat cguid.h chanmgr.h chanmgr.idl channelt.h chanstr.h chprop.h cierror.h ciso646 climits clocale cluadmex.h cluadmex.idl clusapi.h clusmsg.h cmath cmc.h cmdproc.h codecs.h color.dlg colordlg.h comcat.h comcat.idl comdef.h comip.h comlite.h commctrl.h commctrl.rh commdlg.h common.ver complex compobj.h computer.odl comutil.h conio.h control.h control.odl convclss.h convcwrp.h convdll.h convdllc.h convdlle.h convengn.h convincl.h convreg.h convregh.h convstrc.h copyfile.mak core.odl cpl.h cplext.h crtdbg.h csetjmp csignal cstdarg cstddef cstdio cstdlib cstring ctime ctl3d.h ctype.h custcntl.h customaw.h cutlist.h cwchar cwctype cwindow.h cxq_cust.h d3d.h d3dcaps.h d3drm.h d3drmdef.h d3drmobj.h d3drmwin.h d3dtypes.h d3dvec.inl danim.h daogetrw.h dapi.h dapimsg.h data.h datapath.h dbcsstr.h dbdao.h dbdaoerr.h dbdaoid.h dbdaoint.h dbsets.h dbt.h dde.h dde.rh ddeml.h ddkernel.h ddraw.h ddrawex.h ddstream.h ddstream.idl delayhlp.cpp delayimp.h deque devenum.idl devguid.h devtype.h digitalv.h dinput.h direct.h dispatch.h dispdib.h dispex.h dispex.idl dlcapi.h dlgs.h docobj.h docobj.idl domain.odl dos.h dplay.h dplobby.h dprintf.h drivinit.h dsetup.h dskquota.h dsnamesp.odl dsound.h dssclien.h dssenum.h dtchelp.h dv.h dvdevcod.h dvdif.idl dvdmedia.h dvobj.h dvp.h dxmrtp.h edbback.h edbbcli.h edbmsg.h edevdefs.h edk.h edkafx.h edkcfg.h edkcode.h edkdebug.h edkevent.h edkguid.h edkmapi.h edkmdb.h edkmsg.h edksetup.h edktrack.h edkutcpp.h edkutils.h effect.h eh.h emsabtag.h epgdisp.h epgdspid.h epgldrx.h episodet.h epprop.h errcpp.h errcppd.h errno.h error.h errors.h evcode.h eventcpts.h eventcpts_i.c exadmin.h exception exchcli.h exchext.h exchform.h exchinst.h excpt.h exdisp.h exdisp.idl exdisp.odl exdispid.h fastfile.h fcntl.h fileopen.dlg filter.h filterr.h findtext.dlg float.h fmi.h font.dlg fpieee.h frame.h fserv.odl fshare.odl fstream fstream.h ftsiface.h functional g711uids.h genre.h gizmobar.h gl globlmak.mak group.odl gwmain.h gwreport.h header.h hlguids.h hliface.h hliface.idl hlink.h hlink.idl htmlguid.h httpext.h httpfilt.h iaccess.h iaccess.idl iadmw.h iads.h iamovie.idl icm.h icmui.dlg icrsint.h idf.h idispids.h ih26xcd.h iiis.h iimgctx.h iiscnfg.h il21dec.h ilogobj.hxx ils.idl ilsguid.h imagehlp.h ime.h imessage.h imm.h imsconf2.idl inetreg.h inetsdk.h inetsdk.idl inetsdk.mak inilib.h initguid.h initoid.h intshcut.h io.h iomanip iomanip.h ios ios.h iosfwd iostream iostream.h ipifcons.h ipinfoid.h ipmcdefs.h ipmconv.h iprtrmib.h ipxconst.h ipxrip.h ipxrtdef.h ipxsap.h ipxtfflt.h irtprph.h irtpsph.h isguids.h iso646.h issper16.h issperr.h istream istream.h iterator itvx.h javaattr.h javadbg.h javaexec.h jdbgguid.h kerbcon.h kerberos.h ks.h ksuuids.h largeint.h limits limits.h list list.h listing.inc lm.h lmaccess.h lmalert.h lmapibuf.h lmat.h lmaudit.h lmbrowsr.h lmchdev.h lmconfig.h lmcons.h lmdfs.h lmerr.h lmerrlog.h lmmsg.h lmremutl.h lmrepl.h lmserver.h lmshare.h lmsname.h lmstats.h lmsvc.h lmuse.h lmuseflg.h lmwksta.h loadperf.h locale locale.h locality.odl lsapi.h lua_c.h lzexpand.h make.inc malloc.h map mapi.h mapicode.h mapidbg.h mapidefs.h mapiform.h mapiguid.h mapihook.h mapinls.h mapioid.h mapispi.h mapitags.h mapiutil.h mapival.h mapivb.bas mapiwin.h mapiwz.h mapix.h math.h mbctype.h mblogon.h mbstring.h mbxdata.h mciavi.h mcx.h mdcommsg.h mddefw.h mdmsg.h mdsi.h mdsimsgs.h memory memory.h mgmtapi.h midles.h mimeinfo.h mimeinfo.idl minmax.h mlang.h mlang.idl mmc.h mmc.idl mmreg.h mmstream.h mmstream.idl mmsystem.h moniker.h monitor.h monshare.h mpconfig.h mpegtype.h mprapi.h mprerror.h mprui.h mq.h mqoai.h msacm.h msacmdlg.dlg msacmdlg.h msado15.idl msclus.h msclus.idl msclus.tlb msconf.h mscpydis.h msdadc.h msdaguid.h msdaora.h msdaosp.h msdasc.h msdasql.h msdatsrc.h msdetect.h msfs.h msgemit.h msgfiltr.h mshtmcid.h mshtmdid.h mshtmhst.h mshtmhst.idl mshtml.h mshtml.idl msi.h msiquery.h msitool.mak mspab.h mspst.h msregdb.h msshared.h mssip.h msstkppg.h mstask.h mstask.idl msterr.h mstv.h mswsock.h msxml.h msxml.idl msxmldid.h mtsevents.h mtsevents_i.c mtsgrp.h mtsgrp_i.c mtx.h mtxadmin.h mtxadmin_i.c mtxattr.h mtxdm.h mtxdm_i.c mtxspm.h multimon.h multinfo.h nal.h naltypes.h namesps.odl nativcom.h native.h nb30.h nddeapi.h nddesec.h neterr.h network.h new new.h newpst.h nspapi.h ntlmsp.h ntmsapi.h ntmsmli.h ntquery.h ntsdexts.h ntsecapi.h ntverp.h ntwin32.mak numeric oaidl.h oaidl.idl objbase.h objectty.h objerror.h objidl.h objidl.idl objmodel objsafe.h objsafe.idl ocidl.h ocidl.idl ocmm.idl odbcinst.h odbcss.h odbcver.h oemnsvbh.inf oid.h oldplib.h ole.h ole2.h ole2ver.h oleacc.h oleauto.h olectl.h olectlid.h oledb.h oledb11spec.hh oledberr.h oledberr.mc oledbjvs.inc oledbvbs.inc oledlg.dlg oledlg.h oleidl.h oleidl.idl olenls.h olesampl.mak olescrpt.h olestd.h oletx2xa.h ostream ostream.h packet.h parser.h pbt.h pcrt32.h pdh.h pdhmsg.h penwin.h perf.h perf.inc perfsym.h perhist.h perhist.idl plan32.h playlist.h poppack.h postmake.inc printer.odl printjob.odl prnsetup.dlg process.h propbag2.h propbag2.idl proptag.h protocol.h proxygen.h proxyinf.h prsht.h pshpack1.h pshpack2.h pshpack4.h pshpack8.h qnetwork.h qos.h qosname.h qrycodes.h queue queue.h ras.h rasauth.h rasdlg.h raseapif.h raserror.h rassapi.h rasshost.h rating.h ratings.h ratingsy.h rclsid.h recguids.h reconcil.h regstr.h rend.h resapi.h resource.odl retcode.h richedit.h richole.h rmfacade.h rnderr.h rndnot.h routprot.h rpc.h rpcasync.h rpcbak.h rpcdce.h rpcdcep.h rpcndr.h rpcnsi.h rpcnsip.h rpcnterr.h rpcpri.h rpcproxy.h rpcpub.h rtflib.h rtinfo.h rtm.h rtp.h rtutils.h rulecls.h sadapi.h scarddat.h scarddat.idl scarddat_i.c scarderr.h scardmgr.h scardmgr.idl scardmgr_i.c scardsrv.h scardsrv.idl scardsrv_i.c schema.odl schnlsp.h scode.h scrnsave.h scrptids.h sdkbld.mak sdkpropbld.mak sdpblb.h sdperr.h search.h secext.h seclink.h secpkg.h security.h sehmap.h semfperf.h serv.odl servprov.h servprov.idl session.h session.odl set setjmp.h setjmpex.h setupapi.h setupdd.h sgwdata.h share.h shellapi.h shlguid.h shlobj.h shlwapi.h signal.h simpdata.h simpdata.idl sipbase.h smbdata.h smpab.h smpms.h smpxp.h smsapi.h smsinfo.h sna_cnst.h sna_dlc.h snados.h snanls.h snapmon.h snmp.h sporder.h sql.h sqldb.h sqlext.h sqlfront.h sqlole.h sqloleid.h sqltypes.h sqlucode.h srv.h srvapi.h srvconst.h srvdbtyp.h srvmisc.h srvstruc.h srvtok.h srvtypes.h sspguid.h sspi.h sspserr.h sspsidl.h sspsidl.idl sspsidl_i.c sstream stablize.h stack station.h stats.h stattype.h stdarg.h stddef.h stdexcept stdexcpt.h stdio.h stdiostr.h stdlib.h stm.h storage.h streamb.h streambuf streamty.h string string.h strmhelp.h strmif.h strmif.idl strstrea.h strstream subgenre.h subsmgr.h subsmgr.idl svcguid.h svrapi.h syncdtct.h sys tagnames.h tapi.h tapi3.h tchar.h theme.h time.h timeslot.h tlhelp32.h tnef.h tpstart.h trace.h transact.h trkcom.h trkcom.idl trnsdt.h tspi.h tss.h tssadmin.odl tssqsec.h tssutil.h tvdisp.h tvdisp.odl tvdispid.h txcoord.h txctx.h txdtc.h typeinfo typeinfo.h uastrfnc.h unknwn.h unknwn.idl urlhist.h urlhist.idl urlhlink.h urlmon.h urlmon.idl use_ansi.h useoldio.h user.odl utassert.h util.h utility utlist.h utsem.h uuids.h valarray varargs.h variant.h vbsql.bas vbsql.bi vcr.h vdmdbg.h vector ver.h verfile verinfo.h verinfo.ver version.h vfw.h vfwmsgs.h vidsvr.odl vidtypes.h vpconfig.h vpnotify.h vptype.h vsof.h vsop.h vsopcsid.h w32chico.mk w32sut.h wab.h wabapi.h wabcode.h wabdefs.h wabiab.h wabmem.h wabnot.h wabtags.h wabutil.h wchar.h wctype.h wdbgexts.h wfext.h win32.mak winable.h winappc.h winbase.h wincon.h wincpic.h wincrypt.h wincsv.h windef.h windows.h windowsx.h windowsx.h16 winerror.h wingdi.h wininet.h winioctl.h winldap.h winlua.h winmgt.h winnetwk.h winnls.h winnls32.h winnt.h winnt.rh winperf.h winreg.h winres.h winresrc.h winrui.h winscard.h winsli.h winsmcrd.h winsnmp.h winsock.h winsock2.h winspool.h winsvc.h wintrust.h winuser.h winuser.rh winver.h winwlx.h winwrap.h wownt16.h wownt32.h wpapi.h wpapimsg.h wpcrsmsg.h wpftpmsg.h wpguid.h wpobj.h wpobj.idl wppstmsg.h wpspi.h wpspi.idl wpspihlp.h wptypes.h wpwizmsg.h wrpguid.h ws2atm.h ws2dnet.h ws2spi.h ws2tcpip.h wshisotp.h wsipx.h wsnetbs.h wsnwlink.h wsvns.h wsvv.h wtypes.h wtypes.idl xa.h xactomsg.h xcmc.h xcmcext.h xcmcmsx2.h xcmcmsxt.h xcomplex xiosbase xlocale xlocinfo xlocinfo.h xlocmon xlocnum xloctime xmemory xolehlp.h xstddef xstring xtree xutility ymath.h yvals.h zmouse.h MACROS Windows verwendet zahlreiche MACROS, die in C/C++-Header-File enthalten sind. siehe z.B.: windowsx.h ===================== Einige C-Header-Files ===================== math.h ===================== abs Return absolute value of integer parameter acos Calculate arccosine asin Calculate arcsine atan Calculate arctangent atan2 Calculate arctangent, 2 parameters atof Convert string to double ceil Return the smallest integer that is greater or equal to x cos Calculate cosine cosh Calculate hyperbolic cosine exp Calculate exponential fabs Return absolute value of floating-point floor Round down value fmod Return remainder of floating point division frexp Get mantissa and exponent of floating-point value labs Return absolute value of long integer parameter ldexp Get floating-point value from mantissa and exponent log Calculate natural logarithm log10 Calculate logarithm base 10 modf Spli floating-point value into fractional and integer parts pow Calculate numeric power sin Calculate sine sinh Calculate hyperbolic sine sqrt Calculate square root tan Calculate tangent tanh Calculate hyperbolic tangent stdio.h ===================== clearerr Reset error indicators. fclose Close a stream. feof Check if End Of File has been reached. ferror Check for errors. fflush Flush a stream. fgetc Get next character from a stream. fgetpos Get position in a stream. fgets Get string from a stream. fopen Open a file. fprintf Print formatted data to a stream. fputc Write character to a stream. fputchar Write character to stdout. fputs Write string to a stream. fread Read block of data from a stream. freopen Reopen a file using a different file mode. fscanf Read formatted data from a stream. fseek Reposition stream's position indicator. fsetpos Reposition file pointer to a saved location. ftell Return the current position of the file pointer. fwrite Write block of data to a stream. getc Get the next character. getchar Get the next character from stdin. gets Get a string from stdin. getw Get the next int value from a stream. perror Print error message. printf Print formatted data to stdout. putc Write character to a stream. putchar Write character to stdout. puts Write a string to stdout. putw Write an integer to a stream. remove rename rewind scanf setbuf setvbuf sprintf sscanf tmpfile tmpnam ungetc Delete a file. Rename a file or directory. Reposition file pointer to the beginning of a stream. Read formatted data from stdin. Change stream buffering. Change stream buffering. Format data to a string. Read formatted data from a string. Open a temporary file. Generate a unique temporary filename. Push a character back into stream. Streams. Streams are an abstraction used in C and C++ for input and output operations through I/O devices based on characters, like files, keyboard, printer, screen and I/O ports. A stdio.h stream is represented by a pointer to a FILE structure that contains internal info about properties and indicators of a file. Normally data contained in these structures are not referred directly. When using stdio.h functions, pointer to FILE structures are only used to be passed as parameters to I/O functions. Properties. A stream has some properties that defines which functions can be used with it or how the functions will treat the stream. Most of them are defined in the mode parameter when fopen function is called. Access Specifies if the operations performed with the stream will have read and/or write access to the file. Text / Binary Text files are those where lines are delimited by the special character EOL (End Of Line), and some translations occur when this special character is read or written for that these file can be directly outputed to a console. The End of a text file is defined by the first occurrence of the EOF character. A binary file is a file where each byte is read or written as a character, no translations occur, and the End of a binary file matches with the physical End of the File. Buffer A buffer is a block of memory where data is accumulated before being physically read or written to the file. Buffered stream causes I/O operations with the stream to be faster because normally buffers are faster than physical devices like disks or ports. A stream can be unbuffered so the data is directly read or written to the device. The use of stream buffers can be specified using functions setbuf and setvbuf. Indicators. A stream has some indicators that specify the current state of it. These are internally modified and affect the behavior of Input/Output functions: Error Indicator This indicator is set when an error has occurred in an operation related with the stream. This indicator can be checked using ferror, and can be reset by a call to clearerr or by any repositioning functions (rewind, fseek and fsetpos). End-Of-File Indicator When this indicator is set, the last reading or writing operation permormed has reached the End of the file associated with the stream. This can be checked with the feof function, and can be reset by calling to clearerr or by any repositioning functions (rewind, fseek and fsetpos). Position Indicator (File pointer) This indicator is an internal pointer that points to the next character within the stream that has to be read or written by the next I/O operation. This value can be obtained by the ftell and fgetpos functions, and can be changed calling to rewind, fseek and fsetpos unctions Standard Streams When a program that includes stdio.h begin its execution, three predefined streams are opened: stdin This is the standard input stream. By default stdin corresponds to the keyboard, but this can be redirected by the operating system. stdout This is the standard output stream. By default stdout is directed to the screen, but the operating system can redirect it to a file or any other output device. stderr The standard error stream. This is an output stream specifically intendend to receive error messages. By default is directed to the standard output (like stdout), but it can be redirected to a log file or any other output device. stdlib.h =============== * = not ANSI-C, but supported by most compilers. abort Abort current process returning error code abs Return absolute value of integer parameter atexit Specifies a function to be executed at exit atof Convert string to double atoi Convert string to integer atol Convert string to long bsearch Binary search calloc Allocate array in memory div Divide two integer values * ecvt Convert floating point value to string exit Terminate calling process * fcvt Convert floating point value to string free Deallocate dynamically allocated memory * gcvt Convert floating point value to string getenv Get string from environment * itoa Convert integer to string labs Return absolute calue of long integer parameter ldiv Divide two long integer values * lfind Linear search * lsearch Linear search * ltoa Convert long integer value to string malloc Allocate memory block * max Return the greater of two parameters * min Return the smaller of two parameters * putenv Create or modify environment variable qsort Sort using quicksort algorithm rand Generate random number realloc Reallocate memory block srand Initialize random number generator strtod Convert string to double-precision floating-point value strtol Convert string to long integer strtoul Convert string to unsigned long integer * swab Swap bytes system Execute command * ultoa Convert unsigned long integer to string =============== stdlib.h summary: C stdlib.h library functions can be divided in these groups depending on their utility: conversion: atof, atoi, atol, ecvt, fcvt, itoa, ltoa, strtod, strtol, strtoul, ultoa dynamic memory allocation/deallocation: calloc, free, malloc, realloc process control and environment variables: abort, atexit, exit, getenv, putenv, system sorting and searching: bsearch, lfind, lsearch, qsort, swab mathematical operations: abs, div, labs, ldiv string.h ===================== memchr Search buffer for a character memcmp Compare two buffers memcpy Copy bytes to buffer from buffer memmove Copy bytes to buffer from buffer memset Fill buffer with specified character strcat Append string strchr Find character in string strcmp Compare two strings strcoll Compare two strings using locale settings strcpy Copy string strcspn Search string for occurrence of charcter set strerror Get pointer to error message string strlen Return string length strncat Append substring to string strncmp Compare some characters of two strings strncpy Copy characters from one string to another strpbrk Scan string for specified characters strrchr Find last occurrence of character in string strspn Get length of substring composed of given characters strstr Find substring strtok Sequentially truncate string if delimiter is found strxfrm Transform string using locale settings time.h ===================== asctime Convert tm structure to string clock Return number of clock ticks since process start ctime Convert time_t value to string difftime Return difference between two times gmtime Convert time_t value to tm structure as UTC time localtime Convert time_t value to tm structure as local time mktime Convert tm structure to time_t value time Get current time Types and constants: CLK_TCK Constant that defines the number of clock ticks per second. Used by clock function. clock_t and time_t Data types returned by clock and time functions respectivelly. They are generally defined as long int. tm Structure returned or used by asctime, gmtime, localtime and mktime. /*****************************************************************************\ * * * windowsx.h - Macro APIs, window message crackers, and control APIs * * * * Version Win32 / Windows NT * * * * Copyright (c) 1992-1996, Microsoft Corp. All rights reserved.* * * \*****************************************************************************/ #ifndef _INC_WINDOWSX #define _INC_WINDOWSX #ifdef __cplusplus extern "C" { /* Assume C declarations for C++ */ #endif /* __cplusplus */ /****** KERNEL Macro APIs ****************************************************/ #define GetInstanceModule(hInstance) (HMODULE)(hInstance) #define GlobalPtrHandle(lp) \ ((HGLOBAL)GlobalHandle(lp)) #define GlobalLockPtr(lp) \ ((BOOL)GlobalLock(GlobalPtrHandle(lp))) GlobalUnlockPtr(lp) \ GlobalUnlock(GlobalPtrHandle(lp)) #define #define #define (flags)))) #define GlobalAllocPtr(flags, cb) \ (GlobalLock(GlobalAlloc((flags), (cb)))) GlobalReAllocPtr(lp, cbNew, flags) \ (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), GlobalFreePtr(lp) \ (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp))) /****** GDI Macro APIs *******************************************************/ #define #define #define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen)) SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen))) GetStockPen(i) ((HPEN)GetStockObject(i)) #define #define #define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr)) SelectBrush(hdc, hbr) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr))) GetStockBrush(i) ((HBRUSH)GetStockObject(i)) #define DeleteRgn(hrgn) #define #define RGN_AND) #define RGN_DIFF) #define RGN_OR) #define RGN_XOR) CopyRgn(hrgnDst, hrgnSrc) IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnDst, hrgnSrc, 0, RGN_COPY) CombineRgn(hrgnResult, hrgnA, hrgnB, SubtractRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, UnionRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, XorRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, #define DeletePalette(hpal) #define #define #define DeleteFont(hfont) DeleteObject((HGDIOBJ)(HFONT)(hfont)) SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont))) GetStockFont(i) ((HFONT)GetStockObject(i)) #define #define DeleteBitmap(hbm) SelectBitmap(hdc, hbm) DeleteObject((HGDIOBJ)(HRGN)(hrgn)) DeleteObject((HGDIOBJ)(HPALETTE)(hpal)) DeleteObject((HGDIOBJ)(HBITMAP)(hbm)) ((HBITMAP)SelectObject((hdc), (HGDIOBJ)(HBITMAP)(hbm))) #define InsetRect(lprc, dx, dy) InflateRect((lprc), -(dx), -(dy)) /****** USER Macro APIs ******************************************************/ #define GetWindowInstance(hwnd) ((HMODULE)GetWindowLong(hwnd, GWL_HINSTANCE)) #define #define GetWindowStyle(hwnd) GetWindowExStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_STYLE)) ((DWORD)GetWindowLong(hwnd, GWL_EXSTYLE)) #define GetWindowOwner(hwnd) GetWindow(hwnd, GW_OWNER) #define #define #define #define #define GetFirstChild(hwnd) GetFirstSibling(hwnd) GetLastSibling(hwnd) GetNextSibling(hwnd) GetPrevSibling(hwnd) GetTopWindow(hwnd) GetWindow(hwnd, GW_HWNDFIRST) GetWindow(hwnd, GW_HWNDLAST) GetWindow(hwnd, GW_HWNDNEXT) GetWindow(hwnd, GW_HWNDPREV) #define GetWindowID(hwnd) #define SetWindowRedraw(hwnd, fRedraw) \ ((void)SendMessage(hwnd, WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L)) #define SubclassWindow(hwnd, lpfn) \ ((WNDPROC)SetWindowLong((hwnd), GWL_WNDPROC, (LPARAM)(WNDPROC)(lpfn))) #define #define #define IsMinimized(hwnd) IsMaximized(hwnd) IsRestored(hwnd) GetDlgCtrlID(hwnd) IsIconic(hwnd) IsZoomed(hwnd) ((GetWindowStyle(hwnd) & (WS_MINIMIZE | WS_MAXIMIZE)) == 0L) #define SetWindowFont(hwnd, hfont, fRedraw) FORWARD_WM_SETFONT((hwnd), (hfont), (fRedraw), SendMessage) #define GetWindowFont(hwnd) FORWARD_WM_GETFONT((hwnd), SendMessage) #if (WINVER >= 0x030a) #define MapWindowRect(hwndFrom, hwndTo, lprc) \ MapWindowPoints((hwndFrom), (hwndTo), (POINT *)(lprc), 2) #endif #define IsLButtonDown() (GetKeyState(VK_LBUTTON) < 0) #define IsRButtonDown() (GetKeyState(VK_RBUTTON) < 0) #define IsMButtonDown() (GetKeyState(VK_MBUTTON) < 0) #define SubclassDialog(hwndDlg, lpfn) \ ((DLGPROC)SetWindowLong(hwndDlg, DWL_DLGPROC, (LPARAM)(DLGPROC)(lpfn))) #define SetDlgMsgResult(hwnd, msg, result) (( \ (msg) == WM_CTLCOLORMSGBOX || \ (msg) == WM_CTLCOLOREDIT || \ (msg) == WM_CTLCOLORLISTBOX || \ (msg) == WM_CTLCOLORBTN || \ (msg) == WM_CTLCOLORDLG || \ (msg) == WM_CTLCOLORSCROLLBAR || \ (msg) == WM_CTLCOLORSTATIC || \ (msg) == WM_COMPAREITEM || \ (msg) == WM_VKEYTOITEM || \ (msg) == WM_CHARTOITEM || \ (msg) == WM_QUERYDRAGICON || \ (msg) == WM_INITDIALOG \ ) ? (BOOL)(result) : (SetWindowLong((hwnd), DWL_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE)) #define DefDlgProcEx(hwnd, msg, wParam, lParam, pfRecursion) \ (*(pfRecursion) = TRUE, DefDlgProc(hwnd, msg, wParam, lParam)) #define CheckDefDlgRecursion(pfRecursion) \ if (*(pfRecursion)) { *(pfRecursion) = FALSE; return FALSE; } /****** Message crackers ****************************************************/ #define HANDLE_MSG(hwnd, message, fn) \ case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn)) /* void Cls_OnCompacting(HWND hwnd, UINT compactRatio) */ #define HANDLE_WM_COMPACTING(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam)), 0L) #define FORWARD_WM_COMPACTING(hwnd, compactRatio, fn) \ (void)(fn)((hwnd), WM_COMPACTING, (WPARAM)(UINT)(compactRatio), 0L) /* void Cls_OnWinIniChange(HWND hwnd, LPCTSTR lpszSectionName) */ #define HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPCTSTR)(lParam)), 0L) #define FORWARD_WM_WININICHANGE(hwnd, lpszSectionName, fn) \ (void)(fn)((hwnd), WM_WININICHANGE, 0L, (LPARAM)(LPCTSTR)(lpszSectionName)) /* void Cls_OnSysColorChange(HWND hwnd) */ #define HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_SYSCOLORCHANGE(hwnd, fn) \ (void)(fn)((hwnd), WM_SYSCOLORCHANGE, 0L, 0L) /* BOOL Cls_OnQueryNewPalette(HWND hwnd) */ #define HANDLE_WM_QUERYNEWPALETTE(hwnd, wParam, lParam, fn) \ MAKELRESULT((BOOL)(fn)(hwnd), 0L) #define FORWARD_WM_QUERYNEWPALETTE(hwnd, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYNEWPALETTE, 0L, 0L) /* void Cls_OnPaletteIsChanging(HWND hwnd, HWND hwndPaletteChange) */ #define HANDLE_WM_PALETTEISCHANGING(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_PALETTEISCHANGING(hwnd, hwndPaletteChange, fn) \ (void)(fn)((hwnd), WM_PALETTEISCHANGING, (WPARAM)(HWND)(hwndPaletteChange), 0L) /* void Cls_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange) */ #define HANDLE_WM_PALETTECHANGED(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_PALETTECHANGED(hwnd, hwndPaletteChange, fn) \ (void)(fn)((hwnd), WM_PALETTECHANGED, (WPARAM)(HWND)(hwndPaletteChange), 0L) /* void Cls_OnFontChange(HWND hwnd) */ #define HANDLE_WM_FONTCHANGE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_FONTCHANGE(hwnd, fn) \ (void)(fn)((hwnd), WM_FONTCHANGE, 0L, 0L) /* void Cls_OnSpoolerStatus(HWND hwnd, UINT status, int cJobInQueue) */ #define HANDLE_WM_SPOOLERSTATUS(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_SPOOLERSTATUS(hwnd, status, cJobInQueue, fn) \ (void)(fn)((hwnd), WM_SPOOLERSTATUS, (WPARAM)(status), MAKELPARAM((cJobInQueue), 0)) /* void Cls_OnDevModeChange(HWND hwnd, LPCTSTR lpszDeviceName) */ #define HANDLE_WM_DEVMODECHANGE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPCTSTR)(lParam)), 0L) #define FORWARD_WM_DEVMODECHANGE(hwnd, lpszDeviceName, fn) \ (void)(fn)((hwnd), WM_DEVMODECHANGE, 0L, (LPARAM)(LPCTSTR)(lpszDeviceName)) /* void Cls_OnTimeChange(HWND hwnd) */ #define HANDLE_WM_TIMECHANGE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_TIMECHANGE(hwnd, fn) \ (void)(fn)((hwnd), WM_TIMECHANGE, 0L, 0L) /* void Cls_OnPower(HWND hwnd, int code) */ #define HANDLE_WM_POWER(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(wParam)), 0L) #define FORWARD_WM_POWER(hwnd, code, fn) \ (void)(fn)((hwnd), WM_POWER, (WPARAM)(int)(code), 0L) /* BOOL Cls_OnQueryEndSession(HWND hwnd) */ #define HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, fn) \ MAKELRESULT((BOOL)(fn)(hwnd), 0L) #define FORWARD_WM_QUERYENDSESSION(hwnd, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYENDSESSION, 0L, 0L) /* void Cls_OnEndSession(HWND hwnd, BOOL fEnding) */ #define HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam)), 0L) #define FORWARD_WM_ENDSESSION(hwnd, fEnding, fn) \ (void)(fn)((hwnd), WM_ENDSESSION, (WPARAM)(BOOL)(fEnding), 0L) /* void Cls_OnQuit(HWND hwnd, int exitCode) */ #define HANDLE_WM_QUIT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(wParam)), 0L) #define FORWARD_WM_QUIT(hwnd, exitCode, fn) \ (void)(fn)((hwnd), WM_QUIT, (WPARAM)(exitCode), 0L) /* This /* void #define #define message is in Windows 3.1 only */ Cls_OnSystemError(HWND hwnd, int errCode) */ HANDLE_WM_SYSTEMERROR(hwnd, wParam, lParam, fn) 0L FORWARD_WM_SYSTEMERROR(hwnd, errCode, fn) 0L /* BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */ #define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L) #define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_CREATE, 0L, (LPARAM)(LPCREATESTRUCT)(lpCreateStruct)) /* BOOL Cls_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */ #define HANDLE_WM_NCCREATE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPCREATESTRUCT)(lParam)) #define FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_NCCREATE, 0L, (LPARAM)(LPCREATESTRUCT)(lpCreateStruct)) /* void Cls_OnDestroy(HWND hwnd) */ #define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_DESTROY(hwnd, fn) \ (void)(fn)((hwnd), WM_DESTROY, 0L, 0L) /* void Cls_OnNCDestroy(HWND hwnd) */ #define HANDLE_WM_NCDESTROY(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_NCDESTROY(hwnd, fn) \ (void)(fn)((hwnd), WM_NCDESTROY, 0L, 0L) /* void Cls_OnShowWindow(HWND hwnd, BOOL fShow, UINT status) */ #define HANDLE_WM_SHOWWINDOW(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam), (UINT)(lParam)), 0L) #define FORWARD_WM_SHOWWINDOW(hwnd, fShow, status, fn) \ (void)(fn)((hwnd), WM_SHOWWINDOW, (WPARAM)(BOOL)(fShow), (LPARAM)(UINT)(status)) /* void Cls_OnSetRedraw(HWND hwnd, BOOL fRedraw) */ #define HANDLE_WM_SETREDRAW(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam)), 0L) #define FORWARD_WM_SETREDRAW(hwnd, fRedraw, fn) \ (void)(fn)((hwnd), WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L) /* void Cls_OnEnable(HWND hwnd, BOOL fEnable) */ #define HANDLE_WM_ENABLE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam)), 0L) #define FORWARD_WM_ENABLE(hwnd, fEnable, fn) \ (void)(fn)((hwnd), WM_ENABLE, (WPARAM)(BOOL)(fEnable), 0L) /* void Cls_OnSetText(HWND hwnd, LPCTSTR lpszText) */ #define HANDLE_WM_SETTEXT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPCTSTR)(lParam)), 0L) #define FORWARD_WM_SETTEXT(hwnd, lpszText, fn) \ (void)(fn)((hwnd), WM_SETTEXT, 0L, (LPARAM)(LPCTSTR)(lpszText)) /* INT Cls_OnGetText(HWND hwnd, int cchTextMax, LPTSTR lpszText) */ #define HANDLE_WM_GETTEXT(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)((hwnd), (int)(wParam), (LPTSTR)(lParam)) #define FORWARD_WM_GETTEXT(hwnd, cchTextMax, lpszText, fn) \ (int)(DWORD)(fn)((hwnd), WM_GETTEXT, (WPARAM)(int)(cchTextMax), (LPARAM)(LPTSTR)(lpszText)) /* INT Cls_OnGetTextLength(HWND hwnd) */ #define HANDLE_WM_GETTEXTLENGTH(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)(hwnd) #define FORWARD_WM_GETTEXTLENGTH(hwnd, fn) \ (int)(DWORD)(fn)((hwnd), WM_GETTEXTLENGTH, 0L, 0L) /* BOOL Cls_OnWindowPosChanging(HWND hwnd, LPWINDOWPOS lpwpos) */ #define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam)) #define FORWARD_WM_WINDOWPOSCHANGING(hwnd, lpwpos, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_WINDOWPOSCHANGING, 0L, (LPARAM)(LPWINDOWPOS)(lpwpos)) /* void Cls_OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos) */ #define HANDLE_WM_WINDOWPOSCHANGED(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (const LPWINDOWPOS)(lParam)), 0L) #define FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, fn) \ (void)(fn)((hwnd), WM_WINDOWPOSCHANGED, 0L, (LPARAM)(const LPWINDOWPOS)(lpwpos)) /* void Cls_OnMove(HWND hwnd, int x, int y) */ #define HANDLE_WM_MOVE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L) #define FORWARD_WM_MOVE(hwnd, x, y, fn) \ (void)(fn)((hwnd), WM_MOVE, 0L, MAKELPARAM((x), (y))) /* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */ #define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L) #define FORWARD_WM_SIZE(hwnd, state, cx, cy, fn) \ (void)(fn)((hwnd), WM_SIZE, (WPARAM)(UINT)(state), MAKELPARAM((cx), (cy))) /* void Cls_OnClose(HWND hwnd) */ #define HANDLE_WM_CLOSE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_CLOSE(hwnd, fn) \ (void)(fn)((hwnd), WM_CLOSE, 0L, 0L) /* BOOL Cls_OnQueryOpen(HWND hwnd) */ #define HANDLE_WM_QUERYOPEN(hwnd, wParam, lParam, fn) \ MAKELRESULT((BOOL)(fn)(hwnd), 0L) #define FORWARD_WM_QUERYOPEN(hwnd, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYOPEN, 0L, 0L) /* void Cls_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo) */ #define HANDLE_WM_GETMINMAXINFO(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (LPMINMAXINFO)(lParam)), 0L) #define FORWARD_WM_GETMINMAXINFO(hwnd, lpMinMaxInfo, fn) \ (void)(fn)((hwnd), WM_GETMINMAXINFO, 0L, (LPARAM)(LPMINMAXINFO)(lpMinMaxInfo)) /* void Cls_OnPaint(HWND hwnd) */ #define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_PAINT(hwnd, fn) \ (void)(fn)((hwnd), WM_PAINT, 0L, 0L) /* BOOL Cls_OnEraseBkgnd(HWND hwnd, HDC hdc) */ #define HANDLE_WM_ERASEBKGND(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam)) #define FORWARD_WM_ERASEBKGND(hwnd, hdc, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_ERASEBKGND, (WPARAM)(HDC)(hdc), 0L) /* BOOL Cls_OnIconEraseBkgnd(HWND hwnd, HDC hdc) */ #define HANDLE_WM_ICONERASEBKGND(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam)) #define FORWARD_WM_ICONERASEBKGND(hwnd, hdc, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_ICONERASEBKGND, (WPARAM)(HDC)(hdc), 0L) /* void Cls_OnNCPaint(HWND hwnd, HRGN hrgn) */ #define HANDLE_WM_NCPAINT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HRGN)(wParam)), 0L) #define FORWARD_WM_NCPAINT(hwnd, hrgn, fn) \ (void)(fn)((hwnd), WM_NCPAINT, (WPARAM)(HRGN)(hrgn), 0L) /* UINT Cls_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS * lpcsp) */ #define HANDLE_WM_NCCALCSIZE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(0), (NCCALCSIZE_PARAMS *)(lParam)) #define FORWARD_WM_NCCALCSIZE(hwnd, fCalcValidRects, lpcsp, fn) \ (UINT)(DWORD)(fn)((hwnd), WM_NCCALCSIZE, 0L, (LPARAM)(NCCALCSIZE_PARAMS *)(lpcsp)) /* UINT Cls_OnNCHitTest(HWND hwnd, int x, int y) */ #define HANDLE_WM_NCHITTEST(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)) #define FORWARD_WM_NCHITTEST(hwnd, x, y, fn) \ (UINT)(DWORD)(fn)((hwnd), WM_NCHITTEST, 0L, MAKELPARAM((x), (y))) /* HICON Cls_OnQueryDragIcon(HWND hwnd) */ #define HANDLE_WM_QUERYDRAGICON(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)(hwnd) #define FORWARD_WM_QUERYDRAGICON(hwnd, fn) \ (HICON)(UINT)(DWORD)(fn)((hwnd), WM_QUERYDRAGICON, 0L, 0L) #ifdef _INC_SHELLAPI /* void Cls_OnDropFiles(HWND hwnd, HDROP hdrop) */ #define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HDROP)(wParam)), 0L) #define FORWARD_WM_DROPFILES(hwnd, hdrop, fn) \ (void)(fn)((hwnd), WM_DROPFILES, (WPARAM)(HDROP)(hdrop), 0L) #endif /* _INC_SHELLAPI */ /* void Cls_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) */ #define HANDLE_WM_ACTIVATE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (BOOL)HIWORD(wParam)), 0L) #define FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, fn) \ (void)(fn)((hwnd), WM_ACTIVATE, MAKEWPARAM((state), (fMinimized)), (LPARAM)(HWND)(hwndActDeact)) /* void Cls_OnActivateApp(HWND hwnd, BOOL fActivate, DWORD dwThreadId) */ #define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L) #define FORWARD_WM_ACTIVATEAPP(hwnd, fActivate, dwThreadId, fn) \ (void)(fn)((hwnd), WM_ACTIVATEAPP, (WPARAM)(BOOL)(fActivate), (LPARAM)(dwThreadId)) /* BOOL Cls_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized) */ #define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), 0L, 0L) #define FORWARD_WM_NCACTIVATE(hwnd, fActive, hwndActDeact, fMinimized, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_NCACTIVATE, (WPARAM)(BOOL)(fActive), 0L) /* void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus) */ #define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_SETFOCUS(hwnd, hwndOldFocus, fn) \ (void)(fn)((hwnd), WM_SETFOCUS, (WPARAM)(HWND)(hwndOldFocus), 0L) /* void Cls_OnKillFocus(HWND hwnd, HWND hwndNewFocus) */ #define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_KILLFOCUS(hwnd, hwndNewFocus, fn) \ (void)(fn)((hwnd), WM_KILLFOCUS, (WPARAM)(HWND)(hwndNewFocus), 0L) /* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */ #define HANDLE_WM_KEYDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L) #define FORWARD_WM_KEYDOWN(hwnd, vk, cRepeat, flags, fn) \ (void)(fn)((hwnd), WM_KEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags))) /* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */ #define HANDLE_WM_KEYUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L) #define FORWARD_WM_KEYUP(hwnd, vk, cRepeat, flags, fn) \ (void)(fn)((hwnd), WM_KEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags))) /* void Cls_OnChar(HWND hwnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_CHAR(hwnd, ch, cRepeat, fn) \ (void)(fn)((hwnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0)) /* void Cls_OnDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_DEADCHAR(hwnd, ch, cRepeat, fn) \ (void)(fn)((hwnd), WM_DEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0)) /* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */ #define HANDLE_WM_SYSKEYDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L) #define FORWARD_WM_SYSKEYDOWN(hwnd, vk, cRepeat, flags, fn) \ (void)(fn)((hwnd), WM_SYSKEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags))) /* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */ #define HANDLE_WM_SYSKEYUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L) #define FORWARD_WM_SYSKEYUP(hwnd, vk, cRepeat, flags, fn) \ (void)(fn)((hwnd), WM_SYSKEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags))) /* void Cls_OnSysChar(HWND hwnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_SYSCHAR(hwnd, ch, cRepeat, fn) \ (void)(fn)((hwnd), WM_SYSCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0)) /* void Cls_OnSysDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_SYSDEADCHAR(hwnd, ch, cRepeat, fn) \ (void)(fn)((hwnd), WM_SYSDEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0)) /* void Cls_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) */ #define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_MOUSEMOVE(hwnd, x, y, keyFlags, fn) \ (void)(fn)((hwnd), WM_MOUSEMOVE, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) */ #define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_LBUTTONUP(hwnd, x, y, keyFlags, fn) \ (void)(fn)((hwnd), WM_LBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_RBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_RBUTTONDBLCLK : WM_RBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnRButtonUp(HWND hwnd, int x, int y, UINT flags) */ #define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_RBUTTONUP(hwnd, x, y, keyFlags, fn) \ (void)(fn)((hwnd), WM_RBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_MBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_MBUTTONDBLCLK : WM_MBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */ #define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnMButtonUp(HWND hwnd, int x, int y, UINT flags) */ #define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_MBUTTONUP(hwnd, x, y, keyFlags, fn) \ (void)(fn)((hwnd), WM_MBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y))) /* void Cls_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCMOUSEMOVE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCMOUSEMOVE(hwnd, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), WM_NCMOUSEMOVE, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y))) /* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCLBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y))) /* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCLBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnNCLButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCLBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCLBUTTONUP(hwnd, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), WM_NCLBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y))) /* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCRBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCRBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCRBUTTONDBLCLK : WM_NCRBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) ) /* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCRBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnNCRButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCRBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCRBUTTONUP(hwnd, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), WM_NCRBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) ) /* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCMBUTTONDOWN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCMBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCMBUTTONDBLCLK : WM_NCMBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) ) /* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCMBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) /* void Cls_OnNCMButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */ #define HANDLE_WM_NCMBUTTONUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #define FORWARD_WM_NCMBUTTONUP(hwnd, x, y, codeHitTest, fn) \ (void)(fn)((hwnd), WM_NCMBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) ) /* int Cls_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg) */ #define HANDLE_WM_MOUSEACTIVATE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)) #define FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg, fn) \ (int)(DWORD)(fn)((hwnd), WM_MOUSEACTIVATE, (WPARAM)(HWND)(hwndTopLevel), MAKELPARAM((codeHitTest), (msg))) /* void Cls_OnCancelMode(HWND hwnd) */ #define HANDLE_WM_CANCELMODE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_CANCELMODE(hwnd, fn) \ (void)(fn)((hwnd), WM_CANCELMODE, 0L, 0L) /* void Cls_OnTimer(HWND hwnd, UINT id) */ #define HANDLE_WM_TIMER(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam)), 0L) #define FORWARD_WM_TIMER(hwnd, id, fn) \ (void)(fn)((hwnd), WM_TIMER, (WPARAM)(UINT)(id), 0L) /* void Cls_OnInitMenu(HWND hwnd, HMENU hMenu) */ #define HANDLE_WM_INITMENU(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HMENU)(wParam)), 0L) #define FORWARD_WM_INITMENU(hwnd, hMenu, fn) \ (void)(fn)((hwnd), WM_INITMENU, (WPARAM)(HMENU)(hMenu), 0L) /* void Cls_OnInitMenuPopup(HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu) */ #define HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HMENU)(wParam), (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)), 0L) #define FORWARD_WM_INITMENUPOPUP(hwnd, hMenu, item, fSystemMenu, fn) \ (void)(fn)((hwnd), WM_INITMENUPOPUP, (WPARAM)(HMENU)(hMenu), MAKELPARAM((item),(fSystemMenu))) /* void Cls_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) */ #define HANDLE_WM_MENUSELECT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HMENU)(lParam), \ (int)(LOWORD(wParam)), \ (HIWORD(wParam) & MF_POPUP) ? GetSubMenu((HMENU)lParam, LOWORD(wParam)) : 0L, \ (UINT)(((short)HIWORD(wParam) == -1) ? 0xFFFFFFFF : HIWORD(wParam))), 0L) #define FORWARD_WM_MENUSELECT(hwnd, hmenu, item, hmenuPopup, flags, fn) \ (void)(fn)((hwnd), WM_MENUSELECT, MAKEWPARAM((item), (flags)), (LPARAM)(HMENU)((hmenu) ? (hmenu) : (hmenuPopup))) /* DWORD Cls_OnMenuChar(HWND hwnd, UINT ch, UINT flags, HMENU hmenu) */ #define HANDLE_WM_MENUCHAR(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(LOWORD(wParam)), (UINT)HIWORD(wParam), (HMENU)(lParam)) #define FORWARD_WM_MENUCHAR(hwnd, ch, flags, hmenu, fn) \ (DWORD)(fn)((hwnd), WM_MENUCHAR, MAKEWPARAM(flags, (WORD)(ch)), (LPARAM)(HMENU)(hmenu)) /* void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) */ #define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L) #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \ (void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl)) /* void Cls_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */ #define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L) #define FORWARD_WM_HSCROLL(hwnd, hwndCtl, code, pos, fn) \ (void)(fn)((hwnd), WM_HSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)), (LPARAM)(UINT)(hwndCtl)) /* void Cls_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */ #define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L) #define FORWARD_WM_VSCROLL(hwnd, hwndCtl, code, pos, fn) \ (void)(fn)((hwnd), WM_VSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)), (LPARAM)(HWND)(hwndCtl)) /* void Cls_OnCut(HWND hwnd) */ #define HANDLE_WM_CUT(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_CUT(hwnd, fn) \ (void)(fn)((hwnd), WM_CUT, 0L, 0L) /* void Cls_OnCopy(HWND hwnd) */ #define HANDLE_WM_COPY(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_COPY(hwnd, fn) \ (void)(fn)((hwnd), WM_COPY, 0L, 0L) /* void Cls_OnPaste(HWND hwnd) */ #define HANDLE_WM_PASTE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_PASTE(hwnd, fn) \ (void)(fn)((hwnd), WM_PASTE, 0L, 0L) /* void Cls_OnClear(HWND hwnd) */ #define HANDLE_WM_CLEAR(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_CLEAR(hwnd, fn) \ (void)(fn)((hwnd), WM_CLEAR, 0L, 0L) /* void Cls_OnUndo(HWND hwnd) */ #define HANDLE_WM_UNDO(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_UNDO(hwnd, fn) \ (void)(fn)((hwnd), WM_UNDO, 0L, 0L) /* HANDLE Cls_OnRenderFormat(HWND hwnd, UINT fmt) */ #define HANDLE_WM_RENDERFORMAT(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HANDLE)(fn)((hwnd), (UINT)(wParam)) #define FORWARD_WM_RENDERFORMAT(hwnd, fmt, fn) \ (HANDLE)(UINT)(DWORD)(fn)((hwnd), WM_RENDERFORMAT, (WPARAM)(UINT)(fmt), 0L) /* void Cls_OnRenderAllFormats(HWND hwnd) */ #define HANDLE_WM_RENDERALLFORMATS(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_RENDERALLFORMATS(hwnd, fn) \ (void)(fn)((hwnd), WM_RENDERALLFORMATS, 0L, 0L) /* void Cls_OnDestroyClipboard(HWND hwnd) */ #define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_DESTROYCLIPBOARD(hwnd, fn) \ (void)(fn)((hwnd), WM_DESTROYCLIPBOARD, 0L, 0L) /* void Cls_OnDrawClipboard(HWND hwnd) */ #define HANDLE_WM_DRAWCLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_DRAWCLIPBOARD(hwnd, fn) \ (void)(fn)((hwnd), WM_DRAWCLIPBOARD, 0L, 0L) /* void Cls_OnPaintClipboard(HWND hwnd, HWND hwndCBViewer, const LPPAINTSTRUCT lpPaintStruct) */ #define HANDLE_WM_PAINTCLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (const LPPAINTSTRUCT)GlobalLock((HGLOBAL)(lParam))), GlobalUnlock((HGLOBAL)(lParam)), 0L) #define FORWARD_WM_PAINTCLIPBOARD(hwnd, hwndCBViewer, lpPaintStruct, fn) \ (void)(fn)((hwnd), WM_PAINTCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), (LPARAM)(LPPAINTSTRUCT)(lpPaintStruct)) /* void Cls_OnSizeClipboard(HWND hwnd, HWND hwndCBViewer, const LPRECT lprc) */ #define HANDLE_WM_SIZECLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (const LPRECT)GlobalLock((HGLOBAL)(lParam))), GlobalUnlock((HGLOBAL)(lParam)), 0L) #define FORWARD_WM_SIZECLIPBOARD(hwnd, hwndCBViewer, lprc, fn) \ (void)(fn)((hwnd), WM_SIZECLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), (LPARAM)(LPRECT)(lprc)) /* void Cls_OnVScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */ #define HANDLE_WM_VSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L) #define FORWARD_WM_VSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \ (void)(fn)((hwnd), WM_VSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code), (pos))) /* void Cls_OnHScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */ #define HANDLE_WM_HSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L) #define FORWARD_WM_HSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \ (void)(fn)((hwnd), WM_HSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code), (pos))) /* void Cls_OnAskCBFormatName(HWND hwnd, int cchMax, LPTSTR rgchName) */ #define HANDLE_WM_ASKCBFORMATNAME(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(wParam), (LPTSTR)(lParam)), 0L) #define FORWARD_WM_ASKCBFORMATNAME(hwnd, cchMax, rgchName, fn) \ (void)(fn)((hwnd), WM_ASKCBFORMATNAME, (WPARAM)(int)(cchMax), (LPARAM)(rgchName)) /* void Cls_OnChangeCBChain(HWND hwnd, HWND hwndRemove, HWND hwndNext) */ #define HANDLE_WM_CHANGECBCHAIN(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (HWND)(lParam)), 0L) #define FORWARD_WM_CHANGECBCHAIN(hwnd, hwndRemove, hwndNext, fn) \ (void)(fn)((hwnd), WM_CHANGECBCHAIN, (WPARAM)(HWND)(hwndRemove), (LPARAM)(HWND)(hwndNext)) /* BOOL Cls_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg) */ #define HANDLE_WM_SETCURSOR(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)) #define FORWARD_WM_SETCURSOR(hwnd, hwndCursor, codeHitTest, msg, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_SETCURSOR, (WPARAM)(HWND)(hwndCursor), MAKELPARAM((codeHitTest), (msg))) /* void Cls_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) */ #define HANDLE_WM_SYSCOMMAND(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L) #define FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, fn) \ (void)(fn)((hwnd), WM_SYSCOMMAND, (WPARAM)(UINT)(cmd), MAKELPARAM((x), (y))) /* HWND Cls_MDICreate(HWND hwnd, const LPMDICREATESTRUCT lpmcs) */ #define HANDLE_WM_MDICREATE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (LPMDICREATESTRUCT)(lParam)) #define FORWARD_WM_MDICREATE(hwnd, lpmcs, fn) \ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDICREATE, 0L, (LPARAM)(LPMDICREATESTRUCT)(lpmcs)) /* void Cls_MDIDestroy(HWND hwnd, HWND hwndDestroy) */ #define HANDLE_WM_MDIDESTROY(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_MDIDESTROY(hwnd, hwndDestroy, fn) \ (void)(fn)((hwnd), WM_MDIDESTROY, (WPARAM)(hwndDestroy), 0L) /* NOTE: Usable only by MDI client windows */ /* void Cls_MDIActivate(HWND hwnd, BOOL fActive, HWND hwndActivate, HWND hwndDeactivate) */ #define HANDLE_WM_MDIACTIVATE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(lParam == (LPARAM)hwnd), (HWND)(lParam), (HWND)(wParam)), 0L) #define FORWARD_WM_MDIACTIVATE(hwnd, fActive, hwndActivate, hwndDeactivate, fn) \ (void)(fn)(hwnd, WM_MDIACTIVATE, (WPARAM)(hwndDeactivate), (LPARAM)(hwndActivate)) /* void Cls_MDIRestore(HWND hwnd, HWND hwndRestore) */ #define HANDLE_WM_MDIRESTORE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_MDIRESTORE(hwnd, hwndRestore, fn) \ (void)(fn)((hwnd), WM_MDIRESTORE, (WPARAM)(hwndRestore), 0L) /* HWND Cls_MDINext(HWND hwnd, HWND hwndCur, BOOL fPrev) */ #define HANDLE_WM_MDINEXT(hwnd, wParam, lParam, fn) \ (LRESULT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)lParam) #define FORWARD_WM_MDINEXT(hwnd, hwndCur, fPrev, fn) \ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDINEXT, (WPARAM)(hwndCur), (LPARAM)(fPrev)) /* void Cls_MDIMaximize(HWND hwnd, HWND hwndMaximize) */ #define HANDLE_WM_MDIMAXIMIZE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam)), 0L) #define FORWARD_WM_MDIMAXIMIZE(hwnd, hwndMaximize, fn) \ (void)(fn)((hwnd), WM_MDIMAXIMIZE, (WPARAM)(hwndMaximize), 0L) /* BOOL Cls_MDITile(HWND hwnd, UINT cmd) */ #define HANDLE_WM_MDITILE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam)) #define FORWARD_WM_MDITILE(hwnd, cmd, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_MDITILE, (WPARAM)(cmd), 0L) /* BOOL Cls_MDICascade(HWND hwnd, UINT cmd) */ #define HANDLE_WM_MDICASCADE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam)) #define FORWARD_WM_MDICASCADE(hwnd, cmd, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_MDICASCADE, (WPARAM)(cmd), 0L) /* void Cls_MDIIconArrange(HWND hwnd) */ #define HANDLE_WM_MDIICONARRANGE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_MDIICONARRANGE(hwnd, fn) \ (void)(fn)((hwnd), WM_MDIICONARRANGE, 0L, 0L) /* HWND Cls_MDIGetActive(HWND hwnd) */ #define HANDLE_WM_MDIGETACTIVE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)(hwnd) #define FORWARD_WM_MDIGETACTIVE(hwnd, fn) \ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDIGETACTIVE, 0L, 0L) /* HMENU Cls_MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU hmenuWindow) */ #define HANDLE_WM_MDISETMENU(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(wParam), (HMENU)(wParam), (HMENU)(lParam)) #define FORWARD_WM_MDISETMENU(hwnd, fRefresh, hmenuFrame, hmenuWindow, fn) \ (HMENU)(UINT)(DWORD)(fn)((hwnd), WM_MDISETMENU, (WPARAM)((fRefresh) ? (hmenuFrame) : 0), (LPARAM)(hmenuWindow)) /* void Cls_OnChildActivate(HWND hwnd) */ #define HANDLE_WM_CHILDACTIVATE(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_CHILDACTIVATE(hwnd, fn) \ (void)(fn)((hwnd), WM_CHILDACTIVATE, 0L, 0L) /* BOOL Cls_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) */ #define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam) #define FORWARD_WM_INITDIALOG(hwnd, hwndFocus, lParam, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_INITDIALOG, (WPARAM)(HWND)(hwndFocus), (lParam)) /* HWND Cls_OnNextDlgCtl(HWND hwnd, HWND hwndSetFocus, BOOL fNext) */ #define HANDLE_WM_NEXTDLGCTL(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)(lParam)) #define FORWARD_WM_NEXTDLGCTL(hwnd, hwndSetFocus, fNext, fn) \ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_NEXTDLGCTL, (WPARAM)(HWND)(hwndSetFocus), (LPARAM)(fNext)) /* void Cls_OnParentNotify(HWND hwnd, UINT msg, HWND hwndChild, int idChild) */ #define HANDLE_WM_PARENTNOTIFY(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L) #define FORWARD_WM_PARENTNOTIFY(hwnd, msg, hwndChild, idChild, fn) \ (void)(fn)((hwnd), WM_PARENTNOTIFY, MAKEWPARAM(msg, idChild), (LPARAM)(hwndChild)) /* void Cls_OnEnterIdle(HWND hwnd, UINT source, HWND hwndSource) */ #define HANDLE_WM_ENTERIDLE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (HWND)(lParam)), 0L) #define FORWARD_WM_ENTERIDLE(hwnd, source, hwndSource, fn) \ (void)(fn)((hwnd), WM_ENTERIDLE, (WPARAM)(UINT)(source), (LPARAM)(HWND)(hwndSource)) /* UINT Cls_OnGetDlgCode(HWND hwnd, LPMSG lpmsg) */ #define HANDLE_WM_GETDLGCODE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(fn)(hwnd, (LPMSG)(lParam)) #define FORWARD_WM_GETDLGCODE(hwnd, lpmsg, fn) \ (UINT)(DWORD)(fn)((hwnd), WM_GETDLGCODE, (lpmsg ? lpmsg->wParam : 0), (LPARAM)(LPMSG)(lpmsg)) /* HBRUSH Cls_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type) */ #define HANDLE_WM_CTLCOLORMSGBOX(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_MSGBOX) #define FORWARD_WM_CTLCOLORMSGBOX(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORMSGBOX, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLOREDIT(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_EDIT) #define FORWARD_WM_CTLCOLOREDIT(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLOREDIT, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLORLISTBOX(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_LISTBOX) #define FORWARD_WM_CTLCOLORLISTBOX(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORLISTBOX, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLORBTN(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_BTN) #define FORWARD_WM_CTLCOLORBTN(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORBTN, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLORDLG(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_DLG) #define FORWARD_WM_CTLCOLORDLG(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORDLG, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLORSCROLLBAR(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_SCROLLBAR) #define FORWARD_WM_CTLCOLORSCROLLBAR(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSCROLLBAR, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) #define HANDLE_WM_CTLCOLORSTATIC(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_STATIC) #define FORWARD_WM_CTLCOLORSTATIC(hwnd, hdc, hwndChild, fn) \ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSTATIC, (WPARAM)(HDC)(hdc), (LPARAM)(HWND)(hwndChild)) /* void Cls_OnSetFont(HWND hwndCtl, HFONT hfont, BOOL fRedraw) */ #define HANDLE_WM_SETFONT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HFONT)(wParam), (BOOL)(lParam)), 0L) #define FORWARD_WM_SETFONT(hwnd, hfont, fRedraw, fn) \ (void)(fn)((hwnd), WM_SETFONT, (WPARAM)(HFONT)(hfont), (LPARAM)(BOOL)(fRedraw)) /* HFONT Cls_OnGetFont(HWND hwnd) */ #define HANDLE_WM_GETFONT(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(HFONT)(fn)(hwnd) #define FORWARD_WM_GETFONT(hwnd, fn) \ (HFONT)(UINT)(DWORD)(fn)((hwnd), WM_GETFONT, 0L, 0L) /* void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem) */ #define HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (const DRAWITEMSTRUCT *)(lParam)), 0L) #define FORWARD_WM_DRAWITEM(hwnd, lpDrawItem, fn) \ (void)(fn)((hwnd), WM_DRAWITEM, (WPARAM)(((const DRAWITEMSTRUCT *)lpDrawItem)->CtlID), (LPARAM)(const DRAWITEMSTRUCT *)(lpDrawItem)) /* void Cls_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * lpMeasureItem) */ #define HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (MEASUREITEMSTRUCT *)(lParam)), 0L) #define FORWARD_WM_MEASUREITEM(hwnd, lpMeasureItem, fn) \ (void)(fn)((hwnd), WM_MEASUREITEM, (WPARAM)(((MEASUREITEMSTRUCT *)lpMeasureItem)->CtlID), (LPARAM)(MEASUREITEMSTRUCT *)(lpMeasureItem)) /* void Cls_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT * lpDeleteItem) */ #define HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (const DELETEITEMSTRUCT *)(lParam)), 0L) #define FORWARD_WM_DELETEITEM(hwnd, lpDeleteItem, fn) \ (void)(fn)((hwnd), WM_DELETEITEM, (WPARAM)(((const DELETEITEMSTRUCT *)(lpDeleteItem))>CtlID), (LPARAM)(const DELETEITEMSTRUCT *)(lpDeleteItem)) /* int Cls_OnCompareItem(HWND hwnd, const COMPAREITEMSTRUCT * lpCompareItem) */ #define HANDLE_WM_COMPAREITEM(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)((hwnd), (const COMPAREITEMSTRUCT *)(lParam)) #define FORWARD_WM_COMPAREITEM(hwnd, lpCompareItem, fn) \ (int)(DWORD)(fn)((hwnd), WM_COMPAREITEM, (WPARAM)(((const COMPAREITEMSTRUCT *)(lpCompareItem))->CtlID), (LPARAM)(const COMPAREITEMSTRUCT *)(lpCompareItem)) /* int Cls_OnVkeyToItem(HWND hwnd, UINT vk, HWND hwndListbox, int iCaret) */ #define HANDLE_WM_VKEYTOITEM(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (int)(short)HIWORD(wParam)) #define FORWARD_WM_VKEYTOITEM(hwnd, vk, hwndListBox, iCaret, fn) \ (int)(DWORD)(fn)((hwnd), WM_VKEYTOITEM, MAKEWPARAM((vk), (iCaret)), (LPARAM)(hwndListBox)) /* int Cls_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret) */ #define HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (int)(short)HIWORD(wParam)) #define FORWARD_WM_CHARTOITEM(hwnd, ch, hwndListBox, iCaret, fn) \ (int)(DWORD)(fn)((hwnd), WM_CHARTOITEM, MAKEWPARAM((UINT)(ch), (UINT)(iCaret)), (LPARAM)(hwndListBox)) /* void Cls_OnQueueSync(HWND hwnd) */ #define HANDLE_WM_QUEUESYNC(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L) #define FORWARD_WM_QUEUESYNC(hwnd, fn) \ (void)(fn)((hwnd), WM_QUEUESYNC, 0L, 0L) #if (WINVER >= 0x030a) /* void Cls_OnCommNotify(HWND hwnd, int cid, UINT flags) */ #define HANDLE_WM_COMMNOTIFY(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (int)(wParam), (UINT)LOWORD(lParam)), 0L) #define FORWARD_WM_COMMNOTIFY(hwnd, cid, flags, fn) \ (void)(fn)((hwnd), WM_COMMNOTIFY, (WPARAM)(cid), MAKELPARAM((flags), 0)) #endif /* void Cls_OnDisplayChange(HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT cyScreen) */ #define HANDLE_WM_DISPLAYCHANGE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(wParam)), 0L) #define FORWARD_WM_DISPLAYCHANGE(hwnd, bitsPerPixel, cxScreen, cyScreen, fn) \ (void)(fn)((hwnd), WM_DISPLAYCHANGE, (WPARAM)(UINT)(bitsPerPixel), (LPARAM)MAKELPARAM((UINT)(cxScreen), (UINT)(cyScreen))) /* BOOL Cls_OnDeviceChange(HWND hwnd, UINT uEvent, DWORD dwEventData) */ #define HANDLE_WM_DEVICECHANGE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (UINT)(wParam), (DWORD)(wParam)) #define FORWARD_WM_DEVICECHANGE(hwnd, uEvent, dwEventData, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_DEVICECHANGE, (WPARAM)(UINT)(uEvent), (LPARAM)(DWORD)(dwEventData)) /* void Cls_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos) */ #define HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L) #define FORWARD_WM_CONTEXTMENU(hwnd, hwndContext, xPos, yPos, fn) \ (void)(fn)((hwnd), WM_CONTEXTMENU, (WPARAM)(HWND)(hwndContext), MAKELPARAM((UINT)(xPos), (UINT)(yPos))) /****** Static control message APIs ******************************************/ #define Static_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable)) #define Static_GetText(hwndCtl, lpch, cchMax) #define Static_GetTextLength(hwndCtl) #define Static_SetText(hwndCtl, lpsz) GetWindowText((hwndCtl), (lpch), (cchMax)) GetWindowTextLength(hwndCtl) SetWindowText((hwndCtl), (lpsz)) #define Static_SetIcon(hwndCtl, hIcon) STM_SETICON, (WPARAM)(HICON)(hIcon), 0L)) #define Static_GetIcon(hwndCtl, hIcon) STM_GETICON, 0L, 0L)) ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), /****** Button control message APIs ******************************************/ #define Button_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable)) #define Button_GetText(hwndCtl, lpch, cchMax) #define Button_GetTextLength(hwndCtl) #define Button_SetText(hwndCtl, lpsz) GetWindowText((hwndCtl), (lpch), (cchMax)) GetWindowTextLength(hwndCtl) SetWindowText((hwndCtl), (lpsz)) #define Button_GetCheck(hwndCtl) 0L, 0L)) #define Button_SetCheck(hwndCtl, check) (WPARAM)(int)(check), 0L)) ((int)(DWORD)SendMessage((hwndCtl), BM_GETCHECK, #define Button_GetState(hwndCtl) 0L, 0L)) #define Button_SetState(hwndCtl, state) (WPARAM)(int)(state), 0L)) ((int)(DWORD)SendMessage((hwndCtl), BM_GETSTATE, ((void)SendMessage((hwndCtl), BM_SETCHECK, ((UINT)(DWORD)SendMessage((hwndCtl), BM_SETSTATE, #define Button_SetStyle(hwndCtl, style, fRedraw) ((void)SendMessage((hwndCtl), BM_SETSTYLE, (WPARAM)LOWORD(style), MAKELPARAM(((fRedraw) ? TRUE : FALSE), 0))) /****** Edit control message APIs ********************************************/ #define Edit_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable)) #define Edit_GetText(hwndCtl, lpch, cchMax) #define Edit_GetTextLength(hwndCtl) #define Edit_SetText(hwndCtl, lpsz) GetWindowText((hwndCtl), (lpch), (cchMax)) GetWindowTextLength(hwndCtl) SetWindowText((hwndCtl), (lpsz)) #define Edit_LimitText(hwndCtl, cchMax) (WPARAM)(cchMax), 0L)) ((void)SendMessage((hwndCtl), EM_LIMITTEXT, #define Edit_GetLineCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINECOUNT, 0L, 0L)) #define Edit_GetLine(hwndCtl, line, lpch, cchMax) ((*((int *)(lpch)) = (cchMax)), ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINE, (WPARAM)(int)(line), (LPARAM)(LPTSTR)(lpch)))) #define Edit_GetRect(hwndCtl, lprc) (LPARAM)(RECT *)(lprc))) #define Edit_SetRect(hwndCtl, lprc) (LPARAM)(const RECT *)(lprc))) #define Edit_SetRectNoPaint(hwndCtl, lprc) (LPARAM)(const RECT *)(lprc))) ((void)SendMessage((hwndCtl), EM_GETRECT, 0L, #define Edit_GetSel(hwndCtl) 0L)) #define Edit_SetSel(hwndCtl, ichStart, ichEnd) (ichStart), (ichEnd))) #define Edit_ReplaceSel(hwndCtl, lpszReplace) ((DWORD)SendMessage((hwndCtl), EM_GETSEL, 0L, ((void)SendMessage((hwndCtl), EM_SETRECT, 0L, ((void)SendMessage((hwndCtl), EM_SETRECTNP, 0L, ((void)SendMessage((hwndCtl), EM_SETSEL, ((void)SendMessage((hwndCtl), EM_REPLACESEL, 0L, (LPARAM)(LPCTSTR)(lpszReplace))) #define Edit_GetModify(hwndCtl) EM_GETMODIFY, 0L, 0L)) #define Edit_SetModify(hwndCtl, fModified) (WPARAM)(UINT)(fModified), 0L)) ((BOOL)(DWORD)SendMessage((hwndCtl), #define Edit_ScrollCaret(hwndCtl) EM_SCROLLCARET, 0, 0L)) ((BOOL)(DWORD)SendMessage((hwndCtl), #define Edit_LineFromChar(hwndCtl, ich) EM_LINEFROMCHAR, (WPARAM)(int)(ich), 0L)) #define Edit_LineIndex(hwndCtl, line) EM_LINEINDEX, (WPARAM)(int)(line), 0L)) #define Edit_LineLength(hwndCtl, line) EM_LINELENGTH, (WPARAM)(int)(line), 0L)) ((int)(DWORD)SendMessage((hwndCtl), #define Edit_Scroll(hwndCtl, dv, dh) (WPARAM)(dh), (LPARAM)(dv))) ((void)SendMessage((hwndCtl), EM_LINESCROLL, #define Edit_CanUndo(hwndCtl) EM_CANUNDO, 0L, 0L)) #define Edit_Undo(hwndCtl) 0L, 0L)) #define Edit_EmptyUndoBuffer(hwndCtl) EM_EMPTYUNDOBUFFER, 0L, 0L)) ((BOOL)(DWORD)SendMessage((hwndCtl), #define Edit_SetPasswordChar(hwndCtl, ch) EM_SETPASSWORDCHAR, (WPARAM)(UINT)(ch), 0L)) ((void)SendMessage((hwndCtl), ((void)SendMessage((hwndCtl), EM_SETMODIFY, ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), ((BOOL)(DWORD)SendMessage((hwndCtl), EM_UNDO, ((void)SendMessage((hwndCtl), #define Edit_SetTabStops(hwndCtl, cTabs, lpTabs) ((void)SendMessage((hwndCtl), EM_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(const int *)(lpTabs))) #define Edit_FmtLines(hwndCtl, fAddEOL) EM_FMTLINES, (WPARAM)(BOOL)(fAddEOL), 0L)) ((BOOL)(DWORD)SendMessage((hwndCtl), #define Edit_GetHandle(hwndCtl) EM_GETHANDLE, 0L, 0L)) #define Edit_SetHandle(hwndCtl, h) (WPARAM)(UINT)(HLOCAL)(h), 0L)) ((HLOCAL)(UINT)(DWORD)SendMessage((hwndCtl), #if (WINVER >= 0x030a) #define Edit_GetFirstVisibleLine(hwndCtl) EM_GETFIRSTVISIBLELINE, 0L, 0L)) ((void)SendMessage((hwndCtl), EM_SETHANDLE, ((int)(DWORD)SendMessage((hwndCtl), #define Edit_SetReadOnly(hwndCtl, fReadOnly) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_SETREADONLY, (WPARAM)(BOOL)(fReadOnly), 0L)) #define Edit_GetPasswordChar(hwndCtl) EM_GETPASSWORDCHAR, 0L, 0L)) ((TCHAR)(DWORD)SendMessage((hwndCtl), #define Edit_SetWordBreakProc(hwndCtl, lpfnWordBreak) ((void)SendMessage((hwndCtl), EM_SETWORDBREAKPROC, 0L, (LPARAM)(EDITWORDBREAKPROC)(lpfnWordBreak))) #define Edit_GetWordBreakProc(hwndCtl) ((EDITWORDBREAKPROC)SendMessage((hwndCtl), EM_GETWORDBREAKPROC, 0L, 0L)) #endif /* WINVER >= 0x030a */ /****** ScrollBar control message APIs ***************************************/ /* NOTE: flags parameter is a collection of ESB_* values, NOT a boolean! */ #define ScrollBar_Enable(hwndCtl, flags) EnableScrollBar((hwndCtl), SB_CTL, (flags)) #define ScrollBar_Show(hwndCtl, fShow) SW_SHOWNORMAL : SW_HIDE) ShowWindow((hwndCtl), (fShow) ? #define ScrollBar_SetPos(hwndCtl, pos, fRedraw) (fRedraw)) SetScrollPos((hwndCtl), SB_CTL, (pos), #define ScrollBar_GetPos(hwndCtl) #define SB_CTL, #define SB_CTL, GetScrollPos((hwndCtl), SB_CTL) ScrollBar_SetRange(hwndCtl, posMin, posMax, fRedraw) (posMin), (posMax), (fRedraw)) ScrollBar_GetRange(hwndCtl, lpposMin, lpposMax) (lpposMin), (lpposMax)) SetScrollRange((hwndCtl), GetScrollRange((hwndCtl), /****** ListBox control message APIs *****************************************/ #define ListBox_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable)) #define ListBox_GetCount(hwndCtl) LB_GETCOUNT, 0L, 0L)) #define ListBox_ResetContent(hwndCtl) LB_RESETCONTENT, 0L, 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((BOOL)(DWORD)SendMessage((hwndCtl), #define ListBox_AddString(hwndCtl, lpsz) ((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz))) #define ListBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpsz))) #define ListBox_AddItemData(hwndCtl, data) ((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0L, (LPARAM)(data))) #define ListBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data))) #define ListBox_DeleteString(hwndCtl, index) LB_DELETESTRING, (WPARAM)(int)(index), 0L)) ((int)(DWORD)SendMessage((hwndCtl), #define ListBox_GetTextLen(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXTLEN, (WPARAM)(int)(index), 0L)) #define ListBox_GetText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer))) #define ListBox_GetItemData(hwndCtl, index) ((LRESULT)(DWORD)SendMessage((hwndCtl), LB_GETITEMDATA, (WPARAM)(int)(index), 0L)) #define ListBox_SetItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data))) #if (WINVER >= 0x030a) #define ListBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind))) #define ListBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data))) #define ListBox_SetSel(hwndCtl, fSelect, index) ((int)(DWORD)SendMessage((hwndCtl), LB_SETSEL, (WPARAM)(BOOL)(fSelect), (LPARAM)(index))) #define ListBox_SelItemRange(hwndCtl, fSelect, first, last) ((int)(DWORD)SendMessage((hwndCtl), LB_SELITEMRANGE, (WPARAM)(BOOL)(fSelect), MAKELPARAM((first), (last)))) #define ListBox_GetCurSel(hwndCtl) LB_GETCURSEL, 0L, 0L)) #define ListBox_SetCurSel(hwndCtl, index) LB_SETCURSEL, (WPARAM)(int)(index), 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), #define ListBox_SelectString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind))) #define ListBox_SelectItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data))) #define ListBox_GetSel(hwndCtl, index) LB_GETSEL, (WPARAM)(int)(index), 0L)) #define ListBox_GetSelCount(hwndCtl) LB_GETSELCOUNT, 0L, 0L)) #define ListBox_GetTopIndex(hwndCtl) LB_GETTOPINDEX, 0L, 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), #define ListBox_GetSelItems(hwndCtl, cItems, lpItems) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int *)(lpItems))) #define ListBox_SetTopIndex(hwndCtl, indexTop) LB_SETTOPINDEX, (WPARAM)(int)(indexTop), 0L)) ((int)(DWORD)SendMessage((hwndCtl), #define ListBox_SetColumnWidth(hwndCtl, cxColumn) ((void)SendMessage((hwndCtl), LB_SETCOLUMNWIDTH, (WPARAM)(int)(cxColumn), 0L)) #define ListBox_GetHorizontalExtent(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETHORIZONTALEXTENT, 0L, 0L)) #define ListBox_SetHorizontalExtent(hwndCtl, cxExtent) ((void)SendMessage((hwndCtl), LB_SETHORIZONTALEXTENT, (WPARAM)(int)(cxExtent), 0L)) #define ListBox_SetTabStops(hwndCtl, cTabs, lpTabs) ((BOOL)(DWORD)SendMessage((hwndCtl), LB_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(int *)(lpTabs))) #define ListBox_GetItemRect(hwndCtl, index, lprc) ((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMRECT, (WPARAM)(int)(index), (LPARAM)(RECT *)(lprc))) #define ListBox_SetCaretIndex(hwndCtl, index) LB_SETCARETINDEX, (WPARAM)(int)(index), 0L)) #define ListBox_GetCaretIndex(hwndCtl) LB_GETCARETINDEX, 0L, 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), #define ListBox_FindStringExact(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind))) #define ListBox_SetItemHeight(hwndCtl, index, cy) ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMHEIGHT, (WPARAM)(int)(index), MAKELPARAM((cy), 0))) #define ListBox_GetItemHeight(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMHEIGHT, (WPARAM)(int)(index), 0L)) #endif /* WINVER >= 0x030a */ #define ListBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), LB_DIR, (WPARAM)(UINT)(attrs), (LPARAM)(LPCTSTR)(lpszFileSpec))) /****** ComboBox control message APIs ****************************************/ #define ComboBox_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable)) #define ComboBox_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax)) #define ComboBox_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl) #define ComboBox_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz)) #define ComboBox_LimitText(hwndCtl, cchLimit) CB_LIMITTEXT, (WPARAM)(int)(cchLimit), 0L)) ((int)(DWORD)SendMessage((hwndCtl), #define ComboBox_GetEditSel(hwndCtl) ((DWORD)SendMessage((hwndCtl), CB_GETEDITSEL, 0L, 0L)) #define ComboBox_SetEditSel(hwndCtl, ichStart, ichEnd) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEDITSEL, 0L, MAKELPARAM((ichStart), (ichEnd)))) #define ComboBox_GetCount(hwndCtl) CB_GETCOUNT, 0L, 0L)) #define ComboBox_ResetContent(hwndCtl) CB_RESETCONTENT, 0L, 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), #define ComboBox_AddString(hwndCtl, lpsz) ((int)(DWORD)SendMessage((hwndCtl), CB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz))) #define ComboBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpsz))) #define ComboBox_AddItemData(hwndCtl, data) ((int)(DWORD)SendMessage((hwndCtl), CB_ADDSTRING, 0L, (LPARAM)(data))) #define ComboBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data))) #define ComboBox_DeleteString(hwndCtl, index) CB_DELETESTRING, (WPARAM)(int)(index), 0L)) ((int)(DWORD)SendMessage((hwndCtl), #define ComboBox_GetLBTextLen(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXTLEN, (WPARAM)(int)(index), 0L)) #define ComboBox_GetLBText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer))) #define ComboBox_GetItemData(hwndCtl, CB_GETITEMDATA, (WPARAM)(int)(index), #define ComboBox_SetItemData(hwndCtl, CB_SETITEMDATA, (WPARAM)(int)(index), index) ((LRESULT)(DWORD)SendMessage((hwndCtl), 0L)) index, data) ((int)(DWORD)SendMessage((hwndCtl), (LPARAM)(data))) #define ComboBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind))) #define ComboBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data))) #define ComboBox_GetCurSel(hwndCtl) CB_GETCURSEL, 0L, 0L)) #define ComboBox_SetCurSel(hwndCtl, index) CB_SETCURSEL, (WPARAM)(int)(index), 0L)) ((int)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), #define ComboBox_SelectString(hwndCtl, indexStart, lpszSelect) ((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszSelect))) #define ComboBox_SelectItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data))) #define ComboBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), CB_DIR, (WPARAM)(UINT)(attrs), (LPARAM)(LPCTSTR)(lpszFileSpec))) #define ComboBox_ShowDropdown(hwndCtl, fShow) CB_SHOWDROPDOWN, (WPARAM)(BOOL)(fShow), 0L)) ((BOOL)(DWORD)SendMessage((hwndCtl), #if (WINVER >= 0x030a) #define ComboBox_FindStringExact(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind))) #define ComboBox_GetDroppedState(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), CB_GETDROPPEDSTATE, 0L, 0L)) #define ComboBox_GetDroppedControlRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), CB_GETDROPPEDCONTROLRECT, 0L, (LPARAM)(RECT *)(lprc))) #define ComboBox_GetItemHeight(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_GETITEMHEIGHT, 0L, 0L)) #define ComboBox_SetItemHeight(hwndCtl, index, cyItem) ((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMHEIGHT, (WPARAM)(int)(index), (LPARAM)(int)cyItem)) #define ComboBox_GetExtendedUI(hwndCtl) CB_GETEXTENDEDUI, 0L, 0L)) #define ComboBox_SetExtendedUI(hwndCtl, flags) CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L)) #endif /* WINVER >= 0x030a */ ((UINT)(DWORD)SendMessage((hwndCtl), ((int)(DWORD)SendMessage((hwndCtl), /****** Alternate porting layer macros ****************************************/ /* USER MESSAGES: */ #define GET_WPARAM(wp, lp) #define GET_LPARAM(wp, lp) (wp) (lp) #define GET_X_LPARAM(lp) #define GET_Y_LPARAM(lp) ((int)(short)LOWORD(lp)) ((int)(short)HIWORD(lp)) #define #define #define #define GET_WM_ACTIVATE_STATE(wp, lp) LOWORD(wp) GET_WM_ACTIVATE_FMINIMIZED(wp, lp) (BOOL)HIWORD(wp) GET_WM_ACTIVATE_HWND(wp, lp) (HWND)(lp) GET_WM_ACTIVATE_MPS(s, fmin, hwnd) \ (WPARAM)MAKELONG((s), (fmin)), (LONG)(hwnd) #define #define #define #define GET_WM_CHARTOITEM_CHAR(wp, lp) (TCHAR)LOWORD(wp) GET_WM_CHARTOITEM_POS(wp, lp) HIWORD(wp) GET_WM_CHARTOITEM_HWND(wp, lp) (HWND)(lp) GET_WM_CHARTOITEM_MPS(ch, pos, hwnd) \ (WPARAM)MAKELONG((pos), (ch)), (LONG)(hwnd) #define #define #define #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) GET_WM_COMMAND_MPS(id, hwnd, cmd) \ (WPARAM)MAKELONG(id, cmd), (LONG)(hwnd) #define WM_CTLCOLOR 0x0019 #define #define #define #define #define GET_WM_CTLCOLOR_HDC(wp, lp, msg) GET_WM_CTLCOLOR_HWND(wp, lp, msg) GET_WM_CTLCOLOR_TYPE(wp, lp, msg) GET_WM_CTLCOLOR_MSG(type) GET_WM_CTLCOLOR_MPS(hdc, hwnd, type) \ (WPARAM)(hdc), (LONG)(hwnd) (HDC)(wp) (HWND)(lp) (WORD)(msg - WM_CTLCOLORMSGBOX) (WORD)(WM_CTLCOLORMSGBOX+(type)) #define #define #define #define GET_WM_MENUSELECT_CMD(wp, lp) GET_WM_MENUSELECT_FLAGS(wp, lp) GET_WM_MENUSELECT_HMENU(wp, lp) GET_WM_MENUSELECT_MPS(cmd, f, hmenu) \ (WPARAM)MAKELONG(cmd, f), (LONG)(hmenu) LOWORD(wp) (UINT)(int)(short)HIWORD(wp) (HMENU)(lp) /* Note: the following are for interpreting MDIclient to MDI child messages. */ #define GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wp, lp) (lp == (LONG)hwnd) #define GET_WM_MDIACTIVATE_HWNDDEACT(wp, lp) (HWND)(wp) #define GET_WM_MDIACTIVATE_HWNDACTIVATE(wp, lp) (HWND)(lp) /* Note: the following is for sending to the MDI client window. */ #define GET_WM_MDIACTIVATE_MPS(f, hwndD, hwndA)\ (WPARAM)(hwndA), 0 #define GET_WM_MDISETMENU_MPS(hmenuF, hmenuW) (WPARAM)hmenuF, (LONG)hmenuW #define #define #define #define GET_WM_MENUCHAR_CHAR(wp, lp) GET_WM_MENUCHAR_HMENU(wp, lp) GET_WM_MENUCHAR_FMENU(wp, lp) GET_WM_MENUCHAR_MPS(ch, hmenu, f) \ (WPARAM)MAKELONG(ch, f), (LONG)(hmenu) #define #define #define #define #define #define (TCHAR)LOWORD(wp) (HMENU)(lp) (BOOL)HIWORD(wp) GET_WM_PARENTNOTIFY_MSG(wp, lp) GET_WM_PARENTNOTIFY_ID(wp, lp) GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp) GET_WM_PARENTNOTIFY_X(wp, lp) GET_WM_PARENTNOTIFY_Y(wp, lp) GET_WM_PARENTNOTIFY_MPS(msg, id, hwnd) \ (WPARAM)MAKELONG(id, msg), (LONG)(hwnd) #define GET_WM_PARENTNOTIFY2_MPS(msg, x, y) \ (WPARAM)MAKELONG(0, msg), MAKELONG(x, y) LOWORD(wp) HIWORD(wp) (HWND)(lp) (int)(short)LOWORD(lp) (int)(short)HIWORD(lp) #define #define #define #define (int)(short)LOWORD(wp) HIWORD(wp) (HWND)(lp) GET_WM_VKEYTOITEM_CODE(wp, lp) GET_WM_VKEYTOITEM_ITEM(wp, lp) GET_WM_VKEYTOITEM_HWND(wp, lp) GET_WM_VKEYTOITEM_MPS(code, item, hwnd) \ (WPARAM)MAKELONG(item, code), (LONG)(hwnd) #define GET_EM_SETSEL_START(wp, lp) #define GET_EM_SETSEL_END(wp, lp) #define GET_EM_SETSEL_MPS(iStart, iEnd) \ (WPARAM)(iStart), (LONG)(iEnd) #define GET_EM_LINESCROLL_MPS(vert, horz) (WPARAM)horz, (LONG)vert (INT)(wp) (lp) \ #define GET_WM_CHANGECBCHAIN_HWNDNEXT(wp, lp) (HWND)(lp) #define #define #define #define GET_WM_HSCROLL_CODE(wp, lp) GET_WM_HSCROLL_POS(wp, lp) GET_WM_HSCROLL_HWND(wp, lp) GET_WM_HSCROLL_MPS(code, pos, hwnd) \ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd) LOWORD(wp) HIWORD(wp) (HWND)(lp) #define #define #define #define GET_WM_VSCROLL_CODE(wp, lp) GET_WM_VSCROLL_POS(wp, lp) GET_WM_VSCROLL_HWND(wp, lp) GET_WM_VSCROLL_MPS(code, pos, hwnd) \ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd) LOWORD(wp) HIWORD(wp) (HWND)(lp) /****** C runtime porting macros ****************************************/ #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define _ncalloc _nexpand _ffree _fmalloc _fmemccpy _fmemchr _fmemcmp _fmemcpy _fmemicmp _fmemmove _fmemset _fmsize _frealloc _fstrcat _fstrchr _fstrcmp _fstrcpy _fstrcspn _fstrdup _fstricmp _fstrlen _fstrlwr _fstrncat _fstrncmp _fstrncpy _fstrnicmp _fstrnset _fstrpbrk _fstrrchr _fstrrev _fstrset _fstrspn _fstrstr _fstrtok _fstrupr _nfree _nmalloc _nmsize _nrealloc _nstrdup hmemcpy calloc _expand free malloc _memccpy memchr memcmp memcpy _memicmp memmove memset _msize realloc strcat strchr strcmp strcpy strcspn _strdup _stricmp strlen _strlwr strncat strncmp strncpy _strnicmp _strnset strpbrk strrchr _strrev _strset strspn strstr strtok _strupr free malloc _msize realloc _strdup MoveMemory #define DECLARE_HANDLE32 DECLARE_HANDLE #ifdef __cplusplus } /* End of extern "C" { */ #endif /* __cplusplus */ #endif /* !_INC_WINDOWSX */ Entwicklungsumgebung Um aus ASCII-Files ein lauffaehiges *.EXE-Programm zu erstellen werden Programme wie z.B. für die Übersetzungsvorgänge benötigt. Ein direkter Entwurf der Bitmuster des Maschinencodes ist wegen des Umfanges und der Komplexität nicht möglich. Einbettungen von Tools Werzeuge Dateien-Endungen ● ● ● ● ● ● ● ● ● ● Editor ( einfache bzw. auswendige Textbearbeitung und gestaltung ), Quelltext-Generierung ( Assistenten ), Assembler ( übersetzt von Assembler nach Maschinencode ), Compiler ( übersetzt in Assembler bzw. Maschinencode ), Linker ( fügt compilierte Files zusammen ), Projektverwaltung ( überwacht den Build-Prozess ), Resourcen - Tools ( erstellt, übersetzt Properties ), Debugger ( schrittweiser Programmablauf ) , Nachrichten - Verfolgung ( Spy - Tools ), On-Line-Hilfe ( Dokumentation ) ● ● ● ● ● ● ● ● ● *.asm für Assembler - Quelltexte, *.c für C-Quell-Texte, *.cpp für C++-Quell-Texte, *.obj für binärer OpCode nach dem Compilieren, *.lib für Bibliotheks-Routinen und Dll-Zuordnungen, *.rc für Resourcen - Quelltexte, *.res für binärere Resourcen - Files, *.map für die DLL - Adressen, *.exe für den executierbarer File, *.rtf für ASCII-Rich-Text-File incl. Formatierung, *.hlp für binärer HeLP-Files Moderne Werkzeuge bestehen aus Software - Komponenten zur Programmentwicklung. Anstatt diese Programme einzeln zu verwenden, ist es günstiger, eine interaktive, integrierende Bedienungsumgebung zu verwenden. Es bestehen vielschichtige Abhängigkeiten zu ( standardisierten ) Software - Systemen. Je moderner und komplexer ein Entwicklungssystem ist, um so größer ist die Zahl der Einstellungen und Variationen. 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, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, // // // // // extended window style pointer to registered class name pointer to window name window style horizontal position of window int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam // // // // // // // vertical position of window window width window height handle to parent or owner window handle to menu, or child-window identifier handle to application instance pointer to window-creation data ); 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 lpfnAbort Windows verwendet für Nachrichten-, Style-, Control- Konstanten 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/EnableMenuItem() MK_ Key State Masks for Mouse Messages OBM_ OEM Resource Ordinal Numbers PWR_ wParam for WM_POWER SBS_ Scroll Bar Styles System Menu Command Values SC_ SORT_ Sorting IDs. SIZE_ WM_SIZE message wParam values 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_ WVR_ WM_NCCALCSIZE return values Extended Window Styles Handle Win32 nutzt die 32-Bit-CPU-Architektur. Bei Win32 entspricht das Datensegment-Register DS nicht mehr einer direkten Adresse auf das aktuelle Datensegment. ● ● DS entspricht einem Index für die Deskriptor - Tabelle. Es gibt lokale Deskriptortabellen LDT und eine globale Deskriptortabellen GDT. Ein 8 - Byte - Element aus der Deskriptor - Tabelle enthält die endgültige Byte - Zieladresse und das Sicherheits - Byte. Beim erstmaligen Benutzen wird mit dem DS - Index das 8 - Byte - Element aus der Deskriptor - Tabelle geholt und in die CPU übertragen. Jeder CPU - Befehl kann damit ( ohne Verzögerung ) das Element innerhalb der CPU nutzen ( Sicherheitsbyte, Protected Mode, Privileg Level ). Beinahe jede Window - Funktion benötigt globale Window - Daten, Fenstergröße, Device - Kontext, usw. Damit die Funktion richtig ausgeführt wird, muß vorher das Handle beschafft werden. Nur dann kann die Windows - Funktion die benötigten globalen Daten erreichen und nutzen. ● ● ● Hinter dem Handle verbirgt sich der Index in eine Deskriptortabelle. Ein Win16/Win32 - Handle bnutzt 16/32 Bit. Ein Handle mit dem Wert 0 wird nicht verwendet und dient zur Fehler - Erkennung. *.LIB - Files Windows.h enthält die Funktions - Prototypen. Dadurch kann der Compiler die Schreibweise ( Syntax ) in dem eigenen Programm überprüfen. Damit der Linker dnden 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 winspool.lib shell32.lib uuid.lib user32.lib comdlg32.lib ole32.lib odbc32.lib gdi32.lib advapi32.lib oleaut32.lib odbccp32.lib Linker - Fehler Von den Entwicklungs - Werkzeugen mußte der Linker immer mehr Aufgaben übernehmen. Die Linker - Zeiten übersteigen vielfach die Compiler Zeiten. Eine Teilung der Linker - Aufgaben in traditionelles Linken und der Resourcen - Erstellung ist angezeigt. Der Linker fügt Binärcode aneinander und verbindet die wechselseitigen Zuordnungen ( Adressen ). Bei einem Linker - Fehler ist der Zusammenhang mit dem lesbaren ASCII - Quelltext verloren. Der Linker gibt im Fehlerfall die Namen der nicht gefundenen bzw. doppelt vorhanden Symbole aus. Weil bei C und C++ - Code gemäß #ifdef __cplusplus extern "C" { #endif ... ... #ifdef __cplusplus } #endif gemischt werden können, ist zur Fehlererkennung vielfach auf die Schreibweise der ausgegebenen Namen zu beachten. LinkerFehlerAnzeige Diagnose myFkt$int$int Es wurde mit C++ compiliert, bzw. eine C++ Bibliothek wird verwendet. MYFKT Es wurde mit PASCAL deklariert compiliert, bzw. Linkerschalter auf Großbuchstaben, bzw. Win16 - Bibliothek wird verwendet. _myFkt Es wurde mit C, CDECL compiliert, bzw. es werden C - Bibliotheken verwendet. *.RC - Files 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. Übersetzungsvorgang Für den Übersetzungsvorgang von Windows - Applikationen werden die Header-Files #define STRICT #include <windows.h> #include <commdlg.h> #include <windowsx.h> mit den Funktions - Prototypen in den C, C++ - Quelltext eingebunden. Dadurch kann bereits der Compiler in unseren *.C, *.CPP - Files die richtige Schreibweise der Window - Typen und -Funktionen überprüfen. Der Compiler übersetzt die *.CPP - Files in *.OBJ - Files. Wenn der Linker-Pfad zu *.LIB richtig gesetzt ist, kann der Linker aus den Window-Bibliotheken *.LIB die Einsprüngen in die Window-dll´s entnehmen und in unser Programm einbauen. Unser Programm verwendet dann die benötigten Window-DLL’s. Der Resourcen-Compiler erzeugt aus *.RC den binären *.RES-File: *.C, *.CPP *.H, *.RC *.OBJ, *.DEF (*.EXE), *.RES ===> ===> ===> ===> Compiler Resourcen-Compiler Linker Resourcen-Compiler ===> ===> ===> ===> *.OBJ *.RES (*.EXE) *.EXE Die Steuerung des Übersetzungs-Vorganges wird i.a. von der Projekt - Entwicklungs - Umgebeung oder von make.exe ( nmake.exe ) übernommen. Der Übersetzungsvorgang kann auch die automatische Hyphertext - Help - Erzeugung enthalten ( autoduck.exe ). 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. | Adress-Tabelle | | Tabelle | | der enthaltenen | | der | | Funktionen | Dat1 | Dat2 | Func1 | Func2 | Func3 | Func4 | Namen | ---|-----------------|------|------|-------|-------|-------|-------|---------|--DLL Dat1 Dat2 Func1 Func1 Func1 Func1 Tab Adr Adr Adr Adr Adr Adr Adr Adr Die DOS - Interrupttabelle ist grob mit der DLL - Funktionstabelle vergleichbar (die Zuordnung von Interruptzeiger zu Interruptserviceroutinen). 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-Funktionsaufrufe erfolgen über den 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 FindFirstChangeNotification FindCloseChangeNotification Communications Object Creator function Destroyer function device GetStdHandle CloseHandle CreateEvent, Event OpenEvent CloseHandle OpenEventLog, Event log RegisterEventSource, CloseEventLog OpenBackupEventLog File CreateFile CloseHandle, DeleteFile File CreateFileMapping, mapping OpenFileMapping Find file FindFirstFile FindClose Mailslot CreateMailslot CloseHandle Module LoadLibrary, GetModuleHandle FreeLibrary CloseHandle Pipe CreateNamedPipe, CreatePipe CloseHandle, DisconnectNamedPipe CreateSemaphore, OpenSemaphore CloseHandle Mutex CreateMutex, OpenMutex Heap HeapCreate CloseHandle CreateProcess, Process OpenProcess, GetCurrentProcess CloseHandle, TerminateProcess Semaphore CreateThread, Thread CreateRemoteThread, GetCurrentThread CloseHandle, TerminateThread Timer Update resource BeginUpdateResource HeapDestroy CreateWaitableTimer, CloseHandle OpenWaitableTimer 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 Programmierschnittstelle lesbare Daten ( Resources Dialogelemente ( Controls ( Shell and Common ) sind: ): 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 ) Textcursor ( Carets ), Mauscursor ( Cursors ), kleines Symbolbild ( Icons ), Menus, benutzerdefinierte Resourcen-Daten Windows Shell API, standardisierter Dialogelemente ( Common Controls ), Wizard97 Specifications Benutzer-Eingaben ( User Input ) Fensternhirachie ( Windowing ) Nachrichtenzugriff ( Accessibility ), Mauseingaben ( Mouse Input ), Tasten - Code der Tastatur ( Keyboard Input ), standardisierter Tastencode ( Virtual-Key Codes ), AltTasten ( Keyboard Accelerators ), fertige Dialoge ( Common Dialog Box Library ) Fensterbehandlung ( Windows ) Datenzuordnung zu Fenstern ( Window Properties ), mehrere Fenster mit gleichen Eigenschhaften ( Window Classes ), Nachrichtenbearbeitung ( Message and Message Queues ), 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. AdjustWindowRect AdjustWindowRectEx BringWindowToTop CascadeWindows ChildWindowFromPoint DeferWindowPos DestroyWindow EnumChildWindows EnumThreadWindows EnumThreadWndProc GetClientRect GetDesktopWindow GetTopWindow GetWindow GetWindowTextLength GetWindowThreadProcessId IsChild IsWindowVisible IsZoomed MoveWindow SetWindowPlacement SetWindowPos ShowWindowAsync TileWindows WindowFromPoint AnimateWindow ArrangeIconicWindows BeginDeferWindowPos ChildWindowFromPointEx CloseWindow EnableWindow EndDeferWindowPos CreateWindow EnumChildProc CreateWindowEx EnumWindows GetForegroundWindow GetWindowPlacement EnumWindowsProc GetLastActivePopup GetWindowRect FindWindow GetNextWindow GetWindowText FindWindowEx GetParent IsIconic IsWindow IsWindowUnicode OpenIcon SetWindowText SetForegroundWindow ShowOwnedPopups SetParent ShowWindow SetWindowLong 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 DeleteObject EnumObjectsProc GetDCPenColor ReleaseDC SetDCPenColor ChangeDisplaySettings DeviceCapabilities GetCurrentObject GetDeviceCaps ResetDC CreateCompatibleDC DrawEscape GetDC GetGraphicsMode RestoreDC Mit Fonts und Texten werden die folgenden Funktionen benutzt: CreateDC EnumDisplayDevices GetDCBrushColor GetObject SaveDC CreateIC EnumDisplaySettings GetDCEx GetObjectType SelectObject DeleteDC EnumObjects GetDCOrgEx GetStockObject SetDCBrushColor AddFontResource DrawText ExtTextOut GetCharacterPlacement GetFontLanguageInfo GetKerningPairs GetTextAlign GetTextExtentPoint32 RemoveFontResource SetTextColor CreateFont DrawTextEx GetAspectRatioFilterEx GetCharWidth32 GetFontUnicodeRanges GetOutlineTextMetrics GetTextCharacterExtra GetTextFace SetMapperFlags SetTextJustification Nicht mehr benutzt werden sollten: EnumFontFamilies EnumFontFamProc EnumFonts CreateFontIndirect EnumFontFamiliesEx GetCharABCWidths GetCharWidthFloat GetGlyphIndices GetRasterizerCaps GetTextColor GetTextMetrics SetTextAlign TabbedTextOut EnumFontsProc CreateScalableFontResource EnumFontFamExProc GetCharABCWidthsFloat GetFontData GetGlyphOutline GetTabbedTextExtent GetTextExtentExPoint PolyTextOut SetTextCharacterExtra TextOut GetCharWidth GetTextExtentPoint Im Zusammenhang mit der Paint - Nachricht werden die folgenden Funktionen benutzt: BeginPaint DrawState GdiGetBatchLimit GetUpdateRect InvalidateRgn SetBkMode ValidateRect DrawAnimatedRects DrawStateProc GdiSetBatchLimit GetUpdateRgn LockWindowUpdate SetBoundsRect ValidateRgn DrawCaption DrawTextEx GetBkColor GetWindowDC OutputProc SetRectRgn WindowFromDC DrawEdge EndPaint GetBkMode GetWindowRgn PaintDesktop SetROP2 DrawFocusRect ExcludeUpdateRgn GetBoundsRect GrayString RedrawWindow SetWindowRgn DrawFrameControl GdiFlush GetROP2 InvalidateRect SetBkColor UpdateWindow Beispiel: GetDeviceCaps() Als ein Beispiel für den Umfang einer Funktion soll hier GetDeviceCaps() angegeben werden. GetDeviceCaps() gibt Informationen zum Device Kontext zurück. int GetDeviceCaps( HDC hDC, // device-context handle int nIndex // index of capability to query ); Für den Parameter nIndex kann eine der folgenden Zahlen gewählt werden. Die eingerückten Konstanten kennzeichnen die zugehörigen Rückgabewerte. 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. 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. 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. Beispiel: 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 ); wird ein Fenster zentriert. Win - Grundgerüst Weil bereits ein erstes Programm unübersichtlich ist, wird das Grundgerüst zunächst im Pseudocode betrachtet. Ein einfaches Programm hat die folgende Struktur: WinMain(), //Startup-Code RegisterClassEx (..., CALLBACK-Funktion, ...), CreateWindowEx( ), ShowWindow( ), //Nachrichtenschleife while ( GetMessage( & msg, NULL, 0, 0 ) ) { TranslateMessage( & msg ) ; DispatchMessage( & msg ) ; } Wegen der vielen Parameter wird der C - Quelltext z.T. bereits unuebersichtlich. Auch verfuegbare Klassen - Bibliotheken verwenden den gleichen Aufbau ( und sind ebenfalls unuebersichtlich! ). "Hallo Welt" Das folgende Beispiel besteht aus der WinMain() und der WndProc() - CALLBACK - Funktion. Es wird ein Hauptfenster angelegt und Text zentriert hinein geschrieben. #include <windows.h> //====================================== LRESULT CALLBACK WndProc( HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { PAINTSTRUCT ps ; HDC hDC ; RECT rect ; switch ( iMsg ) { case WM_CREATE : break ;//return 0; 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; case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0; } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } //====================================== int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { WNDCLASSEX wc = { 0 } ; MSG msg ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInst ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; HWND hWndMain = CreateWindowEx( WS_EX_LEFT, "my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInst, // program instance handle NULL ) ; // creation parameters ShowWindow ( hWndMain, iShowMain ) ; UpdateWindow ( hWndMain ) ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1 TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return msg.wParam ; } Diese Programm besteht aus 2 Teilen: ● ● der CLALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { ... } und der Funktion int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { ... } WinMain entspricht der main() - Funktion in C. Der (W)indow -(S)tyle WS_OVERLAPPEDWINDOW entspricht #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) #define WS_POPUPWINDOW (WS_POPUP|WS_BORDER|WS_SYSMENU) WinMain() Die Start - Adresse einer Window - Applikation ist die WinMain() - Funktion( APIENTRY ). WinMain ist der Haupt - Eintritts - Punkt für eine Windows - Anwendung. Diese Funktion entspricht der Funktion main() bei einem C-Programm. Der WinMain - Startup - Code ruft die WinMainFunktion durch den Namen auf. Windows verwendet diese Funktion als "initial entry point" APIENTRY). Beim Start wird der Startup-Code ausgeführt, der u.a. die Windows-Funktionen ● ● ● InitTask ( KRNL386 ), InitApp ( USER ) und WaitEvent( KERNEL) aufruft. Danach ruft der Startup - Code unsere WinMain - Funktion auf. Diese Schritte bei Start eines Win - Programmes können grob skizziert werden: WinMain() initialisiert Register InitTask füllt bei Win16 die folgenden Register mit Werten, die beim Laden der Applikation auf den Stack gelegt werden: BX CX DI SI ES = = = = = Stack-Grösse, Heap-Grösse, Instanz-Handle, vorherige Instanz, PSP-Adresse WinMain() initialisiert den Stack Außerdem initialisiert InitTask pStackTop, pStackMin, pStackBottom im Task - Header der aufrufenden Tastk. DLL´s sind keine Task´s, rufen aber in ihrem Startup-Code auch InitTask auf. WinMain() richtet Application-Message-Queue ein Durch InitApp ( USER ) wird eine User - Nachrichten - Warte - Schlange ( Application - Message - Queue ) eingerichtet. Die Nachrichten der Application - Message - Queue haben ein einheitliches Format. Die Nachrichten, die zu unserem Programm gehören, werden durch Windows der ● ● ● System - Message - Queue entnommen, auf ein einheitliches Format gebracht und in unsere Application - Message - Queue gelegt. WinMain() initialisiert die C - Laufzeit - Bibliothek Die C-Laufzeit-Bibliothek wird initialisiert. Die statischen Konstruktoren von C++ werden initialisiert. Der Startup-Code legt die WinMain Parameter auf den Stack und ruft WinMain auf. WinMain() entfernt Prä - Nachrichten WaitEvent ( KRNL386 ) prüft ( PostEvent, Reschedule ), ob bereits ein Ereignis an die aktuelle Task ( 0 ) geschickt wurde. Wenn das Ereignis abgeschickt und noch nicht eingetroffen ist, so wird gewartet und dann die bisher eingetroffenen Ereignisse gelöscht. siehe: Start-Up-Code 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; // LoadIcon ( NULL, IDI_APPLICATION ); HCURSOR hCursor; // LoadCursor( NULL, IDC_ARROW ); HBRUSH hbrBackground; // ( HBRUSH ) GetStockObject( WHITE_BRUSH ); LPCTSTR lpszMenuName; // NULL LPCTSTR lpszClassName; // static char szAppName[] = "HelloWin" ; HICON hIconSm; // LoadIcon( NULL, IDI_APPLICATION ); } WNDCLASSEX; 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 wc = { 0 }; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = ... wc.lpfnWndProc = ... ... wc.lpszClassName = ... if ( ! RegisterClass( & wc ) ) Fehler; Die hinterlegten Daten können mit GetClassInfoEx() erhalten werden. RegisterClassEx() 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 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. 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. Dabei ist das Fenster noch 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, // // // // // // // // // // 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 identifier HINSTANCE hInstance, LPVOID lpParam // 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 ). dwStyle spezifiziert den Style des Fensters und Funktionalität: WS_BORDER, WS_CLIPSIBLINGS, WS_DISABLED, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_POPUP, WS_THICKFRAME, WS_TILED, WS_CAPTION, WS_CHILD, WS_CHILDWINDOW, WS_CLIPCHILDREN, WS_DLGFRAME, WS_GROUP, WS_HSCROLL, WS_MINIMIZE, WS_MINIMIZEBOX,WS_OVERLAPPED, WS_POPUPWINDOW, WS_SIZEBOX, WS_SYSMENU, WS_TILEDWINDOW, WS_VISIBLE, WS_ICONIC, WS_OVERLAPPEDWINDOW, WS_TABSTOP, 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. Nachrichtenschleife // Die Nachrichtenschleife while ( GetMessage( & msg, TranslateMessage( & msg DispatchMessage ( & msg } enthält: NULL, 0, 0 ) ) { ) ; ) ; 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 sendet die aufgerufene DefWindowProc() WM_DESTROY und PostQuitMessage(); beendet die Haupt-Nachrichtenschleife. BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ); // // // // address of structure with message handle of window first message last message 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 ). 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. 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. 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 kommt über den einen System-Buffer in den Applikations-Nachrichten-Buffer, wird dort entnommen und ruft die CALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) des Fensters mit DispatchMessage() auf. Aus dem Handle der Tasten-Nachricht kann das Fenster ersehen werden. DispatchMessage() bestimmt das Fenster und ruft die CALLBACK - Funktion des Fenster auf. ● Kurz-Sprechweise: 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. Die Nachrichten werden innerhalb der CALLBACK - Funktion bearbeitet oder an die DefWindowProc() weiter geleitet. Beispiel: 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. 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, BeginPaint(), EndPaint() Eine WM_PAINT - Nachricht wird meist verarbeitet 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; 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 } PAINTSTRUCT; Das Update- Rechteck wird in einer RECT- Struktur gespeichert typedef struct _RECT { // rc LONG left; LONG top; LONG right; LONG bottom; } RECT; Ein Handle auf den Device-Context hDC ( das zum gesamten Client - Bereich gehört ), wird erhalten durch hDC = GetDC( hWnd ) ; ... ReleaseDC( hWnd, hDC ) ; Das Update - Recheck ( validates ) wird auch gelöscht durch den Aufruf von DefWindowProc(), die ( falls erforderlich ) WM_NCPAINT, WM_ERASEBKGND - Nachrichten sendet. InvalidateRect(), ValidateRect(), GetUpdateRect() Mit der GetUpdateBeginPaint() ... 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. 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. Sichtbarkeit von Fenstern Ein Fenster kann in den Vordergrund geholt werden. Beispiel: BOOL bVisible = IsWindowVisible(hwnd); SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW |(bVisible ? SWP_NOACTIVATE : 0)); if (wParam == TRUE) SetForegroundWindow(hwnd); 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 ChildWindows. 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. DefWindowProc() Einige Nachrichten werden in der eigenen CALL-Klassen-CALBACK-Funktionen 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_ICONERASEBKGND, WM_SYNCPAINT, WM_WINDOWPOSCHANGED,WM_CTLCOLOR, WM_NCLBUTTONUP, WM_NCLBUTTONDBLCLK, WM_SYSKEYUP, WM_SYSCHAR, WM_CHARTOITEM, WM_VKEYTOITEM, WM_QUERYDROPOBJECT, WM_DROPOBJECT, WM_GETTEXTLENGTH, WM_SYSCOMMAND, WM_SETCURSOR, WM_NCMOUSEMOVE, WM_CLOSE, WM_DRAWITEM, WM_PAINT, WM_ACTIVATE, WM_MOUSEACTIVATE, WM_KEYDOWN, WM_QUERYOPEN, WM_GETHOTKEY, WM_PAINTICON, WM_SETREDRAW, WM_SHOWWINDOW, WM_SYSKEYDOWN, WM_QUERYENDSESSION, WM_SETHOTKEY, WM_ERASEBKGND, WM_WINDOWPOSCHANGING, WM_NCLBUTTONDOWN, WM_KEYUP, WM_ISACTIVEICON, WM_QUERYDRAGICON, /*** *crt0.c - C runtime initialization routine * * Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. * *Purpose: * This the actual startup routine for apps. It calls the user's main * routine [w]main() or [w]WinMain after performing C Run-Time Library * initialization. * * (With ifdef's, this source file also provides the source code for * wcrt0.c, the startup routine for console apps with wide characters, * wincrt0.c, the startup routine for Windows apps, and wwincrt0.c, * the startup routine for Windows apps with wide characters.) * *******************************************************************************/ #ifdef _WIN32 #ifndef CRTDLL #include #include #include #include #include #include #include #include #include #include <cruntime.h> <dos.h> <internal.h> <stdlib.h> <string.h> <rterr.h> <windows.h> <awint.h> <tchar.h> <dbgint.h> /* * wWinMain is not yet defined in winbase.h. When it is, this should be * removed. */ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ); #ifdef WPRFLAG _TUCHAR * __cdecl _wwincmdln(void); #else /* WPRFLAG */ _TUCHAR * __cdecl _wincmdln(void); #endif /* WPRFLAG */ /* * command line, environment, and a few other globals */ #ifdef WPRFLAG wchar_t *_wcmdln; #else /* WPRFLAG */ char *_acmdln; #endif /* WPRFLAG */ /* points to wide command line */ /* points to command line */ char *_aenvptr = NULL; /* points to environment block */ wchar_t *_wenvptr = NULL; /* points to wide environment block */ void (__cdecl * _aexit_rtn)(int) = _exit; /* RT message return procedure */ static void __cdecl fast_error_exit(int); /* * _error_mode and * written out. */ int __error_mode = #ifdef _WINMAIN_ int __app_type = #else int __app_type = #endif /* Error exit via ExitProcess */ _apptype, together, determine how error messages are _OUT_TO_DEFAULT; _GUI_APP; /* _WINMAIN_ */ _CONSOLE_APP; /* _WINMAIN_ */ /*** *BaseProcessStartup(PVOID Peb) * *Purpose: * This routine does the C runtime initialization, calls main(), and * then exits. It never returns. * *Entry: * PVOID Peb - pointer to Win32 Process Environment Block (not used) * *Exit: * This function never returns. * *******************************************************************************/ #ifdef _WINMAIN_ #ifdef void #else void #endif WPRFLAG wWinMainCRTStartup( /* WPRFLAG */ WinMainCRTStartup( /* WPRFLAG */ #else /* _WINMAIN_ */ #ifdef void #else void #endif WPRFLAG wmainCRTStartup( /* WPRFLAG */ mainCRTStartup( /* WPRFLAG */ #endif /* _WINMAIN_ */ void ) { int mainret; #ifdef _WINMAIN_ _TUCHAR *lpszCommandLine; STARTUPINFO StartupInfo; #endif /* _WINMAIN_ */ /* * Get the full Win32 version */ _osver = GetVersion(); _winminor = (_osver >> 8) & 0x00FF ; _winmajor = _osver & 0x00FF ; _winver = (_winmajor << 8) + _winminor; _osver = (_osver >> 16) & 0x00FFFF ; #ifdef _MT if ( !_heap_init(1) ) /* _MT */ if ( !_heap_init(0) ) #endif /* _MT */ fast_error_exit(_RT_HEAPINIT); /* initialize heap */ #else #ifdef _MT if( !_mtinit() ) fast_error_exit(_RT_THREAD); #endif /* _MT */ /* initialize heap */ /* write message and die */ /* initialize multi-thread */ /* write message and die */ /* * Guard the remainder of the initialization code and the call * to user's main, or WinMain, function in a __try/__except * statement. */ __try { _ioinit(); /* initialize lowio */ #ifdef WPRFLAG /* get wide cmd line info */ _wcmdln = (wchar_t *)__crtGetCommandLineW(); /* get wide environ info */ _wenvptr = (wchar_t *)__crtGetEnvironmentStringsW(); #else _wsetargv(); _wsetenvp(); /* WPRFLAG */ /* get cmd line info */ _acmdln = (char *)GetCommandLineA(); /* get environ info */ _aenvptr = (char *)__crtGetEnvironmentStringsA(); #endif _setargv(); _setenvp(); /* WPRFLAG */ _cinit(); /* do C data initialize */ #ifdef _WINMAIN_ StartupInfo.dwFlags = 0; GetStartupInfo( &StartupInfo ); #ifdef WPRFLAG lpszCommandLine = _wwincmdln(); mainret = wWinMain( #else /* WPRFLAG */ lpszCommandLine = _wincmdln(); mainret = WinMain( #endif /* WPRFLAG */ GetModuleHandleA(NULL), NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT ); #else /* _WINMAIN_ */ #ifdef WPRFLAG __winitenv = _wenviron; mainret = wmain(__argc, __wargv, _wenviron); #else /* WPRFLAG */ __initenv = _environ; mainret = main(__argc, __argv, _environ); #endif /* WPRFLAG */ #endif /* _WINMAIN_ */ exit(mainret); } __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) ) { /* * Should never reach here */ _exit( GetExceptionCode() ); } /* end of try - except */ } /*** *_amsg_exit(rterrnum) - Fast exit fatal errors * *Purpose: * Exit the program with error code of 255 and appropriate error * message. * *Entry: * int rterrnum - error message number (amsg_exit only). * *Exit: * Calls exit() (for integer divide-by-0) or _exit() indirectly * through _aexit_rtn [amsg_exit]. * For multi-thread: calls _exit() function * *Exceptions: * *******************************************************************************/ void __cdecl _amsg_exit ( int rterrnum ) { #ifdef _WINMAIN_ if ( __error_mode == _OUT_TO_STDERR ) #else /* _WINMAIN_ */ if ( __error_mode != _OUT_TO_MSGBOX ) #endif /* _WINMAIN_ */ _FF_MSGBANNER(); /* write run-time error banner */ _NMSG_WRITE(rterrnum); _aexit_rtn(255); /* write message */ /* normally _exit(255) */ } /*** *fast_error_exit(rterrnum) - Faster exit fatal errors * *Purpose: * Exit the process with error code of 255 and appropriate error * message. * *Entry: * int rterrnum - error message number (amsg_exit only). * *Exit: * Calls ExitProcess. * *Exceptions: * *******************************************************************************/ static void __cdecl fast_error_exit ( int rterrnum ) { #ifdef _WINMAIN_ if ( __error_mode == _OUT_TO_STDERR ) #else /* _WINMAIN_ */ if ( __error_mode != _OUT_TO_MSGBOX ) #endif /* _WINMAIN_ */ _FF_MSGBANNER(); /* write run-time error banner */ _NMSG_WRITE(rterrnum); ExitProcess(255); /* write message */ /* normally _exit(255) */ } #ifndef WPRFLAG #endif /* WPRFLAG */ #endif /* CRTDLL */ #else /* _WIN32 */ #include #include #include #include #include #include #include #include #include #include #include #include #include <cruntime.h> <internal.h> <stdlib.h> <msdos.h> <string.h> <setjmp.h> <dbgint.h> <macos\types.h> <macos\segload.h> <macos\gestalte.h> <macos\osutils.h> <macos\traps.h> <mpw.h> static void __cdecl Inherit(void); /* local function */ int __cdecl main(int, char **, char **); /*generated by compiler*/ unsigned long _GetShellStack(void); static char * __cdecl _p2cstr_internal ( unsigned char * str ); extern MPWBLOCK * _pMPWBlock; extern int __argc; extern char **__argv; /*** *__crt0() * *Purpose: * This routine does the C runtime initialization, calls main(), and * then exits. It never returns. * *Entry: * *Exit: * This function never returns. * *******************************************************************************/ void __cdecl __crt0 ( ) { int mainret; char szPgmName[32]; char *pArg; char *argv[2]; #ifndef _M_MPPC void *pv; /* This is the magic stuff that MPW tools do to get info from MPW*/ pv = (void *)*(int *)0x316; if (pv != NULL && !((int)pv & 1) && *(int *)pv == 'MPGM') { pv = (void *)*++(int *)pv; if (pv != NULL && *(short *)pv == 'SH') { _pMPWBlock = (MPWBLOCK *)pv; } } #endif /* _M_MPPC */ _environ = NULL; if (_pMPWBlock == NULL) { __argc = 1; memcpy(szPgmName, (char *)0x910, sizeof(szPgmName)); pArg = _p2cstr_internal(szPgmName); argv[0] = pArg; argv[1] = NULL; __argv = argv; #ifndef _M_MPPC _shellStack = 0; #endif /* _M_MPPC */ } #ifndef _M_MPPC else { _shellStack = _GetShellStack(); _shellStack += 4; __argc = _pMPWBlock->argc; __argv = _pMPWBlock->argv; #endif Inherit(); } /* _M_MPPC */ /* force ExitToShell */ //return current a6, or first a6 //a6 + 4 is the stack pointer we want /* Inherit file handles - env is set up by _envinit if needed */ /* * call run time initializer */ __cinit(); mainret = main(__argc, __argv, _environ); exit(mainret); } #ifndef _M_MPPC /*** *Inherit() - obtain and process info on inherited file handles. * *Purpose: * * Locates and interprets MPW std files. For files we just save the * file handles. For the console we save the device table address so * we can do console I/O. In the latter case, FDEV is set in the _osfile * array. * *Entry: * Address of MPW param table * *Exit: * No return value. * *Exceptions: * *******************************************************************************/ static void __cdecl Inherit (void ) { MPWFILE *pFile; int i; pFile = _pMPWBlock->pFile; if (pFile == NULL) { return; } for (i = 0; i < 3; i++) { switch ((pFile->pDevice)->name) { case 'ECON': _osfile[i] |= FDEV | FOPEN; _osfhnd[i] = (int)pFile; break; case 'FSYS': _osfile[i] |= FOPEN; _osfhnd[i] = (*(pFile->ppFInfo))->ioRefNum; break; } pFile++; } } #endif /* _M_MPPC */ static char * __cdecl _p2cstr_internal (unsigned char * str) { int cch; unsigned char *pchSrc; unsigned char *pchDst; if ( str && *str ) { pchDst = str; pchSrc = str + 1; for ( cch=*pchDst; cch; --cch ) { *pchDst++ = *pchSrc++;} *pchDst = '\0'; } return( str ); } #endif /* _WIN32 */ Assembler Mnemonische Codes in Assembler: Ein gespeichertes Maschinenprogramm besteht aus einer Folge von Bitmustern. Der Reihe nach holt sich der Prozessor das nächste Bitmuster ( den nächsten Befehl ). Ein Befehl für den Prozessor ist ein Bitmuster, das der Prozessor interpretiert ( "versteht" ). Ein Programm erstellen heißt, für den Prozessor die richtige Folge von Bitmuster-Befehlen erstellen und speichern. Das Bitmuster für ca. 100 OpCode-Befehle sind unübersichtlich. Jedem Bitmuster des Maschinen-Befehlsvorrates wird ein lesbares Kurzwort ( OpCode, Assembler-Befehl ) zugeordnet. Zu jedem Befehl in Assembler gehört ein Mikroprozessor-Befehl. Jede Prozessorfamilie hat eigene Bit-Befehlsmuster und somit eigene Assembler-Befehle. Ein Mnemonik ist die Bezeichnung des in Assembler verwendeten Ein Befehlskürzels ( meist 3 bis 4 Zeichen ) beschreibt die Prozessor-Operation eines Maschinen-Befehls und wird auch als Mnemonik bezeichnet. Ein moderner Computer ist ein komplexes System von Komponenten. Diese tauschen mit elektrischen Signalen Informationen aus. Um die grundlegenden Funktionen zu verstehen, benötigen wir ein einfaches Modell. Ein grundlegendes Modell besteht aus Prozessor, Speicher und allen anderen Komponenten. Auch der Prozessor enthält einige, wenige, interne Speicher ( Register ). Die Prozessor - Befehle stehen als Bitmuster im Speicher und bilden das Maschinen - Programm. Eine Maschinen - Befehl kann nur vom Prozessor ausgeführt werden. Ein Programm wird ausgeführt, wenn nacheinander Maschinen - Befehle ( OpCode ) von Speicher zum Prozessor geschickt werden und der Prozessor diese Befehle ausführt. Das Programm bleibt im Speicher erhalten. Auf die Leitungen ( Datenbus ) zwischen Speicher und Prozessor wird immer eine Kopie des OpCodes gelegt. Wurde ein Befehl ausgeführt ( interpretiert ), so holt sich der Prozessor den nächsten Befehl aus dem Speicher. Die Prozessor - Frequenz und Bus - Frequenz bestimmen die Geschwindigkeit der Befehls Ausführung und Befehls - Übertragung. Enviroment Prozessor Speicher Die Assemblerbefehle sind einfach aufgebaut. Beim Intel 80x86 kann ein Assemblerbefehl durch folgendes Schema beschrieben werden: [Präfix] Mnemonik [Operand 1] [, Operand 2] ● ● ● ● ● Der Maschinencode bildet ein Maschinenprogramm Der Maschinencode steuert den Prozessor Der Maschinencode besteht aus OpCode An dem Bitmuster des OpCode erkennt der Prozessor den Befehl Der OpCode wird mit Binärziffern ( Bin : 0, 1 ) oder Hexa- Dezimal - Ziffern ( Hex : 0, 1, 2, ..., 9, A, B, C, D, E, F ) angegeben. Beispiel eines Assemblerbefehls Soll in das AX - Register des Prozessors eine 10 geschieben werden, so muß das Bitmuster "1011 1000 1010 000 000 000" ( bzw. die Hex-Zahlen "B8 0A 00" mit einem Hex nach Binär - Wandlung ) im Speicher hinterlegen werden. Es wird ein Übersetzungsprogramm ( Assembler ) benutzt, das die Mnemoniks in das Bitmuster umwandelt. In Assembler-Quelltext wird z.B. "MOV AX, 0Ah" geschrieben. Mit Hilfe eines Übersetzungsprogrammes ( Assembler ) wird diese ( dem Menschen eher verständliche Kurz- ) Schreibweise in ein Bitmuster umgewandelt, das von dem Prozessor "verstanden" wird. Ein solches kurzes Bitmuster im Speicher ( Maschinenprogramm ) hat z.B. die folgende Darstellung, wobei beim Assembler-Programm die Mnemonics benutzt werden: Programm in Speicher ( RAM ) Bin: 0001 1110 1011 1000 0000 0000 0000 0000 0101 0000 1111 1100 1000 1100 1100 1000 Hex: 1E B8 Mnemonics: PUSH DS 00 00 MOV AX, 0 50 FC PUSH AX CLD 8C C8 MOV AX, CS Inline-Assembler Kleinere Teile von großen Projekte werden in Assembler ( heute meistens Inline-Assembler ) geschrieben. Gründe sind: ● ● ● Optimierung der Geschwindigkeit von kritischen Teilen, direkten Hardware-Zugriff ( device driver ), für prolog/epilog - Code von naked - Calls. Die folgenden Schreibweisen sind möglich: __asm { mov al, 2 mov dx, 0xD007 out al, dx } // oder __asm mov al, 2 __asm mov dx, 0xD007 __asm out al, dx // oder __asm mov al,2 __asm mov dx,0xD007 __asm out al,dx Beim Inline - Assembler können verwendet werden: ● ● ● ● ● ● Symbole ( einschließlich Labels, Variablen, Funktionsnamen ), Konstanten ( einschließlich Symbolischen Konstanten und Enum ), Macros und Preprocessor - Direktiven, Kommentare ( /* */ und // ), type Namen ( falls MASM Type ), typedef Namen ( Operatoren wie PTR, TYPE oder spezifischen Structure oder union members ), Die folgenden Ergebnisee ( LENGTH, SIZE, TYPE ) beziehen sich auf int arr[8]: int arr[8]; __asm C/C++ Ergebnis LENGTH arr sizeof(arr)/sizeof(arr[0]) 8 SIZE arr sizeof(arr) 16 TYPE arr sizeof(arr[0]) 2 Den Zugriff auf C/C++ - Variablen zeigt das folgende Beispiel: int var = 100; // C __asm mov eax, var // Inline - Assembler Soll in das 6. Element des int array[8] - Array die Zahl 100 geschrieben werden, so kann dies etwa gemäß __asm C/C++ __asm mov array[6 * TYPE int], 100 array[6] = 100; erfolgen. Den Zugriff auf C/C++ - Strukturen zeigt das folgende Beispiel: struct T1 { char * p; int same; }; struct T2 { int xxxx; long same; }; struct T1 t1; struct T2 t2; __asm { mov ebx, OFFSET t1 mov ecx, [ebx]t1.same ; Must use t1 mov esi, [ebx].p ; Can omit t1 } Beispiel C/C++ - Macros können __asm Blöcke enthalten. #define PORTIO __asm { __asm mov al, 2 __asm mov dx, 0xD007 __asm out al, dx } \ \ \ \ \ Obwohl die {} - Klammern gesetzt sind, so werden die letzten drei __asm werden benötigt, weil ein C/C++ - Macro in einer einzigen logischen Text - Zeile expandiert. Ein C - Macro- __asm Block kann Argumente enthalten, aber keine Rückgabewerte, d.h. diese Macros können nicht in einem C - Ausdruck verwendet werden. Die _emit Pseudo - Instruktion ist ähnlich zu der DB - Assembler - Direktiven. Mit _emit kann an der aktuellen Code - Stelle ( im Text - Segment ) ein Byte hinterlegt werden. Beispiel $ entspricht der aktuellen Adresse. Durch jne $+5 kann ein far - Jump übersprungen werden. jne $+5 jmp farLabel // hier ist $+5 . . . farLabel: Beispiel #define randasm __asm _emit 0x4A __asm _emit 0x43 __asm _emit 0x4B . . __asm { randasm } Beispiel Verwendet eine C/C++ - Funktion Inline - Assembler - Instruktionen, so können die Register ● ● ● ● ● EAX, EBX, EDX ohne Store/Restore bei __stdcall, ECX, EDX mit Store/Restore bei __fastcall, ECX mit Store/Restore für this bei #ifdef __cplusplus und __stdcall, EDS, ESS, EES, ESP, EBP mit Store/Restore, ( ESI, EDI auch STD/CLD ) mit Store/Restore verwendet werden. #include <stdio.h> int power2( int num, int power ) { __asm { mov eax, num mov ecx, power shl eax, cl } /* Return with result in EAX */ } void main( void ) { printf( "3 * 2^5 ist %d\n", power2( 3, 5) ); } Beispiel Das folgende Inline - Assembler - Stück ruft printf() auf. Die C - Bibliotheks - Funktionen ( C library functions ) sind mit extern "C" gebunden ( gelinkt ). #include <stdio.h> char format[] = "\n%s %s"; char hallo[] = "Hallo"; char welt[] = "Welt"; void main( void ) { __asm { mov eax, offset welt push eax mov eax, offset hallo push eax mov eax, offset format push eax call printf } } Dies entspricht dem C - Aufruf printf( "\n%s %s", "Hallo", "Welt" ). Die Parameter werden von rechts nach links auf den Stack gelegt. Wegen dem this - Parameter können überladene C++ - Funktionen i.a. nicht Anmerkung: Win16 unterscheidet verschiedene Speicher - Modelle ( Tiny, Small, Medium, Compact, Large, Hughe ). Diese Modelle ermöglichen 2 Byte - und 4 - Byte Adressenbildung ( Zeiger ). Kurze Sprünge sind schneller. Bei Win32 werden lineare Adressen ( 4 Byte je Adresse ) verwendet. jmp weiter ... weiter: Folgendes Beispiel zeigt den direkten Win16 - Speicherzugriff mittels Inline Assembler ( für Microsoft C muß asm durch _asm ersetzt werden ). Ein Speichebereich wird von der Adresse * src ( source ) zur Zielstelle *dst ( Destination ) kopiert. void ram_move ( void * asm push ds asm lds si, src asm les di, dst asm mov cx, anz_byte asm cld asm shr cx,1 asm rep movsw asm adc cx,cx asm pop ds } src, void * dst, int anz_byte) { // // // // // aufsteigend // cx = Anzahl der Worte, cx-// bis cx != 0 // cx = carry => Anzahl der Worte gerade oder ungerade ? Windows-Parameter-Übergabe Auf Maschinenebene werden C/C++Parameter werden i.a. vor der Rücksprungadresse der Funktion auf den User-Stack gelegt. ● ● ● ● ● ● ● ● Der Win32 - Compiler generiert Prolog- und Epilog-Code. Mit Naked Function Calls kann der Prolog - und Epilog - Code geändert werden. Die Parameter einer Funktion werden von rechts nach links auf den Stack gepushed. Bei Funktionen müssen die Register ESI, EDI, EBX, EBP gesichert werden. Alle Argumente werden auf 32 - Bit - Grenzen erweitert. Rückgabe - Werte ( <= 4 Byte ) werden auf 32 - Bit - Grenzen erweitert ( EAX ). Rückgabe - Strukturen ( <= 8 Byte ) werden in EDX:EAX zurück gegeben. Rückgabe - Strukturen ( > 8 Byte ) werden mit EAX als Zeiger zurück gegeben. Die folgende Tabelle zeigt für Win32 die __cdecl, __stdcall, __fastcall - Unterschiede. Keyword Parameter __cdecl von rechts nach links auf Stack __stdcall von rechts nach links auf Stack __fastcall in Register, Rest auf Stack C++ mit this von rechts nach links auf Stack, this in ECX Beispiel void _cdecl foo(char c, short s, int i, double f ); foo( 'x', 12, 8192, 2.7183 ); _foo ECX : nicht benutzt EDX : nicht benutzt -------|------|------|------|------|-------------| Stack: |retAdr| x | 12 | 8192 | 2.7183 | -------|------|------|------|------|-------------| ESP + | 00 | 04 | 08 | 0C | 10 | 14 | -------|------|------|------|------|-------------| void __stdcall foo(char c, short s, int i, double f ); foo( 'x', 12, 8192, 2.7183 ); _foo@20. ECX : this(thiscall) EDX : nicht benutzt -------|------|------|------|------|-------------| Stack: |retAdr| x | 12 | 8192 | 2.7183 | -------|------|------|------|------|-------------| ESP + | 00 | 04 | 08 | 0C | 10 | 14 | -------|------|------|------|------|-------------| void __fastcall foo(char c, short s, int i, double f ); foo( 'x', 12, 8192, 2.7183 ); ECX: x EDX: 12 -------|------|------|------|------| Stack: |retAdr| 8192 | 2.7183 | -------|------|------|------|------| ESP + | 00 | 04 | 08 | 0C | -------|------|------|------|------| Vor einem Funktions - Aufruf werden die Parameter auf den Stack des aufrufenden Programmes gelegt. Eine DLL - Funktion benutzt den Stack des aufrufenden Programmes. Für Win3.x gilt die folgende Tabelle: Funktion CDCL PASCAL C++ Bei dynamischer C++ - Bindung wird vor der Rücksprungadresse zusätzlich der this - Zeiger. auf den Stack gelegt. int fkt ( int i, int j ) Zuerst wird j dann i auf den Stack gelegt, dann die Rücksprungadresse. Weil die Stackkorrektur im aufrufenden Programm erfolgt, kann die Parameter - Anzahl variieren ( ... ). Der Assembler-Name der Funktion ist _fkt Zuerst wird i dann j auf den Stack gelegt, dann die Rücksprungadresse. Weil die Stackkorrektur in der aufgerufenen Funktion erfolgt, kann die Parameteranzahl nicht variieren. Der Assembler-Name der Funktion ist FKT Ein eindeutiger Funktionsname von int fkt ( int i, int j ) wird durch das aneinander fügen von fkt$int$int gebildet. Ein Überladen des Funktionsnamen fkt bedeutet, daß zwar der gleiche Name fkt aber andere Parametertypen oder andere Parameterfolgen verwendet werden. Dadurch ergeben sich im Überladungsfall eindeutige Maschinenadressen. Der Assembler-Name der Funktion ist fkt$int$int Win3.x verwendet ( praktisch immer ) PASCAL deklarierte Funktionen. Link zum main()-Start-Up-Code Dank an Mike Schmit! Top Ten Rules for Pairing Pentium Instructions 1. Both instructions must be simple. 2. Shifts or rotates can only pair in the U pipe. (SHL, SHR, SAL, SAR, ROL, ROR, RCL or RCR) 3. ADC and SBB can only pair in the U pipe. 4. JMP, CALL and Jcc can only pair in the V pipe. (Jcc = jump on condition code). 5. Neither instruction can contain BOTH a displacement and an immediate operand. For example: mov mov [bx+2], 3 mem1, 4 ; 2 is a displacement, 3 is immediate ; mem1 is a displacement, 4 is immediate 6. Prefixed instructions can only pair in the U pipe. This includes extended instructions that start with 0Fh except for the special case of the 16-bit conditional jumps of the 386 and above. Examples of prefixed instructions: mov mov mov ES:[bx], eax, [si] ax, [esi] ; 32-bit operand in 16-bit code segment ; 16-bit operand in 32-bit code segment 7. The U pipe instruction must be only 1 byte in length or it will not pair until the second time it executes from the cache. 8. There can be no read-after-write or write-after-write register dependencies between the instructions except for special cases for the flags register and the stack pointer (rules 9 and 10). mov add mov mov ebx, 2 ; writes to EBX ecx, ebx ; reads EBX and ECX, writes to ECX ; EBX is read after being written, no pairing ebx, 1 ; writes to EBX ebx, 2 ; writes to EBX ; write after write, no pairing 9. The flags register exception allows an ALU instruction to be paired with a Jcc even though the ALU instruction writes the flags and Jcc reads the flags. For example: cmp je dec jnz al, 0 addr cx loop1 ; ; ; ; CMP modifies the flags JE reads the flags, but pairs DEC modifies the flags JNZ reads the flags, but pairs 10. The stack pointer exception allows two PUSHes or two POPs to be paired even though they both read and write to the SP (or ESP) register. push eax ; ESP is read and modified push ebx ; ESP is read and modified, but still pairs Simple Instructions (for Pentium pairing) The following is a list of simple instructions, as required by rule #1 above. Instruction format 16-bit example 32-bit example -----------------------------------------------------------MOV reg, reg mov ax, bx mov eax, edx MOV reg, mem mov ax, [bx] mov eax, [edx] MOV reg, imm mov ax, 1 mov eax, 1 MOV mem, reg mov [bx], ax mov [edx], eax MOV mem, imm mov [bx], 1 mov [edx], 1 alu reg, reg add ax, bx cmp eax, edx alu reg, mem add ax, [bx] cmp eax, [edx] alu reg, imm add ax, 1 cmp eax, 1 alu mem, reg add [bx], ax cmp [edx], eax alu mem, imm add [bx], 1 cmp [edx], 1 where alu = add, adc, and, or, xor, sub, sbb, cmp, test INC INC DEC DEC PUSH POP LEA JMP CALL Jcc reg mem reg mem reg reg reg, mem near near near inc inc dec dec push pop lea jmp call jz ax var1 bx [bx] ax ax ax, [si+2] label proc lbl inc inc dec dec push pop lea jmp call jnz eax [eax] ebx var2 eax eax eax, [eax+4*esi+8] lable2 proc2 lbl2 where Jcc = ja, jae, jb, jbe, jg, jge, jl, jle, je, jne, jc, js, jnp, jo, jp, jnbe, jnb, jnae, jna, jnle, jnl, jnge, jng, jz, jnz, jnc, jns, jpo, jno, jpe NOP shift shift shift shift reg, mem, reg, mem, 1 1 imm imm nop shl shr sal sar ax, 1 [bx], 1 ax, 2 ax, 15 nop rcl rcr rol ror eax, 1 [ebx], 1 esi, 2 [esi], 31 where shift = shl, shr, sal, sar, rcl, rcr, rol, ror Notes: ● ● ● rcl and rcr are not pairable with immediate counts other than 1 all memory-immediate (mem, imm) instructions are not pairable with a displacement in the memory operand instructions with segment registers are not pairable Pentium® Optimization Cross-Reference by Instruction The following is a list of optimizations that may come in handy. Each one is listed alphabetically (more or less) in the first column. The second column lists the CPU or CPU's that this optimization is applicable to; alternatively it may be noted as applicable to 16-bit code or 32-bit code. The third column contains one or more replacement sequences of code that is either faster or smaller (sometimes both) than the first column. For some obscure optimizations, the action of the first column instruction is explained. The forth column contains a description and/or examples. replacement instruction CPU's or action description/notes --------------------------------------------------------------------------aad (imm8) all AL = AL+(AH*imm8) AH = 0 If imm8 is blank uses 10. AAD is almost always slower, but only 2 bytes long. aam (imm8) all AH = AL/imm8 AL = AL MOD imm8 Same as AAD. add 16-bit lea reg, [reg+reg+disp] Use LEA to add base + index + displacement Also preserves flags; for example: add bx, 4 can be replaced by: lea bx, [bx+4] when the flags must not be changed. add 32-bit lea reg, [reg+reg*scale+disp] Use LEA to add base + scaled index + disp Also preserves flags. (See previous example). The 32-bit form of LEA is much more powerful than the 16-bit version because of the scaling and the fact that almost all of the 8 General purpose registers can be used as base and index registers. and reg, reg Pent test reg, reg Use TEST instead of AND on the Pentium because fewer register conflict will result in better pairing bswap Pent ror eax, 16 Pairs in U pipe, BSWAP doesn't pair. disadvantage: modifies flags (Not a direct replacement) call dest1 jmp dest2 286+ push offset dest2 jmp dest1 When CALL is followed by a JMP, change the return address to the JMP destination. call dest1 ret all jmp When a CALL is followed by a RET, the CALL can be replaced by a JMP. cbw 386+ mov ah, 0 When you know AL < 128 use MOV AH, 0 for speed. But use CBW for smaller code size. cdq 486+ xor edx, edx When you know EAX is positive Faster, better pairing. dest1 disadvantage: modifies flags Pent mov edx, eax sar edx, 31 When EAX value could be positive or negative because of better pairing cmp mem, reg 286 cmp reg, mem reg, mem is 1 cycle faster cmp reg, mem 386 cmp mem, reg mem, reg is 1 cycle faster dec reg16 lea reg16, [reg16 - 1] Use to preserve flags for BX, BP, DI, SI dec reg32 lea reg32, [reg32 - 1] Use to preserve flags for EAX, EBX, ECX, EDX EDI, ESI, EBP div <op> 8088 shr accum, 1 When <op> resolves to 2, use shift for division. (use CL for 4, 8, etc.) div <op> 186+ shr accum, n When <op> resolves to a power of 2 use shifts for division. enter imm16, 0 286+ push bp mov bp, sp sub sp, imm16 386+ 32-bit push ebp mov ebp, esp sub esp, imm16 ENTER is always slower and 4 bytes in length if imm16 = 0 then push/mov is smaller inc reg16 lea reg16, [reg16 + 1] inc reg32 lea reg32, [reg32 + 1] jcxz <dest>: 486+ test cx, cx je <dest>: Use to preserve flags for BX, BP, DI, SI Use to preserve flags for EAX, EBX, ECX, EDX EDI, ESI, EBP JCXZ is faster and smaller on 8088-286. On the 386 it is the about the same speed test ecx, ecx je <dest>: Never use JCXZ on 486 or Pentium except for compactness 8088-286 mov reg, OFFSET mem MOV reg, imm is faster on 8088 - 286. 386+ they are the same. lea reg, mem 486+ Note: There are many uses for LEA, see: add, inc, dec, mov, mul leave 486+ mov sp, bp pop bp mov esp, ebp pop ebp LEAVE is only 1 byte long and is faster on the 186-386. The MOV/POP is much faster on 486 and Pentium lodsb 486+ mov al, [si] inc si LODS is only 1 byte long and is faster on 8088-386, much slower on the 486. On the Pentium the MOV/INC or MOV/ADD instructions pair, taking only 1 cycle. lodsw 486+ mov ax, [si] add si, 2 see lodsb lodsd 486+ mov eax, [esi] add esi, 4 see lodsb dec cx jnz <dest>: LOOP is faster and smaller on 8088-286. on 386+ DEC/JNZ is much faster. On the Pentium the DEC/JNZ instructions pair taking only 1 cycle. loop <dest>: 386+ loopd <dest>: dec ecx jnz <dest>: loopXX <dest>: 486+ ( XX = e,ne,z or nz) je $+5 dec cx jnz <dest>: loopdXX <dest>: je $+5 dec ecx jnz <dest>: 486+ The 3 replacement instructions are much faster on the 486+. LOOPxx is smaller and faster on 8088-286 The speed is about the same on the 386. mov reg2, reg1 286+ followed by: inc/dec/add/sub reg2 lea reg2, [reg1+n] LEA is faster, smaller and preserves flags. This is a way to do a MOV and ADD/SUB of a constant, n. mov acc, reg xchg acc, reg Use XCHG for smaller code when one of the registers all final value can be ignored. Note that acc = AL, AX or EAX. mov mem, 1 Pent lea bx, mem mov [bx], 1 mov ax, 1 mov mem, ax mov [bx+2], 1 Pent mov ax, 1 mov [bx+2], ax Displacement/immediate does not pair. LEA/MOV can be used if other code can be placed inbetween to prevent AGI's. MOV/MOV may be easier to pair. Better pairing because displacement/immediate instructions do not pair. lea bx, [bx+2] mov [bx], 1 movsb 486+ mov inc mov inc al, [si] si [di], al di MOVS is faster and smaller to move a single byte, word or dword on the 8088-386. On the 486+ the MOV/INC method is faster. NOTE: REP MOVS is always faster to move a large block. movsw 486+ mov add mov add ax, [si] si, 2 [di], ax di, 2 see MOVSB movsd 486+ mov add mov add eax, [esi] esi, 4 [edi], eax edi, 4 see MOVSB movzx r16, rm8 486+ xor bx, bx mov bl, al movzx r32, rm8 486+ xor ebx, ebx mov bl, al movzx r32, rm16 486+ xor ebx, ebx mov bx, ax mul n 8088+ shl ax, cl Use shifts or ADDs instead of multiply when n is a power of 2 mul n Pent add ax, ax ADD is better than single shift because it pairs better. mul 32-bit lea Use LEA to multiply by 2, 3, 4, 5, 7, 8, 9 MOVZX is faster and smaller on the 386. On the 486+ XOR/MOV is faster. Possible pairing on the Pentium. (source can be reg or mem) disadvantage: modifies flags lea eax, [eax+eax*4] (ex: multiply EAX * 5) LEA is better than SHL on the Pentium because it pairs in both pipes, SHL pairs only in the U pipe. or reg, reg Pent test reg, reg Better pairing because OR writes to register. (This is for src = dest.) pop mem 486+ pop reg mov mem, reg Faster on 486+ Better pairing on Pentium push mem 486+ mov reg, mem push reg Faster on 486 Better pairing on Pentium pushf 486+ rcr reg, 1 To save only the carry flag use a rotate (RCR or RCL) into a register. RCR and RCL are pairiable (U pipe only) and take 1 cycle. PUSHF is slow and not pairable. or rcl reg, 1 popf 486+ rcl reg, 1 or rcr reg, 1 To restore only the carry flag. See PUSHF. rep scasb Pent loop1: mov al, [di] inc di cmp al, reg2 je exit dec cx jnz loop1 exit: REP SCAS is faster and smaller on 8088-486. Expanded code is faster on Pentium due to pairing. shl reg, 1 Pent add reg, reg ADD pairs better. SHL only pairs in the U pipe. stosb 486+ mov [di], al inc di stosw 486+ mov [di], ax add di, 2 STOS is faster and smaller on the 8088-286, and the same speed on the 386. On the 486+ the MOV/INC is slightly faster. stosd 486+ mov [edi], eax add edi, 4 REP STOS is faster on 8088-386. MOV/INC or MOV/ADD is faster on the 486+ Note: use LEA SI, [SI+n] to advance LEA without changing the flags. xchg all xchg reg1, reg2 Pent Use xchg acc, reg to do a 1 byte MOV when one register can be ignored. push push pop pop reg1 reg2 reg1 reg2 pushes and pops are 1 cycle faster on Pentium due to pairing. disadvantage: uses stack Pent mov mov mov reg3, reg1 reg1, reg2 reg2, reg3 xlatb 486+ mov bh, 0 mov bl, al mov al, [bx] xlatb 486+ xor ebx, ebx mov bl, al mov al, [ebx] Faster and better pairing if reg3 is available. XLAT is faster and smaller on 8088-386. MOV's are faster on 486+. Best to rearrange instructions to prevent AGI's and get pairing on Pentium. Force high part of BX/EBX to zero outside of loop. disadvantage: modifies flags 80x86 Integer Instruction Set (8088 - Pentium) Legend: General reg = r8 = r16 = r32 = imm = imm8 = imm16 = mem = mem8 = mem16 = mem32 = mem48 = dest = short = acc = AL, AX or EAX unless specified otherwise any general register any 8-bit register any general purpose 16-bit register any general purpose 32-bit register immediate data 8-bit immediate data 16-bit immediate data memory address address of 8-bit data item address of 16-bit data item address of 32-bit data item address of 48-bit data item 16/32-bit destination 8-bit destination Integer instruction timings: n - generally refers to a number of repeated counts m - in a jump or call; 286: bytes in next instruction 386/486: number of components (each byte of opcode) + 1 (if immed data) + 1 (if displacement) EA = cycles to calculate the Effective Address 8088/8086: base = 5 BP+DI or BX+SI = 7 BP+DI+disp or BX+SI+disp = 11 index = 5 BX+DI or BP+SI = 8 BX+DI+disp or BP+SI+disp = 12 disp = 6 segment override = +2 286 - 486: base+index+disp = +1 all others, no penalty instruction length: The byte count includes the opcode length and length of any required displacement or immediate data. If the displacement is optional, it is shown as d() with the possible lengths in parentheses. If the immediate data is optional, it is shown as i() with the possible lengths in parentheses. pairing categories for NP = not pairable UV = pairable in the U PU = pairable in the U PV = pairable in the V Pentium: pipe or V pipe pipe only pipe only Instruction formats, clock cycles and Pentium® Pairing info AAA ASCII adjust after addition bytes 1 Example: 8088 8 186 8 286 3 386 4 486 3 Pentium 3 NP AAD aaa ASCII adjust AX before division (second byte is divisor) bytes 2 Example: 8088 60 186 15 286 14 386 19 486 14 Pentium 10 NP AAM aad ASCII adjust AX after multiply (second byte is divisor) bytes 2 Example: 8088 83 186 19 286 16 386 17 486 15 Pentium 18 NP AAS aam ASCII adjust AL after subtraction bytes 1 Example: 8088 8 186 7 286 3 386 4 486 3 Pentium 3 NP ADC 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 Pentium 1 PU 3 PU 2 PU 1 PU 3 PU* 4 3 2 1 aas Integer add with carry operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 4 1 PU * = not pairable if there is a displacement and immediate Example: ADD adc eax, ebx Integer addition operands bytes 8088 186 286 386 486 Pentium reg, mem, reg, reg, mem, reg reg mem imm imm acc, imm 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 3 24+EA 13+EA 4 23+EA 3 10 10 4 16 2 7 7 3 7 2 7 6 2 7 1 3 2 1 3 1 3 2 1 3 UV UV UV UV UV* 4 3 2 1 1 UV 4 * = not pairable if there is a displacement and immediate Example: AND add eax, ebx Logical AND operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 4 3 2 1 4 Pentium 1 UV 3 UV 2 UV 1 UV 3 UV* 1 UV * = not pairable if there is a displacement and immediate Example: ARPL and eax, ebx Adjust RPL field of selector (286+) operands reg, reg mem, reg Example: bytes 2 2+d(0-2) BOUND arpl 286 10 11 386 20 21 486 9 9 Pentium 7 NP 7 NP 386 10 486 7 Pentium 8 NP 386 10+3n 10+3n 10+3n 10+3n 486 6-42 6-42 7-43 7-43 Pentium 6-34 NP 6-42 NP 6-35 NP 6-43 NP 386 10+3n 10+3n 10+3n 10+3n 486 6-103 7-104 6-103 7-104 Pentium 7-39 NP 7-71 NP 7-40 NP 7-72 NP ax, bx Check array index against bounds (186+) operands reg, mem Example: bytes 4 BSF bound 186 35 286 13 bx, array Bit scan forward (386+) operands r16, r16 r32, r32 r16, m16 r32, m32 Example: bytes 3 3 3+d(0,1,2) 3+d(0,1,2,4) BSR bsf eax, [esi] Bit scan reverse (386+) operands r16, r16 r32, r32 r16, m16 r32, m32 Example: BSWAP bytes 3 3 3+d(0,1,2) 3+d(0,1,2,4) bsr eax, [esi] Byte swap (486+) operand r32 Example: bytes 2 BT bswap 486 1 Pentium 1 NP 386 3 12 3 6 486 3 8 3 3 Pentium 4 NP 9 NP 4 NP 4 NP 386 6 13 6 8 486 6 13 6 8 Pentium 7 NP 13 NP 7 NP 8 NP eax Bit test (386+) operands reg, reg mem, reg reg, imm8 mem, imm8 Example: BTC bytes 3 3+d(0,1,2,4) 3+i(1) 3+d(0,1,2,4)+i(1) bt eax, 4 Bit test and complement (386+) operands reg, reg mem, reg reg, imm8 mem, imm8 bytes 3 3+d(0,1,2,4) 3+i(1) 3+d(0,1,2,4)+i(1) Example: BTR btc eax, 4 Bit test and reset (386+) operands reg, reg mem, reg reg, imm8 mem, imm8 Example: bytes 3 3+d(0,1,2,4) 3+i(1) 3+d(0,1,2,4)+i(1) BTS btr 386 6 13 6 8 486 6 13 6 8 Pentium 7 NP 13 NP 7 NP 8 NP 386 6 13 6 8 486 6 13 6 8 Pentium 7 NP 13 NP 7 NP 8 NP 386 7+m 7+m 10+m 17+m 22+m 486 3 5 5 18 17 Pentium 1 PV 2 NP 2 NP 4 NP 4 NP 386 34+m 38+m 486 20 20 Pentium 4-13 NP 5-14 NP eax, 4 Bit test and set (386+) operands reg, reg mem, reg reg, imm8 mem, imm8 Example: bytes 3 3+d(0,1,2,4) 3+i(1) 3+d(0,1,2,4)+i(1) CALL bts eax, 4 Call subroutine operand near reg mem16 far mem32 bytes 3 2 2+d(0-2) 5 2+d(0-2) 8088 23 20 29+EA 36 53+EA 186 14 13 19 23 38 286 7+m 7+m 11+m 13+m 16+m Protected Mode operand far mem32 bytes 5 2+d(0-2) 286 26+m 29+m cycles not shown for calls through call and task gates Example: CBW call my_function Convert byte to word bytes 1 Example: 8088 2 (AL --> AX) 186 2 286 2 386 3 486 3 Pentium 3 NP CWDE 386 3 486 3 Pentium 3 NP 386 2 486 3 Pentium 2 NP 386 2 486 3 Pentium 2 NP 386 2 486 2 Pentium 2 NP cbw Convert word to dword (386+) (AX --> EAX) bytes 1 Example: CWD cwde Convert word to double bytes 1 Example: 8088 5 (AX --> DX:AX) 186 4 286 2 CDQ cwd Convert double to quad (EAX --> EDX:EAX) bytes 1 Example: CLC cdq Clear the carry flag bytes 1 Example: 8088 2 186 2 286 2 CLD clc Clear the direction flag (set to forward direction) bytes 1 Example: cld 8088 2 186 2 286 2 386 2 486 2 Pentium 2 NP CLI Clear the interrupt flag (disable interrupts) bytes 1 Example: 8088 2 186 2 286 3 386 3 486 5 Pentium 7 NP CLTS 286 2 386 5 486 7 Pentium 10 NP 186 2 286 2 386 2 486 2 Pentium 2 NP 186 3 10 10 4 10 286 2 7 6 3 6 386 2 5 6 2 5 486 1 2 2 1 2 Pentium 1 UV 2 UV 2 UV 1 UV 2 UV* 4 3 2 1 cli Clear task switched flag in CR0 (286+) bytes 2 Example: CMC clts Complement carry flag bytes 1 Example: 8088 2 CMP cmc Compare two operands operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 13+EA 13+EA 4 14+EA 4 1 UV * = not pairable if there is a displacement and immediate Example: cmp CMPS/CMPSB/CMPSW/CMPSD variations cmpsb cmpsw cmpsd repX cmpsb repX cmpsw repX cmpsd bytes 1 1 1 2 2 2 eax, 3 Compare string operands 8088 30 9+30n 9+30n - 186 22 5+22n 5+22n - 286 8 5+9n 5+9n - 386 10 10 10 5+9n 5+9n 5+9n 486 8 8 8 7+7n* 7+7n* 7+7n* Pentium 5 NP 5 NP 5 NP 9+4n NP 9+4n NP 9+4n NP 486 6 7-10 Pentium 5 NP 6 NP repX = repe, repz, repne or repnz * : 5 if n = 0 Example: repne cmpsb CMPXCHG Compare and Exchange (486+) operands reg, reg mem, reg Example: bytes 3 3+d(0-2) cmpxchg ebx, edx CMPXCHG8B Compare and Exchange 8 bytes (Pentium+) operands mem, reg Example: bytes 3+d(0-2) Pentium 10 NP CPUID cmpxchg8b [ebx], edx CPU identification (Pentium+) bytes 2 Example: Pentium 14 NP DAA cpuid Decimal adjust AL after addition bytes 1 Example: 8088 4 186 4 286 3 386 4 486 2 Pentium 3 NP DAS 386 4 486 2 Pentium 3 NP daa Decimal adjust AL after subtraction bytes 1 Example: das 8088 4 186 4 286 3 DEC Decrement operand r8 r16 r32 mem bytes 2 1 1 2+d(0,2) 186 3 3 3 15 286 2 2 2 7 386 2 2 2 6 486 1 1 1 3 Pentium 1 UV 1 UV 1 UV 3 UV operand bytes 8088 186 r8 2 80-90 29 r16 2 144-162 38 r32 2 mem8 2+d(0-2) 86-96+EA 35 mem16 2+d(0-2) 150-168+EA 44 mem32 2+d(0-2) - 286 14 22 17 25 - 386 14 22 38 17 25 41 486 16 24 40 16 24 40 Pentium 17 NP 25 NP 41 NP 17 NP 25 NP 41 NP Example: DIV dec 8088 3 3 3 23+EA eax Unsigned divide implied dividend AX / DX:AX / EDX:EAX / operand byte word dword Example: ENTER div quotient = = = remainder AL AX EAX AH DX EDX ebx Make stack frame for procedure parameters (186+) operands bytes imm16, 0 3 imm16, 1 4 imm16, imm8 4 Example: ESC enter 8088 186 15 25 22+16n n = imm8-1; 286 11 15 12+4n i = imm8 386 10 12 15+4n 486 14 17 17+3i Pentium 11 NP 15 NP 15+2i NP 1, 0 Escape escape opcodes D8 - DF are used by floating point instructions HLT Halt bytes 1 Example: 8088 2 186 2 386 5 486 4 Pentium 4 NP 486 19 27 43 20 28 44 Pentium 22 NP 30 NP 46 NP 22 NP 30 NP 46 NP 486 13-18 13-26 13-42 13-18 13-26 13-42 Pentium 11 NP 11 NP 10 NP 11 NP 11 NP 10 NP hlt IDIV Signed divide operand bytes 8088 r8 2 101-112 r16 2 165-184 r32 2 mem8 2+d(0-2) 107-118+EA mem16 2+d(0-2) 171-190+EA mem32 2+d(0-2) - implied dividend AX / DX:AX / EDX:EAX / operand byte word dword Example: IMUL 286 2 idiv 186 44-52 53-61 50-58 59-67 - quotient = = = AL AX EAX 286 17 25 20 28 - 386 19 27 43 22 30 46 remainder AH DX EDX ebx Signed multiply Accumulator Multiplies operand bytes 8088 r8 2 80-98 r16 2 128-154 r32 2 mem8 2+d(0-2) 86-104+EA mem16 2+d(0-2) 134-160+EA mem32 2+d(0-2) - implied operand multiplicand (multiplier) AL AX * * byte word 186 25-28 34-37 32-34 40-43 - result = = AX DX:AX 286 13 21 16 24 - 386 9-14 9-22 9-38 12-17 12-25 12-41 EAX * Example: dword = imul EDX:EAX ebx 2 and 3 operand Multiplies operands r16, imm r32, imm r16,r16,imm r32,r32,imm r16,m16,imm bytes 186 2+i(1,2) 2+i(1,2) 2+i(1,2) 22/29 2+i(1,2) 2+d(0-2) 25/32 +i(1,2) 2+d(0-2)+i(1,2) 2+i(1,2) 2+i(1,2) 2+d(0-2)+i(1,2) 2+d(0-2)+i(1,2) r32,m32,imm r16, r16 r32, r32 r16, m16 r32, m32 286 386 486 21 9-14/9-22 13-18/13-26 9-38 13-42 21 9-14/9-22 13-18/13-26 9-38 13-42 24 12-17/12-25 13-18/13-26 - 12-41 9-22 9-38 12-25 12-41 all forms: dest, src or dest, src1, src2 Example: IN imul 13-42 13-18/13-26 13-42 13-18/13-26 13-42 cycles for: Pentium 10 NP 10 NP 10 NP 10 NP 10 NP 10 10 10 10 10 NP NP NP NP NP byte/word dword eax, ebx, 10 Input from port operands al, imm8 ax, imm8 eax, imm8 al, dx ax, dx eax, dx bytes 2 2 2 1 1 1 8088 14 14 12 12 - 186 10 10 8 8 - 286 5 5 5 5 - 386 12 12 12 13 13 13 486 14 14 14 14 14 14 Pentium 7 NP 7 NP 7 NP 7 NP 7 NP 7 NP 486 9/29/27 8/28/27 Pentium 4/21/19 NP 4/21/19 NP Protected mode operands acc, imm acc, dx bytes 2 1 386 6/26/26 7/27/27 cycles for: CPL <= IOPL / CPL > IOPL / V86 Example: INC in al, dx Increment operand r8 r16 r32 mem Example: bytes 2 1 1 2+d(0,2) 8088 3 3 3 23+EA inc 286 2 2 2 7 386 2 2 2 6 486 1 1 1 3 Pentium 1 UV 1 UV 1 UV 3 UV 486 17 17 17 Pentium 9 NP 9 NP 9 NP ebx INS/INSB/INSW/INSD variations insb insw insd 186 3 3 3 15 Input from port to string bytes 1 1 1 8088 - 186 14 14 - 286 5 5 - 386 15 15 15 Protected Mode bytes 1 386 486 Pentium 9/29/29 10/32/30 6/24/22 NP cycles for: CPL <= IOPL / CPL > IOPL / V86 Example: INT rep insb Call interrupt procedure operands 3 imm8 bytes 1 2 8088 72 71 186 45 47 286 23+m 23+m 386 33 37 486 26 30 Pentium 13 NP 16 NP Protected mode Example: INTO bytes 1 8088 - int 21h 186 - 286 386 (40-78)+m 59-99 Call interrupt procedure if overflow 486 44-71 Pentium 27-82 NP bytes 1 8088 4/73 186 4/48 286 3/24+m 386 3/35 486 3/28 Pentium 4/13 NP 486 44-71 Pentium 27-56 NP Protected mode bytes 1 286 386 (40-78)+m 59-99 Task switch clocks not shown Example: INVD into Invalidate data cache (486+) bytes 2 Example: 8088 - 186 - 286 - 386 - 486 4 Pentium 15 NP INVLPG 486 12 Pentium 25 NP 486 15 Pentium 8-27 NP 486 15 Pentium 10-27 NP 486 1/3 1/3 Pentium 1 PV 1 PV invd Invalidate TLB entry (486+) operands mem32 bytes 5 Example: IRET invlpg [eax] Return from interrupt bytes 1 8088 44 186 28 286 17+m 386 22 Task switch clocks not shown Example: IRETD iret 32-bit return from interrupt (386+) bytes 1 386 22 Task switch clocks not shown Example: Jcc iretd Jump on condition code operand near8 near16 bytes 2 3 8088 4/16 - 186 4/13 - cycles for: 286 3/7+m - 386 3/7+m 3/7+m no jump/jump conditional jump instructions: ja jae jb jbe jg jge jl jle jump jump jump jump jump jump jump jump je jne jc js jnp jo jp jnbe jnb jnae jna jnle jnl jnge jng jump jump jump jump jump jump jump jump jump if equal jump if not equal jz jnz jump if zero jump if not zero jump jump jump jump jump jnc jns jpo jno jpe jump jump jump jump jump Example: if if if if if if if if if if if if if above above or equal below below or equal greater greater or equal less less or equal carry sign no parity (odd) overflow parity (even) jne JCXZ/JECXZ operand dest dest JMP if if if if if not not not not not not not not below or equal below above or equal above less or equal less greater or equal greater not carry not sign parity odd not overflow parity even not_equal Jump if CX/ECX = 0 bytes 2 2 8088 6/18 - 186 5/16 - cycles for: Example: if if if if if if if if jcxz cx_is_zero Unconditional jump 286 4/8+m no jump/jump 386 5/9+m 5/9+m 486 5/8 5/8 Pentium 5/6 NP 5/6 NP operand short near far r16 mem16 mem32 bytes 2 3 5 2 2+d(0,2) 2+d(4) r32 mem32 mem48 2 2+d(0,2) 2+d(6) 8088 15 15 15 11 18+EA 24+EA 186 13 13 13 11 17 26 286 7+m 7+m 11+m 7+m 11+m 15+m 386 7+m 7+m 12+m 7+m 10+m 12+m 486 3 3 17 5 5 13 - - 7+m 10+m 12+m 5 5 13 - Pentium 1 PV 1 PV 3 NP 2 NP 2 NP 4 NP 2 2 4 NP NP NP cycles for jumps through call gates not shown Example: LAHF jmp target_address Load flags into AH bytes 1 Example: 8088 4 186 2 286 2 386 2 486 3 Pentium 2 NP LAR 286 14 16 - 386 15 15 16 16 486 11 11 11 11 Pentium 8 NP 8 NP 8 NP 8 NP 286 7 386 7 486 6 Pentium 4 NP 286 7 386 7 486 6 Pentium 4 NP 386 7 486 6 Pentium 4 NP 386 7 486 6 Pentium 4 NP 386 7 486 6 Pentium 4 NP 386 2 2 486 1-2 1-2 Pentium 1 UV 1 UV 386 4 486 5 Pentium 3 NP lahf Load access rights byte (286+) operands r16, r16 r32, r32 r16, m16 r32, m32 Example: bytes 3 3 3 3 LDS lar eax, ebx Load far pointer operands reg, mem Example: bytes 2+d(2) LES lds 8088 24+EA 186 18 si, ptr_1 Load far pointer operands reg, mem Example: bytes 2+d(2) LFS les 8088 24+EA 186 18 di, ptr_2 Load far pointer (386+) operands reg, mem Example: bytes 3+d(2,4) LGS lfs si, ptr_3 Load far pointer (386+) operands reg, mem Example: bytes 3+d(2,4) LSS lgs si, ptr_4 Load stack segment and offset operands reg, mem Example: bytes 3+d(2,4) LEA lss bp, ptr_5 Load effective address operands r16, mem r32, mem Example: LEAVE bytes 2+d(2) 2+d(2) 8088 2+EA - lea eax, [eax+ebx*2+3] 286 3 - High level procedure exit (186+) bytes 1 Example: LGDT 186 6 - 186 8 286 5 leave Load global descriptor table register (286+) operand mem48 Example: bytes 5 286 11 LIDT lgdt 386 11 486 11 Pentium 6 NP 486 11 Pentium 6 NP descriptor[ebx] Load interrupt descriptor table register (286+) operand mem48 Example: bytes 5 286 12 LLDT lidt 386 11 descriptor[ebx] Load local descriptor table register (286+) operand r16 mem16 Example: bytes 3 3+d(0-2) LMSW lldt 286 17 19 386 20 24 486 11 11 Pentium 9 NP 9 NP 286 3 6 386 10 13 486 13 13 Pentium 8 NP 8 NP 386 0 486 1 Pentium 1 NP ax Load machine status word (286+) operand r16 mem16 Example: bytes 3 3+d(0-2) LOCK lmsw ax Lock bus on next instruction (prefix) bytes 1 8088 2 186 2 286 0 (Note: xchg always is locked whether it is specified or not) Example: lock mov LODS/LODSB/LODSW/LODSD variations lodsb lodsw lodsd Example: bytes 1 1 1 Load string operand 8088 16 16 - 186 10 10 - 286 5 5 - 386 5 5 5 486 5 5 5 Pentium 2 NP 2 NP 2 NP 286 4/8+m 386 11+m 486 6/7 Pentium 5/6 NP 386 11+m 486 6/9 Pentium 7/8 NP 386 11+m 486 6/9 Pentium 7/8 NP 386 486 Pentium lodsb LOOP Loop control with CX counter operand short loopw short loopd short Example: operand short loopew loopzw looped loopzd bytes 2 8088 5/17 short short short short Example: loop_start Loop while equal (or zero) bytes 2 (uses (uses (uses (uses 8088 6/18 short short short short Example: 286 4/8 loop_start Loop while not equal (or not zero) operand bytes short 2 loopnew loopnzw loopned loopnzd 186 5/16 CX in 32-bit mode) CX in 32-bit mode) ECX in 16-bit mode) ECX in 16-bit mode) loope LOOPNE/LOOPNZ 186 5/15 (uses CX in 32-bit mode) (uses ECX in 16-bit mode) loop LOOPE/LOOPZ LSL mem, 1 (uses (uses (uses (uses 8088 5/19 186 5/16 286 4/8 CX in 32-bit mode) CX in 32-bit mode) ECX in 16-bit mode) ECX in 16-bit mode) loopne loop_start Load segment limit (286+) operands bytes 286 r16, r32, r16, r32, r16 r32 m16 m32 Example: 3 3 3+d(0,2) 3+d(0,2) LTR lsl 14 16 - 20/25 20/25 21/26 21/26 10 10 10 10 8 8 8 8 NP 286 17 19 386 23 27 486 20 20 Pentium 10 NP 10 186 2 9 12 12-13 286 2 3 5 3 386 2 2 4 2 486 1 1 1 1 Pentium 1 UV 1 UV 1 UV 1 UV* 3-4 2 2 1 1 UV 8 9 5 3 4 2 1 1 1 1 UV UV eax, ebx Load task register (286+) operand r16 mem16 Example: bytes 3 3+d(0,2) MOV ltr ax Move data operands reg, reg mem, reg reg, mem mem, imm reg, imm bytes 2 2+d(0-2) 2+d(0-2) 2+d(0-2) +i(1,2) 2+i(1,2) acc, mem mem, acc 3 3 8088 2 13+EA 12+EA 14+EA 4 14 14 * = not pairable if there is a displacement and immediate Example: mov eax, ebx Segment Register Moves operands seg, r16 seg, m16 r16, seg m16, seg Example: bytes 8088 2 2 2+d(0,2) 12+EA 2 2 2+d(0,2) 13+EA mov Real Mode 186 286 2 2 9 5 2 2 11 3 386 2 5 2 2 486 3 3 3 3 Pentium 2-11 NP 3-12 NP 1 NP 1 NP ds, ax Protected Mode Differences 286 386 486 Pentium 17 18 9 2-11* NP 19 19 9 3-12* NP * = add 8 if new descriptor; add 6 if SS operands seg, r16 seg, m16 bytes 2 2+d(0,2) MOVE to/from special registers (386+) operands r32, cr32 cr32, r32 bytes 3 3 386 6 4/10* 486 4 4/16* Pentium 4 NP 12/22* NP 2/12* NP 11/12* NP r32, dr32 dr32, r32 3 3 14/22* 16/22* 10 11 r32, tr32 tr32, r32 3 3 12 12 3/4* 4/6* - NP NP * = cycles depend on which special register Example: mov cr0, eax MOVS/MOVSB/MOVSW/MOVSD variations movsb movsw movsd rep movsb rep movsw rep movsd bytes 1 1 1 2 2 2 Move data from string to string 8088 18 26 9+17n 9+25n - 186 9 9 8+8n 8+8n - 286 5 5 5+4n 5+4n - 386 7 7 7 7+4n 7+4n 7+4n 486 7 7 7 12+3n* 12+3n* 12+3n* Pentium 4 NP 4 NP 4 NP 3+n NP 3+n NP 3+n NP 486 3 3 Pentium 3 NP 3 NP * = 5 if n=0, 13 if n=1 (n = count of bytes, words or dwords) Example: MOVSX rep movsb Move with sign-extend (386+) operands reg, reg reg, mem bytes 3 3+d(0,1,2,4) 386 3 6 (Note: destination reg is 16 or 32-bits; source is 8 or 16 bits) Example: MOVZX movsx ebx, ax Move with zero-extend (386+) operands reg, reg reg, mem bytes 3 3+d(0,1,2,4) 386 3 6 486 3 3 Pentium 3 NP 3 NP (Note: destination reg is 16 or 32-bits; source is 8 or 16 bits) Example: MUL movzx ebx, ax Unsigned multiply operand bytes 8088 r8 2 70-77 r16 2 118-133 r32 2 mem8 2+d(0-2) 76-83+EA mem16 2+d(0-2) 124-139+EA mem32 2+d(0-2) implied operand multiplicand (multiplier) AL * byte = AX * word = EAX * dword = Example: NEG mul 186 26-28 35-37 32-34 41-43 - 286 13 21 16 24 - 386 9-14 9-22 9-38 12-17 12-25 12-41 486 13-18 13-26 13-42 13-18 13-26 13-42 Pentium 11 NP 11 NP 10 NP 11 NP 11 NP 10 NP 186 3 13 286 2 7 386 2 6 486 1 3 Pentium 1 NP 3 NP 186 3 286 3 386 3 486 1 Pentium 1 UV 186 3 13 286 2 7 386 2 6 486 1 3 Pentium 1 NP 3 NP 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 Pentium 1 UV 3 UV 2 UV 1 UV 3 UV* 4 3 2 1 result AX DX:AX EDX:EAX ebx Two's complement negation operand reg mem Example: bytes 2 2+d(0-2) NOP neg 8088 3 24+EA eax No operation bytes 1 Example: 8088 3 NOT nop One's complement negation operands reg mem Example: bytes 2 2+d(0-2) OR not 8088 3 24+EA eax Logical inclusive or operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 4 1 UV * = not pairable if there is a displacement and immediate Example: OUT or eax, ebx Output to port operands imm8, al imm8, ax imm8, eax dx, al dx, ax dx, eax bytes 2 2 2 1 1 1 8088 14 14 12 12 - 186 9 9 7 7 - 286 3 3 3 3 - 386 10 10 10 11 11 11 486 16 16 16 16 16 16 Pentium 12 NP 12 NP 12 NP 12 NP 12 NP 12 NP Protected Mode operands imm8, acc dx, acc bytes 2 1 386 486 Pentium 4/24/24 11/31/29 9/26/24 NP 5/25/25 10/30/29 9/26/24 NP cycles for: CPL <= IOPL / CPL > IOPL / V86 Example: out dx, al OUTS/OUTSB/OUTSW/OUTSD variations outsb outsw outsd Output string to port bytes 1 1 1 186 14 14 - 286 5 5 - 386 14 14 14 486 17 17 17 Pentium 13 NP 13 NP 13 NP Protected Mode bytes 1 386 486 Pentium 8/28/28 10/32/30 10/27/25 NP cycles for: CPL <= IOPL / CPL > IOPL / V86 Example: POP rep outsw Pop a word/dword from the stack operand reg mem seg FS/GS bytes 1 2+d(0-2) 1 2 8088 12 25+EA 12 - 186 10 20 8 - 286 5 5 5 - 386 4 5 7 7 486 1 6 3 3 Pentium 1 UV 3 NP 3 NP 3 NP 386 21 21 21 486 9 9 9 Pentium 3-12 NP 8-17 NP 3-12 NP 486 9 9 Pentium 5 NP 5 NP 386 5 5 486 9 9 Pentium 6 NP 6 NP 286 5 - 386 5 5 486 6 6 Pentium 4 NP 4 NP 286 3 5 3 3 - 386 2 5 2 2 2 486 1 4 3 1 3 Pentium 1 UV 2 NP 1 NP 1 NP 1 NP 486 11 11 Pentium 5 NP 5 NP 486 4 Pentium 9 NP Protected Mode operand CS/DS/ES SS FS/GS bytes 1 1 2 Example: pop POPA/POPAD 286 20 20 eax Pop all (186+)/Pop all double (386+) variations popa popad bytes 1 1 186 51 - 286 19 - 386 24 24 popa = pop di, si, bp, sp, bx, dx, cx, ax popad = pop edi, esi, ebp, esp, ebx, edx, ecx, eax (sp and esp are discarded) Example: POPF/POPFD popa Pop flags/Pop flags double (386+) variations popf popfd bytes 1 1 8088 12 - 186 8 - 286 5 - Protected Mode popf popfd Example: PUSH bytes 1 1 popf push a word/dword to the stack operand bytes reg 1 mem 2+d(0-2) seg 1 imm 1+i(1,2) FS/GS 2 Example: push 8088 15 24+EA 14 - 186 10 16 9 - eax PUSHA/PUSHAD Push all (186+)/Push all double (386+) variations bytes 186 286 386 pusha 1 36 17 18 pushad 1 18 pusha = push ax, cx, dx, bx, sp, bp, si, di, pushad = push eax, ecx, edx, ebx, esp, ebp, esi, edi Example: PUSHF/PUSHFD variations pushf pusha Push flags/Push flags double (386+) bytes 1 8088 14 186 9 286 3 386 4 pushfd 1 - - - 4 4 9 NP 286 3 - 386 4 4 486 3 3 Pentium 3 NP 3 NP 286 2 7 5+n 8+n 5+n 8+n 386 9 10 9 10 9 10 486 3 4 8-30 9-31 8-30 9-31 Pentium 1 PU 3 PU 7-24 NP 9-26 NP 8-25 NP 10-27 NP 286 2 7 5+n 8+n 5+n 8+n 386 9 10 9 10 9 10 486 3 4 8-30 9-31 8-30 9-31 Pentium 1 PU 3 PU 7-24 NP 9-26 NP 8-25 NP 10-27 NP 286 2 7 5+n 8+n 5+n 8+n 386 3 7 3 7 3 7 486 3 4 3 4 2 4 Protected Mode pushf pushfd Example: bytes 1 1 RCL pushf Rotate bits left with CF operands reg, 1 mem, 1 reg, cl mem, cl reg, imm mem, imm Example: bytes 8088 186 2 2 2 2+d(0,2) 23+EA 15 2 8+4n 5+n 2+d(0,2) 28+EA+4n 17+n 3 5+n 3+d(0,2) 17+n RCR rcl eax, 16 Rotate bits right with CF operands reg, 1 mem, 1 reg, cl mem, cl reg, imm mem, imm Example: bytes 8088 186 2 2 2 2+d(0,2) 23+EA 15 2 8+4n 5+n 2+d(0,2) 28+EA+4n 17+n 3 5+n 3+d(0,2) 17+n ROL rcr eax, 16 Rotate bits left operands reg, 1 mem, 1 reg, cl mem, cl reg, imm mem, imm bytes 8088 186 2 2 2 2+d(0,2) 23+EA 15 2 8+4n 5+n 2+d(0,2) 28+EA+4n 17+n 3 5+n 3+d(0,2) 17+n Pentium 1 PU 3 PU 4 NP 4 NP 1 PU 3 PU* * = not pairable if there is a displacement and immediate Example: ROR rol eax, 16 Rotate bits right operands reg, 1 mem, 1 reg, cl mem, cl reg, imm mem, imm bytes 8088 186 2 2 2 2+d(0,2) 23+EA 15 2 8+4n 5+n 2+d(0,2) 28+EA+4n 17+n 3 5+n 3+d(0,2) 17+n 286 2 7 5+n 8+n 5+n 8+n 386 3 7 3 7 3 7 486 3 4 3 4 2 4 Pentium 1 PU 3 PU 4 NP 4 NP 1 PU 3 PU* * = not pairable if there is a displacement and immediate Example: RDMSR ror eax, 16 Read from model specific register (Pentium+) bytes 2 Example: REP See: See: REPE See: See: REPNE See: See: Pentium 20-24 NP rdmsr Repeat string operation MOVS (rep movs) STOS (rep stos) move block fill block Repeat while equal (or zero) string operation CMPS (repe cmps) CMPS (repe scas) find non-matching memory items find non-acc matching byte in memory Repeat while not equal (or not zero) string operation CMPS (repne cmps) SCAS (repne scas) RET/RETN/RETF find first matching memory items find first matching memory item to acc Return from procedure variations/ operands retn retn imm16 retf retf imm16 bytes 1 1+d(2) 1 1+d(2) 8088 20 24 34 33 186 16 18 22 25 286 11+m 11+m 15+m 15+m 386 10+m 10+m 18+m 18+m 486 5 5 13 14 Pentium 2 NP 3 NP 4 NP 4 NP RET is coded by the assembler as near or far based on the procedure declaration and program model, as: RETN (return near) RETF (return far) Example: ret Protected Mode variations/ operands bytes retf 1 retf imm16 1+d(2) 286 25+m/55 25+m/55 386 486 32+m/62 18/33 32+m/68 17/33 Pentium 4-13/23 NP 4-13/23 NP cycles for: same privilege level/lower privilege level RSM Resume from system management mode (Pentium+) bytes 2 Example: Pentium 83 NP rsm SAL/SHL/SAR/SHR operands reg, 1 mem, 1 reg, cl mem, cl reg, imm mem, imm Shift bits bytes 8088 186 2 2 2 2+d(0,2) 23+EA 15 2 8+4n 5+n 2+d(0,2) 28+EA+4n 17+n 3 5+n 3+d(0,2) 17+n 286 2 7 5+n 8+n 5+n 8+n 386 3 7 3 7 3 7 486 3 4 3 4 2 4 Pentium 1 PU 3 PU 4 NP 4 NP 1 PU 3 PU* * = not pairable if there is a displacement and immediate sal = shift arithmetic left shl = shift left (same as sal) Example: SAHF shl sar = shr = shift arithmetic right shift right eax, 1 Store AH into flags bytes 1 Example: 8088 4 186 3 286 2 386 3 486 2 Pentium 2 NP SBB 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 Pentium 1 PU 3 PU 2 PU 1 PU 3 PU* 4 3 2 1 sahf Integer subtraction with borrow operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 4 1 PU * = not pairable if there is a displacement and immediate Example: sbb eax, ebx SCAS/SCASB/SCASW/SCASD variations scasb scasw scasd repX scasb repX scasw repX scasd bytes 1 1 1 2 2 2 Scan string data 8088 19 19 9+15n 9+19n - 186 15 15 5+15n 5+15n - 286 7 7 5+8n 5+8n - 386 7 7 7 5+8n 5+8n 5+8n 486 6 6 6 7+5n* 7+5n* 7+5n* repX = repe or repz or repne or repnz * = 5 if n=0 (n = count of bytes, words or dwords) Example: repne scasb Pentium 4 NP 4 NP 4 NP 8+4n NP 8+4n NP 8+4n NP SET Set byte to 1 on condition else set to 0 (386+) operand r8 mem8 bytes 3 3+d(0-2) 386 4 5 Cycles are for: 486 4/3 3/4 Pentium 1/2 NP 1/2 NP 486 10 Pentium 4 NP true/false setCC = one of: seta setg setnb setnl seto setae setge setnbe setnle setp Example: setb setl setnc setno setpe SGDT setne setc setna setng setns sets sete setnae setnge setnz setz al Store global descriptor table register (286+) operand mem48 Example: bytes 5 286 11 sgdt SIDT 386 9 descriptor[ebx] Store interrupt descriptor table register (286+) operand mem48 Example: bytes 5 286 12 sidt SHLD 386 9 486 10 Pentium 4 NP 386 3 7 3 7 486 2 3 3 4 Pentium 4 NP 4 NP 4 NP 5 NP 386 3 7 3 7 486 2 3 3 4 Pentium 4 NP 4 NP 4 NP 5 NP 386 2 2 486 2 3 Pentium 2 NP 2 NP 286 2 3 386 2 3 486 2 3 Pentium 4 NP 4 NP 286 2 386 2 486 2 Pentium 2 NP descriptor[ebx] Double precision shift left (386+) operands reg, reg, mem, reg, reg, reg, mem, reg, Example: bytes 4 4+d(0-2) 4 4+d(0-2) imm imm cl cl shld SHRD eax, ebx, 16 Double precision shift right (386+) operands reg, reg, mem, reg, reg, reg, mem, reg, Example: bytes 4 4+d(0-2) 4 4+d(0-2) imm imm cl cl shrd SLDT eax, ebx, 16 Store local descriptor table register (286+) operands r16 mem16 Example: bytes 3 3+d(0-2) sldt SMSW 286 2 3 ax Store machine status word (286+) operands r16 mem16 Example: bytes 3 3+d(0-2) smsw STC ax Set the carry flag bytes 1 Example: 8088 2 186 2 stc STD Set direction flag (set to reverse string direction) bytes 1 Example: STI setbe setle setne setnp setpo 8088 2 186 2 286 2 386 2 486 2 Pentium 2 NP 286 386 486 Pentium std Set interrupt flag (enable) bytes 8088 186 1 Example: 2 2 2 3 5 7 NP sti STOS/STOSB/STOSW/STOSD variations stosb stosw stosd rep stosb rep stosw rep stosd bytes 1 1 1 2 2 2 Store string data 8088 11 15 9+10n 9+14n - 186 10 10 6+9n 6+9n - 286 3 3 4+3n 4+3n - 386 4 4 4 5+5n 5+5n 5+5n 486 5 5 5 7+4n* 7+4n* 7+4n* Pentium 3 NP 3 NP 3 NP 3+n NP 3+n NP 3+n NP * = 5 if n=0, 13 if n=1 (n = count of bytes, words or dwords) Example: STR rep stosd Store task register (286+) operand r16 mem16 Example: bytes 3 3+d(0-2) SUB str 286 2 3 386 2 2 486 2 3 Pentium 2 NP 2 NP 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 Pentium 1 UV 3 UV 2 UV 1 UV 3 UV* 4 3 2 1 bx Integer subtraction operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 4 1 UV * = not pairable if there is a displacement and immediate Example: TEST sub eax, ebx Logical compare operands reg, reg mem, reg reg, mem reg, imm mem, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) acc, imm 1+i(1,2) 8088 3 13+EA 13+EA 5 11+EA 286 2 6 6 3 6 386 2 5 5 2 5 486 1 2 2 1 2 4 3 2 1 4 186 3 10 10 4 10 Pentium 1 UV 2 UV 2 UV 1 UV 2 UV* 1 UV * = not pairable if there is a displacement and immediate Example: VERR sub eax, ebx Verify a segment for reading (286+) operand r16 mem16 Example: bytes 3 3+d(0,2) VERW verr 286 14 16 386 10 11 486 11 11 Pentium 7 NP 7 NP 286 14 16 386 15 16 486 11 11 Pentium 7 NP 7 NP 286 3 386 6 486 1-3 Pentium 1 NP 486 5 Pentium 2000+ NP ax Verify a segment for writing (286+) operand r16 mem16 Example: bytes 3 3+d(0,2) WAIT verr ax Wait for co-processor bytes 1 Example: 8088 4 186 6 WBINVD wait Write-back and invalidate data cache (486+) bytes 2 Example: wbinvd WRMSR Write to model specific register (PENTIUM+) bytes 2 Example: Pentium 30-45 NP XADD wrmsr Exchange and add (486+) operands reg, reg mem, reg bytes 3 3+d(0-2) Example: XCHG xadd 486 3 4 Pentium 3 NP 4 NP Pentium 3 NP 3 NP 3 NP eax, ebx Exchange register/memory with register operands reg, reg reg, mem mem, reg bytes 8088 2 4 2+d(0-2) 25+EA 2+d(0-2) 25+EA acc, reg reg, acc 1 1 286 3 5 5 386 3 5 5 486 3 5 5 3 3 3 3 3 3 3 3 186 11 286 5 386 5 486 4 Pentium 4 NP 186 3 10 10 4 16 286 2 7 7 3 7 386 2 7 6 2 7 486 1 3 2 1 3 Pentium 1 UV 3 UV 2 UV 1 UV 3 UV* 4 3 2 1 3 3 186 4 17 17 2 2 NP NP in above: acc = AX or EAX only Example: xchg XLAT/XLATB ax, dx Table look-up translation bytes 1 Example: 8088 11 XOR xlat Logical exclusive or operands reg, reg mem, reg reg, mem reg, imm mem, imm acc, imm bytes 2 2+d(0,2) 2+d(0,2) 2+i(1,2) 2+d(0,2) +i(1,2) 1+i(1,2) 8088 3 24+EA 13+EA 4 23+EA 4 1 UV * = not pairable if there is a displacement and immediate Example: xor eax, ebx x86 Glossary of Terms Address: Location of a data item in memory. Also see Linear address, Physical address. AGI: Address Generation Interlock. On the 486 and Pentium processors the pipeline is stalled for one cycle if a component of an address is loaded or calculated in the previous machine cycle. Arithmetic Logic Unit: The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR and CMP. Alignment: The placement of data or code on a specific address boundary (i.e. a 2, 4, or 8 byte evenly divisible address). ALU: See Arithmetic Logic Unit. Arithmetic Logic Unit: The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR and CMP. ASCII: American Standard Code for Information Interchange. A standard code for representing English characters and symbols with various extensions for foreign characters. Assembler: A program that translates an assembly language program to machine language (or object code). Assembly Language: A programming language, based on the architecture of a particular machine, where most statements translate into one machine instruction. Base address: The address at the start of a structure or of data array. Base register: A register that contains a base address. Usually BX (EBX) or BP (EBP) is a base register. For 16-bit code the base register must be BX or BP, for 32-bit code any of EAX, EBX, ECX, EDX, ESI, EDI, EBP or ESP. Base: Also See base address. In number systems, used to specify the number of digits in a system, i.e. base 10 has ten digits, base 2 has two, etc. BCD: Binary Coded Decimal. See also Packed BCD. This is a format for encoding base 10 numbers where the low order 4 bits are used to store the numercial value. Big-endian: A method of storing multi-byte data types where the low-order byte is stored at the highest address and the high-order byte is stored at the lower address. BIOS: Basic Input/Output System. Built-in software (usually stored in ROM) that is used to start up the computer and controls low-level functionality of devices such as the keyboard, screen, disks and I/O ports. Bit: A binary digit. Can be a zero or a one. Byte: A data type consisting of 8 bits. Cache: A small fast memory buffer that holds a copy of the most recently used or most active portions of the larger slower memory. Also see Disk Cache. Central Processor Unit: The main processing unit in a computer. Sometimes referred to as the processor, the chip or the computer. Character String: A data type that is an array of characters. Usually followed by a byte of 0 in assembly language or C. Character: A data type that is the same as a byte. Checksum: A simple error detection scheme where values are added (summed) into a variable to be compared with a similar previously calculated value. Chip: A small piece of semiconducting material on which an electronic circuit is placed. A CPU chip is also known as a microprocessor. CISC: See Complex Instruction Set Computer. Clock Speed: The speed that a processor executes instructions. Code Segment: The addressable area of memory defined by the segment in the CS register. Compiler: A program that translates a high level language (such as C, Pascal or Fortran) into machine language or sometimes into assembly language. Processors designed with many complex and sometimes irregular instructions, especially Complex Instruction Set Computer: instructions that access memory operands and operate on them. The 80x86 architecture is considered CISC. See RISC. CP/M: Control Program for Microcomputers. An operating system originally designed for 8080 and Z-80 based computers. CPU: See Central Processor Unit. CRC: Cyclic redundancy check. A complex error detection scheme, similar to a checksum, but each value is operated on in a position-dependent manner. This increases the reliability of the error detection. Cycles: Periodic pulses created by an electronic clock that causes CPU activity. Data Segment: The addressable area of memory defined by the segment in the DS register. Data Structure: A scheme for organizing related data items. Debugger: A program that allows executing, monitoring and modifying a program's code and data to enable a programmer to locate program errors (or bugs). Directive: An assembler statement that contains information for the use of the assembler rather than an instruction to be assembled and executed as part of the program. Disassembler: A program that attempts the difficult task of reconstructing an assembly language source file from machine language. Disk Cache: A program and/or areas of memory set aside keep frequently used or most recently used data from a disk for quicker access. Displacement: The constant part of an effective address (EA). DOS: Disk Operating System. Also called MS-DOS or PC-DOS. DRAM: Dynamic RAM. The type of memory chip used in most computers. It is called dynamic because it must continually be refreshed or the contents will be lost. Dword: A data type consisting of a double word or 32-bits. EA: See Effective Address Editor: A program that allows the user to create and edit files. Effective Address: The combination of any or all of a base register, index register and displacement used to produce an offset within a segment. Emulator: A program that attempts to emulate, or work the same as, another program or machine. Endian: See Little-endian and Big-endian. Exception: A forced call to an interrupt routine that handles error conditions. External Cache: A memory cache not physically located on the same chip as the CPU. Extra Segment: The addressable area of memory defined by the segment in the ES register. Far Pointer: A reference to memory consisting of a segment and an offset. In real mode the segment is the upper 16 bits of a 20-bit segment starting address. In protected mode the segment is a selector. Fault: An exception that is called with the return address on the stack of the instruction that caused the fault. File: An organized collection of data or information, usually stored on a disk with a specific name or filename. Flat Model: A program model where all segment registers are the same and are usually set to be larger than 64K segments. Floating Point Unit: The portion of the 80486 or Pentium that performs the floating point operations like the floating point processor. FPP: See Floating Point Processor. Floating Point Processor: A floating point math processor. The processing unit that performs IEEE 754 floating point arithmetic on 32-bit, 64-bit and 80-bit signed numbers with exponents. FPU: See Floating Point Unit. Hertz: A frequency of one cycle per second. HLL: High Level Language. Such as C, Basic, Pascal and Fortran. Hz: Abbreviation for Hertz. IEEE: Institute of Electrical and Electronic Engineers. An organization best known for developing electrical and electronic standards for the computer industry. Index register: A register that contains an index value. Usually SI (ESI) or DI (EDI) is an index register. For 16-bit code the index register must be SI or DI, for 32-bit code any of EAX, EBX, ECX, EDX, ESI, EDI or EBP. Integer: A positive whole number, negative whole number or zero. On computers integers have a limited range, for example byte integers have a range of -128 to +127. Interpreter: A program that executes another program by reading each program statement and interpreting the actions to be taken. Interrupt Handler: A routine specifically designed to respond to an interrupt. Interrupt Vector Table: An array of 256 far pointers to interrupt handlers. Located at address 0000:0000. I/O: Input/Output. IVT: See Interrupt Vector Table Label: An identifier used in assembly language programs to specify a memory address by name rather than by its actual numerical address. LDT: See Local Descriptor Table. Library: A collection of programs or subroutines stored in object file format, usually in a .LIB file. Linear Address: A 20-, 24-, or 32-bit address into a large unsegmented memory space. With paging (virtual memory) disabled the linear address is the physical address. With paging enabled the paging mechanism translates the linear address to a physical address. Link: The complex process of combining object files and hooking, or linking together, subroutines or data in one file that are referenced in another file. Linker: A program that links one or more object files into an executable program file, usually a .EXE file. Little-endian: A method of storing multi-byte data types where the low-order byte is stored at the lowest address and the high-order byte is stored at the highest address. The Intel 80x86 processor use this format. Logical Address: A segment and offset combine to generate a logical address. The segmentation unit translates the logical address into a linear address. Long Integer: See integer. An integer data format consisting of 32-bits. Machine Language: The binary codes that a machine (CPU) can execute. Mask: A bit pattern constructed to be logically combined with a data value to allow only some bits of the original data value to show through (i.e. the others are masked out). Math Coprocessor: A floating point math processor. Termed a "co-processor" when added as an optional separate chip. MegaHertz: A million hertz; A million cycles per second. Mhz: MegaHertz. Microprocessor: A computer processor fully contained on one integrated circuit (or chip). Module: Part of a program, usually one file, containing one or more procedures or subroutines and/or data values. MS-DOS: Microsoft DOS (Disk Operating System). Near Pointer: A reference to memory containing only the offset portion of the address. The offset must be combined with a segment or selector in one of the segment registers. Nibble: 4 bits. There are two nibbles in a byte. (Also nybble) NPX: Numerical Processor Extension. Original name for the 8087 floating point co-processor. Numeric Coprocessor: A floating point math processor. Object code: An intermediate form of machine language produced by assemblers and compilers that is structured so that it can be linked together. Offset: A 16-bit number that specifies the byte number beyond the start of a segment. On the 80386 and above segments may have 32-bit offsets. Operand: Data provided in a register, in memory or immediately with an instruction to be used in the processing of the instruction. Operating System: The program(s) that load applications and control access to memory, disk files, I/O ports, etc., such as DOS, Windows, OS/2 and UNIX. OS: See Operating System. Packed BCD: Packed Binary Coded Decimal. A data format that stores one decimal digit in each nibble of a byte. Page: A 4K-byte block of memory. This is the size of memory block used for paging. Paging: A method of managing memory, by an operating system, to implement a virtual memory system. Pages of memory are stored on a disk when not in use and recalled later when needed. Pairing: The process of issuing two instructions at the same time to each of the U and V pipelines of the Pentium. Paragraph: 16 bytes of memory. Parity: An error detection system commonly used in data communications where the sum of the set bits in a data packet is odd or even. PC-DOS: Personal Computer DOS. IBM's version of MS-DOS. Physical Address: The actual hardware address of memory issued by the processor. The maximum physical address is determined by the number of address pins on the processor. Port: A channel, or connection, for data to enter or leave the CPU. Prefix: One of several machine language codes that can be placed in front of other instructions to modify their actions or default conditions. Processor: Short for microprocessor. The part of the computer that actually performs the arithmetic, logical and control functions of a computer. Protected Mode: A CPU mode where memory address ranges are protected from being read and/or written to by unauthorized segments of code. Pseudo-op: Another term for assembler directives. Quadword: A data type consisting of 8 bytes or 64-bits. RAM: Random Access Memory. The read/write memory used by the computer, usually consisting of DRAM chips. Re-entrant: A quality of a procedure or program that allows it to be interrupted and called or run again and both logical instances remain intact and properly execute independently of each other. Real Mode: The only CPU mode of the 8088 and 8086 and the startup mode for the 80286 and above. There is no memory protection as in the protected mode. Register: A storage area in a CPU. Each register usually has a number of operations that can be directly performed on it by the CPU, unlike a memory storage location. Reduced Instruction Set Computer: Processors designed with the general concepts of a load/store architecture, few addressing modes, many registers, fixed length instructions and the "simple is faster" design criteria. Segment Override: A prefix for an instruction that causes a segment register, other than the normal default segment register to be used during the execution of the following instruction. Segment: Real mode: A portion of memory specified by a 20-bit starting address of which the low 4 bits are always zero and whose length can be up to 64K. Protected mode: A portion of memory described by a descriptor table entry. Selector: In protected mode, a pointer to a segment descriptor. A selector is a 16-bit value and is used in protected mode instead of a paragraph address in a segment register. SRAM: Static RAM. Faster and more stable than DRAM, but requires more power and is more expensive. Usually used in memory caches. Stack Segment: A portion of memory pointed to by the stack segment register for use as the system stack. Stack: A last-in first-out data data structure in memory used for saving return addresses, temporary variables and system status information. A system can have any number of stacks, but only one may be in use at any time String: Any consectutive bytes of memory can be a string. HLL's specify rules for defining strings. In the C language strings must end with a byte containing a value of zero. Superscalar: A CPU that can complete more than one instruction per machine cycle. Task: One of many programs currently executing or waiting to execute in a multi-tasking system. Two's Complement: A mathematical operation where a binary value is multiplied by -1. Each bit is changed to the opposite value and then one is added to the entire value. Unsigned Integer: A positive whole number or zero. On computers unsigned integers have a limited ranged, for example an 8-bit unsigned integer has a range of 0 to 255. V86 Mode: See Virtual-8086 Mode. Virtual Memory: A scheme used that allows programs to logically allocate and use more memory than is physically available by moving and swapping portions that are not currently needed or infrequently used to a hard disk. Virtual-8086 Mode: A mode on 386 and above processors that provides for the emulation of the 8086 architecture. An operating system may run a mix of protected mode tasks amd virtual-8086 mode tasks. Word: A data type consisting of two bytes or 16 bits. (On non-x86 architectures a word usually refers to a data element the size of the accumulator and registers, typically 32 bits. Console - Applikation Eine Console - Applikation hat eine main() - Funktion. Es kann in C/C++ programmiert werden. Die Standard - Klassen Bibliotheken sind verfügbar. Es können die folgenden Console-Funktionen und Console-Strukturen benutzt werden: Console-Funktionen AllocConsole FreeConsole GenerateConsoleCtrlEvent GetConsoleScreenBufferInfo GetConsoleTitle HandlerRoutine PeekConsoleInput ReadConsoleOutputCharacter ScrollConsoleScreenBuffer SetConsoleCursorPosition SetConsoleMode WriteConsoleInput WriteConsoleOutput CreateConsoleScreenBuffer FillConsoleOutputAttribute FillConsoleOutputCharacter FlushConsoleInputBuffer GetConsoleCP GetConsoleCursorInfo GetConsoleMode GetLargestConsoleWindowSize GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons GetStdHandle ReadConsole ReadConsoleInput GetConsoleOutputCP ReadConsoleOutput ReadConsoleOutputAttribute SetConsoleActiveScreenBuffer SetConsoleCP SetConsoleCtrlHandler SetConsoleCursorInfo See SetConsoleWindowInfo SetStdHandle WriteConsole WriteConsoleOutputAttribute WriteConsoleOutputCharacter Console-Strukturen CHAR_INFO COORD KEY_EVENT_RECORD SMALL_RECT CONSOLE_CURSOR_INFO FOCUS_EVENT_RECORD MENU_EVENT_RECORD WINDOW_BUFFER_SIZE_RECORD CONSOLE_SCREEN_BUFFER_INFO INPUT_RECORD MOUSE_EVENT_RECORD WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben #define #define #define #define #define #define #define #define FOREGROUND_BLUE FOREGROUND_GREEN FOREGROUND_RED FOREGROUND_INTENSITY BACKGROUND_BLUE BACKGROUND_GREEN BACKGROUND_RED BACKGROUND_INTENSITY 0x0001 0x0002 0x0004 0x0008 0x0010 0x0020 0x0040 0x0080 // // // // // // // // text color text color text color text color background background background background contains blue contains green contains read is intensified color contains blue color contains green color contains red color is intensified Gelbe Textschrift auf blauem Hintergrund wird z.B. durch ( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE ) in FillConsoleOutputAttribute() eingestellt. Eine Console-Applikation hat als Startpunkt die main()-Funktion: int main() { ... return 0; }. Es kann in C/C++ programmiert werden. Die Standard-Klassen-Bibliotheken sind verfügbar. Beispiel // in2bat.c // bricht Eingabezeilen bei sep_char = '&'; um // ( z.B. nützlich für NMAKE.EXE nach BAT ) #include <stdio.h> #include <string.h> #define MAXLINE 4096 char in_buf [ MAXLINE ]; // = {0}; char sep_char = '&'; int main(int argc, char **argv) { if ( argc != 1 || argv[1] ) {// Hilfetext printf("Usage: in2bat.exe < getippte_Eingabe > output_file_Name\n" "Für Eingabe von Hand braucht das Programm keine Argumente\n" ); return 1; } printf ( "@echo off\n" ) ; //hole und bearbeite jede Eingabe-Zeile while ( fgets(in_buf, sizeof( in_buf ), stdin ) ) { char * pNext, * pStart = in_buf ; char * pFinish = pStart + strlen( pStart ) ; //printf ( "\n--- %s", pStart ) ; // Entferne newline char if ( ( pFinish > pStart) && ( pFinish[-1] == '\n' ) ) pFinish[-1] = '\0' ; do { // skip blanks und tabs ( whitespaces ) while ( * pStart == ' ' || * pStart == '\t' ) ++ pStart ; // finde das nächsten command separator sep_char='&' oder end of line pNext = strchr(pStart, sep_char) ; if (! pNext) pNext = pStart + strlen(pStart) ; pFinish = pNext ; if (pStart == pNext) break ; // skip führende whitespace while ( ( pFinish > pStart ) && ( pFinish [ -1 ] == ' ' || pFinish [ -1 ] == '\t' ) ) -- pFinish ; // Kopiere nach stdout while ( pStart < pFinish ) putchar(*pStart++) ; putchar ( '\n' ) ; pStart = pNext ; } while ( *pStart++ ) ; } return 0 ; } Eine Windows-Console-Applikation kann zusätlich zu den Standard-Klassen die folgenden Console-Funktionen verwenden: AllocConsole FillConsoleOutputAttribute FillConsoleOutputCharacter GenerateConsoleCtrlEvent GetConsoleMode GetConsoleScreenBufferInfo GetConsoleTitle GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons PeekConsoleInput ReadConsoleOutput ReadConsoleOutputCharacter ScrollConsoleScreenBuffer SetConsoleCtrlHandler SetConsoleCursorPosition SetConsoleMode SetStdHandle WriteConsoleOutput WriteConsoleOutputCharacter CreateConsoleScreenBuffer FlushConsoleInputBuffer GetConsoleCP GetConsoleOutputCP FreeConsole GetConsoleCursorInfo GetLargestConsoleWindowSize GetStdHandle ReadConsole ReadConsoleOutputAttribute HandlerRoutine ReadConsoleInput SetConsoleActiveScreenBuffer SetConsoleCursorInfo SetConsoleCP See SetConsoleWindowInfo WriteConsole WriteConsoleInput WriteConsoleOutputAttribute Diese Funktionen verwenden die Console - Strukturen: CHAR_INFO COORD KEY_EVENT_RECORD SMALL_RECT CONSOLE_CURSOR_INFO FOCUS_EVENT_RECORD MENU_EVENT_RECORD WINDOW_BUFFER_SIZE_RECORD CONSOLE_SCREEN_BUFFER_INFO INPUT_RECORD MOUSE_EVENT_RECORD Für den Text - Bildschirm sind in WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben definiert: #define #define #define #define #define #define #define FOREGROUND_BLUE FOREGROUND_GREEN FOREGROUND_RED FOREGROUND_INTENSITY BACKGROUND_BLUE BACKGROUND_GREEN BACKGROUND_RED 0x0001 0x0002 0x0004 0x0008 0x0010 0x0020 0x0040 // // // // // // // text color text color text color text color background background background contains blue contains green contains read is intensified color contains blue color contains green color contains red #define BACKGROUND_INTENSITY 0x0080 // background color is intensified Gelbe Text - Schrift auf blauem Hintergrund wird z.B. durch ( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE ) in FillConsoleOutputAttribute() eingestellt. Beispiel ... einige windows-typedef's ... typedef struct _CHAR_INFO { union { WCHAR UnicodeChar; CHAR AsciiChar; } Char; WORD Attributes; } CHAR_INFO; typedef struct _COORD { SHORT X; SHORT Y; } COORD; typedef struct _CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; WORD wAttributes; SMALL_RECT srWindow; COORD dwMaximumWindowSize; } CONSOLE_SCREEN_BUFFER_INFO; typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } CONSOLE_CURSOR_INFO; typedef struct _INPUT_RECORD { WORD EventType; union { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } Event; } INPUT_RECORD; typedef struct _SMALL_RECT { SHORT Left; SHORT Top; SHORT Right; SHORT Bottom; } SMALL_RECT; typedef struct _KEY_EVENT_RECORD { BOOL bKeyDown; WORD wRepeatCount; WORD wVirtualKeyCode; WORD wVirtualScanCode; union { WCHAR UnicodeChar; CHAR AsciiChar; } uChar; DWORD dwControlKeyState; } KEY_EVENT_RECORD; Verwendung der typdefs's in einem Console-TEST-Programm //////////////////////////////////////////////////////////////// #define UNICODE // Unicode fuer Win32-Headerfiles einschalten #define _UNICODE // Die C-Header brauchen eine separate Einladung #define STRICT // Striktere Typ-Pruefungen einschalten #define WIN32_LEAN_AND_MEAN // Nur wichtige Headerfiles compilieren #include <windows.h> #include <stdio.h> #include <tchar.h> //Unicode //////////////////////////////////////////////////////////////// typedef struct tagMYSCREEN { //eigene globale Struktur HANDLE hOut; HANDLE hIn ; CONSOLE_SCREEN_BUFFER_INFO screen ; //screen.dwSize.X, Y } MYSCREEN ; /////////////////////////////////////////////////////////////// VOID Console_Init( MYSCREEN * mScreen ) { mScreen->hOut = GetStdHandle( STD_OUTPUT_HANDLE ) ; mScreen->hIn = GetStdHandle( STD_INPUT_HANDLE ) ; SetConsoleMode( mScreen->hIn, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT ) ; GetConsoleScreenBufferInfo( mScreen->hOut, & mScreen->screen ) ; return; } //////////////////////////////////////////////////////////////// VOID Cursor_Off( MYSCREEN *mScreen ) { CONSOLE_CURSOR_INFO cursor ; GetConsoleCursorInfo( mScreen->hOut, & cursor ) ; cursor.bVisible = FALSE ; SetConsoleCursorInfo( mScreen->hOut, & cursor ) ; } //////////////////////////////////////////////////////////////// VOID Cursor_On( MYSCREEN *mScreen ) { CONSOLE_CURSOR_INFO cursor ; cursor.bVisible = TRUE ; SetConsoleCursorInfo( mScreen->hOut, & cursor ) ; } //////////////////////////////////////////////////////////////// VOID Cursor_Set( MYSCREEN *mScreen, SHORT x, SHORT y ) { COORD point; point.X = x; point.Y = y; SetConsoleCursorPosition( mScreen->hOut, point ) ; } //////////////////////////////////////////////////////////////// int Cursor_GetX( MYSCREEN *mScreen ) { return mScreen->screen.dwCursorPosition.X; } int Cursor_GetY( MYSCREEN *mScreen ) { return mScreen->screen.dwCursorPosition.Y; } int Screen_GetX( MYSCREEN *mScreen ) { return mScreen->screen.dwSize.X; } int Screen_GetY( MYSCREEN *mScreen ) { return mScreen->screen.dwSize.Y; } //////////////////////////////////////////////////////////////// INPUT_RECORD Read_Input( MYSCREEN *mScreen, DWORD * nIn ) { INPUT_RECORD evt ; DWORD n; if ( nIn == NULL ) nIn = & n; ReadConsoleInput( mScreen->hIn, & evt, 1, nIn ) ; return evt; } //////////////////////////////////////////////////////////////// DWORD Write_Attr( MYSCREEN *mScreen, int x, int y, DWORD anz, WORD Attr ) { DWORD nOut ; COORD point; point.X = ( SHORT) x; point.Y = ( SHORT) y; if ( anz <= 0 ) anz = 1; FillConsoleOutputAttribute( mScreen->hOut, Attr, anz, point, & nOut ) ; return nOut; } //////////////////////////////////////////////////////////////// DWORD Write_Str( MYSCREEN *mScreen, int x, int y, DWORD anz, TCHAR * pStr ) { DWORD nOut ; COORD point; point.X = ( SHORT) x; point.Y = ( SHORT) y; if ( anz <= 0 ) anz = 1; WriteConsoleOutputCharacter( mScreen->hOut, pStr, anz, point, & nOut ) ; return nOut; } //////////////////////////////////////////////////////////////// // Einen Teil des Bildschirms scrollen VOID Scroll_Screen( MYSCREEN *mScreen, int xNew, int yNew, SMALL_RECT * pRect, CHAR_INFO fillChar ) { COORD newPoint; newPoint.X = ( SHORT) xNew; newPoint.Y = ( SHORT) yNew; ScrollConsoleScreenBuffer( mScreen->hOut, pRect, // Groesse des Scrollbereichs NULL, // Clipping-Rechteck, nicht verwendet newPoint, // neue Position des Scrollbereichs & fillChar // Fuellzeichen und -attribut fuer den freiwerdenen Bereich ) ; } //////////////////////////////////////////////////////////////// // Fuellt den kompletten Schirm mit einem Vordergrund/Hintergrundattribut VOID Fill_Screen_Attr( MYSCREEN *mScreen, WORD Attr ) { DWORD nOut ; COORD point = { 0, 0 }; // d.h. point.X=0; point.Y=0; FillConsoleOutputAttribute( mScreen->hOut, Attr, ( mScreen->screen.dwSize.X ) * ( mScreen->screen.dwSize.Y ), point, & nOut ); } //////////////////////////////////////////////////////////////// VOID Fill_Screen_Char( MYSCREEN *mScreen, TCHAR c ) { // Fuellt Bildschirm mit einem Zeichen DWORD nOut ; COORD point = { 0, 0 }; // d.h. point.X=0; point.Y=0; FillConsoleOutputCharacter( mScreen->hOut, c, (mScreen->screen.dwSize.X)*(mScreen->screen.dwSize.Y), point, & nOut ) ; } //////////////////////////////////////////////////////////////// TCHAR Key_Hit1( MYSCREEN *mScreen ) {// Wartet auf eine Taste ( Ctrl/Shift bewirken nichts ) TCHAR c ; DWORD nIn ; ReadConsole( mScreen->hIn, & c, 1, & nIn, NULL ) ; return c; } //////////////////////////////////////////////////////////////// INPUT_RECORD Key_Hit( MYSCREEN *mScreen ) { INPUT_RECORD evt ; DWORD nIn ; do { // Wartet auf Taste ( auch Ctrl usw. ) ReadConsoleInput( mScreen->hIn, & evt, 1, & nIn ) ; if ( ( evt.EventType == KEY_EVENT ) && ( evt.Event.KeyEvent.bKeyDown == TRUE ) ) break ; } while ( TRUE ) ; return evt; } //////////////////////////////////////////////////////////////// int main() { //////////////////////////////////////////////////////////////// TCHAR pStr[] = TEXT( "ESC beendet" ); TCHAR szEmpty[] = TEXT( " " ) ; COORD point ; SMALL_RECT rect ; CHAR_INFO fillChar ; INPUT_RECORD evt ; TCHAR iChar[] = TEXT( " " ) ; DWORD i ; MYSCREEN ms; Console_Init( &ms ); _tprintf( TEXT( "ScreenCol: %d\n"), Screen_GetX(&ms) ); _tprintf( TEXT( "ScreenRow: %d\n"), Screen_GetY(&ms) ); _tprintf( TEXT( "Cursor-Pos: (%d,%d)\n" ), Cursor_GetX(&ms),Cursor_GetY(&ms) ); _tprintf( TEXT( "Bitte Taste fuer Fill_Screen_Attr(): gelb auf blau\n" )); Key_Hit(&ms) ; Fill_Screen_Attr( &ms,FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE ) ; _tprintf( TEXT( "Bitte Taste fuer ScreenCode-Ausgabe mit Write_Str()\n" )); for ( i = 0 ; i < 512 ; i ++ ) { iChar[0] = (TCHAR)i; Key_Hit(&ms) ; Write_Str( &ms, i%64, 10 + i/64, 1, iChar ); } _tprintf( TEXT( "Bitte Taste fuer Fill_Screen_Char( TEXT(' '), Write_Attr(), Write_Str() )\n") ); Cursor_Set( &ms, 0, 0 ); evt = Key_Hit(&ms) ; Fill_Screen_Char( &ms, TEXT(' ') ) ; // Bildschirm loeschen for (i = 0 ; i < 6 ; i ++ ) { Write_Attr( &ms, i*3, i, _tcslen( pStr ), FOREGROUND_BLUE | BACKGROUND_RED ); Write_Str ( &ms, i*3, i, _tcslen( pStr ), pStr ); } _tprintf( TEXT( "Bitte Taste fuer Scroll_Screen()\n" )); Key_Hit(&ms) ; #ifdef UNICODE //CHAR_INFO fillChar ; fillChar.Char.UnicodeChar = L'#' ; fillChar.Attributes = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ; #else fillChar.Char.AsciiChar = '#' ; fillChar.Attributes = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ; #endif for ( i = 0 ; i < (DWORD) Screen_GetY(&ms) - 16 ; i ++ ) { rect.Left = (short)i ; rect.Right = (short)i+22 ; rect.Top = (short)i ; rect.Bottom = (short)i+6 ; Scroll_Screen( &ms, i + 1, i + 1, & rect, fillChar ) ; Sleep( 500 ) ; // 500 ms } _tprintf( TEXT( "\n\nBitte mit Maus aufziehen\n" ) ); point.X = 9 ; point.Y = 9 ; Cursor_Off(&ms); do { evt = Read_Input( &ms, NULL ) ; if ( evt.EventType == MOUSE_EVENT ) { // Mausaktivitaet if ( memcmp( & point, & evt.Event.MouseEvent.dwMousePosition, sizeof(COORD))) { Write_Str( &ms, point.X, point.Y, _tcslen( szEmpty ), szEmpty ); point = evt.Event.MouseEvent.dwMousePosition ; Write_Str( &ms, point.X, point.Y, _tcslen( pStr ), pStr ); } } } while ( evt.Event.KeyEvent.wVirtualKeyCode != 27 ) ; // bis escape kommt Cursor_On(&ms); return 0 ; } //////////////////////////////////////////////////////////////// Nachrichten Windows ist ein Nachrichten - gesteuertes System. Die Behandlung von Nachrichten ist ein zentraler Bestandteil des Betriebssystems. System-Message-Queue Die Maus- und Tastatur - Ereignisse werden der System - Message - Queue( Hardware - Buffer ) entnommen und in ein einheitliches MSG - Format gebracht. Dann werden die Nachrichten in die Application - Message - Queue( Nachrichten an unser Fenster ) gestellt. Durch GetMessage() werden die Nachrichten dem Application - Buffer entnommen. Sollen z.B. sämtliche Nachrichten an alle Anwendungen abgehorcht werden, so ist direkt hinter der System - Message - Queue ( Hardware - Buffer ) ein Hook ( z.B. CallNextHookEx ) einzubauen. Application-Message-Queue Jede Anwendung hat eine eigene Application - Message - Queue. Ist diese leer, so können in der Zwischenzeit andere Programme ausgeführt werden ( kooperatives Multitasking ). ● ● Mit der Window - Funktion PostMessage() kann per Programm eine Nachricht hinten in die Application - Message Queue geschrieben werden. Mit SendMessage() kann per Programm eine Nachricht direkt an unser Fenster geschickt werden. SendMessage() überholt alle Nachrichten, die sich in der eigene Application - Message - Queue befinden. Für die Nachrichten verwendet Windows den MSG-Typ: typedef struct tagMSG { HWND hwnd ; UINT message ; WPARAM wParam ; LPARAM lParam ; DWORD time ; POINT pt ; } MSG ; MSG msg ; Die msg-Nachricht enthält auch msg.message. Durch message wird die Art der Nachricht eindeutig spezifiziert. Jede Nachricht kann in msg.wParam, msg.lParam zusätzliche Informationen hinterlegen. Die genaue Bedeutung der msg.wParam, msg.lParam - Bits hängt von msg.message ab. Für viele einfache Nachrichten reichen die Bits von wParam, lParam aus. In msg.lParam kann auch ein Zeiger auf benötigte Informationen enthalten sein. msg.time enthält die Ereignis - Zeit. Die Cursor - Koordinaten ( zur Ereignis-Zeit ) werden in pt übergeben. Soll z.B. die nächste Nachricht aus der Application-Message-Queue geholt werden, so wird mit GetMessage( & msg ) diese Nachricht in die ( vorher angelegte ) Variable MSG msg ; gespeichert. Haupt - Nachrichten - Schleife ( nach WinMain ) ist eine ( beinahe ) Unendlich-Schleife, die nur durch die WM_QUIT Nachricht verlassen werden kann. while ( GetMessage( & msg, NULL, 0, 0 ) ) { ... DispatchMessage ( & msg ) ; } Durch RegisterClass() wurde unsere ( Klassen - ) CALLBACK - Funktion WNDCLASS. lpfnWndProc = ( WNDPROC ) WndProc ; eingetragen. Durch DispatchMessage ( & msg ) wird die aktuelle Nachricht an diese Funktion weiter gereicht, d.h. die WndProc() wird mit den msg - Paramtern aufgerufen. Jedes Fenster hat ein eindeutiges Handle. Deshalb kann DispatchMessage ( & msg ) mit Hilfe von msg.hWnd die Nachricht über die ( globalen ) Klassen - Daten - Struktur an die CALLBACK - Funktion weiter geben. Die Haupt Nachrichten - Schleife wird bei einer WM_QUIT - Botschaft abgebrochen. Nach dem Eintreffen von WM_DESTROY fügen wir in der Application - Message - Queue durch PostQuitMessage() die Nachricht WM_QUIT ein. Wenn GetMessage() die WM_QUIT Nachricht entnimmt, so wird die Haupt - Nachrichten - Schleife beendet. Message - Cracker - Macros In windowsX.h sind die Message - Cracker - Macros enthalten. Durch diese Macros wird das Nachrichten - Carsting vermieden und die Win16/Win32 - Portabilität erhöht. Beispiele für soche Macros sind: #define HANDLE_MSG(hWnd, iMsg, fn) \ case (iMsg): return HANDLE_##iMsg((hWnd), (wParam), (lParam), (fn)) Ein HANDLE_MSG(hWnd, WM_CHAR, fn) - Macro - Aufruf enpandiert in ein weiteres ( in WindowsX.h enthaltenes ) HANDLE_WM_CHAR() - Macro: /* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */ #define HANDLE_WM_CHAR( hWnd, wParam, lParam, fn) \ ((fn)(( hWnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) #define FORWARD_WM_CHAR( hWnd, ch, cRepeat, fn) \ (void)(fn)(( hWnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0)) Viele HANDLE_ - Macros ( z.B. HANDLE_WM_CHAR ) zerlegen die Nachrichten typentreu in die enthaltenen Nachrichten Parameter und rufen damit die Funktion ( hier fn ) auf. Die FORWARD_ - Macros machen diesen Vorgang rückgängig und erzeugen wieder die ursprüngliche ( hWnd, iMsg, wParam, lParam ) - Nachricht. Mit dem HANDLE_MSG - Macro hat eine CALLBACK - Funktion etwa den folgenden Aufbau: LRESULT CALLBACK myCallbackProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { HANDLE_MSG( hWnd, WM_CHAR, myOnChar); HANDLE_MSG( ... ); ... default: return myOrgProc( hWnd, iMsg, wParam, lParam); } } Vielfach wird myOrgProc() der DefWindowProc() von Windows entsprechen. Die Funktion myOnChar() wird etwa wie folgt aufgebaut: void myOnChar( HWND hWnd, UINT ch, int cRepeat) { if ( ch == testvalue ) { // handle it here } else { FORWARD_WM_CHAR( hWnd, ch, cRepeat, myOrgProc); } } Das FORWARD_ - Macro setzt die zerlegte Nachricht wieder zur ursprünglichen ( hWnd, iMsg, wParam, lParam ) - Nachricht zusammen. In WindowsX.h sind ( als Kommentar ) die Funktions - Parameter für myOnChar() angegeben. /* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */ Soll für myOrgProc() nicht DefWindowProc() sondern die orginal Klassen - CALLBACK - Funktion lpOrgProc aufgerufen werden, so kann myOrgProc definiert werden durch: LRESULT myOrgProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { return CallWindowProc( lpOrgProc, hWnd, iMsg, wParam, lParam); } CallWindowProc() ruft die Funktion lpOrgProc auf. In WindowsX.h ist #define Sumy_classWindow( hWnd, lpfn) \ ((WNDPROC)SetWindowLong(( hWnd), GWL_WNDPROC, \ (LPARAM)(WNDPROC)MakeProcInstance((FARPROC)(lpfn),GetModuleHandle(NULL)))) enthalten. Damit kann ein Sumy_classing gemäß WNDPROC lpOrgProc = NULL; lpOrgProc = Sumy_classWindow( hWnd, myCallbackProc)); ... erfolgen. Portabilität Beim Übergang von WIN16 auf WIN32 hat sich das Nachrichten - Format geändert. Bei WIN16 war wParam ein WORD - Typ, bei WIN32 ist wParam ein LONG - Typ. Bei WIN32 benötigt ein Handle 32 Bits. Win32 32 Bit 32 Bit |---------------------------------|---------------------------------| | wParam | lParam | |----------------|----------------|---------------------------------| | | | | | wmCMD | wmID | wmHWND | Win16 16 Bit 32 Bit |----------------|---------------------------------| | wParam | lParam | |----------------|---------------------------------| | | | | | wmID | wmCMD | wmHWND | Der Button sendet Nachrichten an das Parent - Window, wenn sich sein Zustand ändert. Der Button - Identifizierer wird mit wmID, die Notification Messages ( z.B. BN_CLICKED ) wird mit wmCMD und das Control - Handle mit wmHWND bezeichnet. Wegen der WIN16/WIN32 - Portabilität sind die windoesX.h - Macros sinnvoll: Nachrichten - Casting WindosX.h-Macros #ifdef WIN16 int wmCMD = HIWORD( lParam ) ; #else int wmCMD = HIWORD( wParam ) ; #endif int wmID = LOWORD( wParam ); HWND wmHWND= (HWND)(UINT)lParam; int wmCMD = GET_WM_COMMAND_CMD (wParam,lParam); int wmID = GET_WM_COMMAND_ID (wParam,lParam); HWND wmHWND= GET_WM_COMMAND_HWND(wParam,lParam); 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 bx, [bp+4] ;ASCII returned MOV [bx], al MOV bx, [bp+6] ;Extended code returned MOV [bx], ah POP bp RET key_read ENDP END Tasten - Scan - Code Der folgende Tasten - Scan - Code ist festgelegt worden: 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’ case ‘\t’ case ‘\n’ default : : Rücktaste; break; : Tabulatortaste; break; : LF-Taste; break; //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 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 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 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 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 WINVER<=0x0400 = 0xE5 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 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. 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. 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 ( || ( GetAsyncKeyState ( ) { // ... z.B. exit ( // ... SendMessage } VK_LBUTTON ) < 0 ) // linke Maus - Taste down VK_ESCAPE ) < 0 ) // Escape Taste -1 ); oder ( 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 gewechselt, wenn das 0. Bit gleich 1 ist ( tggled ). Normalerweise ist eine Taste nicht gedrückt, dann ist das 0. Bit gleich 1. 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 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. 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 ) - Bit Bit HIWORD( lParam ) - Bit Bit HIWORD( lParam ) - Bit Bit HIWORD( lParam ) - Bit 1 if the key is up; 15 0 if the key is down. 1 if the key was previously up; 14 0 if the key was previously down. 13 1 if the ALT key is down. 12 1 if Windows displays a menu. 8 1 if the key is extended; 0 if it is not. 11 1 if Windows displays a dialog box. 10 Not used. 9 Not used. 7 generally 0. hardware-scan code 6..0 ( used mainly in the translation of ALT+number-pad character code input ) 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. 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 wc={ 0 }; wc.cbSize=sizeof(WNDCLASSEX); ... wc.style = ... | CS_DBLCLKS; // Zeitgeber ½ sec. RegisterClass( & wc ); erforderlich. WM_MOUSE - 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 nHittest see WM_ NC HITTEST Nachricht WM_CAPTURECHANGED wParam, lParam enthalten ... hwndNewCapture = (HWND) lParam; // handle of window to gain mouse capture WM_MOUSEMOVE WM_LBUTTONDOWN WM_LBUTTONUP WM_RBUTTONDOWN WM_RBUTTONUP WM_MBUTTONDOWN WM_MBUTTONUP WM_LBUTTONDBLCLK WM_MBUTTONDBLCLK WM_RBUTTONDBLCLK fwKeys = wParam; // key flags xPos = LOWORD(lParam); // horizontal position of cursor yPos = HIWORD(lParam); // vertical position of cursor 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. WM_MOUSEACTIVATE hwndTopLevel = (HWND) wParam; // handle of top-level parent nHittest = (INT) LOWORD(lParam); // hit-test value uMsg = (UINT) HIWORD(lParam); // mouse message 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 WM_MOUSEWHEEL 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. WM_NCHITTEST 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 WM_NCLBUTTONDBLCLK nHittest = (INT) wParam; // hit-test value WM_NCLBUTTONDBLCLK pts = MAKEPOINTS(lParam); // position of cursor WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCMBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMOUSEMOVE WM_NCRBUTTONDBLCLK WM_NCRBUTTONDOWN WM_NCRBUTTONUP Das Maus - Rad ( WM_MOUSEWHEEL ) kann z.B. zur Steuerung von Scroll - Bars eingesetzt werden. // Window Messages #define WM_NULL #define WM_CREATE #define WM_DESTROY #define WM_MOVE #define WM_SIZE 0x0000 0x0001 0x0002 0x0003 0x0005 #define WM_ACTIVATE 0x0006 // WM_ACTIVATE state values #define WA_INACTIVE 0 #define WA_ACTIVE 1 #define WA_CLICKACTIVE 2 #define WM_SETFOCUS #define WM_KILLFOCUS #define WM_ENABLE #define WM_SETREDRAW #define WM_SETTEXT #define WM_GETTEXT #define WM_GETTEXTLENGTH #define WM_PAINT #define WM_CLOSE #define WM_QUERYENDSESSION #define WM_QUIT #define WM_QUERYOPEN #define WM_ERASEBKGND #define WM_SYSCOLORCHANGE #define WM_ENDSESSION #define WM_SHOWWINDOW #define WM_WININICHANGE #if(WINVER >= 0x0400) #define WM_SETTINGCHANGE #endif /* WINVER >= 0x0400 */ 0x0007 0x0008 0x000A 0x000B 0x000C 0x000D 0x000E 0x000F 0x0010 0x0011 0x0012 0x0013 0x0014 0x0015 0x0016 0x0018 0x001A #define #define #define #define #define #define #define #define #define WM_DEVMODECHANGE WM_ACTIVATEAPP WM_FONTCHANGE WM_TIMECHANGE WM_CANCELMODE WM_SETCURSOR WM_MOUSEACTIVATE WM_CHILDACTIVATE WM_QUEUESYNC 0x001B 0x001C 0x001D 0x001E 0x001F 0x0020 0x0021 0x0022 0x0023 #define #define #define #define #define #define #define #define #define #define #define #define #define #define WM_GETMINMAXINFO WM_PAINTICON WM_ICONERASEBKGND WM_NEXTDLGCTL WM_SPOOLERSTATUS WM_DRAWITEM WM_MEASUREITEM WM_DELETEITEM WM_VKEYTOITEM WM_CHARTOITEM WM_SETFONT WM_GETFONT WM_SETHOTKEY WM_GETHOTKEY 0x0024 0x0026 0x0027 0x0028 0x002A 0x002B 0x002C 0x002D 0x002E 0x002F 0x0030 0x0031 0x0032 0x0033 WM_WININICHANGE #define WM_QUERYDRAGICON #define WM_COMPAREITEM 0x0037 0x0039 #define #define #define #define 0x0041 0x0044 0x0046 0x0047 WM_COMPACTING WM_COMMNOTIFY WM_WINDOWPOSCHANGING WM_WINDOWPOSCHANGED #define WM_POWER /* no longer suported */ 0x0048 // wParam for WM_POWER window message and DRV_POWER driver notification #define PWR_OK 1 #define PWR_FAIL (-1) #define PWR_SUSPENDREQUEST 1 #define PWR_SUSPENDRESUME 2 #define PWR_CRITICALRESUME 3 #define WM_COPYDATA #define WM_CANCELJOURNAL 0x004A 0x004B #if(WINVER >= 0x0400) #define WM_NOTIFY #define WM_INPUTLANGCHANGEREQUEST #define WM_INPUTLANGCHANGE #define WM_TCARD #define WM_HELP #define WM_USERCHANGED #define WM_NOTIFYFORMAT 0x004E 0x0050 0x0051 0x0052 0x0053 0x0054 0x0055 #define #define #define #define NFR_ANSI NFR_UNICODE NF_QUERY NF_REQUERY 1 2 3 4 #define WM_CONTEXTMENU #define WM_STYLECHANGING #define WM_STYLECHANGED #define WM_DISPLAYCHANGE #define WM_GETICON #define WM_SETICON #endif /* WINVER >= 0x0400 */ 0x007B 0x007C 0x007D 0x007E 0x007F 0x0080 #define #define #define #define #define #define #define WM_NCCREATE WM_NCDESTROY WM_NCCALCSIZE WM_NCHITTEST WM_NCPAINT WM_NCACTIVATE WM_GETDLGCODE 0x0081 0x0082 0x0083 0x0084 0x0085 0x0086 0x0087 #define #define #define #define #define WM_NCMOUSEMOVE WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCLBUTTONDBLCLK WM_NCRBUTTONDOWN 0x00A0 0x00A1 0x00A2 0x00A3 0x00A4 #define #define #define #define #define WM_NCRBUTTONUP WM_NCRBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMBUTTONDBLCLK 0x00A5 0x00A6 0x00A7 0x00A8 0x00A9 #define #define #define #define #define #define #define #define #define #define WM_KEYFIRST WM_KEYDOWN WM_KEYUP WM_CHAR WM_DEADCHAR WM_SYSKEYDOWN WM_SYSKEYUP WM_SYSCHAR WM_SYSDEADCHAR WM_KEYLAST 0x0100 0x0100 0x0101 0x0102 0x0103 0x0104 0x0105 0x0106 0x0107 0x0108 #if(WINVER >= 0x0400) #define WM_IME_STARTCOMPOSITION #define WM_IME_ENDCOMPOSITION #define WM_IME_COMPOSITION #define WM_IME_KEYLAST #endif /* WINVER >= 0x0400 */ 0x010D 0x010E 0x010F 0x010F #define #define #define #define #define #define #define #define #define #define #define WM_INITDIALOG WM_COMMAND WM_SYSCOMMAND WM_TIMER WM_HSCROLL WM_VSCROLL WM_INITMENU WM_INITMENUPOPUP WM_MENUSELECT WM_MENUCHAR WM_ENTERIDLE 0x0110 0x0111 0x0112 0x0113 0x0114 0x0115 0x0116 0x0117 0x011F 0x0120 0x0121 #define #define #define #define #define #define #define WM_CTLCOLORMSGBOX WM_CTLCOLOREDIT WM_CTLCOLORLISTBOX WM_CTLCOLORBTN WM_CTLCOLORDLG WM_CTLCOLORSCROLLBAR WM_CTLCOLORSTATIC 0x0132 0x0133 0x0134 0x0135 0x0136 0x0137 0x0138 #define WM_MOUSEFIRST #define WM_MOUSEMOVE #define WM_LBUTTONDOWN #define WM_LBUTTONUP #define WM_LBUTTONDBLCLK #define WM_RBUTTONDOWN #define WM_RBUTTONUP #define WM_RBUTTONDBLCLK #define WM_MBUTTONDOWN #define WM_MBUTTONUP #define WM_MBUTTONDBLCLK #if(_WIN32_WINNT >= 0x0400) #define WM_MOUSEWHEEL #endif /* _WIN32_WINNT >= 0x0400 */ 0x0200 0x0200 0x0201 0x0202 0x0203 0x0204 0x0205 0x0206 0x0207 0x0208 0x0209 0x020A #if (_WIN32_WINNT < 0x0400) #define WM_MOUSELAST 0x0209 #else #define WM_MOUSELAST 0x020A #endif /* if (_WIN32_WINNT < 0x0400) */ #if(_WIN32_WINNT >= 0x0400) #define WHEEL_DELTA #endif /* _WIN32_WINNT >= 0x0400 */ #if(_WIN32_WINNT >= 0x0400) #define WHEEL_PAGESCROLL #endif /* _WIN32_WINNT >= 0x0400 */ #define #define #define #define #define WM_PARENTNOTIFY MENULOOP_WINDOW MENULOOP_POPUP WM_ENTERMENULOOP WM_EXITMENULOOP #if(WINVER >= 0x0400) #define WM_NEXTMENU #define WM_SIZING #define WM_CAPTURECHANGED #define WM_MOVING #define WM_POWERBROADCAST #define WM_DEVICECHANGE 120 (UINT_MAX) /* Scroll one page */ 0x0210 0 1 0x0211 0x0212 0x0213 0x0214 0x0215 0x0216 0x0218 0x0219 #define WM_IME_SETCONTEXT #define WM_IME_NOTIFY #define WM_IME_CONTROL #define WM_IME_COMPOSITIONFULL #define WM_IME_SELECT #define WM_IME_CHAR #define WM_IME_KEYDOWN #define WM_IME_KEYUP #endif /* WINVER >= 0x0400 */ 0x0281 0x0282 0x0283 0x0284 0x0285 0x0286 0x0290 0x0291 #define #define #define #define #define #define #define #define #define #define WM_MDICREATE WM_MDIDESTROY WM_MDIACTIVATE WM_MDIRESTORE WM_MDINEXT WM_MDIMAXIMIZE WM_MDITILE WM_MDICASCADE WM_MDIICONARRANGE WM_MDIGETACTIVE 0x0220 0x0221 0x0222 0x0223 0x0224 0x0225 0x0226 0x0227 0x0228 0x0229 #define #define #define #define #define WM_MDISETMENU WM_ENTERSIZEMOVE WM_EXITSIZEMOVE WM_DROPFILES WM_MDIREFRESHMENU 0x0230 0x0231 0x0232 0x0233 0x0234 #if(_WIN32_WINNT >= 0x0400) /* Value for rolling one detent */ #define WM_MOUSEHOVER #define WM_MOUSELEAVE #endif /* _WIN32_WINNT >= 0x0400 */ 0x02A1 0x02A3 #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define 0x0300 0x0301 0x0302 0x0303 0x0304 0x0305 0x0306 0x0307 0x0308 0x0309 0x030A 0x030B 0x030C 0x030D 0x030E 0x030F 0x0310 0x0311 0x0312 WM_CUT WM_COPY WM_PASTE WM_CLEAR WM_UNDO WM_RENDERFORMAT WM_RENDERALLFORMATS WM_DESTROYCLIPBOARD WM_DRAWCLIPBOARD WM_PAINTCLIPBOARD WM_VSCROLLCLIPBOARD WM_SIZECLIPBOARD WM_ASKCBFORMATNAME WM_CHANGECBCHAIN WM_HSCROLLCLIPBOARD WM_QUERYNEWPALETTE WM_PALETTEISCHANGING WM_PALETTECHANGED WM_HOTKEY #if(WINVER >= 0x0400) #define WM_PRINT #define WM_PRINTCLIENT 0x0317 0x0318 #define WM_HANDHELDFIRST #define WM_HANDHELDLAST 0x0358 0x035F #define WM_AFXFIRST #define WM_AFXLAST #endif /* WINVER >= 0x0400 */ 0x0360 0x037F #define WM_PENWINFIRST #define WM_PENWINLAST 0x0380 0x038F #if(WINVER >= 0x0400) #define WM_APP #endif /* WINVER >= 0x0400 */ 0x8000 /* NOTE: All Message Numbers below 0x0400 are RESERVED. * Private Window Messages Start Here: */ #define WM_USER #define WM_DDE_FIRST #define WM_DDE_INITIATE 0x0400 0x03E0 (WM_DDE_FIRST) #define #define #define #define #define #define #define #define #define WM_DDE_TERMINATE WM_DDE_ADVISE WM_DDE_UNADVISE WM_DDE_ACK WM_DDE_DATA WM_DDE_REQUEST WM_DDE_POKE WM_DDE_EXECUTE WM_DDE_LAST (WM_DDE_FIRST+1) (WM_DDE_FIRST+2) (WM_DDE_FIRST+3) (WM_DDE_FIRST+4) (WM_DDE_FIRST+5) (WM_DDE_FIRST+6) (WM_DDE_FIRST+7) (WM_DDE_FIRST+8) (WM_DDE_FIRST+8) ============================================= ACHTUNG! Nicht lauffähig! Nur Pseudo Code! ============================================= LRESULT API IDefWindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { int i; HBRUSH hbr; HWND hWndT; switch ( iMsg ) { case WM_NCCREATE: // If WS_HSCROLL or WS_VSCROLL, initialize storage for scroll positions. // NOTE: Scroll bar storage and text storage will be freed automatically //by Windows during CreateWindow() if (TestWF(hWnd, (WFHSCROLL | WFVSCROLL))) { // Initialize extra storage for if (InitPwSB(hWnd) == NULL) return((LONG)FALSE); } // Store window text if present. return((LRESULT)(LONG)DefSetText(hWnd, ((LPCREATESTRUCT)lParam)->lpszName)); case WM_NCCALCSIZE: // wParam = fCalcValidRects // lParam = LPRECT rgrc[3]: // lprc[0] = rcWindowNew = New window rectangle // if fCalcValidRects: // lprc[1] = rcWindowOld = Old window rectangle // lprc[2] = rcClientOld = Old client rectangle // On return: // rgrc[0] = rcClientNew = New client rect // if fCalcValidRects: // rgrc[1] = rcValidDst = Destination valid rectangle // rgrc[2] = rcValidSrc = Source valid rectangle CalcClientRect(hWnd, (LPRECT)lParam); break; case WM_NCHITTEST: // Determine what area the passed coordinate is in. return((LRESULT)(DWORD)FindNCHit(hWnd, (LONG)lParam)); case WM_NCPAINT: // Do non-client area drawing. DWP_DoNCPaint(hWnd, (HRGN)wParam); break; case WM_NCACTIVATE: // Do non-client drawing in response to activation or deactivation. DWP_DoNCActivate(hWnd, (BOOL)wParam); return (LRESULT)(DWORD)TRUE; case WM_CANCELMODE: // Terminate any modes the system might be in, //such as scrollbar tracking, menu mode, button capture, etc. DWP_DoCancelMode(hWnd); break; case WM_SETTEXT: // Set the new text and redraw the caption or icon title window. DefSetText(hWnd, (LPCSTR)lParam); DWP_RedrawTitle(hWnd); break; case WM_GETTEXT: // If the buffer size is > 0, copy as much of the window text as // will fit (making sure to zero terminate the result). if (wParam){ if (hWnd->hName) return (LRESULT)(LONG)TextCopy(hWnd->hName, (LPSTR)lParam, (int)wParam); // No string: make sure we return an empty string. ((LPSTR)lParam)[0] = 0; } return (0L); case WM_GETTEXTLENGTH: // Just return the length of the window text (excluding 0 terminator) if (hWnd->hName) return((LRESULT)(LONG)lstrlen(TextPointer(hWnd->hName))); return(0L); case WM_PAINT: case WM_PAINTICON: DWP_Paint( iMsg, hWnd); break; case WM_ERASEBKGND: case WM_ICONERASEBKGND: return (LRESULT)(LONG)DWP_EraseBkgnd(hWnd, iMsg, (HDC)wParam); case WM_SYNCPAINT: // This message is sent when SetWindowPos() is trying to get the screen // looking nice after window rearrangement, and one of the windows involved // is of another task. This message avoids lots of inter-app message traffic // by switching to the other task and continuing the recursion there. // wParam = flags // LOWORD(lParam) = hrgnClip // HIWORD(lParam) = hWndSkip (not used; always NULL) // hWndSkip is now always NULL. // NOTE: THIS MESSAGE IS FOR INTERNAL USE ONLY! ITS BEHAVIOR // IS DIFFERENT IN 3.1 THAN IN 3.0!! DoSyncPaint(hWnd, NULL, ((WORD)wParam | DSP_WM_SYNCPAINT)); break; case WM_SYSCOMMAND: SysCommand(hWnd, (int)wParam, lParam); break; case WM_ACTIVATE: // By default, windows set the focus to themselves when activated. if ((BOOL)wParam) SetFocus(hWnd); break; case WM_SETREDRAW: // Set or clear the WS_VISIBLE bit, without invalidating the window. // (Also performs some internal housekeeping to ensure that window // DC clip regions are computed correctly). DWP_SetRedraw(hWnd, (BOOL)wParam); break; case WM_WINDOWPOSCHANGING: // If the window's size is changing, and the window has // a size border (WS_THICKFRAME) or is a main window (WS_OVERLAPPED), // then adjust the new width and height by sending a WM_MINMAXINFO message. #define ppos ((WINDOWPOS FAR *)lParam) if (!(ppos->flags & SWP_NOSIZE)) AdjustSize(hWnd, &ppos->cx, &ppos->cy); #undef ppos break; case WM_WINDOWPOSCHANGED: // If (!(lpswp->flags & SWP_NOCLIENTMOVE) // send WM_MOVE message // If (!(lpswp->flags & SWP_NOCLIENTSIZE) // send WM_SIZE message with wParam set based on // current WS_MINIMIZED/WS_MAXIMIZED style. // If DefWindowProc() is not called, WM_MOVE and WM_SIZE messages // will not be sent to the window. HandleWindowPosChanged(hWnd, (WINDOWPOS FAR *)lParam);break; case WM_CTLCOLOR: // Set up the supplied DC with the foreground and background // colors we want to use in the control, and return a brush // to use for filling. switch (HIWORD(lParam)) { case CTLCOLOR_SCROLLBAR: // Background = white // Foreground = black // brush = COLOR_SCROLLBAR. SetBkColor((HDC)wParam, RGB(255, 255, 255)); SetTextColor((HDC)wParam, RGB(0, 0, 0)); hbr = sysClrObjects.hbrScrollbar; // The scroll bar color may be dithered, so unrealize it. UnrealizeObject(hbr); break; default: // Background = COLOR_WINDOW // Foreground = COLOR_WINDOWTEXT // Brush = COLOR_WINDOW SetBkColor((HDC)wParam, sysColors.clrWindow); SetTextColor((HDC)wParam, sysColors.clrWindowText); hbr = sysClrObjects.hbrWindow; } return((LRESULT)(DWORD)(WORD)hbr); case WM_SETCURSOR: // wParam == hWndHit == hWnd that cursor is over // lParamL == codeHT == Hit test area code (result of WM_NCHITTEST) // lParamH == msg == Mouse message number (may be 0) // Strategy: First forward WM_SETCURSOR message to parent. If it // returns TRUE (i.e., it set the cursor), just return. Otherwise, // set the cursor based on codeHT and msg. return (LRESULT)(LONG)DWP_SetCursor(hWnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)); case WM_MOUSEACTIVATE:// First give the parent a chance to process the message. hWndT = GetChildParent(hWnd); if (hWndT) { i = (int)(DWORD)SendMessage(hWndT, WM_MOUSEACTIVATE, wParam, lParam); if (i != 0) return (LRESULT)(LONG)i; } // If the user clicked in the title bar, don't activate now: // the activation will take place later when the move or size occurs. if (LOWORD(lParam) == HTCAPTION) return((LRESULT)(LONG)MA_NOACTIVATE); return((LRESULT)(LONG)MA_ACTIVATE); case WM_SHOWWINDOW: // If we are being called because our owner window is being shown, // hidden, minimized, or un-minimized, then we must hide or show // show ourself as appropriate. // // This behavior occurs for popup windows or owned windows only. // It's not designed for use with child windows. if (LOWORD(lParam) != 0 && (TestwndPopup(hWnd) || hWnd->hWndOwner)) { // The WFHIDDENPOPUP flag is an internal flag that indicates // that the window was hidden because its owner was hidden. // This way we only show windows that were hidden by this code, // not intentionally by the application. // // Go ahead and hide or show this window, but only if: // // a) we need to be hidden, or // b) we need to be shown, and we were hidden by // an earlier WM_SHOWWINDOW message if ((!wParam && TestWF(hWnd, WFVISIBLE)) || (wParam && !TestWF(hWnd, WFVISIBLE) && TestWF(hWnd, WFHIDDENPOPUP))) // Remember that we were hidden by WM_SHOWWINDOW processing ClrWF(hWnd, WFHIDDENPOPUP); if (!wParam) SetWF(hWnd, WFHIDDENPOPUP); ShowWindow(hWnd, (wParam ? SW_SHOWNOACTIVATE : SW_HIDE)); } { } break; case case case case WM_NCLBUTTONDOWN: WM_NCLBUTTONUP: WM_NCLBUTTONDBLCLK: WM_NCMOUSEMOVE: // Deal with mouse messages in the non-client area. DWP_NCMouse(hWnd, message, wParam, lParam); break; case WM_KEYDOWN: // Windows 2.0 backward compatibility: // Alias F10 to the menu key // (only for apps that don't handle WM_KEY* messages themselves) if ((WORD)wParam == VK_F10) fF10Status = TRUE; break; case WM_SYSKEYDOWN: // Is the ALT key down? if (HIWORD(lParam) & SYS_ALTERNATE) { // Toggle only if this is not an autorepeat key if ((HIWORD(lParam) & SYS_PREVKEYSTATE) == 0) { if (((WORD)wParam == VK_MENU) && (!fMenuStatus)) fMenuStatus = TRUE; else fMenuStatus = FALSE; } fF10Status = FALSE; DWP_ProcessVirtKey((WORD)wParam); } else { if ((WORD)wParam == VK_F10) { fF10Status = TRUE; } else { if ((WORD)wParam == VK_ESCAPE) { if (GetKeyState(VK_SHIFT) < 0) { SendMessage(hWnd, WM_SYSCOMMAND,(WPARAM)SC_KEYMENU, (LPARAM)(DWORD)MENUSYSMENU); } } } } break; case WM_KEYUP: case WM_SYSKEYUP: // Press and release F10 or ALT. Send this only to top-level // windows, otherwise MDI gets confused. The fix in which // DefMDIChildProc() passed up the message was insufficient in the // case a child window of the MDI child had the focus. // if ( ((WORD)wParam == VK_MENU && (fMenuStatus == TRUE)) || ((WORD)wParam == VK_F10 && fF10Status) ) { SendMessage(GetTopLevelWindow(hWnd), WM_SYSCOMMAND,(WPARAM)SC_KEYMENU, 0L); } fF10Status = fMenuStatus = FALSE; break; case WM_SYSCHAR: // If syskey is down and we have a char... */ fMenuStatus = FALSE; if ((WORD)wParam == VK_RETURN && TestWF(hWnd, WFMINIMIZED)) { // If the window is iconic and user hits RETURN, we want to restore this window. PostMessage(hWnd, WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L); break; } if ((HIWORD(lParam) & SYS_ALTERNATE) && wParam) { if ((WORD)wParam == VK_TAB || (WORD)wParam == VK_ESCAPE) break; // Send ALT-SPACE only to top-level windows. if (((WORD)wParam == MENUSYSMENU) && (TestwndChild(hWnd))) SendMessage(hWnd->hWndParent, message, wParam, lParam); else SendMessage(hWnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)(WORD)wParam); } else { // Ctrl-Esc produces a WM_SYSCHAR, but should not beep if ((WORD)wParam != VK_ESCAPE) MessageBeep(0); } break; case WM_CLOSE: // Default WM_CLOSE handling is to destroy the window. DestroyWindow(hWnd); break; case WM_QUERYOPEN: case WM_QUERYENDSESSION: return((LRESULT)(LONG)TRUE); case WM_ISACTIVEICON: return ((LRESULT)(DWORD)(BOOL)(TestWF(hWnd, WFFRAMEON) != 0)); case WM_CHARTOITEM: case WM_VKEYTOITEM: // Return -1 to cause default processing return((LRESULT)-1L); case WM_DRAWITEM: #define lpdis ((LPDRAWITEMSTRUCT)lParam) if (lpdis->CtlType == ODT_LISTBOX) LBDefaultListboxDrawItem(lpdis); #undef lpdis break; case WM_GETHOTKEY: return((LRESULT)(LONG)DWP_GetHotKey(hWnd)); break; case WM_SETHOTKEY: return((LRESULT)(LONG)SetHotKey(hWnd, (WORD)wParam)); break; case WM_QUERYDRAGICON: return((LRESULT)(DWORD)(WORD)DWP_QueryDragIcon(hWnd)); break; case WM_QUERYDROPOBJECT: // If the application is WS_EX_ACCEPTFILES, return TRUE. if (TestWF(hWnd, WEFACCEPTFILES)) return (LRESULT)(DWORD)TRUE; return (LRESULT)(DWORD)FALSE; case WM_DROPOBJECT: return (LRESULT)(DWORD)DO_DROPFILE; } // end switch return(0L); } ============================================= ACHTUNG! Nicht lauffähig! Nur Pseudo Code! ============================================= LRESULT API IDefDlgProc( HWND hWnd, WORD iMsg, WPARAM wParam, LPARAM lParam) { HWND hWndT1; HWND hWndT2; BOOL result; ((PDLG)hWnd)->resultWP = 0L; result = FALSE; // Call the dialog proc if it exists if (((PDLG)hWnd)->lpfnDlg == NULL || !(result = CallDlgProc(hWnd, iMsg, wParam, lParam))) { // Make sure window still exists. if (!IsWindow(hWnd)) { DebugErr(DBF_ERROR, "Dialog window destroyed in dialog callback"); goto ReturnIt; } switch (iMsg) { case WM_ERASEBKGND: FillWindow(hWnd, hWnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG); return((LRESULT)(LONG)TRUE); case WM_SHOWWINDOW: // If hiding the window, save the focus. If showing the window // by means of a SW_* command and the fEnd bit is set, do not // pass to DWP so it won't get shown. if (!wParam) SaveDlgFocus(hWnd); else if (LOWORD(lParam) && pdlg->fEnd) break; return(DefWindowProc(hWnd, iMsg, wParam, lParam)); case WM_SYSCOMMAND: // If we're minimizing and a dialog control has the focus, // save the hWnd for that control if ((int) wParam == SC_MINIMIZE) SaveDlgFocus(hWnd); return( DefWindowProc ( hWnd, iMsg, wParam, lParam ) ) ; case WM_ACTIVATE: if ( fDialog = ( wParam != 0 ) ) RestoreDlgFocus( hWnd ) ; else SaveDlgFocus( hWnd ) ; break; case WM_SETFOCUS: if (!pdlg->fEnd && !RestoreDlgFocus(hWnd)) DlgSetFocus(GetFirstTab(hWnd)); break; case WM_CLOSE: // Make sure cancel button is not disabled before sending the // IDCANCEL. Note that we need to do this as a message instead // of directly calling the dlg proc so that any dialog box // filters get this. hWndT1 = GetDlgItem( hWnd, IDCANCEL ) ; if ( hWndT1 && TestWF( hWndT1, WFDISABLED ) ) MessageBeep(0); else PostMessage(hWnd, WM_COMMAND, (WPARAM)IDCANCEL, MAKELPARAM(hWndT1, BN_CLICKED)); break; case WM_NCDESTROY: fDialog = FALSE; /* clear this flag */ // Make sure we are going to terminate the mode loop, in case DestroyWindow // was called instead of EndDialog. We'll RIP in DialogBox2. ((PDLG)hWnd)->fEnd = TRUE; if (!(hWnd->style & DS_LOCALEDIT)) { if (((PDLG)hWnd)->hData) { GlobalUnlock(((PDLG)hWnd)->hData); ReleaseEditDS(((PDLG)hWnd)->hData); ((PDLG)hWnd)->hData = NULL; } } // Delete the user defined font if any if (((PDLG)hWnd)->hUserFont) { DeleteObject((HANDLE)((PDLG)hWnd)->hUserFont); ((PDLG)hWnd)->hUserFont = NULL; } // Always let DefWindowProc do its thing to ensure that // everything associated with the window is freed up. DefWindowProc(hWnd, iMsg, wParam, lParam); break; case DM_SETDEFID: if (!(((PDLG)hWnd)->fEnd)) { // Make sure that the new default button has the highlight. // We need to ignore this if we are ending the dialog box // because hWnd->result is no longer a default window id but // rather the return value of the dialog box. // // Catch the case of setting the defid to null or setting // the defid to something else when it was initially null. // CheckDefPushButton(hWnd, (((PDLG)hWnd)->result ? GetDlgItem(hWnd, ((PDLG)hWnd)->result) : NULL), (wParam ? GetDlgItem(hWnd, (int) wParam ) : NULL) ); ((PDLG)hWnd)->result = (int)wParam; } return((LRESULT)(DWORD)TRUE); case DM_GETDEFID: if (!((PDLG)hWnd)->fEnd && ((PDLG)hWnd)->result) return(MAKELRESULT(((PDLG)hWnd)->result, DC_HASDEFID)); else return(0L); case WM_NEXTDLGCTL: // This message is so TAB-like operations can be properly handled // (simple SetFocus won't do the default button stuff) // hWndT2 = hWndFocus; if (LOWORD(lParam)) { if (hWndT2 == NULL) hWndT2 = hWnd; // wParam contains the hWnd of the ctl to set focus to hWndT1 = (hWnd)wParam; } else { if (hWndT2 == NULL) { // Set focus to the first tab item. hWndT1 = GetFirstTab(hWnd); hWndT2 = hWnd; } else { // If window with focus not a dlg ctl, ignore message. if (!IsChild(hWnd, hWndT2)) return((LRESULT)(LONG)TRUE); // wParam = TRUE for previous, FALSE for next hWndT1 = GetNextDlgTabItem(hWnd, hWndT2, (BOOL)wParam); } } DlgSetFocus(hWndT1); CheckDefPushButton(hWnd, hWndT2, hWndT1); return((LRESULT)(LONG)TRUE); case WM_ENTERMENULOOP: case WM_LBUTTONDOWN: case WM_NCLBUTTONDOWN: // PLEASE NOTE: The following code is a VERY UGLY compatibility // hack. NEVER write code that looks at the window proc address // in order to determine the window type. The following code will // not work with subclassed combo or edit controls. // if (hWndT1 = hWndFocus) { if (hWndT1->pcls->lpfnWndProc == ComboBoxCtlWndProc) { // If user clicks anywhere in dialog box and a combo box (or // the editcontrol of a combo box) has the focus, then hide // it's listbox. SendMessage(hWndT1, CB_SHOWDROPDOWN, FALSE, 0L); } else { if (hWndT1->pcls->lpfnWndProc == EditWndProc && hWndT1->hWndParent->pcls->lpfnWndProc==ComboBoxCtlWndProc) { SendMessage(hWndT1->hWndParent,CB_SHOWDROPDOWN, FALSE, 0L); } } } return(DefWindowProc(hWnd, iMsg, wParam, lParam)); case WM_GETFONT: return (LRESULT)(DWORD)(WORD)((PDLG)hWnd)->hUserFont; // We don't want to pass the following messages to DefWindowProc: // instead, return the value returned by the dialog proc (FALSE) case WM_VKEYTOITEM: case WM_COMPAREITEM: case WM_CHARTOITEM: case WM_INITDIALOG: break; default: return(DefWindowProc(hWnd, iMsg, wParam, lParam)); } } ReturnIt: // These messages are special cased in an unusual way: the return value // of the dialog function is not BOOL fProcessed, but instead it's the // return value of these messages. // if (iMsg == WM_CTLCOLOR || iMsg == WM_COMPAREITEM || iMsg == WM_VKEYTOITEM || iMsg == WM_CHARTOITEM || iMsg == WM_QUERYDRAGICON || iMsg == WM_INITDIALOG) { return((LRESULT)(DWORD)result); } return(((PDLG)hWnd)->resultWP); } BOOL SaveDlgFocus(HWND hWnd) { if (hWndFocus && IsChild(hWnd, hWndFocus) && !((PDLG)hWnd)->hWndFocusSave) { ((PDLG)hWnd)->hWndFocusSave = hWndFocus; RemoveDefaultButton(hWnd, hWndFocus); return(TRUE); } return(FALSE); } BOOL RestoreDlgFocus(HWND hWnd) { BOOL fRestored = FALSE; if (((PDLG)hWnd)->hWndFocusSave && !TestWF(hWnd, WFMINIMIZED)) { if (IsWindow(((PDLG)hWnd)->hWndFocusSave)) { CheckDefPushButton(hWnd, hWndFocus, ((PDLG)hWnd)->hWndFocusSave); SetFocus(((PDLG)hWnd)->hWndFocusSave); fRestored = TRUE; } ((PDLG)hWnd)->hWndFocusSave = NULL; } return(fRestored); } Objekte Windows-Objekte werden mit einem Handle identifiziert. Ein Zugriff auf intern von Windows gespeicherten Daten ist nur mit Zugriffsfunktionen möglich ( Sytem - Konsistenz, GetWindowLong(),SetWindowLong(), GetClassLong(),SetClassLong() ). ● ● ● ● Ein Objekt hat nur ein Handle. Ein Duplizieren eines Handles ist nicht sinnvoll. Handles sind public für alle Prozesse. Ein Benutzer kann maximal 65536 Handles verwenden. Die folgende Tabelle enthält ( Benutzer - ) Objekte. User Objects Creator function Accelerator CreateAcceleratorTable table Destroyer function User Objects Creator function Destroyer function DestroyAcceleratorTable Cursor LoadCursor, GetCursor, CreateCursor SetCursor DestroyCursor GetThreadDesktop Applications cannot delete this object. DDE conversation DdeConnect, DdeConnectList, DdeQueryNextServer, DdeReconnect DdeDisconnect, DdeDisconnectList Hook SetWindowsHook, SetWindowsHookEx UnhookWindowsHook, Menu UnhookWindowsHookEx 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 BeginDeferWindowPos EndDeferWindowPos Window station GetProcessWindowStation Applications cannot delete this object. Desktop Window position Lebensdauer von Objekten Applikationen können Objekte erzeugen und verwenden. Objekte entsprechen Instanzen ( Bitmuster im Speicher ). Ein Objekt kann auch von mehreren Applikationen benutzt werden ( shared ). Das Betriessystem erzeugt und nutzt ( Stock - ) Objekte, die von Applikationen ( ohne Freigabe ) genutzt werden können. Typ Gebunden durch Sichtbarkeit Lebensdauer Overhead Automatic Compiler Funktion Funktion 0 (Stackwort) Static Linker ( Lader ) Programm, Block Programm 0 (Allignment) Heap System allokiert Programm, Block Programm, Block 32 Byte ( System bei shared ) bis zur Freigabe ( System bei shared ) Resourcen RC-Compiler ( Linker, Lader ) GDI Objekte USER-Funktionen System ( Linker mit *.lib, Lader ) ( Programm ) User Objekte Linker Programm, Block (System bei stock) Programm, Block Programm (System bei stock) ca. 32 Byte Programm, Block bis zur Freigabe ( System bei stock ) ca. 30-50 Byte Programm, Block bis zur Freigabe 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 ). Gegenüberstellung Viele C Run-time Funktionen haben ein Win32-Äquivqlent ( API: application programming interface ). Funktionen mit (*) existieren nur bei 16bit C Run-time. Im folgenden werden statische C-run-time Funktionen und dynamischen Win32-Funktionen gegenüber gestellt. String Manipulation C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 lstrcat none lstrcmp strcat, wcscat strchr, wcschr strcmp, wcscmp lstrcpy none strcpy, wcscpy strcspn, wcscspn none _strdup, _wcsdup FormatMessage _strerror FormatMessage _stricmp, _wcsicmp lstrcmpi strerror CharLower, lstrlen none strlen, wcslen _strlwr, _wcslwr strncat, wcsncat CharLowerBuffer strncmp, wcsncmp none strncpy, wcsncpy none _strnicmp, _wcsnicmp none FillMemory, none _strnset, _wcsnset strpbrk, wcspbrk none strrchr, wcsrchr ZeroMemory FillMemory, none _strrev, _wcsrev none _strset, _wcsset strspn, wcsspn ZeroMemory CharUpper, none none strstr, wcsstr strtok, wcstok _strupr, _wcsupr CharUpperBuffer Buffer Manipulation C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 none CopyMemory _memccpy none memchr memcmp none memcpy FillMemory, none _memicmp none memmove MoveMemory memset _swab ZeroMemory C-Runtime Win32 isalnum IsCharAlphaNumeric __iscsym none islower isupper _tolower IsCharLower, GetStringTypeW (Unicode) IsCharUpper, GetStringTypeW (Unicode) none Character Classification C-RunC-Run-time Win32 time IsCharAlpha, GetStringTypeW isalpha __isascii (Unicode) __iscsymf none isdigit isprint none ispunct isxdigit toupper none, GetStringTypeW (Unicode) CharUpper Win32 none none, GetStringTypeW (Unicode) none, GetStringTypeW (Unicode) __toascii none _toupper none C-Runtime Win32 iscntrl none, GetStringTypeW (Unicode) isgraph none isspace none, GetStringTypeW (Unicode) tolower CharLower Directory Control C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 SetCurrentDirectory SetCurrentDirectory GetCurrentDirectory GetCurrentDirectory _chdir _chdrive _getcwd _getdrive CreateDirectory RemoveDirectory _searchenv SearchPath _mkdir _rmdir File Handling C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 none SetFileAttributes _chsize SetEndOfFile GetFileSize _access _chmod _filelength See Note 5 _fullpath GetFullPathName _get_osfhandle none GetFileType _fstat _isatty LockFileEx _makepath none GetTempFileName _open_osfhandle none _locking _mktemp DeleteFile rename MoveFile none none remove _setmode _splitpath none none DeleteFile _stat _umask _unlink Creating Text Output Routines C-Run-time Win32 C-Run-time Win32 SetConsoleCursorInfo _displaycursor* _gettextcolor* GetConsoleScreenBufferInfo GetConsoleCursorInfo _gettextcursor* _gettextposition* GetConsoleScreenBufferInfo WriteConsole _gettextwindow* GetConsoleWindowInfo _outtext* SetConsoleTextAttribute _scrolltextwindow* ScrollConsoleScreenBuffer _settextcolor* SetConsoleCursorInfo _settextcursor* _settextposition* SetConsoleCursorPosition SetConsoleMode _settextwindow* SetConsoleWindowInfo _wrapon* C-Run-time Win32 none clearerr none feof _fgetchar none none _flushall Stream Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 CloseHandle none fclose _fcloseall none _fdopen none FlushFileBuffers fgetc none ferror fflush none none none fgetpos fgets _fileno CreateFile none none fopen fprintf fputc freopen none ReadFile SetStdHandle fputs fread (std handles) SetFilePointer SetFilePointer _fsopen CreateFile fseek fsetpos _fputchar none fscanf none SetFilePointer fwrite (check return value) none _getw none puts none scanf none sprintf none tmpnam none _vsnprintf ftell gets putchar _rmtmp _snprintf tmpfile vprintf WriteFile getc none printf none _putw none setbuf wsprintf sscanf GetTempFileName ungetc none vsprintf none getchar none none none none none none wvsprintf putc rewind setvbuf _tempnam vfprintf none SetFilePointer none GetTempFileName none Low-Level I/O C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _lclose, CloseHandle _commit FlushFileBuffers _creat _lcreat, CreateFile DuplicateHandle _close _dup none none _llseek, SetFilePointer _open _lopen, CreateFile _dup2 _eof _lseek SetFilePointer _lread, ReadFile CreateFile _lread _read _sopen _tell _write (check return value) C-Run-time Win32 none _cgets Console and Port I/O Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 none none _cscanf none _cprintf _cputs _getch _kbhit _ungetch ReadConsoleInput _getche PeekConsoleInput _outp none ReadConsoleInput _inp none _outpw none none _inpw _putch none WriteConsoleInput Memory Allocation C-RunC-Run-time Win32 C-Run-time Win32 Win32 C-Run-time Win32 time none GlobalAlloc _alloca _bfreeseg* none _bheapseg* none calloc none GlobalFree _freect* GlobalMemoryStatus _halloc* GlobalAlloc _expand free none none _heapadd _heapchk none _heapmin none _heapset none GlobalFree malloc GlobalAlloc GlobalMemoryStatus _heapwalk _hfree* _memavl GlobalMemoryStatus _msize* GlobalSize realloc GlobalReAlloc _memmax _set_new_handler none _set_hnew_handler* none _stackavail* none Process and Environment Control Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 none none none none abort assert atexit _cexit none ExitProcess ExitProcess _c_exit _exec functions none exit _exit GetEnvironmentVariable _getpid GetCurrentProcessId none none getenv longjmp _onexit FormatMessage SetEnvironmentVariable raise RaiseException setjmp none perror _putenv signal SetConsoleCtrlHandler _spawn functions CreateProcess CreateProcess system (ctrl-c only) Klassen - Objekte Fenster - Objekte Alle existierenden Fenster-Objekte können in einer Schleife durchlaufen werden. Im folgenden Beispiel wird von einem existierenden hWndFenster gestartet und das erste Fensterhandle mit GetWindow( hWnd, GW_HWNDFIRST ) geholt. Die verkettete Liste endet mit hNext == NULL. Beispiel CreateWindow(), DestroyWindow() 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. Die Liste der vorhandenen Fenster-Objekte kann durchlaufen werden. Mit dem erhaltenen Handle können die zugänglichen Fenster-Daten ausgelesen bzw. vewendet werden. Hie ein Beispiel: CHAR buf[256]; CHAR pStr[5000]; CHAR * p = pStr; for ( HWND hNext = GetWindow( hWnd, GW_HWNDFIRST ); hNext != NULL ; hNext = GetWindow( hNext, GW_HWNDNEXT)) { if ( GetWindowText( hNext,buf,sizeof(buf)) ) if ( IsWindowVisible( hNext ) && ( (p-pStr) < sizeof(pStr)-sizeof(buf))) { p += wsprintf( p, "%s\n", buf ); } else { p += wsprintf( p,"\t%s\n", buf ); } } MessageBox( hWnd, pStr, "Alle Fenster:", MB_OK); Wurde mit WNDCLASS.cbWndExtra=sizeof( void * ) bei Windows für jedes Fenster zusätzlicher Benutzer - Speicher ( 4 Byte ) reserviert, so kann z.B. mit SetWindowLong() ein Zeiger auf einen vom Benutzer allokierten MYSTRUCT - Heap - Speicher hinterlegt werden. MYSTRUCT * p = ( MYSTRUCT * ) GetWindowLong( hNext, DWL_USER ) ; if ( ! IsBadReadPtr( p, sizeof(MYSTRUCT) ) { ... // mit p kann lesend auf MYSTRUCT zugegriffen werden } Beim Zugriff auf diesen Speicher kann mit IsBadReadPtr( p, sizeof(MYSTRUCT) geprüft werden, ob dieser Speicher gültig und benutzbar ist. GDI - Objekte Die GDI - DLL enthält ( viele ) Funktionen. Hier sollen lediglich einige GDI - Funktionen zum Zeichnen und Schreiben ausgewählt und behandelt werden. Das Erstellen und Aktualisieren des Bildschirmes erfolgt durch die WM_PAINT - Nachricht. Device Kontext Die meisten GDI - Funktionen benutzen globale Daten ( Seiten - Effekt ) aus dem als Device - Kontext. Der Funktions - Parameter ist HDC hDC. Bei der WM_NCPAINT und WM_NCACTIVATE - Nachrichten - Behandlung wird der Device - Kontext benutzt. Unter case iMsg = WM_PAINT wird der Device - Kontext z.B. gemäß case WM_PAINT : hDC = BeginPaint( hWnd, & ps ) GetClientRect ( hWnd, & rect DrawText ( hDC, "Hallo, | DT_VCENTER ) ; EndPaint ( hWnd, & ps ) break ; //return 0; ; ) ; Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER ; benutzt. Die Aktualisierung findet im Client - Bereich statt. Durch GetWindowDC() oder GetDCEx() mit DCX_WINDOW kann der Device Kontext für das gesamte Fenster ( incl. not Client - Bereich mit (0,0) oben links, clipping region ) erhalten werden. Nach der Benutzung ist dieser Device - Kontext durch ReleaseD() wieder frei zu geben. Ist der Device - Kontext bekannt, so kann durch hWnd WindowFromDC( HDC hDC ); das Fenster - Handle ermittelt werden. Funktionen zum Zeichnen MoveToEx(), LineTo(), Polyline() Unter WM_PAINT wird mit MoveToEx(), LineTo() eine x - Achse gezeichnet. Die y - Werte von POINT pt [NUM] - Array werden mit den sin() - Werten gefüllt. Mit Polyline() wird die Folge von Punkten gezeichnet. #include <math.h> #define NUM 1000 #define TWOPI (2 * 3.14159) LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { static int cxClient, cyClient ; POINT pt [NUM] ; switch ( iMsg ) { case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; break; case WM_PAINT: { PAINTSTRUCT ps ; HDC hDC ; hDC = BeginPaint ( hWnd , &ps ) ; MoveToEx ( hDC, 0, cyClient / 2, NULL) ; LineTo ( hDC, cxClient, cyClient / 2) ; for ( int i = 0 ; i < NUM ; i++ ) { pt[i].x = i * cxClient / NUM ; pt[i].y = ( int ) ( cyClient / 2 * ( 1 - sin( TWOPI * i / NUM ) ) ) ; } Polyline ( hDC, pt, NUM ) ; EndPaint ( hWnd, & ps ) ; EndPaint(); } return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc ( hWnd , iMsg, wParam, lParam ) ; } Rectangle(), MoveToEx(), LineTo(), MoveToEx(), LineTo(), Ellipse(), RoundRect() In dem folgenden Beispiel wird in WM_SIZE die aktuelle Client - Fenster - Größe in den static - Variablen int cxClient, cyClient hinterlegt. Unter WM_PAINT werden die Funktionen Rectangle(), MoveToEx(), LineTo(), MoveToEx(), LineTo(), Ellipse(), RoundRect() aufgerufen. LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { static int cxClient, cyClient ; HDC hDC ; PAINTSTRUCT ps ; switch ( iMsg ) { case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; break; case WM_PAINT: hDC = BeginPaint ( hWnd , & ps ) ; Rectangle ( hDC,cxClient/8, cyClient/8, 5*cxClient/8, 5*cyClient/8) ; MoveToEx ( hDC, 0, 0, NULL ) ; LineTo ( hDC, cxClient, cyClient ) ; MoveToEx ( hDC, 0, cyClient, NULL ) ; LineTo ( hDC, cxClient, 0 ) ; Ellipse ( hDC,cxClient/8,cyClient/8,5*cxClient/8,5*cyClient/8) ; RoundRect ( hDC,cxClient/5,cyClient/5,2*cxClient/5,2*cyClient/5,cxClient/5,cyClient/5 ) ; EndPaint ( hWnd , & ps ) ; break; //return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc ( hWnd , iMsg, wParam, lParam ) ; } Funktionen zum Schreiben TextOut() Die TextOut() - Funktion wird in der CALLBACK - FUnktion unter iMsg = WM_PAINT etwa in der folgende Art aufgerufen: case WM_PAINT: hDC = BeginPaint ( hWnd , & ps ) ; SelectObject( hDC, GetStockObject( SYSTEM_FONT ) ); // x y 012345678901234 TextOut( hDC, 50, 50, "TextOut Example", 15 ); TextOut( hDC, 50, 75, "_______________", 15 ); TextOut( hDC, 50, 100, "1.Zeile", 7 ); TextOut( hDC, 50, 125, "2.Zeile", 7 ); TextOut( hDC, 50, 150, "3.Zeile", 7 ); TextOut( hDC, 50, 175, "4.Zeile", 7 ); TextOut( hDC, 50, 200, "5.Zeile", 7 ); TextOut( hDC, 50, 225, "6.Zeile", 7 ); TextOut( hDC, 50, 250, "7.Zeile", 7 ); TextOut( hDC, 50, 275, "8.Zeile", 7 ); TextOut( hDC, 50, 300, "9.Zeile", 7 ); EndPaint ( hWnd , & ps ) ; break; Beispiel: DrawText() Die DrawText() - Funktion benutzt den Device Kontext hDC, der u.a. den ausgewählten Font, die Text - Farbe und die Text - Hintergrund Farbe enthält. ● Die DrawText() - Funktion schreibt einen String *lpString in ein umschließendes Rechteck *lpRect. Falls die Anzahl der auszugebenden Zeichen nCount = -1 ist, so muß *lpRect ein 0 terminierter String sein. Der Text kann gemäß expandierender Tabs, der Ausrichtung ( Linksbündig, Rechtsbündig, Zentriert ), der Umbrüche am Zeilenrand, usw. justiert werden. Diese Funktion verwendet intern TextOut(). Die DrawText() gibt die Höhe des Textes zurück. int DrawText( HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat ); // // // // // handle to device context pointer to string to draw string length, in characters pointer to struct with formatting dimensions text-drawing flags Für uFormat können die Konstanten DT_BOTTOM, DT_END_ELLIPSIS oder DT_INTERNAL, DT_NOPREFIX, DT_TABSTOP, DT_WORD_ELLIPSIS DT_CALCRECT, DT_PATH_ELLIPSIS, DT_LEFT, DT_RIGHT, DT_TOP, DT_CENTER, DT_EXPANDTABS, DT_MODIFYSTRING, DT_RTLREADING, DT_VCENTER, DT_EDITCONTROL, DT_EXTERNALLEADING, DT_NOCLIP, DT_SINGLELINE, DT_WORDBREAK, benutzt werden. Für eine bequemere Benutzung können die benötigten uFormat - FLags unter einer Zahl < -1 angesprochen werden. Die folgende Funktion int Draw_Text( ) setzt für uFormat = -1, bzw. 0 die gewünschten uFormat - FLags. Falls ( y1 >= y2 ) ist, so wird DrawText() benutzt, um mit DT_CALCRECT die benötigte Rechteckgröße zu ermitteln. int Draw_Text ( HDC hDC, //Handle für den Device Kontext LPCTSTR lpString , //auszugebender String int nCount , //falls nCount <= 0 ist, so muss ein \0-String vorliegen und //es wird dann automatisch strlen ( lpString ) benutzt LPRECT lpRect , //umschließendes Recheck int uFormat // Window DrawText-Format, wie z.B. // ( DT_CENTER / DT_LEFT / DT_RIGHT ) // ( DT_VCENTER / DT_TOP / DT_BOTTOM ) ) { RECT rcText; UINT Fmt ; int dx , dy ; if ( ( lpString == NULL ) || ( hDC == NULL ) ) return 0 ; if ( lpRect != NULL ) { rcText = * lpRect ; } else { HWND hWnd = WindowFromDC( hDC ); GetClientRect( hWnd , & rcText ); } if ( uFormat < 0 ) { // DEFAULT Fmt = DT_EXTERNALLEADING | DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_NOPREFIX | DT_WORDBREAK ; } else if ( uFormat == 0 ) { Fmt = DT_EXTERNALLEADING | DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ; } else { Fmt = uFormat ; } int x1 = rcText.left ; int y1 = rcText.top ; int x2 = rcText.right ; int y2 = rcText.bottom ; if ( y1 >= y2 ) { SetTextAlign ( hDC, TA_NOUPDATECP | TA_LEFT | TA_TOP ) ; DrawText ( hDC, lpString, nCount, & rcText, Fmt | DT_CALCRECT ) ; dx = x2 - x1 ; dy = y2 - y1 ; if ( ( Fmt & DT_CENTER ) || ( Fmt & DT_RIGHT ) ) { if ( Fmt & DT_CENTER ) dx >>= 1 ; if ( dx > x1 ) dx = x1 ; x1 -= dx ; x2 -= dx ; } if ( ( Fmt & DT_VCENTER ) || ( Fmt & DT_BOTTOM ) ) { if ( Fmt & DT_VCENTER ) dy >>= 1 ; if ( dy > y1 ) dy = y2 ; y1 -= dy ; y2 -= dy ; } SetRect ( & rcText, x1, y1, x2, y2 ) ; } return DrawText ( hDC , lpString , nCount , & rcText , Fmt ) ; } Resourcen Um einen ausführbaren, binär - File ( *.EXE ) zu erzeugen, müssen ASCII - Files in Maschinen-Code übersetzt werden: *.C, *.CPP *.H, *.RC *.OBJ, *.DEF (*.EXE), *.RES ===> ===> ===> ===> Compiler Resourcen-Compiler Linker Resourcen-Compiler ===> ===> ===> ===> *.OBJ *.RES (*.EXE) *.EXE Die *.RC - Resourcen - Files ( ASCII ) enthalten z.B. ● ● ● Filenamen für Bilder ( Mauszeiger, Rasterbilder, Icons ), Text - und Hotkey - Tabellen, Menu - und Dialog - Beschreibungen. Die *.RC - Resourcen - Files ( ASCII ) können "von Hand" geschrieben werden, aber vielfach ist die "visuelle Erstellung" mit einem Tool ( Resourcen Workshop ) bequemer. Das Tool benutzt einen binäre Hilfsfiles und generiert automatisch den *.RC - ASCII - File und den zugehörigen *.H-File für die Identifizierer. Die *.RC - Syntax wird bei der automatsichen Generierung berücksichtigt und braucht nicht gelernt werden. Durch den Resourcen-Compiler wird der *.RC - File in einen binären *.RES - File übersetzt. Eine "visuelle Erstellung" ändert, ergänzt und überschreibt den alten *.RC - ASCII - File automatisch. Eine *.RC - Erstellung sollte entweder "von Hand" oder durchgängig "visuelle" mit einem Tool erstellt werden. Weil im *.RC - File auch WS_ - , DS_ -, SS_ - Windows - Konstanten benutzt werden, so ist deren Bedeutung bei der Erzeugung von Dialog-Rssourcen ( trotz Automatik ) zu kennen. *.RC-Syntax Die *.RC - ASCII - Datei wird mit dem Resourcen-Compiler in eine *.RES - Binärdatei übersetzt. Der allgemeiner Aufbau einer *.RC Zeile ist: ID - Identität RC-Typ Speicheroperationen Datenquelle auch BEGIN ... END Die Speicher - Operationen PRELOAD ( nur Win16: mit *.exe geladen), LOADONCALL ( nur Win16: bei Ausführung geladen), FIXED ( nur Win16: Resource bleibt an fester Adresse ), MOVEABLE ( nur Win16: Resource kann verschoben werden ), DISCARDABLE ( nur Win16: Resource kann entfernt werden ). Im C/C++ - Programm wird mit der ID - Identität ( identifizierende Zahl ) auf die Resource zugegriffen. Die Resourcen entsprechen einer Aufzählung von benötigten, lesbaren Daten. Deshalb ist im *.RC-File die Reihenfolge der Resourcen nicht wesentlich. Für Dialoge werden Control Parameter ( wie z.B. PUSHBUTTON or CHECKBOX ) verwendet. Die Breite cx wird in 1/4-character units angegeben. Die Höhe cy wird in 1/8-character units angegeben. Controls ( innerhalb eines Rssourcen-Templates ) haben die Syntax: Control-Typ [text,] id, x, y, cx, cy [, style [, extended-style]] Diese CONTOLS gehören zu einer ( in Windows enthaltenen ) Klasse, wie z:b: "BUTTON", "EDIT", "LISTBOX", "SCROLLBAR", "COMBOBOX". Alternativ können Klassen ( mit Prefix: 0xFFFF ) auch identifiziert werden. Zu jeder Klasse ist eine zugehörige CALLBACK-Funktion implizit verfügbar. Mit Hilfe von GetClassInfoEx() können die Daten in wcx geschrieben werden. Die Dialog-Klasse MAKEINTRESOURCE(0x8002) z.B. durch GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx). Beispiele: #define #define #define #define #define #define BUTTON EDIT STATIC LISTBOX SCROLLBAR COMBOBOX 0x80 0x81 0x82 0x83 0x84 0x85 WNDCLASSEX wcx = {0}; GetClassInfoEx(GetModuleHandle(0),"EDIT", &wcx); GetClassInfoEx(GetModuleHandle(0),"BUTTON", &wcx); GetClassInfoEx(GetModuleHandle(0),"COMBOBOX",&wcx); GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx); Zur Vereinfachung der Ressourcen-Schreinweise enthält Windows die folgenden ( vor - ) definierten Dialog - Elemente ( #define´s ): Vereinfachung entspricht dem CONTROL ... #define LTEXT text, id, x, y, cx, cx, style CONTROL text, id, "Static", SS_LEFT | WS_GROUP | style, x, y, cx, cy #define CTEXT text, id, x, y, cx, cx, style CONTROL text, id, "Static", SS_CENTER | WS_GROUP | style, x, y, cx, cy #define RTEXT text, id, x, y, cx, cx, style CONTROL text, id, "Static", SS_RIGHT | WS_GROUP | style, x, y, cx, cy #define SCOLLBAR text, id, x, y, cx, cx, style CONTROL "", id, "Static", SBS_HORZ | style, x, y, cx, cy #define ICON text, id, x, y, cx, cx, style CONTROL text, id, "Static", SS_ICON | style, x, y, cx, cy #define PUSHBUTTON text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_PUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy #define DEFPUSHBUTTON text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_DEFPUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy #define RADIOBUTTON text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_RADIOBUTTON | WS_TABSTOP | style, x, y, cx, cy #define CHECKBOX text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_CHECKBOX | WS_TABSTOP | style, x, y, cx, cy #define GROUPBOX text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_GROUPBOX | WS_TABSTOP | style, x, y, cx, cy #define COMBOBOX text, id, x, y, cx, cx, style CONTROL text, id, "Combobox", CBS_SIMPLE | WS_TABSTOP | style, x, y, cx, cy #define EDITTEXT text, id, x, y, cx, cx, style CONTROL text, id, "Edit", ES_LEFT | WS_BORDER | WS_TABSTOP | style, x, y, cx, cy Vordefinierte Resourcen - Typen Für die vordefinierte Resourcen - Typen gibt es die Konstanten: #define #define #define #define #define #define #define #define #define #define #define RT_CURSOR RT_BITMAP RT_ICON RT_MENU RT_DIALOG RT_STRING RT_FONTDIR RT_FONT RT_ACCELERATOR RT_RCDATA RT_MESSAGETABLE MAKEINTRESOURCE(1) MAKEINTRESOURCE(2) MAKEINTRESOURCE(3) MAKEINTRESOURCE(4) MAKEINTRESOURCE(5) MAKEINTRESOURCE(6) MAKEINTRESOURCE(7) MAKEINTRESOURCE(8) MAKEINTRESOURCE(9) MAKEINTRESOURCE(10) MAKEINTRESOURCE(11) //für Mauszeiger //für Rasterbilder //Symbol - Rasterbilder //für Menuleisten //für Dialogfelder //für Stringtabellen //Verzeichnisse der Schriftarten //für Schriftarten //für Tastaturkürzel //für Daten ohne feste Bindung //für Nachrichten MAKEINTRESOURCE() - Macro Der Kern des Betriebssystems vewaltet Atome. Einem String wird ein Hash - Code zugeordnet. Bei Resourcen werden i.a. WORD ID_ ... - Identifizierer verwendet. Benötigt eine Windows - Funktion den zugeordneten String, so kann das MAKEINTRESOURCE() - Macro verwendet werden. Das MAKEINTRESOURCE() - Macro ist definiert durch #define MAKEINTRESOURCE( idRes ) (LPSTR)((DWORD)((WORD)( idRes ))) Resourcen - Itentifizierer Ressourcen-Tools ( AppWizard zur Erzeugung der *.RC - Quelltexte ) benutzen i.a. typische Präfixe für die Identifizierer ( z.B. #define IDD_DIALOG1 1000: (I)(D)entifiziere-einen_(D)ialog 1 ). Diese Identifizierer sind WORD - Zahlen und werden oft durch MAKEINTRESOURCE(IDD_DIALOG1) übergeben. In dem jeweiligen Kontext müssen die Identifizierer so geählt werden, daß diese eindeutig sein. Die MFC - Konvention schlägt die folgenden Präfixe vor. Prefix Type of Symbol Example Range IDR_ Identification shared by multiple resources of different types IDR_MAINFRAME 1 to 0x6FFF IDD_ Dialog resource IDD_SPELL_CHECK 1 to 0x6FFF HIDD_SPELL_CHECK 0x20001 to 0x26FF HIDD_ Dialog-resource Help context IDB_ Bitmap resource IDB_COMPANY_LOGO 1 to 0x6FFF IDC_ Cursor resource IDC_PENCIL 1 to 0x6FFF IDI_ Icon resource IDI_NOTEPAD 1 to 0x6FFF ID_ _ Command from menu item or toolbar ID_TOOLS_SPELLING 0x8000 to 0xDFFF HID_ Command Help context HID_TOOLS_SPELLING 0x18000 to 0x1DFFF IDP_ Message-box prompt IDP_INVALID_PARTNO 8 to 0xDFFF Message-box Help context HIDP_INVALID_PARTNO 0x30008 to 0x3DFFF IDS_ String resource IDS_COPYRIGHT 1 to 0x7FFF IDC_ Control within dialog box IDC_RECALC 8 to 0xDFFF HIDP_ Benutzerdefinierte Resourcen - Macros Damit die unterschiedliche Syntax und Bezeichner im *.RC, *.H und *.CPP Files bei den Übersetzungen unterschieden werden können, gibt es vordefinierte Konstanten ( z.B. RC_INVODED ). Durch #ifdef RC_INVODED #define ID(x) x #else #define ID(x) MAKEINTRESOURCE(x) #endif wird während der Resourcen - Übersetzung anstelle von ID(x) das Macro MAKEINTRESOURCE(x) verwendet und sonst die Zahl x direkt. Für die Erstellung eines *.RC - Resourcen - Files ( ASCII ) "von Hand" können die folgenden Macros hilfreich sein. Durch solche Macros kann eine einheitliche, übersichtliche Gestaltung des *.RC - Files erreicht werden. Im C/C++ - Programm wird eine Resource durch einen Idetifizierer ( idRes = ID_ ... ) angesprochen. #define ICON_NAME(idRes, pFileName) idRes ICON DISCARDABLE pFileName #define STR_BEGIN STRINGTABLE DISCARDABLE BEGIN #define STR_END END #define MENU_BEGIN(idRes) idRes MENU DISCARDABLE BEGIN #define MENU_END END #define MENU_ITEM_BEGIN(text) POPUP text BEGIN #define MENU_ITEM_END END #define MENU_ITEM(idRes, text, style) MENUITEM text, idRes, style #define MENU_SEPARATOR MENUITEM SEPARATOR #define ACCEL_BEGIN(idRes) \ idRes ACCELERATORS MOVEABLE PURE BEGIN #define ACCEL_END END #define DLG_BEGIN_MODAL( idRes, txt, x,y,dx,dy ) \ idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\ STYLE DLG_MODAL_STYLE \ FONT DLG_FONT \ CAPTION txt \ BEGIN #define DLG_BEGIN( idRes, txt, x,y,dx,dy ) \ idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\ STYLE DLG_MODELES_STYLE \ FONT DLG_FONT \ CAPTION txt \ BEGIN #define DLG_END END #define is_RECT "Static", SS_BLACKRECT | WS_GROUP//|SS_NOPREFIX #define is_ICON SS_ICON #define is_LTEXT "Static", SS_LEFT | WS_GROUP//|SS_NOPREFIX #define is_RTEXT "Static", SS_RIGHT | WS_GROUP//|SS_NOPREFIX #define is_CTEXT "Static", SS_CENTER | WS_GROUP//|SS_NOPREFIX #define is_GROUP "Button", BS_GROUPBOX | WS_TABSTOP|WS_GROUP #define is_RADIO "Button", BS_AUTORADIOBUTTON| WS_TABSTOP #define is_CHECK "Button", BS_AUTOCHECKBOX | WS_TABSTOP #define is_PUSH "Button", BS_PUSHBUTTON | WS_TABSTOP #define is_PUSHx "Button", BS_DEFPUSHBUTTON | WS_TABSTOP #define is_PUSH0 "Button", BS_OWNERDRAW | WS_TABSTOP #define is_COMBO "ComboBox",CBS_OEMCONVERT|CBS_DROPDOWN\ |CBS_HASSTRINGS|CBS_AUTOHSCROLL|ES_LEFT|ES_NOHIDESEL\ |WS_CHILD|WS_TABSTOP|WS_VSCROLL #define is_LIST "ListBox",LBS_NOTIFY\ |LBS_USETABSTOPS|LBS_DISABLENOSCROLL|LBS_OWNERDRAWFIXED\ |WS_BORDER|LBS_SORT|LBS_HASSTRINGS|WS_VSCROLL #define is_VSCROLL "Scrollbar", SBS_VERT|WS_TABSTOP #define is_HSCROLL "Scrollbar", SBS_HORZ|WS_TABSTOP #define is_EDIT "Edit",ES_AUTOHSCROLL|ES_LEFT|WS_BORDER\ |ES_OEMCONVERT|WS_CHILD|WS_TABSTOP|WS_GROUP//|ES_WANTRETURN #define is_EDIT_X "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ |ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\ |WS_VISIBLE|WS_HSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP #define is_EDIT_Y "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ |ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\ |WS_VISIBLE|WS_VSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP #define is_EDIT_XY "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ |ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL\ |ES_WANTRETURN|WS_CHILD\ |WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|WS_BORDER\ |WS_TABSTOP|WS_GROUP #define DLG_MODELES_STYLE DS_SETFONT|WS_THICKFRAME|WS_MINIMIZEBOX\ |WS_MAXIMIZEBOX|WS_VISIBLE|WS_CAPTION\ |WS_POPUPWINDOW //WS_BORDER|WS_POPUP|WS_SYSMENU #define DLG_MODAL_STYLE DS_MODALFRAME|DS_SETFONT|WS_POPUP|WS_CAPTION\ |WS_SYSMENU|WS_VISIBLE #define DLG_FONT 7, "MS Sans Serif" //"Helv" #define DLG_ITEM(idRes,text,style,x,y,width,height) \ CONTROL text, idRes,style,x,y,width,height #define DLG_ICON(idRes,text,style,x,y,width,height) \ ICON idRes,-1,x,y,width,height,style Cursor - Resource Ein Maus - Cursor wird definiert durch zwei 16x16 Bitmaps und einen kennzeichnenden Punkt ( Hotspot ). Die erste 16x16 Bitmap wird mit dem Hintergrund AND- und die zweite XOR- verknüpft. Der Hotspot gibt innerhalb der Maske die Pixel - Position an, welche z.B. die Spitze des Pfeils symbolisiert. Die Erstellung eines Maus - Cursor - Bitmap durch den Benutzer ist nur dann erforderlich, wenn die verfügbaren Maus - Cursor - Bitmaps nicht ausreichen. Icon - Resource Ist ein Icon in dem File "c:\\pfad\\...\\myName.ico" enthalten, so kann dieses Icon gemäß IDI_MYICON ICON DISCARDABLE "c:\\pfad\\...\\myName.ico" in den *.RC - ASCII - File aufgenommen werden. Im C/C++ - Programm wird dieses Icon z.B. durch wndclass.hIcon = LoadIcon( GetModuleHandle(0), IDI_MYICON ); geladen. String - Table - Resource Tabellen von Strings werden für Fehler - Meldungen, statische Anzeigetexte und Ausgaben benutzt. Das C/C++ - Programm läd bei Bedarf diese Strings. Wird eine Applikation in eine andere Landes - Sprachen übersetzt, so muß nur die Stringtabellen auswechselt werden. Bei C/C++ wird ein String "..." automatisch mit einem zusätzlichem \0 - Zeichen abgeschlossen. ● ● Ein *.RC - String wird nicht automatisch mit einem \0 abgeschlossen. Sonderzeichen innerhalb eines *.RC - Strings müssen oktal eingegeben werden ( ein "für" wird zu "f\374r" ). Im *.RC sieht eine STRINGTABLE etwa wie folgt aus: STRINGTABLE DISCARDABLE BEGIN IDS_STRING1, "Error in Runtime 1" .... IDS_STRING16, "Wert = %d" END Eine Tabelle sollte maximal 16 Strings enthalten. Die Strings aus der Resourcen - String - Tabelle werden dann gemäß CHAR buf[256]; LoadString( GetModuleHandle(0), IDS_STRING1, buf, sizeof(buf) ) geladen. hInstance = GetModuleHandle(0) entspricht der Anfangsadresse des ausgeführten Programmes. Der WinMain( ) - Aufruf übergibt den Parameter hInstance an das Programm. hInstance wird in unterschiedlichen Funktionen benötigt. Deshable kann hInstance ( anstelle des Aufrufes GetModuleHandle(0) ) auch in einer globale Variablen gespeichert werden. Alternativ kann hInstance auch beim WM_CREATE - Ereignis ( infolge von CreateWindow ) durch my_hInstance = ( LPCREATESTRUCT ) lParam -> hInstance erhalten werden. Eine vereinfachte Funktion Load_String( int idRes ) gibt den Zeiger auf den geladenen String zurück. LPSTR Load_String( int idRes ) { static char buf[256]; if ( LoadString( GetModuleHandle(0), idRes, buf, sizeof(buf) ) < 0 ) return NULL; else return ( LPSTR ) buf; } Sollen drei Resourcen - Strings geladenen, aneinander gefügt und angezeigt werden, so kann dies z.B. gemäß CHAR buf[1024]; LPSTR pp = &buf[0]; pp += sprintf( pp, Load_String( IDS_STRING1 ) ); pp += sprintf( pp, Load_String( IDS_STRING2 ) ); pp += sprintf( pp, Load_String( IDS_STRING3 ) ); MessageBox( hWnd, buf, "3 Strings", MB_OK ); erfolgen. Sollen drei Strings gleichzeitig, nebeneinander benutzt werden ( nrStr = 0, 1, 2 ), so kann eine erweitert Funktion Load_String_into() geschrieben werden. LPSTR Load_String_into( int nrStr, int idRes ) { static CHAR buf[3][256]; LoadString( GetModuleHandle( NULL ), idRes, buf[nrStr], 256 ); return ( LPSTR ) buf[nrStr]; } // Die drei static Buffer können mehrfach geladen und // p0, p1, p2 können unabhängig voneinander benutzt werden. LPSTR p0 = Load_String_into( 0, IDS_STRING0 ); LPSTR p1 = Load_String_into( 1, IDS_STRING1 ); LPSTR p2 = Load_String_into( 2, IDS_STRING2 ); geladen werden. Mit (NULL!=FindResource(GetModuleHandle(0),MAKEINTRESOURCE((idRes>>4)+1),RT_STRING)) kann geprüft werden, ob die StringRessource im 16-Block existiert. Menu - Resourcen Ein *.RC - File kann etwa wie folgt aufgebaut werden: IDR_MAIN_MENU MENU LOADONCALL MOVEABLE DISCARDABLE { POPUP "&File" { MENUITEM "&New", ID_MAIN_NEW, GRAYED MENUITEM SEPARATOR MENUITEM "&Exit", ID_MAIN_EXIT } POPUP "&Examples" { MENUITEM "Example&1 F1", ID_MAIN_EXAMPLE_1 MENUITEM "Example&2 F2", ID_MAIN_EXAMPLE_2 } POPUP "&Help" { MENUITEM "∓About", ID_MAIN_ABOUT } } Um das Menu anzuzeigen, wird in RegisterClass() WNDCLASS wndclass.lpszMenuName = MAKEINTRESOURCE( IDR_MAIN_MENU ); eingetragen. Bei einem Menu - Klick wird die CALLBACK - Funktion mit case iMsg = WM_COMMAND aufgerufen. In LOWORD( wParam ) wird der Resourcen - Identifizierer ID_... an die CALLBACK - Funktion übergeben. case WM_COMMAND: wmId = LOWORD( wParam ); wmEvent = HIWORD( wParam ); switch ( wmId ) { case ID_MAIN_EXAMPLE_1: MessageBox( NULL, "ID_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION | MB_YESNO ) ; break ; } System - Menu Das Windows - System verwendet ( oben links ) das System - Menu ( Wiederherstellen, Verschieben, Größe ändern, Minimieren, Maximieren, Schließen, Nächstes ). Das System - Menu kann z.B. in WM_CREATE gemäß HMENU hSysMenu = GetSystemMenu ( hWnd, FALSE ); if ( hSysMene ) { InsertMenu ( hSysMenu, SC_RESTORE, MF_STRING, ID_SYSMAIN_HELP, "&Help" ); InsertMenu ( hSysMenu, SC_RESTORE, MF_SEPARATOR, 0, NULL ); } erweitert werden. Die CALLBACK - Funktion ist dann zu ergänzen. case WM_SYSCOMMAND: switch ( LOWORD( wPar ) ) { case ID_SYSMAIN_HELP: MessageBox( hWnd, "ID_SYSMAIN_HELP", NULL, MB_OK ) ; break ; } Beschleunigungs - Tasten Mit Beschleuniguungs - Tasten ( Alt - Hot - Keys ) kann das Menu schneller bedient werden. Hierzu wird im Menu - Text das '&' - Markierungs - Zeichen verwendet. Es können aber auch andere Tasten einem Menu - Punkt zugeordnet werden. Der bMain.rc - File enthält z.B. ID_MAIN_ACCEL ACCELERATORS LOADONCALL MOVEABLE VK_F1, ID_MAIN_EXAMPLE_1, VIRTKEY VK_F2, ID_MAIN_EXAMPLE_2, VIRTKEY "?", ID_..., ASCII, ALT } { Vor der Haupt - Nachrichten - Schleife wird dieAccelerator - Tabelle geladen. HACCEL hAccel = LoadAccelerators( GetModuleHandle(0), MAKEINTRESOURCE( ID_MAIN_ACCEL ) ); Die Haupt-Nachrichten-Schleife wird ergänzt. ... while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1 if ( ( hAccel != NULL ) && ( ! TranslateAccelerator ( msg.hwnd, hAccel, & msg ) ) ) { TranslateMessage( & msg ) ; DispatchMessage ( & msg ) ; } } return msg.wParam ; Zum Testen des F1-Hot-Keys kann case WM_SYSCOMMAND: //case WM_COMMAND: switch ( LOWORD( wPar ) ) { case ID_MAIN_EXAMPLE_1: MessageBox( NULL, "ID_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION | MB_YESNO ) ; break ; } in die WndProc - CALLBACK - Funktion eingefügt werden. LoadMenuIndirect Ein Menu kann per Programm im Speicher aufgebaut werden und dann durch LoadMenuIndirect() aufgebaut und mit SetMenu() dem Fenster hinzugefügt werden. Im Speicher beginnt ein Menu mit dem MENUITEMTEMPLATEHEADER ( meist versionNumber=0; offset=0, falls nachfolgend MENUITEMTEMPLATE-Struktur kommt ). Dann folgen die MENUITEMTEMPLATE-Einträge. Header für Menu-Ressourcen Kopf eines Menu MENUITEMTEMPLATEHEADER Jedes Popup/Item MENUITEMTEMPLATE typedef struct { WORD versionNumber; // 0 WORD offset; // 0 } MENUITEMTEMPLATEHEADER; typedef struct { WORD mtOption; // Item-Flag z.B. 0/MF_POPUP/MF_END WORD mtID; // ID, fehlt bei Popup-Eintrag WCHAR mtString[1]; // 00-beendeter Text } MENUITEMTEMPLATE; Beispiel für den Menu-Ressourcen-Aufbau ( WORD-aligned ) Beispiel: 0 VersionNumber von MENUITEMTEMPLATEHEADER 0 Offset von MENUITEMTEMPLATEHEADER MF_POPUP Kennzeichen für einen Pupup-Eintrag 'Pop1' als Pupup-Text Unicode-Word-Text mit 00-Ende 0 Kennzeichen für einen Item-Eintrag IDM_100 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam) 'Item 100' als Item-Text Unicode-Word-Text mit 00-Ende 0 Kennzeichen für einen Item-Eintrag IDM_110 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam) 'Item 110' als Item-Text Unicode-Word-Text mit 00-Ende MF_END Kennzeichen für das letzte Item, das zu einem Popup gehören IDM_120 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam) 'Item 120' als Item-Text Unicode-Word-Text mit 00-Ende MF_POPUP| MF_END Kennzeichen für den letzten Pupup-Eintrag 'Pop2' als Pupup-Text Unicode-Word-Text mit 00-Ende 0 Kennzeichen für das letzte Item, das zu einem Popup gehören IDM_200 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam) 'Item 200' als Item-Text Unicode-Word-Text mit 00-Ende MF_END Kennzeichen für das letzte Item, das zu einem Popup gehören IDM_210 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam) 'Item 210' als Item-Text Unicode-Word-Text mit 00-Ende verwendete User-Struktur typedef struct _MENU_STRUCT { WORD _id; // Menu-Id's, etwa ab 100 LPSTR _txt; // Menu-Popup/Item-Text MENUFUNC _fn; // auzurufende Funktion } MENU_STRUCT; MENU_STRUCT menu_struct[] = { { 0, "Pop1", 0 }, { 100, "Item 100", ... }, { 110, "Item 110", ... }, { 120, "Item 120", ... }, { 0, "Pop2", 0 }, { 200, "Item 200", ... }, { 210, "Item 210", ... }, {0,NULL, ... } }; // <== Endekriterium ist Pflicht! Alternative mit LoadMenuIndirect() int nCopyAnsiToWideChar(LPWORD p,LPSTR pAnsiIn) { int nChar = 0; do { *p++ = (WORD)*pAnsiIn; nChar++; } while (*pAnsiIn++); return nChar; } HMENU _set_menu(HWND hwnd,menu_struct * pMenu) { int k; if((!hwnd)||(!pMenu))return NULL; WORD buf[4000]={0};//memset(...) WORD * p = buf; *p++ = 0; //(MENUITEMTEMPLATEHEADER); *p++ = 0; //(MENUITEMTEMPLATEHEADER); WORD *p1=NULL, *p2=NULL; for( k=0; pMenu[k]._txt; k++){ if(0 == pMenu[k]._id) { p1 = p; //CALLBACK-Pseudocode: if(p2) *p2 = MF_END; case WM_COMMAND:{if(HIWORD(wParam))break; *p++ = MF_POPUP; for( int k=0; (pMenu+k)->_txt; k++) { p += nCopyAnsiToWideChar(p, if( LOWORD(wParam) == (pMenu+k)->_id ) { TEXT(pMenu[k]._txt)); menu_fn_aktiv = (pMenu+k)->_fn; } else { p2 = p; if ( menu_fn_aktiv ) { *p++ = 0; return menu_fn_aktiv(hwnd); *p++ = pMenu[k]._id; } p += nCopyAnsiToWideChar(p, } TEXT(pMenu[k]._txt)); } // for } break; } //ende WM_COMMAND } if(p1) *p1 = MF_POPUP|MF_END; if(p2) *p2 = MF_END; HMENU hMenu = LoadMenuIndirect(buf); Alternative mit AppendMenu() SetMenu(hwnd, hMenu); return hMenu; HMENU } set_menu(HWND hwnd,menu_struct * pMenu) { HMENU hMenu=CreateMenu(), hPopup = NULL; LPSTR pSave=NULL; int j,k=0; if((!hwnd)||(!pMenu))return NULL; while(pMenu[k]._txt) { hPopup = CreateMenu(); for(j=k+1; pMenu[j]._id; j++){ AppendMenu(hPopup,MF_STRING, pMenu[j]._id, pMenu[j]._txt); } AppendMenu(hMenu,MF_POPUP, (UINT_PTR)hPopup,pMenu[k]._txt); k = j; } if(!hMenu)DestroyMenu(hMenu); SetMenu(hwnd,hMenu);return hMenu; } CREATE_DLG_INDIRECT Ein DLGTEMPLATE kann auch ohne Ressourcen ( ohne *.RC, *.RES ) im C/C++-Programm "bitweise zusammengebastelt" werden und dann durch die Funktion CreateDialogIndirect() aufgerufen werden. Bei solchen Ressourcen ( im Speicher ) ist das Alignment ( WORD- bzw. DWORD-weise ) wesentlich. Dies bedeutet z.B., dass ein LPSTR-Strings lpAnsiIn WORDweise in p geschrieben werden muss und das Stringende durch 0x0000 gekennzeichnet ist. int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn) { int nChar = 0; do { *p++ = (WORD) *lpAnsiIn; nChar++; } while (*lpAnsiIn++); return nChar; } Aufbau der CDLGTEMPLATE-Struktur für CreateDialogIndirect() [Resource header (type = 5)] Jedes Control beginnt an DWORD-Grenze struct DialogBoxHeader { struct ControlData { DWORD lStyle; DWORD lStyle;//WS_CHILD,WS_VISIBLE... DWORD lExtendedStyle; DWORD lExtendedStyle; WORD NumberOfItems; WORD x,y,cx,cy; WORD x,y,cx,cy; WORD wId; [Name or Ordinal] MenuName; [Name or Ordinal] ClassId; [Name or Ordinal] ClassName; [Name or Ordinal] Text; WCHAR szCaption[]; WORD nExtraStuff; // soll 0x0000 sein WORD wPointSize; //nur bei DS_SETFONT }; WCHAR szFontName[];//nur bei DS_SETFONT }; Die Bezeichnung [Name or Ordinal] bedeutet, dass hier z.B. für eine für LISTBOX stehen darf: entweder 0xFFFF gefolgt von 0x0083 oder ein String mit 0x0000- Ende. Intern wird für das Auslesen verwendet if (*pw == (WORD)-1) pw += 2; else while(*pw++); Für einen Dialog wird DLG_STRUCT dlg1[] = {... } ( beginnend mit "DIALOG" ) besetzt, bevor dann durch den CREATE_DLG_INDIRECT()-Aufruf der Dialog erzeugt wird. Als Ctrl-Identifizierer wird der Index i von [i] verwendet. Die 0-enn ( 1. Spalte von DLG_STRUCT ) werden mit dem Ctrl-Handles dlg1[i].hwnd überschrieben. dlg1[0].hwnd ist das Handle des Dialog-Fensters. Sind die Ctrl-Handles bekannt, so werden keine Identifizierer benötigt. ///////////////////////////////////////////// // verwendete Struktur zur Ctrl-Beschreibung: ///////////////////////////////////////////// /////////////////////////////////////////// // Beispiel für Aufruf: /////////////////////////////////////////// static typedef struct _DLG_STRUCT { DLG_STRUCT dlg1[] = { // x, y, cx, cy HWND hwnd; // wird später eingesetzt {0,"DIALOG", "dlg-Titel", 50, 50,100,145},//[0] LPSTR pKlasse; // z.B. "BUTTON" {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] LPSTR pText; // wird in das Ctrl geschrieben {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] WORD x,y,cx,cy; // Position {0,"EDIT", "dlg-Edit", 10, 85, 80, 40},//[3] } DLG_STRUCT; {0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4] {0,"BUTTON", "OK", 10,130, 80, 12},//[5] {0,"", 0,0,0,0}};//Endekriterium ist Pflicht CREATE_DLG_INDIRECT(hwnd, dlg1, dlg_callback_func); // LISTBOX hat [2] SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"1"); SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"2"); SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"3"); // COMBOBOX hat [4] SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"1"); SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"2"); SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"3"); /////////////////////////////////////////// // class CREATE_DLG_INDIRECT /////////////////////////////////////////// class CREATE_DLG_INDIRECT { int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn) { int nChar = 0; do { *p++ = (WORD)*lpAnsiIn; nChar++; } while (*lpAnsiIn++); return nChar; } #define es_ist(str) (CSTR_EQUAL==CompareString(\ LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,(str),-1,pD->pKlasse,-1)) ////////////////// // so sieht es aus ////////////////// public: CREATE_DLG_INDIRECT( HWND hwnd, DLG_STRUCT * pDlg, DLGPROC dlgProc) { DWORD lStyle, lExtStyle; DLG_STRUCT * pD; WORD pDlgStruct[4000] = {0}, *p = pDlgStruct; int i, nCtrl=0; // = NumberOfItems !!! if(!pDlg)return; while((*pDlg[nCtrl].pKlasse) &&( pDlg[nCtrl].cx) &&( pDlg[nCtrl].cy)) nCtrl++; nCtrl--; // = NumberOfItems !!! if(nCtrl<1) return; // Dialog: ///////////////////////////////////////////// pD = pDlg+0; //pD zeigt auf den 0-ten DLG_STRUCT-Eintrag if(!es_ist("DIALOG"))return; lStyle = WS_CAPTION|WS_SYSMENU|WS_VISIBLE | DS_SETFOREGROUND|DS_MODALFRAME|DS_SETFONT; lExtStyle = WS_EX_DLGMODALFRAME;//WS_EX_CLIENTEDGE; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = nCtrl; *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = 0; // Menu *p++ = 0; // Class p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 7; // point size; braucht DS_SETFONT p += nCopyAnsiToWideChar(p,TEXT("Times New Roman")); for ( i=1; i<=nCtrl; i++){ p = (WORD*)(((DWORD)p + 3) & ~3); // WORD align pD = pDlg+i; //pD zeigt auf den i-ten DLG_STRUCT-Eintrag if(es_ist("STATIC")){ lExtStyle = 0;//WS_EX_CLIENTEDGE|WS_EX_STATICEDGE; lStyle = WS_VISIBLE|WS_CHILD|SS_NOPREFIX|SS_LEFTNOWORDWRAP; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = 0xffff; //IDOK; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0082;// alternativ: //p += nCopyAnsiToWideChar(p,TEXT("STATIC")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("BUTTON")){ lExtStyle = 0;//WS_EX_CLIENTEDGE; lStyle = WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; //IDOK; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0080;//alternativ: //p += nCopyAnsiToWideChar(p,TEXT("BUTTON")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("LISTBOX")){ lExtStyle = WS_EX_CLIENTEDGE; lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS |LBS_DISABLENOSCROLL |LBS_HASSTRINGS|LBS_STANDARD; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0083;//alternativ: //p += nCopyAnsiToWideChar(p,TEXT("LISTBOX")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("EDIT")){ lExtStyle = WS_EX_CLIENTEDGE; lStyle = WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_CLIPSIBLINGS |ES_MULTILINE|ES_AUTOVSCROLL ; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0081;// alternativ: //p += nCopyAnsiToWideChar(p,TEXT("EDIT")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("COMBOBOX")){ lExtStyle = WS_EX_CLIENTEDGE; lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS |CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0085; //alternativ: //p += nCopyAnsiToWideChar(p,TEXT("COMBOBOX")); p += nCopyAnsiToWideChar(p,TEXT(""));//pD->pText)); *p++ = 0; } } // ende for HWND hDlg = CreateDialogIndirect(GetModuleHandle(0), (LPDLGTEMPLATE) pDlgStruct, hwnd, (DLGPROC) dlgProc); if(!hDlg)return; //////////////////////////////////////////////////////// // hinterlege die Ctrl-Handles in die Struktur: pDlg->hwnd = hDlg; for ( i=1; i<=nCtrl; i++){ pD = pDlg+i; //pD zeigt auf den i-ten Eintrag pD->hwnd = GetDlgItem( hDlg, i ); if(es_ist("COMBOBOX")){ SetWindowText(pD->hwnd,pD->pText); } else if(es_ist("LISTBOX")){ SendMessage(pD->hwnd,LB_ADDSTRING,0L,(LPARAM)pD->pText); } } } #undef es_ist }; user-typedef's MENU_STRUCT WORD _id; // Menu-Id's,etwa ab 100 LPSTR _txt;// Menu-Item-Text MENUFUNC _fn; // auzurufende Funktion DLG_STRUCT HWND LPSTR LPSTR WORD hwnd; //des Ctrl's pKlasse;//z.B."EDIT" pText; //Initialisierung x,y,cx,cy;//Ctrl-Position mit typedef BOOL (* MENUFUNC)(HWND hwnd); kann WM_COMMAND-Aufruf 'automatisiert' werden //Beispiel: BOOL menu_fn100(HWND hwnd) { if(hwnd != _hModeless) MessageBox(hwnd, "kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf, "global _hModeless=%08x",_hModeless); MessageBox(hwnd,buf,"info",MB_OK); return TRUE; } static // static ist Pflicht! MENU_STRUCT menu_struct[] = { { 0, "Test1", 0 }, { 100, "100", menu_fn100 }, //{ 120, "120", menu_fn120 }, //{ 0, "Test2", 0 }, //{ 200, "200", menu_fn100 }, //{ 210, "210", menu_fn120 }, {0,NULL,0}};//<== Endekrit.ist Pflicht! //Aufruf falls hwnd existiert: static DLG_INDIRECT * pDlg = new DLG_INDIRECT(hwnd); pDlg -> set_menu(menu_struct); //Beispiel: static // static ist Pflicht! DLG_STRUCT DLG_STRUCT[] = { // x, y, cx, cy {0,"DIALOG", "dlg1-Titel", 40, 20,100,160},//[0] {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] {0,"EDIT", "dlg-Edit", 10, 85, 80, 40},//[3] {0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4] {0,"BUTTON", "OK", 10,130, 80, 12},//[5] {0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht //Aufruf mit CALLBAC dlg1_proc: static DLG_INDIRECT * pDlg = new DLG_INDIRECT(hwnd); pDlg -> create_dlg_indirect(DLG_STRUCT, dlg1_proc); if(!pDlg) error ... if(!pDlg) error ... "MDICLIENT" Dialoge Eingebaute klassen zur Ereignisbehandlung Der Entwickler kann eigene Klassen anlegen (RegisterClass) und dort eine CALLBACK-Funktion für die Ereignissteuerung hinterlegen. Es existieren auch bereits verfügbare WindowsKlassen, die der Ereignissteuerung dienen und die bereits eine CALLBACK-Funktion enthalten. Die ersten Windows-Versionen enthielten in User(32).dll und Comctl(32).dll die Klassen: 0x0080 "Button", 0x0081 "Edit", 0x0083 "ListBox", 0x0084 "ScrollBar", und die Dialog Box Klasse "#32770". 0x0082 "Static", 0x0085 "ComboBox" Hier eine aktuelle Übersicht (User Interface Element Reference): Animation control Calendar control (ANIMATE_CLASS, "SysAnimate32" in Commctrl.h) (MONTHCAL_CLASS, "SysMonthCal32" in Commctrl.h) Caret Pop-up menu ("#32768") Progress bar control (PROGRESS_CLASS, "msctls_progress" in Commctrl.h) Push button ("BUTTON") Check box ("BUTTON") Client object (text, graphics) Combo box ("COMBOBOX") Radio button ("BUTTON") Scroll bar ("SCROLLBAR") Size grip (special mouse pointer) IDC_IBEAM "Edit", IDC_WAIT "Wait", Cursor IDC_ARROW "Normal", IDC_CROSS "Graphic", IDC_UPARROW "Up", IDC_SIZENWSE "NWSE size", IDC_SIZENESW "NESW size", IDC_SIZEWE "Horizontal size", IDC_SIZENS "Vertical size", IDC_SIZEALL "Move", IDC_NO "Forbidden", IDC_APPSTARTING "App start",IDC_HELP "Help", Custom cursor "Unknown" Slider control (TRACKBAR_CLASS, "msctls_trackbar" in Commctrl.h) Static text ("STATIC") Status bar control (STATUSCLASSNAME, "msctls_statusbar32" in Commctrl.h) Switch window ("#32771") Tab control (WC_TABCONTROL, "SysTabControl" in Commctrl.h) Toolbar control (TOOLBARCLASSNAME, "ToolbarWindow32" in Commctrl.h) ToolTip control (TOOLTIPS_CLASS, "tooltips_class" in Commctrl.h) Title bar Desktop window ("#32769") Dialog box ("#32770") Edit control "EDIT", "RichEdit", "RichEdit20A" Header control Hot key control (WC_HEADER, "SysHeader32" in Commctrl.h) (HOTKEY_CLASS, "msctls_hotkey32" in Commctrl.h) List box ("LISTBOX") List view control (WC_LISTVIEW, "SysListView" in Commctrl.h) MDI client window ("MDIClient") Tree view control (WC_TREEVIEW, "SysTreeView" in Commctrl.h) Up-down control (UPDOWN_CLASS, "msctls_updown32" in Commctrl.h) Menu bar Menu item ( "#32768") Es gibt zahlreiche Funktionen, die zum Erzeugen und Manipulieren von modalen/modeless Dialogen und deren Unterfenster ( Controls ) dienen: CreateDialog CreateDialogParam DialogBoxIndirect DialogProc GetDlgCtrlID GetDlgItemText IsDialogMessage MessageBoxEx SetDlgItemText CreateDialogIndirect DefDlgProc DialogBoxIndirectParam EndDialog GetDlgItem GetNextDlgGroupItem MapDialogRect SendDlgItemMessage MessageBoxIndirect CreateDialogIndirectParam DialogBox DialogBoxParam GetDialogBaseUnits GetDlgItemInt GetNextDlgTabItem MessageBox SetDlgItemInt 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 PushButtons. int MessageBoxEx( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, WORD wLanguageId ); // // // // // handle of owner window address of text in message box address of title of message box style of message box 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 positiven Wert zurück. Der Rückgabe - Wert entspricht dem gedrückten Button. IDABORT IDCANCEL IDIGNORE IDNO IDOK Abort button was selected. Cancel button or ESC key was selected. Ignore button was selected. No button was selected. OK button was selected. IDRETRY IDYES Retry button was selected. 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 ( exclamation-point ) 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 The first button is the default button. MB_DEFBUTTON2 The second button is the default button. MB_DEFBUTTON3 The third button is the default button. MB_DEFBUTTON4 The 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 Beispiele: MessageBox() als einfacher ( Benachrichtigungs-) Dialog MessageBox( 0, "Client-Bereich", 0, MB_OK ); MessageBox( hwnd, "Client-Bereich", "Titel", MB_OK ); MessageBox( hwnd, "MB_ICONSTOP", "Titel", MB_OK|MB_ICONSTOP); MessageBox(hwnd, "MB_ICONINFORMATION", "Titel", MB_OK|MB_ICONINFORMATION); MessageBox(hwnd, "MB_ICONQUESTION", "Titel", MB_OK|MB_ICONQUESTION); int mb_val = MessageBox(hwnd, "Rückgabewert", Titel", MB_OKCANCEL|MB_DEFBUTTON2); mb_val wirdt IDOK oder IDCANCEL DialogBox() 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( hInstance, lpTemplate, hWndParent, lpDialogFunc) \ 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 ); hInstance kann durch GetModuleHandle( NULL) oder unter WM_CREATE durch static HINSTANCE hInstance = ( LPCREATESTRUCT ) lParam-> hInstance ermittelt werden. Beispiel: DialogBox als Hauptprogramm Existiert eine IDD_DIALOG-Dialog-Ressource und die dlg-CALLBACK-Funktion 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. Gegenüber einer MessageBox() ist der Programmier - Aufwand bei Verwendung von DialogBox() größer. int DialogBox( HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc ); // // // // handle to application instance identifies dialog box template handle to owner window 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. 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; } 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. 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. *.RC-File-Ausschnitt Der *.RC-File-Ausschnitt für den About - Dialog und das Menu: IDI_MAIN_ICON ICON DISCARDABLE "bMain.ico" IDD_DIALOG_ABOUT DIALOG DISCARDABLE 0, 0, 192, 141 STYLE DS_SYSMODAL | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "MS Sans Serif" BEGIN ICON IDI_MAIN_ICON, IDC_STATIC, 30,19, 20,20 LTEXT "Prof.Dr.W.Bachmann",IDC_STATIC, 87, 5, 68,8 LTEXT "FH-Giessen", IDC_STATIC, 87,17, 38,8 LTEXT "Wiesenstrasse 14", IDC_STATIC, 87,28, 57,8 LTEXT "(D-35390) GIESSEN", IDC_STATIC, 85,40, 66,8 CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,8,59,175,5 LTEXT "Bitte beachten Sie:",IDC_STATIC,62,74,61,8 LTEXT "den Abgabetermin für die Übung",IDC_STATIC,41,84,103,8 LTEXT "die vollständige Dokumentation incl. aller Quellen", IDC_STATIC,15,94,155,8 LTEXT "( *.CPP, *.H, *.RCT, *.RC, *.ICO, usw. )",IDC_STATIC,31,105,123,8 DEFPUSHBUTTON "OK",IDOK,8,120,175,14 END IDR_MENU_MAIN MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Exit", ID_MENUITEM_EXIT END POPUP "&Examples" BEGIN MENUITEM "Example&1", ID_MENUITEM_EXAMPLE1 MENUITEM "Example&2", ID_MENUITEM_EXAMPLE2 MENUITEM "Example&3", ID_MENUITEM_EXAMPLE3 END POPUP "&Help" BEGIN MENUITEM "&About", ID_MENUITEM_ABOUT END END 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; } 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 ) ; } 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 ); } } In der Modeless - Dialog - CALLBACK - Funktion wird die WM_ACTIVATE - Nachricht benutzt, um das globale hDlgModeless - Handle zu setzen. Durch DestroyWindow() wird der Modeless-Dialog freigegeben. für Modeless: in der CALLBACK ... switch ( iMsg ) { case WM_ACTIVATE: { if ( 0 == wParam ) hDlgModeless = NULL; // wird inactive else hDlgModeless = hWnd; // wird active return FALSE; break; } case WM_CLOSE: { // ggf. Heap-freigeben if( hDlgModeless == hWnd ) DestroyWindow( hWnd ) ; break; } ... Ein Modless-Dialog wird mit CreateDialog() oder CreateDialogParam() erzeugt. Mit dem Letzten Parameter von CreateDialogParam() kann bereits mit dem CreateDialogParam()-Aufruf von "aussen" ein 4 Byte-Wert val zur CALLBACK-Funktion ( WM_INITDIALOG ) "durchgereicht" werden. für Modeless: Aufruf HWND hDlg = CreateDialogParam( GetModuleHandle(0), MAKEINTRESOURCE(idRes), hParent, dlgProc, val ); if ( hDlg == NULL ) { ... error } } Oft sollen Daten zugehörig zum jeweiligen Fenster ( speichern zwischen Fenster-Wechseln ) gespeichert werden. Jedes Fenster hat dann neben den internen Daten auch die benötigten UserDaten. Dies kann Zugeordnet erfolgen, indem durch SetWindowLong( hDlg, GWL_USERDATA, value ) ein 4 Byte-Wert value hinterlegt wird. SetWindowLong() gibt den alten gespeicherten Wert zurück und hinterlegt den neuen value. für Modeless: im Fenster hinterlegen LONG old_value = SetWindowLong( hDlg, DWL_USER,(LONG)value ); } CreateDialog() - Aufruf für Modeless: 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(). *.RC enthält IDD_DIALOG_MODELESS DIALOG DISCARDABLE 0, 0, 186, 129 STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Modeless" FONT 8, "MS Sans Serif" BEGIN LTEXT "IDC_EDIT0",IDC_STATIC,6,6,38,8 EDITTEXT IDC_EDIT0,5,17,115,14,ES_AUTOHSCROLL PUSHBUTTON "showEB 0",IDC_BUTTON0,129,18,50,14 DEFPUSHBUTTON "OK",IDOK,130,108,50,14, WS_TABSTOP END *.CPP enthält BOOL CALLBACK dlgModelessProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { static CHAR * pEdit; int len, idx; HWND hCtl0; switch ( iMsg ) { case WM_INITDIALOG: // idRes = lParam; if ( pEdit != NULL ) { DestroyWindow( hWnd ) ; //keine doppelten Dialoge } else { pEdit = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); hCtl0 = GetDlgItem( hWnd, IDC_EDIT0 ) ; Edit_LimitText( hCtl0, 256 ); strcpy( pEdit, "...Text..." ); Edit_SetText ( hCtl0, pEdit ); } break; case WM_ACTIVATE: if ( 0 == wParam ) hDlgModeless = NULL; // becoming inactive else hDlgModeless = hWnd; // becoming active return FALSE; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDC_BUTTON0: len = GetDlgItemText( hWnd, IDC_EDIT0, pEdit, 256 ); MessageBox( hWnd, pEdit, "Eingabe-Feld", MB_OK); break; case IDC_BUTTON1: len = GetDlgItemText( hWnd, IDC_COMBO1, p1, 256 ); MessageBox( hWnd, p1, "Kombinations-Feld", MB_OK); break; case IDOK: //fall case IDCANCEL: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; } break; case WM_CLOSE: free( pEdit ); pEdit = NULL; EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ) ; break; } return FALSE; } Interne Dialog - CALLBACK - Funktion Alle Dialog - Klassen sind Window - Klassen. Eine Dialog - Box ist ein Window zu einer vorhandenen Klasse. Es wird zusätzlicher Speicher WNDCLASS cbWndExtra = DLGWINDOWEXTRA benötigt. Für einen DialogBox() - oder CreateDialog() - Aufruf wird i.a. keine eigene Klasse registriert. Anstelle einer eigenen Klassen - CALLBACK - Funktion wird die eingebaute und bereits unter 0x8002 registrierte USER.EXE - interne IDefDlgProc() - Funktion benutzt. Durch DialogBox() werden die folgenden Nachrichten versendet. DM_GETDEFID WM_CTLCOLORDLG WM_GETDLGCODE DM_REPOSITION WM_CTLCOLORMSGBOX WM_INITDIALOG DM_SETDEFID WM_ENTERIDLE WM_NEXTDLGCTL In der internen IDefDlgProc() wird durch result = CallDlgProc( hWnd, iMsg, wParam, lParam)) die eingetragene Benutzer - CALLBACK - Funktion aufgerufen. Der BOOL - Rückgabe Wert entscheidet über die weitere Bearbeitung der Nachrichten. Die CALLBACK - Funktion ● BOOL myDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) des Benutzers sollte kann z.B. die Nachrichten WM_INITDIALOG, WM_CLOSE, WM_COMMAND ( mit IDOK und IDCANCEL ) bearbeiten. Der BOOL - Rückgabe - Wert entscheidet über die weitere Bearbeitung der Nachrichten. Falls in WM_INITDIALOG alles erledigt wurde, so wird der iMsg = WM_INITDIALOG - Case mit return TRUE, sonst return FALSE ( Normalfall ) beendet. WM_CLOSE soll EndDialog ( hWnd, wParam ) aufrufen. WM_COMMAND mit IDOK und IDCANCEL kann z.B. die Nachricht ( hWnd, WM_CLOSE, wParam, 0L ) senden. Das folgende Fragment zeigt den Aufruf der eingetragenen Benutzer - CALLBACK - Funktion ( PDLG ) hWnd ) -> lpfnDlg mit Hilfe von CallDlgProc(). Falls keine lpfnDlg - Funktion eingetragen wurde oder CallDlgProc() FALSE zurück gibt, so erfolgt eine default Behandlung durch Windows. LRESULT API IDefDlgProc( HWND hWnd, WORD iMsg, WPARAM wParam, LPARAM lParam) { ( ( PDLG ) hWnd ) -> resultWP = 0L; BOOL result = FALSE; if ( ( ( PDLG ) hWnd ) -> lpfnDlg == NULL || ! ( result = CallDlgProc( hWnd, iMsg, wParam, lParam ))) { if ( ! IsWindow( hWnd ) ) { DebugErr(DBF_ERROR, "..." ); goto ReturnIt; } switch ( iMsg ) { case WM_ERASEBKGND: ... case WM_SHOWWINDOW: ... case WM_SYSCOMMAND: ... case WM_ACTIVATE: ... case WM_SETFOCUS: ... case WM_CLOSE: ... case WM_NCDESTROY: ... case DM_SETDEFID: ... case DM_GETDEFID: ... case WM_NEXTDLGCTL: ...//TAB-like operations case WM_ENTERMENULOOP:... case WM_LBUTTONDOWN: ... case WM_NCLBUTTONDOWN:... case WM_GETFONT: ... case WM_VKEYTOITEM: ... case WM_COMPAREITEM: ... case WM_CHARTOITEM: ... case WM_INITDIALOG: ... default: return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } ReturnIt: if (iMsg == WM_CTLCOLOR || iMsg == WM_COMPAREITEM || iMsg == WM_VKEYTOITEM || iMsg == WM_CHARTOITEM || iMsg == WM_QUERYDRAGICON || iMsg == WM_INITDIALOG) { return( (LRESULT)(DWORD) result ); } return( ( ( PDLG ) hWnd ) -> resultWP ); } Standard - Dialoge CHAR * get_Open_File_Name ( HWND hWnd, CHAR * pNamExt, CHAR * pTitle ) { OPENFILENAME ofn = { 0 } ; static char buf[MAX_PATH] ; buf[0] = '\0' ; if ( pNamExt == NULL ) pNamExt = "All Files\000*.*\000" ; ofn.lStructSize = sizeof( OPENFILENAME ); ofn.hwndOwner = hWnd ; ofn.hInstance = GetModuleHandle( NULL ); ofn.lpstrTitle = pTitle ; ofn.lpstrFile = buf ; ofn.nMaxFile = sizeof( buf ) ; ofn.lpstrFilter = pNamExt ; ofn.lpstrDefExt = "*" ; ofn.nFilterIndex = 1L ; if ( GetOpenFileName( & ofn ) ) return buf ; return NULL ; } 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_FINDSTRING CB_GETCURSEL CB_GETDROPPEDWIDTH CB_GETHORIZONTALEXTENT CB_GETLBTEXT CB_GETTOPINDEX CB_LIMITTEXT CB_SETCURSEL CB_SETEXTENDEDUI CB_SETITEMHEIGHT CB_SHOWDROPDOWN CBN_DROPDOWN CBN_ERRSPACE CBN_SELENDCANCEL WM_COMPAREITEM CB_DELETESTRING CB_FINDSTRINGEXACT CB_GETDROPPEDCONTROLRECT CB_GETEDITSEL CB_GETITEMDATA CB_GETLBTEXTLEN CB_INITSTORAGE CB_RESETCONTENT CB_SETDROPPEDWIDTH CB_SETHORIZONTALEXTENT CB_SETLOCALE CBN_CLOSEUP CBN_EDITCHANGE CBN_KILLFOCUS CBN_SELENDOK WM_DRAWITEM CB_DIR CB_GETCOUNT CB_GETDROPPEDSTATE CB_GETEXTENDEDUI CB_GETITEMHEIGHT CB_GETLOCALE CB_INSERTSTRING CB_SELECTSTRING CB_SETEDITSEL CB_SETITEMDATA CB_SETTOPINDEX CBN_DBLCLK CBN_EDITUPDATE CBN_SELCHANGE CBN_SETFOCUS 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. Die folgenden Funktionen werden oft verwendet: HWND hCtl = GetDlgItem ( HWND hDlg, int idRes ); int idRes = GetDlgCtrlID( HWND hCtl ); BOOL SetDlgItemText ( HWND hDlg, int idRes, LPCSTR lpString); UINT GetDlgItemText ( HWND hDlg, int idRes, LPSTR lpString, int nMaxCount); BOOL SetDlgItemInt ( HWND hDlg, int idRes, UINT uValue, BOOL bSigned); UINT GetDlgItemInt ( HWND hDlg, int idRes, BOOL *lpTranslated, BOOL bSigned); BOOL CheckDlgButton ( HWND hDlg, int idRes, UINT uCheck); BOOL CheckRadioButton ( HWND hDlg, int nIDFirstButton, int nIDLastButton, int nIDCheckButton); UINT IsDlgButtonChecked ( HWND hDlg, int idRes); HWND GetNextDlgGroupItem( HWND hDlg, HWND hCtl, BOOL bPrevious); HWND GetNextDlgTabItem ( HWND hDlg, HWND hCtl, BOOL bPrevious); Static Text Control Static Text Controls Static Text Controls Static_Enable (hCtl, Static_GetIcon (hCtl, Static_GetText (hCtl, Static_GetTextLength(hCtl) Static_SetIcon (hCtl, Static_SetText (hCtl, fEnable) hIcon) lpch, cchMax) hIcon) lpsz) Button Control In windowX.h sind die folgenden Button - Macros definiert: Button Controls Button Controls Button_Enable (hCtl, Button_GetCheck (hCtl) Button_GetState (hCtl) Button_GetText (hCtl, Button_GetTextLength(hCtl) Button_SetCheck (hCtl, Button_SetState (hCtl, Button_SetStyle (hCtl, Button_SetText (hCtl, fEnable) lpch, cchMax) check) state) style, fRedraw) lpsz) Ein Button kann auf drei Arten selektiert werden: ● ● ● durch Klicken mit der Maus, durch Auswählen mit der Tab - Taste und dann die Enter - Taste drücken, durch Auswählen des Group - Rahmens mit der Tab - Taste ( falls der Button den WS_GROUP - Style hat ) und dann kann innerhalb des Group - Rahmens mit den Pfeilchen Tasten der Button selektiert weren. Die Button - Auswahl bewirkt die folgenden Ereignisse: ● ● ● ● Button erhält den Keyboard - Focus ( WM_FOCUS ), Button sendet bei Selektion an das Parent - Window eine Benachrichtigung ( Notification Message ), das Parent - Window sendet an den Button eine Nachricht zur Zustands - Änderung, das Parent Window zeichnet den Button neu im Zustand: focus-state / push-state / check-state. Eine Applikation kann den aktuelle Zustand mit BM_GETCHECK oder BM_GETSTATE abfragen und mit BM_SETCHECK oder BM_SETSTATE setzen. Der Button sendet Nachrichten an das Parent - Window, wenn sich sein Zustand ändert. Der Button - Identifizierer wird mit wmID, die Notification Messages ( z.B. BN_CLICKED ) wird mit wmCMD und das Control - Handle mit wmHWND bezeichnet. Wegen der WIN16/WIN32 - Portabilität sind die windoesX.h - Macros sinnvoll: Nachrichten - Casting WindosX.h-Macros #ifdef WIN16 int wmCMD = HIWORD( lParam ) ; #else int wmCMD = HIWORD( wParam ) ; #endif int wmID = LOWORD( wParam ); HWND wmHWND=(HWND)(UINT)lParam; int wmCMD = GET_WM_COMMAND_CMD ( wParam, lParam ) ; int wmID = GET_WM_COMMAND_ID ( wParam, lParam ) ; HWND wmHWND= GET_WM_COMMAND_HWND( wParam, lParam ) ; Beim Übergang von WIN16 auf WIN32 hat sich das Nachrichten - Format geändert. Bei WIN16 war wParam ein WORD - Typ, bei WIN32 ist wParam ein LONG - Typ. Bei WIN32 benötigt ein Handle 32 Bits Es gibt die folgenden Button - Notification - Messages ButtonNotificationMessages Erklärung BN_CLICKED Der Benutzer hat den Button geklickt BN_DBLCLK Der Benutzer hat den Button doppelt geklickt BN_DISABLE Der Button ist gesperrt BN_PUSHED Der Benutzer hat den Button gedrückt BN_KILLFOCUS Der Button verliert den Keyboard - Focus BN_PAINT Der Button sollte gezeichnet werden BN_SETFOCUS Der Button erhält den Keyboard - Focus BN_UNPUSHED Der Button ist nicht mehr gedrückt Sendet der Button ID_MY_BUTTON1 z.B. die BN_CLICKED - Notification - Messages an das Parent - Window, so kann diese Nachricht gemäß int wmCMD = GET_WM_COMMAND_CMD ( wParam, lParam ) ; int wmID = GET_WM_COMMAND_ID ( wParam, lParam ) ; switch ( iMsg ) { ... case WM_COMMAND: switch ( wmID ) { case ID_MY_BUTTON1: HWND hMyButton1 = GET_WM_COMMAND_HWND( wParam, lParam ) ; if ( wmCMD == BN_CLICKED ) { ... } ... } ... } in der CALLBACK - Funktion des Parent - Window bearbeitet werden. Damit die BN_DISABLE, BN_PUSHED, BN_KILLFOCUS, BN_PAINT, BN_SETFOCUS und BN_UNPUSHED Notification - Nachrichten an das Parent - Window gesendet werden, muß der Button den BS_NOTIFY - Style besitzen. Ein Owner - Drawn - Button sendet WM_DRAWITEM an das Parent - Window. Edit Control Edit Controls Edit Controls Edit_CanUndo (hCtl) Edit_EmptyUndoBuffer(hCtl) Edit_Enable (hCtl, Edit_FmtLines (hCtl, Edit_GetFirstVisible(hCtl) Edit_GetHandle (hCtl) Edit_GetLine (hCtl, Edit_GetLineCount (hCtl) Edit_GetModify (hCtl) Edit_GetRect (hCtl, Edit_GetSel (hCtl) Edit_GetText (hCtl, Edit_GetTextLength (hCtl) Edit_LimitText (hCtl, Edit_LineFromChar (hCtl, Edit_LineIndex (hCtl, Edit_LineLength (hCtl, fEnable) fAddEOL) line, lpch, cchMax) lprc) lpch, cchMax) cchMax) ich) line) line) Edit_ReplaceSel (hCtl, Edit_Scroll (hCtl, Edit_SetHandle (hCtl, Edit_SetModify (hCtl, Edit_SetPasswordChar(hCtl, Edit_SetRect (hCtl, Edit_SetRectNoPaint (hCtl, Edit_SetSel (hCtl, Edit_SetTabStops (hCtl, Edit_SetText (hCtl, Edit_SetWordBreak (hCtl, Edit_Undo(hCtl) lpszReplace) dv, dh) h) fModified) ch) lprc) lprc) ichStart, ichEnd) cTabs, lpTabs) lpsz) lpfnWordBreak) Beispiel Die folgende Funktion Print_Lines() holt aus einer Multi - Line - Edit - Box alle Zeilen und gibt diese durch PrintInWindow() aus. Print_Lines() wird in unterschiedlicher Schreibweise ( mit/ohne den Edit_GetLineCount-, Edit_GetLine - Macros aus WINDOWS.H ) angegeben. void Print_Lines( HWND hEdit, WHND hDisplay ) { int line; int lineLast = (int) SendMessage( hEdit, EM_GETLINECOUNT, 0, 0L ); for ( line = 0; line < lineLast; line ++ ) { int cch; char ach[256]; *( (LPINT) ach ) = sizeof( ach ); cch = (int) SendMessage( hEdit, EM_GETLINE, line, (LONG)(LPSTR) ach ); PrintInWindow( ach, hDisplay); } } In WINDOWS.H ist definiert: #define Edit_GetLineCount( hEdit ) \ ((int)(DWORD)SendMessage((hEdit),\ EM_GETLINECOUNT,0L,0L)) #define Edit_GetLine( hEdit, line, lpch, cchMax) \ ((*((int *)(lpch)) = (cchMax)), ((int)(DWORD)\ SendMessage((hEdit),\ EM_GETLINE,(WPARAM)(int)(line),(LPARAM)(LPTSTR)(lpch)))) Bei Verwendung der Edit_GetLineCount-, Edit_GetLine - Macros wird ein mehrfaches Casten vermieden. void Print_Lines( HWND hEdit, WHND hDisplay ) { int line; int lineLast = Edit_GetLineCount( hEdit ); for ( line = 0; line < lineLast; line ++ ) { int cch; char ach[256]; cch = Edit_GetLine( hEdit, line, ach, sizeof(ach) ); PrintInWindow( ach, hDisplay ); } } List Box Control List Box Controls List Box Controls ListBox_AddFile (hCtl, lpszFilename) ListBox_AddItemData (hCtl, data) ListBox_AddString (hCtl, lpsz) ListBox_DeleteString (hCtl, index) ListBox_Dir (hCtl, attrs, lpszFileSpec) ListBox_FindItemData (hCtl, indexStart, data) ListBox_Enable (hCtl, fEnable) ListBox_FindString (hCtl, indexStart, lpszFind) ListBox_GetAnchorIndex(hCtl) ListBox_GetCaretIndex (hCtl) ListBox_GetCount (hCtl) ListBox_GetCurSel (hCtl) ListBox_GetHorizontalExtent(hCtl) ListBox_GetItemData (hCtl, index) ListBox_GetItemHeight (hCtl, index) Win32 ListBox_GetItemRect (hCtl, index, lprc) ListBox_GetSel (hCtl, index) ListBox_GetSelCount (hCtl) ListBox_GetText (hCtl, index, lpszBuffer) ListBox_GetSelItems (hCtl, cItems, lpIndices) ListBox_GetTextLen (hCtl, index) ListBox_GetTopIndex (hCtl) ListBox_InsertItemData(hCtl, lpsz, index) ListBox_InsertString (hCtl, lpsz, index) ListBox_ResetContent (hCtl) ListBox_SelectItemData(hCtl, indexStart, data) ListBox_SelectString (hCtl, indexStart, lpszFind) ListBox_SelItemRange (hCtl, fSelect, first, last) ListBox_SetAnchorIndex(hCtl, index) ListBox_SetCaretIndex (hCtl, index) ListBox_SetColumnWidth(hCtl, cxColumn) ListBox_SetCurSel (hCtl, index) ListBox_SetItemData (hCtl, index, data) ListBox_SetHorizontalExtent(hCtl, cxExtent) ListBox_SetSel (hCtl, fSelect, index) ListBox_SetItemHeight (hCtl, index, cy) Win32 ListBox_SetTabStops (hCtl, cTabs, lpTabs) ListBox_SetTopIndex (hCtl, indexTop) Combo Box Control Eine Combo - Box besteht aus einer Edit - Zeile und einer zusätzlichen List - Box. Hat eine Combo - Box den Style CBS_DROPDOWN, so kann die Combo - Box aufgeklappt werden. List Zeilen können mit Klick oder Cursor - Tasten in die Edit - Zeile geholt werden. Combo Box Controls Combo Box Controls ComboBox_AddItemData (hCtl, data) ComboBox_AddString (hCtl, lpsz) ComboBox_DeleteString (hCtl, index) ComboBox_Dir (hCtl, attrs, lpszFileSpec) ComboBox_Enable (hCtl, fEnable) ComboBox_FindItemData (hCtl, indexStart, data) ComboBox_GetCount (hCtl) ComboBox_FindString (hCtl, indexStart, lpszFind) ComboBox_GetCurSel (hCtl) ComboBox_GetDroppedControlRect(hCtl, lprc) Win32 ComboBox_GetDroppedState (hCtl) Win32 ComboBox_GetEditSel (hCtl) ComboBox_GetExtendedUI (hCtl) Win32 ComboBox_GetItemData (hCtl, index) ComboBox_GetItemHeight (hCtl) ComboBox_GetLBText (hCtl, index, lpszBuffer) ComboBox_GetLBTextLen (hCtl, index) ComboBox_GetText (hCtl, lpch, cchMax) ComboBox_GetTextLength (hCtl) ComboBox_InsertItemData (hCtl, index, data) ComboBox_InsertString (hCtl, index, lpsz) ComboBox_LimitText (hCtl, cchLimit) ComboBox_ResetContent (hCtl) ComboBox_SelectItemData (hCtl, indexStart, data) ComboBox_SetCurSel (hCtl, index) ComboBox_SelectString (hCtl, indexStart, lpszSelect) ComboBox_SetExtendedUI (hCtl, flags)Win32 ComboBox_SetEditSel ComboBox_SetItemHeight ComboBox_SetItemData ComboBox_SetText ComboBox_ShowDropdown (hCtl, (hCtl, (hCtl, (hCtl, (hCtl, ichStart, ichEnd) cyItem)Win32 index, data) lpsz) fShow) Beispiel Im *.RC - File soll in einer STRINGTABLE ein String IDS_STRING0 abgelegt werden, der zum Füllen einer Combo - Box verwendet werden soll. Die List - Box - Zeilen werden durch \000 beendet. Bei Win16 ist anstelle von Der *.RC - File enthält dann z.B. STRINGTABLE DISCARDABLE BEGIN IDS_STRING0 "(EB_ und 0.LB_Text0\000(1.LB_Text)\000(2.LB_Text)\000" END IDD_MYDIALOG DIALOG DISCARDABLE 0, 0, 186, 129 STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION ... FONT 8, "MS Sans Serif" BEGIN // idCombo, x, y, dx,dy, Combo-Style COMBOBOX IDC_COMBO1, 5,53, 115,80, CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP END Die Combo - Box wird mit IDC_COMBO1 identifiziert. Die aufgeklappte Box hat hier eine Höhe von 80 Dialog - Pixeln. Es wird eine Funktion ComboBox_fillFromResString() angegeben, die idString=IDS_STRING0 holt und in idCombo=IDC_COMBO1 schreibt. Auch die aufgeklappten List - Zeilen werden eingetragen. HWND ComboBox_fillFromResString ( HWND hWnd, int idString, int idCombo ) { int idx = 0 ; char buf[512]; int idxMax = LoadString( GetModuleHandle(NULL), idString, buf, 512 ); HWND hCombo = GetDlgItem( hWnd, idCombo ) ; if ( ( idxMax <= 0 ) || ( hCombo == NULL ) ) return NULL; SetWindowRedraw ( hCombo, FALSE ); //CB refresh aus ComboBox_SetText( hCombo, buf ); //EB while ( idx < idxMax ) { //LBs ComboBox_AddString ( hCombo, & buf[idx] ); idx += strlen( & buf[idx] ) + 1 ; } SetWindowRedraw( hCombo, TRUE ); //CB refresh ein return hCombo; } Durch SetWindowRedraw( ) wird eine wiederholte Auffrischung bei jedem Eintrag unterdrück. Dadurch wird das Bildschirm - Flackern reduziert. In der Dialog - CALLBACK - Funktion werden die Controls meistens unter WM_INITDIALOG initialisiert: BOOL CALLBACK myDlgProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { case WM_INITDIALOG: hCombo = ComboBox_fillFromResString ( hWnd, IDS_STRING0, IDC_COMBO1 ); break; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: ... break; } break; case WM_CLOSE: ... break; ... } return FALSE; } Hex - Calc IDD_DIALOG_HEXCALC DIALOG DISCARDABLE 5, 10, 188, 135 STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_THICKFRAME CAPTION "Hex - Calc" FONT 8, "MS Sans Serif" BEGIN COMBOBOX IDC_COMBO0, 5,5,115,125,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "0",48,6,117,14,14,NOT WS_TABSTOP PUSHBUTTON "1",49,6,99,14,14,NOT WS_TABSTOP PUSHBUTTON "2",50,24,99,14,14,NOT WS_TABSTOP PUSHBUTTON "3",51,42,99,14,14,NOT WS_TABSTOP PUSHBUTTON "4",52,6,81,14,14,NOT WS_TABSTOP PUSHBUTTON "5",53,24,81,14,14,NOT WS_TABSTOP PUSHBUTTON "6",54,42,81,14,14,NOT WS_TABSTOP PUSHBUTTON "7",55,6,64,14,14,NOT WS_TABSTOP PUSHBUTTON "8",56,24,64,14,14,NOT WS_TABSTOP PUSHBUTTON "9",57,42,64,14,14,NOT WS_TABSTOP PUSHBUTTON "A",65,42,47,14,14,NOT WS_TABSTOP PUSHBUTTON "B",66,24,47,14,14,NOT WS_TABSTOP PUSHBUTTON "C",67,6,47,14,14,NOT WS_TABSTOP PUSHBUTTON "D",68,42,30,14,14,NOT WS_TABSTOP PUSHBUTTON "E",69,24,30,14,14,NOT WS_TABSTOP PUSHBUTTON "F",70,6,30,14,14,NOT WS_TABSTOP PUSHBUTTON "+",43,64,81,14,14,NOT WS_TABSTOP PUSHBUTTON "-",45,64,99,14,14,NOT WS_TABSTOP PUSHBUTTON "*",42,82,81,14,14,NOT WS_TABSTOP PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON DEFPUSHBUTTON CONTROL CONTROL "/",47,82,99,14,14,NOT WS_TABSTOP "%",37,64,30,14,14,NOT WS_TABSTOP "=",61,24,117,31,14,NOT WS_TABSTOP "&&",38,82,63,14,14,NOT WS_TABSTOP "|",124,64,63,14,14,NOT WS_TABSTOP "^",94,64,46,14,14,NOT WS_TABSTOP "<",60,82,30,14,14,NOT WS_TABSTOP ">",62,82,46,14,14,NOT WS_TABSTOP "M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP "M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP "BS",8,64,117,31,14,NOT WS_TABSTOP "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP "Schliessen",IDOK,135,117,50,14,NOT WS_TABSTOP "",IDC_STATIC,"Static", SS_BLACKRECT,126,5,6,125 "",IDC_STATIC,"Static", SS_BLACKRECT,5,21,116,6 END Die folgenden Programmfragmente zeigen lediglich das Prinzip und können zum Experimentieren dienen. void hex_show_number ( HWND hWnd, INT idRes, UINT iNum ) { CHAR buf[256] ; HWND hCtl = GetDlgItem( hWnd, IDC_COMBO0 ) ; strupr( ltoa( iNum, buf, 16 )); ComboBox_SetText( hCtl, buf ) ; if ( idRes == IDC_COMBO0 ) { if ( ComboBox_GetCount ( hCtl ) >= 15 ) ComboBox_DeleteString( hCtl, 15 ) ; ComboBox_InsertString ( hCtl, 0, buf ); } } DWORD hex_calc_it ( UINT iFirstNum, INT iOperation, UINT iNum ) { switch ( iOperation ) { default : return 0 ; case '=' : return iNum ; case '+' : return iFirstNum + iNum ; case '-' : return iFirstNum - iNum ; case '*' : return iFirstNum * iNum ; case '&' : return iFirstNum & iNum ; case '|' : return iFirstNum | iNum ; case '^' : return iFirstNum ^ iNum ; case '<' : return iFirstNum << iNum ; case '>' : return iFirstNum >> iNum ; case '/' : return iNum ? iFirstNum / iNum : UINT_MAX ; case '%' : return iNum ? iFirstNum % iNum : UINT_MAX ; } } BOOL CALLBACK dlgHexCalcProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL bNewNumber = TRUE ; static INT iOperation = '=' ; static UINT iNumber, iFirstNum ; static CHAR * pCombo; HWND hCtl; switch ( iMsg ) { case WM_INITDIALOG: //keine doppelten Dialoge if ( pCombo != NULL ) DestroyWindow( hWnd ) ; pCombo = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); strcpy( pCombo, "0" ); hCtl = GetDlgItem( hWnd, IDC_COMBO0 ) ; ComboBox_SetText ( hCtl, pCombo ); break; case WM_COMMAND : switch ( LOWORD( wParam ) ) { case IDOK: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; case IDC_COMBO0: case IDC_BUTTON0: case IDC_BUTTON1: case IDC_BUTTON2: case IDC_BUTTON3: case IDC_BUTTON4: case IDC_BUTTON5: break ; case VK_BACK: hex_show_number( hWnd, 0, iNumber /= 16 ) ; break ; case VK_ESCAPE: hex_show_number( hWnd, 0, iNumber = 0) ; break ; default: if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit if ( bNewNumber == TRUE ) { iFirstNum = iNumber ; iNumber = 0 ; } if ( iNumber <= UINT_MAX >> 4 ) { iNumber = 16 * iNumber + wParam - ( isdigit( wParam ) ? '0' : 'A' - 10 ) ; hex_show_number ( hWnd, 0, iNumber ) ; } else MessageBeep( 0 ) ; bNewNumber = FALSE ; } else { // operation if ( bNewNumber == FALSE ) { iNumber = ( UINT ) hex_calc_it ( iFirstNum, iOperation, iNumber ) ; hex_show_number ( hWnd, IDC_COMBO0, iNumber ) ; } iOperation = LOWORD( wParam ) ; bNewNumber = TRUE ; } break; } break; case WM_CLOSE: free( pCombo ); pCombo = NULL; EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ) ; break; } return FALSE ; } Hex-Rechner1 ohne *.rc Mit Hilfe der CreateWindowEx()-Funktion und den Styles: Button: WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP ComboBox: WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN Edit: WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN können Dialogähnliche Controls in ein Fenster auch ohne *.rc-Resourcen gesetzt werden. Allerdings fehlt dann die Dialog-Klasse, die z.B. eine Bedienung der Controls mit der Tab-Taste ermöglicht. Die Funktionen my_button(), my_combo(), my_edit() vereinfachen die Tipp-Arbeit und die zurück gelieferten HWND hCombo; HWND hEdit; werden direkt verwendet, anstelle von HWND hCombo = GetDlgItem(hwnd,IDC_COMBO); HWND hEdit = GetDlgItem(hwnd,IDC_EDIT); void my_button(HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes) { // Bei idRes = 0 wird für idRes der Txt-ASCII-Wert verwendet: // Beisp.: txt = "A" erzeugt idRes = 65 if(idRes <= 0) idRes = (WORD) *txt; CreateWindowEx(0,"BUTTON",txt, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP, x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); } ///////////////////////////////////////////////// HWND my_combo( HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes) { HWND hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN, x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); //RECT rc; // existiert Combo-Liste kann getestet werden mit: //SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc); return hCombo; } ///////////////////////////////////////////////// HWND my_edit(HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes) { HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT |ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0); return hEdit; } Hier ein *.cpp-Testprogramm (braucht keinen *.rc): #include <windows.h> #include <windowsx.h> #include <limits.h> ///////////////////////////////////////////////// //Hauptprogramm #define err_if(e,str) \ ///////////////////////////////////////////////// if(e)MessageBox(0,(str),0,MB_OK|MB_ICONSTOP); int APIENTRY WinMain ///////////////////////////////////////////////// (HINSTANCE hInst,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain) // globales { ///////////////////////////////////////////////// // HINSTANCE hInst = GetModuleHandle(0); const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText() // Nutze die vorhandene Desktop-Klasse const UINT MAX_COMBO_CHAR = 8;//ComboBox_LimitText() // für die Registrierung: const UINT USE_CE = 1; // Ziel Combo-Edit WNDCLASSEX wc = { 0 }; const UINT USE_CL = 2; // Ziel Combo-Liste GetClassInfoEx(hInst,"#32769",&wc);//Desktop-Window const UINT USE_EM = 4; // Ziel Edit-Multiline wc.cbSize = sizeof(wc); wc.lpszClassName = "my_class" ; // eigener Class-Name: // UINT (M)em(SUM)men-Speicher MSUM wc.lpfnWndProc = HexCalcProc; // eigene CALLBACK einfügen: // MSUM hält den Summenwert ('M+','M-') wc.hIcon = ExtractIcon(hInst,"Shell32.dll",12); //'MR' für Anzeige, 'MC' setzt MSUM=0 if (!RegisterClassEx(&wc)) err_if(1,"RegisterClassEx()"); UINT MSUM; // HEX-Rechner als Haupt-Fenster: // Verwendet werden hCombo, hEdit dadurch entfällt: int X = 100, Y = 100, DX = 204, DY = 380; HWND hwnd = // HWND hCombo = GetDlgItem(hwnd,IDC_COMBO); CreateWindowEx(WS_EX_LEFT,wc.lpszClassName,"HEX-Rechner", // HWND hEdit = GetDlgItem(hwnd,IDC_EDIT); WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME, HWND hCombo; //hCombo anstelle von IDC_COMBO X,Y,DX,DY,0,0,hInst,0); HWND hEdit; //hEdit anstelle von IDC_EDIT // anzeigen: ///////////////////////////////////////////////// ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd); void my_button (HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) // alle Button's per Programm "createn" { if(idRes<=0)idRes=(WORD)*txt; int cx=24, cy=24, dx=26, dy=26, x,y, CreateWindowEx(0,"BUTTON",txt, x0= 4, y0= 5, //für ComboBox WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP, x1= 4, y1=40, //1.Button-Spalte x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); x2= 34, y2=40, //2.Button-Spalte } x3= 64, y3=40, //3.Button-Spalte ///////////////////////////////////////////////// x4=100, y4=40, //4.Button-Spalte HWND my_combo x5=130, y5=40, //5.Button-Spalte (HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) { HWND hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN, x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); //RECT rc; //SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc); return hCombo; } ///////////////////////////////////////////////// HWND my_edit (HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) { HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT |ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0); return hEdit; } ///////////////////////////////////////////////// // print_append() kann aus den hSrc-Fenster Text holen // und gemäss "printf-ähnlichem" Formats Text "anhängen" // und den gesamten Text in das hDst-Fenster schreiben. // Dadurch entsteht ein "append" von Text // // Anstelle der Aufruffolge: // print_append(hEdit,hEdit, "\r\n"); // print_append(hEdit,hEdit, "%u ", u1); // print_append(hEdit,hEdit, "%u ", u2); // // ist günstiger: // print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2); ///////////////////////////////////////////////// int CDECL print_append ( HWND hDst, HWND hSrc, LPTSTR pFormat, ...) { static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048 err_if(!hDst,"print_append(): hDst?"); memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf; va_list argList; va_start( argList, pFormat ) ; if(hSrc) // hole Text aus hSrc pBuf += GetWindowText(hSrc,Buf,sizeof(Buf)); // bei Speichermangel pBuf auf Buf[0] if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf; pBuf += wvsprintf( pBuf, pFormat, argList ) ; va_end( argList ) ; // schreibe erweiterten Text in hDest x6=168, y6=40; //6.Button-Spalte x=x0; y=y0; WORD IDC_COMBO = 1000; hCombo = my_combo(hwnd,x,y,188,180,"COMBO",IDC_COMBO); ComboBox_LimitText(hCombo, MAX_COMBO_CHAR); ComboBox_SetText (hCombo, "0"); // keine Hand-Eingabe, falls // ComboBox_Enable(hCombo, FALSE); x=x1; y=y1; my_button(hwnd,x,y,dx,cy,"F",0);y+=dy; my_button(hwnd,x,y,dx,cy,"C",0);y+=dy; my_button(hwnd,x,y,dx,cy,"7",0);y+=dy; my_button(hwnd,x,y,dx,cy,"4",0);y+=dy; my_button(hwnd,x,y,dx,cy,"1",0);y+=dy; my_button(hwnd,x,y,dx,cy,"0",0); x=x2; y=y2; my_button(hwnd,x,y,dx,cy,"E",0);y+=dy; my_button(hwnd,x,y,dx,cy,"B",0);y+=dy; my_button(hwnd,x,y,dx,cy,"8",0);y+=dy; my_button(hwnd,x,y,dx,cy,"5",0);y+=dy; my_button(hwnd,x,y,dx,cy,"2",0);y+=dy; my_button(hwnd,x,y,2*dx+4,cy,"=",0); x=x3; y=y3; my_button(hwnd,x,y,dx,cy,"D",0);y+=dy; my_button(hwnd,x,y,dx,cy,"A",0);y+=dy; my_button(hwnd,x,y,dx,cy,"9",0);y+=dy; my_button(hwnd,x,y,dx,cy,"6",0);y+=dy; my_button(hwnd,x,y,dx,cy,"3",0); x=x4; y=y4; my_button(hwnd,x,y,dx,cy,"%",0);y+=dy; my_button(hwnd,x,y,dx,cy,"^",0);y+=dy; my_button(hwnd,x,y,dx,cy,"|",0);y+=dy; my_button(hwnd,x,y,dx,cy,"+",0);y+=dy; my_button(hwnd,x,y,dx,cy,"-",0);y+=dy; my_button(hwnd,x,y,2*dx+4,dy,"BS",1000); x=x5; y=y5; my_button(hwnd,x,y,dx,cy,"<",0);y+=dy; my_button(hwnd,x,y,dx,cy,">",0);y+=dy; my_button(hwnd,x,y,dx,cy,"&&",0);y+=dy; my_button(hwnd,x,y,dx,cy,"*",0);y+=dy; my_button(hwnd,x,y,dx,cy,"/",0); x=x6; y=y6; my_button(hwnd,x,y,dx,cy,"M+",1001);y+=dy; my_button(hwnd,x,y,dx,cy,"M-",1002);y+=dy; SetWindowText( hDst, Buf ); return (pBuf-Buf); } ///////////////////////////////////////////////// // show_hex() schreibt uNum in das ziel. // Beispiel: show_hex(10,USE_CE); // Ziel kann sein (USE_CE|USE_CL|USE_EM) ///////////////////////////////////////////////// void show_hex(UINT uNum, int ziel ) { char buf[256]; int radix = 16; //global sind hCombo, hEdit //schreibe uNum als hex-String (basis 16) in buf strupr( ltoa(uNum, buf, radix) ); //Ausgabe von buf in ziel if (USE_CE & ziel) {//in Combo-Liste eintragen: ComboBox_SetText(hCombo, buf ) ; } if (USE_CL & ziel) { //in Combo-Liste eintragen: if ( ComboBox_GetCount(hCombo) >= 30) ComboBox_DeleteString(hCombo,30); ComboBox_InsertString(hCombo, 0, buf ); } if (USE_EM & ziel) { //in Edit-Journal eintragen: print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum); } } ///////////////////////////////////////////////// // Beispiel: UINT erg = berechne(6,'+',4); // Schreibt auch in hEdit ///////////////////////////////////////////////// UINT berechne(UINT uNum1, char Op, UINT uNum2 ) { UINT erg; switch ( Op ) { default : erg = 0; return erg; case '=' : erg = uNum2 ; return erg; case '+' : erg = uNum1 + uNum2 ; break; case '-' : erg = uNum1 - uNum2 ; break; case '*' : erg = uNum1 * uNum2 ; break; case '&' : erg = uNum1 & uNum2 ; break; case '|' : erg = uNum1 | uNum2 ; break; case '^' : erg = uNum1 ^ uNum2 ; break; case '<' : erg = uNum1 << uNum2 ; break; case '>' : erg = uNum1 >> uNum2 ; break; case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ; break; case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ; break; my_button(hwnd,x,y,dx,cy,"MR",1003);y+=dy; my_button(hwnd,x,y,dx,cy,"MC",1004);y+=dy; my_button(hwnd,x,y,dx,cy,"AC",1005);y+=dy; my_button(hwnd,x,y,dx,cy,"EC",1006);y+=dy; char * pInfo = "MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n" "EC löscht diese Anzeige\r\nMR zeigt M an\r\n" "M+ addiert zu M \r\nM- subtr. von M\r\n"; WORD IDC_EDIT = 2000; hEdit = my_edit(hwnd,x0,y+4,188,140,pInfo,IDC_EDIT); Edit_LimitText(hEdit, MAX_EDIT_CHAR); // Hauptnachrichtenschleife BOOL bRet; MSG msg; while (bRet=GetMessage(&msg, NULL,0,0)){ err_if(-1==bRet,"GetMessage()"); TranslateMessage(&msg); DispatchMessage (&msg); } return 0; } } print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n", uNum1,Op,uNum2,erg); print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n", uNum1,Op,uNum2,erg); return erg; } ///////////////////////////////////////////////// // CALLBACK ///////////////////////////////////////////////// LRESULT CALLBACK HexCalcProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL isNewNum = FALSE ; char buf[1024]; static char Op = '=' ; static UINT uNum1, uNum2, uNum ; //1.2.-Zahl switch ( iMsg ) { case WM_COMMAND : { WORD hwp = HIWORD(wParam); if(hwp)//NOTIFY von Combo oder Edit { if(hEdit==(HWND)lParam) // EDIT-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify EN_: 0x%",hwp); } if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp); if(CBN_SELCHANGE==HIWORD(wParam)) { //etwas wird in Comboliste ausgewählt memset(buf,0,sizeof(buf)); int index = ComboBox_GetCurSel(hCombo); ComboBox_GetLBText(hCombo,index,buf); isNewNum = TRUE; char *p = buf; while(*p) { // Zeichenweise: WPARAM wp =(WPARAM)(char)*p++; SendMessage(hwnd,WM_COMMAND,wp,0); } } if(CBN_EDITCHANGE==HIWORD(wParam)) { // es wurde was in Combo getippt ComboBox_SetText(hCombo, "0") ; isNewNum=TRUE; uNum1=uNum2=0; MessageBox(0,"Bitte keine Tasteneingabe",0, MB_OK|MB_ICONSTOP); return 0; } } break; } ///////////////////////////////////////////////////// switch ( LOWORD( wParam ) ) { default:{ if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;} if (uNum2 <= UINT_MAX >> 4 ) { uNum2 = 16 * uNum2 + wParam - (isdigit(wParam)?'0':'A'-10) ; } else MessageBeep( 0 ) ; show_hex(uNum2, USE_CE|USE_CL); isNewNum = FALSE ; } else { // operation if ( isNewNum == FALSE ) { uNum2 = berechne(uNum1, Op, uNum2) ; show_hex(uNum2, USE_CE); } Op = LOWORD(wParam); isNewNum = TRUE ; } break;}// Ende von default case VK_ESCAPE: show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break ; case 1000:show_hex(uNum2/=16, USE_CE);//"BS"; break; case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+"; isNewNum = TRUE ; break; case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-" isNewNum = TRUE ; break; case 1003://zeige MSUM in Combo an: "MR" show_hex(uNum2=MSUM, USE_CE|USE_CL); isNewNum = TRUE ; print_append(hEdit,hEdit, "MR=%u MR=0x%X\r\n",MSUM,MSUM); break; case 1004: MSUM=0;//Clear MSUM: "MC" break; case 1005: // Clear Combo: "AC" show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break; case 1006: // Clear Edit: "EC" SetWindowText(hEdit, ""); break; } break; } case WM_DESTROY : PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,iMsg,wParam,lParam); } Scroll Bar Control Scroll Bar Controls Scroll Bar Controls ScrollBar_Enable (hCtl, ScrollBar_GetPos (hCtl) ScrollBar_GetRange(hCtl, ScrollBar_SetPos (hCtl, ScrollBar_SetRange(hCtl, ScrollBar_Show (hCtl, flags) lpposMin, lpposMax) pos, fRedraw) posMin, posMax, fRedraw) fShow) Arrow - Keys und Notification Nachrichten Mit den Funktionen SetScrollInfo(), SetScrollPos(), SetScrollRange(), GetScrollInfo(), GetScrollPos() und GetScrollRange() können Scroll - Bars eingerichtet werden. Scroll - Bars werden mit der Maus bedient. Das System unterstützt die Maus - Ereignisse. Wenn z.B. bei einer vertikalen Scroll Bar ein Scroll - Ereignies eintritt, so wird die WM_VSCROLL Nachricht an das Fenster gesendet. Die WM_VSCROLL - Nachricht enthält in wParam und lParam die folgenden Anteile. WM_VSCROLL - Nachricht ● ● ● nScrollCode = ( int ) LOWORD( wParam ); // scroll bar value nPos = ( short int ) HIWORD( wParam ); // scroll box position hwndScrollBar = ( HWND ) lParam; // handle of scroll bar Der nScrollCode - Parameter kann die Werte ● ● ● ● ● ● ● ● ● SB_BOTTOM ( Scrolls to the lower right), SB_ENDSCROLL ( Ends scroll ), SB_LINEDOWN ( Scrolls one line down ), SB_LINEUP ( Scrolls one line up ), SB_PAGEDOWN ( Scrolls one page down ), SB_PAGEUP ( Scrolls one page up ), SB_THUMBPOSITION ( der Benutzer hat die scroll box ( Thumb ) gezogen ( dragged ) und losgelassen. Dann gibt nPos ( 16 bits ) die Los-Lass-Position an ), SB_THUMBTRACK ( der Benutzer ist noch am Ziehen ( dragging ). nPos ist die aktuelle Thumb - Position ), SB_TOP ( Scrolls to the upper left ) nPos wird nur bei SB_THUMBPOSITION oder SB_THUMBTRACK benutzt. hwndScrollBar ist NULL, wenn die Nachricht nicht von einem Scroll - Bar kommt. Scroll Bars Nachrichten ● Die CALLBACK - Funktion sollte 0 zurück geben, wenn die CALLBACK - Funktion die abschließende Bearbeitung übernommen hat. Keyboard - Interface für Scroll - Bars Ein Keyboard - Interface für Scroll - Bars ermöglicht die zusätzliche Bedienung mit der Tastatur. Wenn ein Sroll Bar den Keyboard - Focus hat, so werden bei einer Pfeil - Taste ( Arrow Key ) an das Eltern - Fenster die WM_HSCROLL - bzw. WM_VSCROLL - Nachricht gesendet. Taste sendet virtueller Key-Code und soll die Maus-Notification-Nachricht auslösen ... DOWN VK_DOWN SB_LINEDOWN oder SB_LINERIGHT UP VK_UP SB_LINEUP oder SB_LINELEFT END VK_END SB_BOTTOM HOME VK_HOME SB_TOP PGDN VK_NEXT SB_PAGEDOWN oder SB_PAGERIGHT PGUP VK_PRIOR SB_PAGEUP oder SB_PAGELEFT LEFT VK_LEFT SB_LINEUP oder SB_LINELEFT RIGHT VK_RIGHT SB_LINEDOWN oder SB_LINERIGHT Ein Inteface soll eine z.B. SB_TOP bzw. SB_BOTTOM Notification - Nachricht senden, wenn VK_HOME bzw. VK_END eintrifft. Diese VK_ - Nachrichten werden unter iMsg == WM_KEYDOWN abgehört und die zugeordnete Notification - Nachricht gesendet. Ein Keyboard - Interface für Scroll - Bars kann dann z.B. gemäß LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { ... case WM_KEYDOWN : { UINT w = -1; switch ( LOWORD(wParam) ) { case VK_HOME: w = SB_TOP; break; case VK_END: w = SB_BOTTOM; break; case VK_UP: w = SB_LINEUP; break; case VK_DOWN: w = SB_LINEDOWN; break; case VK_LEFT: case VK_PRIOR: w = SB_PAGEUP; break; case VK_RIGHT: case VK_NEXT: w = SB_PAGEDOWN; break; ... } if ( w != -1 ) SendMessage( hWnd, WM_VSCROLL, MAKELONG(w,0), 0L ); } break; ... } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; } aufgebaut werden. Hier wurden nur UINT iMsg und WPARAM wParam verwendet. In LPARAM lParam sind weitere, spezielle Tasten - Scan - Anteile enthalten. Custom Controls Eine Applikation kann benutzerdefinierte Controls erstellen, die über die verfügbaren Controls hinaus gehen. Dies kann aus verschiedene Arten erfolgen: ● ● ● Benutzung von Buttons, Listbox -, Combobox - Nachrichten zum benutzerdefinierten Zeichnen ( owner-drawn ), Subclassing einer existierenden Control - Klasse, Vollständige Neugestaltung, Registrierung einer eigenen Window - Klasse. DLL's Ein typisches Windows-Programm ( *.exe ) erzeugt Fenster, deren CALLBACK-Funktion die Nachrichten aus dem Applikations-Buffer geschickt werden. DLL's ( dynamic link libraries, *.dll ) sind i.a. nicht direkt ausführbar, bekommen keine Nachrichten und enthalten oft System-Funktionen, die von Programmen oder anderen DLL's genutzt werden können ( Export-Table ). Eine DLL braucht ( benutzt ) i.a. Funktionen von anderen DLL's ( Import-Table ). DLL's können wie eine Sammlung von Funktionen in Maschinen-Code betrachtet werden ( dynamic link libraries ). DLL's können auch Ressourcen enthalten. Static-Linking Mit Hilfe von höhere Programmiersprachen (C, C++, Pascal, FORTRAN, usw. ) und den übersetzenden Werkzeugen können ausführbare Files ( *.exe ) erstellt werden. Werden die Bibliotek-Object-Files ( Maschinen-Code ) in den ausführbaren File aufgenommen und zu einem festen Bestandteil des *.exe-Files verbunden ( Linker ), so wird vom permanenten Linken oder statischem Linken ( static linking ) gesprochen. Dynamic-Linking Dynamisches Linken ( dynamic linking ) verknüpft die Bibliotheken zur Laufzeit. DLL's werden nicht in die Applikation kopiert, sondern haben einen eigenen Adressraum und können von mehreren Anwendungen genutzt werden. Wenn eine DLL genutzt werden soll, so läd das Operating-System die DLL ( aufgrund des File-Namens ) in en Speicher. Wird eine DLL von keiner Alpplikation benötigt, so wird die DLL vom Operating-System ( unload ) aus dem Speicher entfernt. Der Lade/EntladeMechanismus kann explizit durch die Applikation oder implizit Operating-System ausgelöst werden. Unterschiede zwischen Static-DynamicLinking WDifferences Between Static-Link Libraries and Windows DLLs Windows DLLs differ considerably from static-link libraries. Basic differences between the two are as follows: ● ● ● ● ● ● ● ● ● Statische Bibliotheken sind in *.LIB-Files ( object files ) enthalten Jede Applikation hat eine Kopie der statischen Bibliothek. Die statische Bibliotek nutzt den Adressraum der Applikation. Dynamische Bibliotheken sind in ladbaren, auführbaren Files ( *.exe explizit ladbar mit LoadLibrary, *.dll implizit ladbar ) untergebracht. Dynamische Bibliotheken können Maschinen-Code, Daten, Ressourcen ( z.B. Bitmaps, Icons, Cursors, usw. ) enthalten. Beispiele für DLL's sind: A DLL is a Windows dynamic link library residing in a .DLL file. System DLLs may have .EXE extensions, for example, USER.EXE, GDI.EXE, KRNL286.EXE, KRNL386.EXE, .DRV ( device driver, wie z.B. MOUSE.DRV, KEYBOARD.DRV ) Nur .DLL-Extension können automatisch durch das Operating-System geladen werden. Applikationen enthalten beim dynamischem Linken nur die Namen der benötigten DLL's und implizit hinzugefügte ( oder explizit angegebene ) Ladeanweisungen. Eine DLL kann von vielen Applikationen benutzt werden. Eine DLL hat oft seinen eigenen Daten-Adress-Raum ( shared ), der in den Adress-raum der Applikation gemappt wird. What makes a data segment shared? shared data segment These three pragma statements override the default data segment behavior and creates a shared data segment. See MyClass.cpp in the DLL. // Aufbau etwa wie folgt: // Hier stehen globale und // static Variablen( "nicht shared" ) ... ... // Anfang vom shared data segment #pragma data_seg("SHARED") // Definition von einfachen Variablen, // wie z.B. int, char[] arrays, zeiger // Keine Klassen verwenden, die einen // tiefen Copy Constructors brauchen // Endd des "shared data segment" // Zurück zum normalen Daten-Segment-Bereich #pragma data_seg() // Das folgende Linker-Pragma veranlasst den Linker // die notwendigen initialisierungen für das // "shared data segment" zu erzeugen #pragma comment(linker, "/section:SHARED,RWS") ////////////////////////////// ////////////////////////////// ////////////////////////////// // Eins dieser pragmas sollte funktionieren: #pragma comment (linker, "/ENTRY:mainCRTStartup") #pragma comment (linker, "/ENTRY:wmainCRTStartup") #pragma comment (linker, "/ENTRY:WinMainCRTStartup") #pragma comment (linker, "/ENTRY:wWinMainCRTStartup") // bzw.: #pragma comment (linker, "/SUBSYSTEM:WINDOWS") #pragma comment (linker, "/SUBSYSTEM:CONSOLE") #pragma warning( disable : 4305) //Double-float-Warnung #pragma comment(lib, "OpenGL32.lib") ////////////////////////////// Es sind unterschiedliche Methoden zu testen, die eine Überprüfung des allokierten Heap-Speicher-Bereiches ermöglichen. void heap_size( void ) { CHAR Buf [1024]; LPSTR pp = Buf; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionEx(&os)) return; switch(os.dwPlatformId){ case VER_PLATFORM_WIN32s: pp += wsprintf(pp, "Win32s or Windows 3.1 \tVers: %ld.%ld",os.dwMajorVersion,os.dwMinorVersion); break; case VER_PLATFORM_WIN32_WINDOWS: if(0 == os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 95"); if(0 < os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 98"); break; case VER_PLATFORM_WIN32_NT: pp += wsprintf(pp, "Win32 or NT \tVers: %ld.%ld",os.dwMajorVersion,os.dwMinorVersion); break; default: pp += wsprintf(pp, "unbekannt"); break; } pp += wsprintf(pp, " \tServicePack: %s",os.szCSDVersion); MEMORYSTATUS ms; ms.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus( &ms ) ; pp += wsprintf(pp,"\nmemory in use\t:%12ld %%",ms.dwMemoryLoad); pp += wsprintf(pp,"\nphys mem free/total\t:%12ld \t%12ld" , ms.dwAvailPhys , ms.dwTotalPhys ) ; pp += wsprintf(pp,"\npaging file free/total\t:%12ld \t%12ld" , ms.dwAvailPageFile , ms.dwTotalPageFile ) ; pp += wsprintf(pp,"\nuser space free/total\t:%12ld \t%12ld" , ms.dwAvailVirtual , ms.dwTotalVirtual ) ; pp += wsprintf(pp,"\n_______________________________________________" ) ; MessageBox(auxGetHWND(),Buf,"Heap-Size",MB_OK); } ======================================= COM Tutorial Samples Tutorial Home Previous Lesson Lesson List Next Lesson DLLSKEL - Win32 DLL Skeleton SUMMARY The DLLSKEL sample introduces the basic DLL skeleton that can be used as a point of departure for more complex Win32 DLLs (dynamic link libraries). It is used as a base for other COM Tutorial code samples. In this series of COM Tutorial code samples, DLLSKEL works with the DLLUSER code sample to illustrate how DLLSKEL's function services are called by an EXE consumer. For functional descriptions and a tutorial code tour of DLLSKEL, see the Code Tour section in DLLSKEL.HTM. For details on setting up the programmatic usage of DLLSKEL, see the Usage section in DLLSKEL.HTM. To read DLLSKEL.HTM, run TUTORIAL.EXE in the main tutorial directory and click the DLLSKEL lesson in the table of lessons. You can also achieve the same thing by clicking the DLLSKEL.HTM file after locating the main tutorial directory in the Windows Explorer. See also DLLUSER.HTM in the main tutorial directory for more details on the DLLUSER application and how it works with DLLSKEL.DLL. You must build DLLSKEL.DLL before building DLLUSER. After producing DLLSKEL.DLL and DLLUSER.EXE, the makefile for DLLSKEL copies the necessary DLLSKEL.H, DLLSKEL.LIB, and DLLSKEL.DLL files to the appropriate sibling directories. For details on setting up your system to build and test the code samples in this COM Tutorial series, see Building the Code Samples. The supplied makefile (MAKEFILE) is Microsoft NMAKE-compatible. To create a debug build, issue the NMAKE command in the Command Prompt window. For convenient use in Microsoft's Visual Studio, a project file is provided for each sample. To load the project for the DLLSKEL sample, you can run Visual Studio at the Command Prompt in the sample's directory as follows: MSDEV DLLSKEL.DSP You can also simply double-click the DLLSKEL.DSP file in the Windows Explorer to load a sample's project into Visual Studio. From within Visual Studio you can then browse the C++ classes of the sample source and generally perform the other edit-compile-debug operations. Note that, as part of the Platform SDK, the compilation of these samples from within Visual Studio requires the proper setting of directory paths in Visual Studio. For more details, see Building the Code Samples. Usage DLLSKEL is a DLL that you can access from applications by either performing an explicit LoadLibrary call or implicitly loading the DLL by linking to its associated .LIB file. In either case, you need to include DLLSKEL.H to declare the functions that are defined as exported in the DLLSKEL DLL. In the case of this Tutorial lesson, a representative DLLUSER.EXE application is provided to illustrate the programmatic use of DLLSKEL.DLL. DLLUSER is built in the DLLUSER lesson (in sibling directory DLLUSER). See below for more details. Run the Sample The client sample and other related samples must be compiled before you can run the client. For more details on building the samples, see Building the Code Samples. If you have already built the appropriate samples, DLLUSER.EXE is the client executable to run for this sample. CODE TOUR Files DLLSKEL.TXT MAKEFILE DLLSKEL.H DLLSKEL.CPP Description Short sample description. The generic makefile for building the DLLSKEL.DLL code sample of this tutorial lesson. The include file for declaring as imported or defining as exported the service functions in DLLSKEL.DLL. Meant for eventual use by outside users of the DLL. The main implementation file for DLLSKEL.DLL. Has DllMain DLLSKELI.H DLLSKEL.RC DLLSKEL.ICO DLLSKEL.DSP and the two exported service functions. The include file for the internal class declarations and the identifier definitions for resources stored inside the DLLSKEL.DLL. The DLL resource definition file. The icon resource. Microsoft Visual Studio Project file. In the context of this tutorial, the goal of DLLSKEL is to illustrate a C++ DLL skeleton that can serve as a point of departure for making more sophisticated DLLs. The resulting DLL is meant to work in conjuntion with DLLUSER.EXE to illustrate how to link to and call services in Win32 DLLs. It is the basic DLL framework for subsequent code samples in this tutorial. Study the code comments to learn more about this Win32 C++ DLL skeleton. DLLSKEL makes use of many of the utility classes and services provided by APPUTIL. For more details on APPUTIL, study the source code located in the sibling APPUTIL directory APPUTIL.HTM in the main tutorial directory. In DLLSKEL.CPP, two exported functions are defined to export representative calls to outside consumers: DllHelloBox and DllAboutBox. After incrementing a shared global counter variable, DllHelloBox uses APPUTIL's CMsgBox facility to show a simple information message box. This box says hello and shows the DLL's user instance count and a total count of the number of times this Hello function has been called by any user. The following DllHelloBox code from DLLSKEL.CPP shows one method to protect the incrementation of a global counting variable in a multitasking environment. The use of the Win32 InterlockedIncrement function enforces mutual exclusion for the incrementing operation when multiple processes attempt to increment a shared variable. STDENTRY_(BOOL) DllHelloBox( HWND hWnd) { int iHelloCount; CDllShared* pShared = (CDllShared*) g_pvShared; // Increment the cummulative global count of all Hellos. InterlockedIncrement((LONG*) &pShared->iHelloCount); iHelloCount = pShared->iHelloCount; // Now show the user a -Notice- message box and load the display strings // out of this DLL's resources. Use the format string to show the // user instance count of this loaded DLL and the shared hello count. g_pDll->pMsgBox->Init(g_pDll->hDllInst, hWnd); g_pDll->pMsgBox->NoteFmtID( IDS_HELLOCOUNTFMT, g_pDll->iUserCount, iHelloCount); return TRUE; } The global hello count variable is accessed in a shared memory location that is part of a section of file-mapped memory. A g_pvShared global variable is used to store a pointer to the file-mappped shared memory. This g_pvShared variable is a static global variable within the DLL. It is newly created and assigned for each user process that attaches to the DLL. In the above fragment, the address of the iHelloCount counter within a shared data object ( ie, a within CDllShared object) is passed to the InterlockedIncrement function. This use of a CDllShared object and the appropriate (CDllShared*) casting shows how to apply the object as a template over the file-mapped shared memory image pointed to by g_pvShared. See the discussion of DllMain below for more details on how the shared memory object is set up as a file mapping. The DllAboutBox exported function creates an object of the CAboutBox class, as implemented in the APPUTIL utility library, to load a dialog box from the DLL's resources and then display an About box. DLLSKEL.CPP defines the DllMain entry function for the entire DLL. To construct a Win32 DLL, you must provide the DllMain entry function and handle the following messages sent to the DLL via that function: DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, DLL_THREAD_ATTACH, DLL_THREAD_DETACH. The following code fragment from DLLSKEL.CPP shows how the DllMain function is defined and how the messages are handled. In this sample, no specific actions are taken during thread attach and detach. BOOL WINAPI DllMain( HINSTANCE hDllInst, DWORD fdwReason, LPVOID lpvReserved) { BOOL bResult = TRUE; // Dispatch this call based on the reason it was called. switch (fdwReason) { case DLL_PROCESS_ATTACH: // The DLL is being loaded for the first time by a given process. // Perform per-process initialization here. If the initialization // is successful, return TRUE; if unsuccessful, return FALSE. bResult = FALSE; if (UnicodeOk()) { // Instantiate a DLL global data encapsulator class. g_pDll = new CDllData; if (NULL != g_pDll) { // Remember the DLL Instance handle. g_pDll->hDllInst = hDllInst; // Create a MsgBox object. g_pDll->pMsgBox = new CMsgBox; if (NULL != g_pDll->pMsgBox) { BOOL fFirst; int iSharedSize = sizeof(CDllShared); // Create a named file mapping object. g_hMapObj = CreateFileMapping( (HANDLE) 0xFFFFFFFF, // Use paging file NULL, // No security attributes PAGE_READWRITE, // Read/Write access 0, // Mem Size: high 32 bits iSharedSize, // Mem Size: low 32 bits DLLSKELSHARED_STR); // Name of map object if (NULL != g_hMapObj) { // Determine if this is the first create of the file mapping. fFirst = (ERROR_ALREADY_EXISTS != GetLastError()); // Now get a pointer to the file-mapped shared memory. g_pvShared = MapViewOfFile( g_hMapObj, // File Map obj to view FILE_MAP_WRITE, // Read/Write access 0, // high: map from beginning 0, // low: 0); // default: map entire file if (NULL != g_pvShared) { CDllShared* pShared = (CDllShared*) g_pvShared; if (fFirst) { // If this is the first attaching process, init the // shared memory. memset(g_pvShared, 0, iSharedSize); pShared->iUserCount = 1; } else { // Increment the cummulative global count of all // attached processes (ie, the count of DLL users). InterlockedIncrement((LONG*) &pShared->iUserCount); } // Save a local instance copy of this user instance // count. Each user process has its own g_pDll instance // data and can thus remember it's user instance count. g_pDll->iUserCount = pShared->iUserCount; bResult = TRUE; } } } } } break; case DLL_PROCESS_DETACH: // The DLL is being unloaded by a given process. Do any // per-process clean up here, such as undoing what was done in // DLL_PROCESS_ATTACH. The return value is ignored. // Unmap any shared memory from the process's address space. UnmapViewOfFile(g_pvShared); // Close the process's handle to the file-mapping object. CloseHandle(g_hMapObj); if (NULL != g_pDll) { // Delete the message box and global DLL instance data. DELETE_POINTER(g_pDll->pMsgBox); DELETE_POINTER(g_pDll); } break; case DLL_THREAD_ATTACH: // A thread is being created in a process that has already loaded // this DLL. Perform any per-thread initialization here. The // return value is ignored. break; case DLL_THREAD_DETACH: // A thread is exiting cleanly in a process that has already // loaded this DLL. Perform any per-thread clean up here. The // return value is ignored. break; default: break; } return (bResult); } When the DLL is attached to a process, DllMain is called with DLL_PROCESS_ATTACH. During DLL_PROCESS_ATTACH above the UnicodeOk function is called to determine if the DLL will run on the platform when compiled for Unicode strings. If the platform doesn't support Unicode and yet the DLL is compiled for Unicode, the DllMain function fails, and the DLL is unloaded. The global instance data object is created. This object is pointed to by global variable, g_pDLL. This CDllData object encapsulates instance data that is instantiated separately for each process that attaches. In this sample, this object contains the DLL's instance handle, a place to save the count of the user instance, and a pointer to the Message Box object. The Message Box object is created during DLL_PROCESS_ATTACH. After its creation, the pointer to it is assigned. The remainder of the work during DLL_PROCESS_ATTACH sets up the file-mapped memory section for a shared CDllShared object. First CreateFileMapping is called to assign a global handle to the mapping object, g_hMapObj. The current operating system virtual memory paging file is used for the file. No security attributes are needed. Read/Write access is specified. A size equal to the size of the shared object is specified. The mapping object is given a name so that it can be explicitly shared by instances of this DLL. The DLLSKELSHARED_STR macro is used to specify the name string "DLLSkelShared" as ANSI or Unicode depending on whether DLLSKEL is being compiled for Unicode or not. This macro is defined immediately before DllMain as follows. #if defined(UNICODE) #define DLLSKELSHARED_STR L"DLLSkelShared" #else #define DLLSKELSHARED_STR "DLLSkelShared" #endif The mapping object is then used to map a memory view of the file. This action obtains a pointer to the shared memory and assigns it to global variable g_pvShared. If this is the first creation (rather than a re-open) of the mapping object, then the shared memory area is initialized to zero and the user instance counter is intitialized to 1. If this is not the initial creation of the shared object, then the user instance counter is incremented to keep a cumulative count of the attaching processes. Since this is globally shared memory, the Win32 InterlockedIncrement function is used to ensure mutual exclusion during the increment operation. Once this user counter is incremented the new value is saved in a nonshared variable, g_pDll->iUserCount, that is part of the instance data that is specific to the attaching process. When the DLL is detached from the process DllMain is called with DLL_PROCESS_DETACH. During DLL_PROCESS_DETACH the mapped memory view is unmapped and the mapping object is closed. The CMsgBox and CDllData objects are then deleted. To perform the delete, the DELETE_POINTER macro is used to delete the memory object pointed to by the pointer. Here is the macro definition from APPUTIL.H: #define DELETE_POINTER(p){if(NULL != p){delete p; p = NULL;}} If the original pointer value was not NULL, the macro deletes the memory object that was pointed to. By then immediately setting the pointer to NULL, the macro prevents other threads from using it. To build the DLL, you provide specific DLL-related instructions when you compile the modules of the DLL and when you link the modules with the Link command. The following fragment from the DLLSKEL makefile (file MAKEFILE) shows the compilation rule for the DLLSKEL.CPP module. # Compilation/Dependency rules for the .DLL source files. $(TDIR)\$(DLL).obj: $(DLL).cpp $(DLL).h $(DLL)r.h $(cc) $(cvarsdll) $(cflags) $(cdebug) -Fo$@ $(DLL).cpp Note the use of the 'cvarsdll' macro when compiling module components of a DLL. This is in contrast to the 'cvars' macro normally used in linking EXE applications. Both of these macros are defined in the makefile include file WIN32.MAK. For more details, see WIN32.MAK in the \MSSDK\INCLUDE directory of the Platform SDK. All of the COM Tutorial code sample makefiles include WIN32.MAK. If there are to be resources in the DLL (as there are in the DLLSKEL DLL), the appropriate .RC file is RC-compiled in the normal manner as follows. # Compile the DLL resources. $(TDIR)\$(DLL).res: $(DLL).rc $(DLL).ico $(DLL)r.h rc $(RCFLAGS) -r -fo$@ $(DLL).rc To link the modules and the resources together to build the DLL binary, you provide a Link command like the following from the DLLSKEL makefile: # Link the object and resource binaries into the target DLL binary. # Build the import LIB file so apps can link to and use this DLL. $(DLL).dll: $(DLLOBJS) $(TDIR)\$(DLL).res $(LINK) @<< $(LINKFLAGS) $(dlllflags) -base:0x1C000000 -out:$@ -map:$(TDIR)\$*.map -implib:$*.lib $(DLLOBJS) $(TDIR)\$*.res $(olelibsdll) $(APPLIBS) << The 'implib:$*.lib' directive to the Linker instructs it to produce the DLLSKEL.LIB import library file. This .LIB file is used in turn when the DLL is linked with any application that calls the DLL. Note also that this DLL makes calls to another library, APPUTIL, by statically linking to it. The APPLIBS macro reduces to APPUTIL.LIB. In this case, the compiled content of APPUTIL is contained entirely in APPUTIL.LIB. APPUTIL itself could have been a DLL. It is a judgement call as to whether you build one library type or another. Usually, if you are exporting C++ class definitions across the library boundary, the exported names are decorated in a manner proprietary to the compiler vendor. This approach restricts the use of such a DLL to applications that are also compiled with the same compiler. If the exported classes are small, it is often more convenient to put them into a static .LIB (as is the case with APPUTIL) than to put them into a .DLL. Because the DLLSKEL DLL has resources and because it is desirable to provide outside users of the DLL with an .H file of the same name, a separate DLLSKELI.H is used for internal class declarations and resource identifier definitions, while the DLLSKEL.H file is intended solely for the DLL's function import declarations and export definitions. For the consumer application (in this case DLLUSER.EXE) to link to and properly call the exported functions in the DLL, it must import them. The following fragment from DLLSKEL.H shows how to use the same convenient 'STDENTRY' macros to serve both the consumer application's import declaration and the provider DLL's export definition needs. #if !defined(_DLLEXPORT_) // If _DLLEXPORT_ is not defined then the default is to import. #if defined(__cplusplus) #define DLLENTRY extern "C" __declspec(dllimport) #else #define DLLENTRY extern __declspec(dllimport) #endif #define STDENTRY DLLENTRY HRESULT WINAPI #define STDENTRY_(type) DLLENTRY type WINAPI // Here is the list of service APIs offered by the DLL (using the // appropriate entry API declaration macros just #defined above). STDENTRY_(BOOL) DllHelloBox (HWND); STDENTRY_(BOOL) DllAboutBox (HWND); #else // _DLLEXPORT_ // Else if _DLLEXPORT_ is defined then we've been told to export. #if defined(__cplusplus) #define DLLENTRY extern "C" __declspec(dllexport) #else #define DLLENTRY __declspec(dllexport) #endif #define STDENTRY DLLENTRY HRESULT WINAPI #define STDENTRY_(type) DLLENTRY type WINAPI #endif // _DLLEXPORT_ The DLLENTRY macro allows you more freedom to specify return types and calling conventions. The STDENTRY assumes the COM/OLE standard HRESULT return type and the WINAPI calling conventions (usually defined as __stdcall). The STDENTRY_ macro makes this same assumption but does allow you to specify a return type. The '__declspec(dllimport)' and '__declspec(dllexport)' directives are one way to declare DLL imports and to define DLL exports in Win32 programming. Another way is to Link the executable using a module definition (.DEF) file that contains import and export statements. This technique was commonly used in Win16 programming but is often not needed in Win32 programming. Note that the __declspec specifications are Microsoft-specific techniques in C++ programs. DLL exports can also be designated using the export switch on the Linker command line. Note the use of extern "C" when compiling under C++ (__cplusplus). This tells the compiler, during compilation of both the DLL and the calling code, that the default C++ function name decoration will not be used. This is usually preferred in generic DLLs, whose function calls might be called by applications that could be compiled with a variety of C++ compiler tools, including straight C compilers. The default behavior of DLLSKEL.H is to serve calling applications that import the functions in the DLL. Such applications simply include DLLSKEL.H during compilation of such a calling module. When the DLL itself is compiled, however, this file is included as in the following fragment from DLLSKEL.CPP. #define _DLLEXPORT_ #include "dllskel.h" When _DLLEXPORT_ is thus defined, the behavior of DLLSKEL.H is to serve the DLL itself in defining its exported functions. The following fragment from DLLSKEL.CPP shows such a function definiton. STDENTRY_(BOOL) DllAboutBox(HWND hWnd); { ... } When the DllAboutBox function is defined in DLLSKEL.CPP, the STDENTRY_ macro expands to yield the following: extern "C" __declspec(dllexport) BOOL WINAPI DllAboutBox(HWND hWnd) { ... } Likewise, when the DllAboutBox function is imported in DLLSKEL.H, the declaration is expanded to the following import function prototype. extern "C" __declspec(dllimport) BOOL WINAPI DllAboutBox(HWND hWnd); The WINAPI macro expands to various things, depending on the build environment, but generally stipulates the calling convention (usually __stdcall). See WIN32.MAK and the standard Windows include file WINDEF.H for more details on the WINAPI macro. Back to page top © 1995-1998 Microsoft Corporation GLOBALS.C /******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright 1993 - 1998 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ /****************************** Module Header ******************************* * Module Name: globals.c * * Contains global data for the dialog box editor. * ****************************************************************************/ #include "dlgedit.h" #include "dlgextrn.h" /* Including this verifies they are synched.*/ #include "dlgfuncs.h" #include "dialogs.h" #include "dlghelp.h" HANDLE ghInst; HMENU ghMenuMain; PRESLINK gprlHead = NULL; CURRENTDLG gcd; HPEN hpenDarkGray; HANDLE ghAccTable; INT gMenuSelected = 0; HBITMAP ghbmDragHandle = NULL; HBITMAP ghbmDragHandle2 = NULL; HDC ghDCMem = NULL; INT gCurTool = W_NOTHING; PWINDOWCLASSDESC gpwcdCurTool = BOOL gfToolLocked = FALSE; PCUSTLINK gpclHead = NULL; /* Application instance handle. */ /* Main menu handle. */ /* Head of the linked list of resources.*/ /* Describes the current dialog. */ /* A dark gray pen. */ /* The accelerator table handle. */ /* Currently selected menu item. */ /* Handle for the drag handle bitmap. */ /* Handle for hollow drag handle bitmap.*/ /* Memory DC for drawing bitmaps. */ /* Currently selected tool. */ NULL; /* Describes current tool. */ /* TRUE if a tool is locked down. */ /* Head of custom control linked list. */ /* * When the dialog editor displays one of its own dialogs, this value * will contain the resource id of it. It is zero if there is not a * dialog up. */ INT gidCurrentDlg = 0; /* * Ordinal for the icon control to display in the dialog. * initialized to one of the editor's own icons. */ ORDINAL gordIcon; It will be /* * Bitmap handles for the up and down W_NOTHING (pointer) tool bitmaps. */ HBITMAP ghbmPointerToolUp = NULL; HBITMAP ghbmPointerToolDown = NULL; /*-- Initialized "Preferences" Data ------------------------------------*/ /* * Initialization data structure. This describes each profile entry * that is contained in the initialization file. */ INIENTRY gaie[] = { { L"fHexMode", &gfHexMode, FALSE, 0 }, { L"fTranslateMode",&gfTranslateMode, FALSE, 0 }, { L"fShowToolbox", &gfShowToolbox, TRUE, 0 }, { L"fUseNewKeywords",&gfUseNewKeywords, TRUE, 0 }, { L"cxGrid", &gcxGrid, DEFCXGRID, 0 }, { L"cyGrid", &gcyGrid, DEFCYGRID, 0 }, { L"xMargin", &gxMargin, DEFXMARGIN, 0 }, { L"yMargin", &gyMargin, DEFYMARGIN, 0 }, { L"xSpace", &gxSpace, DEFXSPACE, 0 }, { L"ySpace", &gySpace, DEFYSPACE, 0 }, { L"xMinPushSpace", &gxMinPushSpace, DEFXMINPUSHSPACE, 0 }, { L"xMaxPushSpace", &gxMaxPushSpace, DEFXMAXPUSHSPACE, 0 }, { L"yPushSpace", &gyPushSpace, DEFYPUSHSPACE, 0 }, { NULL, NULL, 0, 0 } }; BOOL gfHexMode; BOOL gfTranslateMode; BOOL gfShowToolbox; BOOL gfUseNewKeywords; INT gcxGrid; INT gcyGrid; INT gxMargin; INT gyMargin; INT gxSpace; INT gySpace; INT gxMinPushSpace; INT gxMaxPushSpace; INT gyPushSpace; /* /* /* /* /* /* /* /* /* /* /* /* /* TRUE if in "hex" mode. TRUE if in "translate" mode. TRUE if Toolbox is to be shown. FALSE to only use "CONTROL" keyword. Current X grid. Current Y grid. Top/bottom margin. Left/right margin. Horizontal control spacing. Vertical control spacing. Minimum horizontal button spacing. Maximum horizontal button spacing. Vertical button spacing. */ */ */ */ */ */ */ */ */ */ */ */ */ TCHAR szAppPos[] = L"AppPos"; /* App window's position keyname. */ TCHAR szTBPos[] = L"TBPos"; /* Toolbox window's position keyname. */ TCHAR szCustomDLL[] = L"CustomDLL";/* Section name for DLL cust. cntls. */ /*-HWND HWND HWND HWND HWND HWND Sundry Handles.----------------------------------------------------*/ hwndStatus = NULL; /* Status ribbon window handle. */ ghwndToolbox = NULL; /* Toolbox window handle. */ ghwndTestDlg = NULL; /* Handle of the Test Mode dialog. */ ghwndMain = NULL; /* Main application window. */ ghwndSubClient = NULL; /* The "fake" client area. */ ghwndTrackOver = NULL; /* Window being tracked over. */ /*-- Some System constants.---------------------------------------------*/ INT gcxSysChar; /* Pixel width of system font char box. */ INT gcySysChar; /* Pixel height of system font char box.*/ INT gcyBorder; /* System height of a border. */ INT gcxPreDragMax; /* Max X mouse move during pre-drag. */ INT gcyPreDragMax; /* Max Y mouse move during pre-drag. */ INT gmsecPreDrag; /* The milliseconds that pre-drag lasts.*/ INT gcyPixelsPerInch; /* Vertical pixels/inch of system. */ INT gcyStatus; /* Saves height of the status window. */ /*-- Some state variables.----------------------------------------------*/ INT gState = STATE_NORMAL; /* Has the editor "state" or mode. */ BOOL gfResChged = FALSE; /* Tell if RES has changed */ BOOL gfIncChged = FALSE; /* Tell if include has changed */ BOOL gfDlgChanged = FALSE; /* TRUE if current dialog has changed. */ INT gcSelected = 0; /* Count of selected windows. */ BOOL gfTestMode = FALSE; /* TRUE if in "test" mode. */ BOOL gfDisabled = FALSE; /* TRUE if editing is disabled for now. */ BOOL gfEditingDlg = FALSE; /* TRUE means a dlg is picked to edit. */ BOOL gfDlgSelected = FALSE; /* TRUE if the dialog has the selection.*/ /* * Contains the window rectangle, in window units, for the "client" * area for the currently chosen dialog being edited. This rectangle * is relative to the dialog box window. The xLeft and yBottom fields * contain the offset from the window origin of the dialog box to the * origin of the "client" area. */ RECT grcDlgClient; /* * Contains a rectangle that surrounds all the existing controls. This * is used during tracking of the dialog to limit the minimum size that * the dialog can be sized to. */ RECT grcMinDialog; /* * Contains the offset from the origin of the currently selected * control to the mouse pointer. This is updated when a control * is clicked on and is used for dragging calculations. */ POINT gptCursorOffset; /* * Contains the rectangle that surrounds the selected control(s). * rectangle is only valid if there are selected controls. */ RECT grcSelected; This /* * Contains the rectangle that surrounds the control(s) that are being * copied. This is also used during a clipboard paste operation. In * that case, it contains the rectangle that surrounds the control(s) * as they are defined in the res image. */ RECT grcCopy; /* * These contain the current location of the tracking rectangle when * dragging a control. The values for grcTrackDU are in Dialog Units * (DU's) and the values in grcTrackWin are in window units. The * grcTrackWin values will only be valid if gfTrackRectShown is TRUE; */ RECT grcTrackDU; /* Track rect in dialog units. RECT grcTrackWin; /* Track rect in window units. BOOL gfTrackRectShown = FALSE; /* TRUE if track rect is visible. HDC ghDCTrack; /* Clip DC used when tracking. /* * Contains the current drag handle that is being tracked. * be one of the DRAG_* constants. */ INT gHandleHit = DRAG_CENTER; */ */ */ */ This will /* * Contains the overhang that is allowed during the current tracking * operation. This is used by various routines during dragging so * that limiting the tracking to the dialog boundaries works properly. * In actuality, this is only non-zero when a combo box control is * being drapped or dragged. It will be the height of the listbox * portion of the combo. This is how combos are allowed to extend * below the bottom of the dialog. */ INT gnOverHang; /* Maximum overhang during the drag. /* * This pointer is either NULL, or else it points to a dialog resource. * It is used when copying dialogs/controls, either with the Duplicate * command or pasting from the clipboard. */ */ PRES gpResCopy; /* Copy of dialog/controls. */ /*-- CTYPE linked lists.------------------------------------------------*/ NPCTYPE npcHead = NULL; /* Linked List of controls. */ INT cWindows = 0; /* Number of Controls in pctype list. */ /* * Pointer to the CTYPE structure for the currently selected control. * This will be NULL if there is no control selected. */ NPCTYPE gnpcSel = NULL; /*-- Cursors used by editor.--------------------------------------------*/ HCURSOR hcurArrow = NULL; /* Normal arrow cursor. */ HCURSOR hcurWait = NULL; /* User Wait cursor, Hourglass. */ HCURSOR hcurOutSel = NULL; /* Outline selection cursor. */ HCURSOR hcurMove = NULL; /* System "Move" cursor. */ HCURSOR hcurInsert = NULL; /* Insert cursor for Order/Group dialog.*/ HCURSOR hcurDropTool = NULL; /* Cursor for when dropping new ctrls. */ HCURSOR hcurSizeNESW = NULL; /* System sizing "NESW" cursor. */ HCURSOR hcurSizeNS = NULL; /* System sizing "NS" cursor. */ HCURSOR hcurSizeNWSE = NULL; /* System sizing "NWSE" cursor. */ HCURSOR hcurSizeWE = NULL; /* System sizing "WE" cursor. */ HBITMAP hbmTabStop = NULL; /* Bitmap for showing WS_TABSTOP style. */ HBITMAP hbmTabStopSel = NULL; /* Selected version of the above. */ /*-- Window Class Strings.----------------------------------------------*/ TCHAR szMainClass[] = L"DlgEdit";/* Application window class. */ TCHAR szDragClass[] = L"Drag"; /* Class for drag handle windows. */ TCHAR szSubClientClass[] = L"SubClient"; /* Short client area window class. */ TCHAR szToolboxClass[] = L"Toolbox"; /* Toolbox window class. */ TCHAR szToolBtnClass[] = L"ToolBtn"; /* Toolbox button window class. */ TCHAR szCustomClass[] = L"DlgCustom"; /* Our custom emulator class. */ /*-- Miscellaneous variables.-------------------------------------------*/ UINT fmtDlg; /* The Dialog Clipboard format */ TCHAR szEmpty[] = L""; /* An empty string. */ HHOOK ghhkMsgFilter; /* Hook handle for message filter func. */ /*-- Buffers.-----------------------------------------------------------*/ TCHAR szFullResFile[CCHMAXPATH]; /* Full resource file name */ LPTSTR pszResFile; /* Points to resource file name */ TCHAR szFullIncludeFile[CCHMAXPATH];/* Full include file name */ LPTSTR pszIncludeFile; /* Points to include file name */ TCHAR gszHelpFile[CCHMAXPATH]; /* Path to the help file. */ /* * Write buffer and index into it. This buffer is used by several * sections to write out the different files. Note that only one * file can be written out at a time using these globals. */ TCHAR gachWriteBuffer[CCHFILEBUFFER];/* Buffer for written file data. INT cbWritePos; /* Pointer into gachWriteBuffer. */ */ /*-- Include Data.------------------------------------------------------*/ NPLABEL plInclude = NULL; /* Pointer to Include data */ NPLABEL plDelInclude = NULL; /* Pointer to deleted includes */ /* * Describes each window class. Indexed by the W_ defined constants. * The define CCONTROLS needs to be updated if controls are added or * removed from this array. Note that CCONTROLS does NOT count the * W_DIALOG type as a control, however. */ WINDOWCLASSDESC awcd[] = { /* * W_TEXT */ { W_TEXT, WS_CHILD | WS_GROUP | WS_VISIBLE | SS_LEFT, WS_DISABLED, 0, 0, 20, 8, IC_STATIC, NULL, FALSE, FALSE, TRUE, TRUE, TRUE, DID_TEXTSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_TEXTSTYLES, IDS_DEFTXTTEXT, NULL, NULL, IDBM_CTTEXT, NULL, NULL, IDBM_TUTEXT, NULL, IDBM_TDTEXT, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_EDIT */ { W_EDIT, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL, WS_DISABLED, 0, 0, 32, 12, IC_EDIT, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_EDITSTYLES, (WNDPROC)EditStylesDlgProc, HELPID_EDITSTYLES, IDS_NULL, NULL, NULL, IDBM_CTEDIT, NULL, NULL, IDBM_TUEDIT, NULL, IDBM_TDEDIT, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_GROUPBOX */ { W_GROUPBOX, WS_CHILD | WS_VISIBLE | BS_GROUPBOX, WS_DISABLED, 0, 0, 48, 40, IC_BUTTON, NULL, FALSE, FALSE, TRUE, TRUE, FALSE, DID_GROUPBOXSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_GROUPBOXSTYLES, IDS_DEFTXTGROUP, NULL, NULL, IDBM_CTGROUP, NULL, NULL, IDBM_TUGROUP, NULL, IDBM_TDGROUP, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_PUSHBUTTON */ { W_PUSHBUTTON, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, WS_DISABLED, 0, 0, 40, 14, IC_BUTTON, NULL, FALSE, FALSE, TRUE, TRUE, TRUE, DID_PUSHBUTTONSTYLES, (WNDPROC)PushButtonStylesDlgProc, HELPID_PUSHBUTTONSTYLES, IDS_DEFTXTPUSHBUTTON, NULL, NULL, IDBM_CTPUSH, NULL, NULL, IDBM_TUPUSH, NULL, IDBM_TDPUSH, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_CHECKBOX */ { W_CHECKBOX, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP, WS_DISABLED, 0, 0, 40, 10, IC_BUTTON, NULL, FALSE, FALSE, TRUE, TRUE, TRUE, DID_CHECKBOXSTYLES, (WNDPROC)CheckBoxStylesDlgProc, HELPID_CHECKBOXSTYLES, IDS_DEFTXTCHECKBOX, NULL, NULL, IDBM_CTCHECK, NULL, NULL, IDBM_TUCHECK, NULL, IDBM_TDCHECK, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_RADIOBUTTON */ { W_RADIOBUTTON, WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, WS_DISABLED, 0, 0, 39, 10, IC_BUTTON, NULL, FALSE, FALSE, TRUE, TRUE, TRUE, DID_RADIOBUTTONSTYLES, (WNDPROC)RadioButtonStylesDlgProc, HELPID_RADIOBUTTONSTYLES, IDS_DEFTXTRADIOBUTTON, NULL, NULL, IDBM_CTRADIO, NULL, NULL, IDBM_TURADIO, NULL, IDBM_TDRADIO, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_COMBOBOX */ { W_COMBOBOX, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWN | CBS_SORT, WS_DISABLED | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS, CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS, 0, 48, 35, IC_COMBOBOX, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_COMBOBOXSTYLES, (WNDPROC)ComboBoxStylesDlgProc, HELPID_COMBOBOXSTYLES, IDS_NULL, NULL, NULL, IDBM_CTCOMBO, NULL, NULL, IDBM_TUCOMBO, NULL, IDBM_TDCOMBO, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_LISTBOX */ { W_LISTBOX, WS_CHILD | WS_VISIBLE | LBS_STANDARD | WS_TABSTOP, WS_DISABLED | LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NODATA, LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NODATA, 0, 48, 40, IC_LISTBOX, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_LISTBOXSTYLES, (WNDPROC)ListBoxStylesDlgProc, HELPID_LISTBOXSTYLES, IDS_NULL, NULL, NULL, IDBM_CTLIST, NULL, NULL, IDBM_TULIST, NULL, IDBM_TDLIST, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_HORZSCROLL */ { W_HORZSCROLL, WS_CHILD | WS_VISIBLE | SBS_HORZ, WS_DISABLED, 0, 0, 48, 0, IC_SCROLLBAR, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_HORZSCROLLSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_HORZSCROLLSTYLES, IDS_NULL, NULL, NULL, IDBM_CTHSCROL, NULL, NULL, IDBM_TUHSCROL, NULL, IDBM_TDHSCROL, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_VERTSCROLL */ { W_VERTSCROLL, WS_CHILD | WS_VISIBLE | SBS_VERT, WS_DISABLED, 0, 0, 0, 40, IC_SCROLLBAR, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_VERTSCROLLSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_VERTSCROLLSTYLES, IDS_NULL, NULL, NULL, IDBM_CTVSCROL, NULL, NULL, IDBM_TUVSCROL, NULL, IDBM_TDVSCROL, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_FRAME */ { W_FRAME, WS_CHILD | WS_VISIBLE | SS_BLACKFRAME, WS_DISABLED, 0, 0, 20, 16, IC_STATIC, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_FRAMESTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_FRAMESTYLES, IDS_NULL, NULL, NULL, IDBM_CTFRAME, NULL, NULL, IDBM_TUFRAME, NULL, IDBM_TDFRAME, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_RECT */ { W_RECT, WS_CHILD | WS_VISIBLE | SS_BLACKRECT, WS_DISABLED, 0, 0, 20, 16, IC_STATIC, NULL, FALSE, FALSE, FALSE, TRUE, FALSE, DID_RECTSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_RECTSTYLES, IDS_NULL, NULL, NULL, IDBM_CTRECT, NULL, NULL, IDBM_TURECT, NULL, IDBM_TDRECT, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_ICON */ { W_ICON, WS_CHILD | WS_VISIBLE | SS_ICON, WS_DISABLED, 0, 0, 0, 0, IC_STATIC, NULL, FALSE, FALSE, TRUE, FALSE, FALSE, DID_ICONSTYLES, (WNDPROC)GenericStylesDlgProc, HELPID_ICONSTYLES, IDS_NULL, NULL, NULL, IDBM_CTICON, NULL, NULL, IDBM_TUICON, NULL, IDBM_TDICON, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_CUSTOM * * For Custom controls, we do not allow our emulator control * to be created with any other styles than the default ones * (WS_CHILD and WS_VISIBLE), but whatever styles the user * specifies are written out to the .res and .dlg files, * of course. */ { W_CUSTOM, WS_CHILD | WS_VISIBLE, WS_DISABLED, 0, 0, 40, 14, IC_CUSTOM, NULL, TRUE, FALSE, TRUE, TRUE, FALSE, DID_CUSTOMSTYLES, (WNDPROC)CustomStylesDlgProc, HELPID_CUSTOMSTYLES, IDS_NULL, NULL, NULL, IDBM_CTCUSTOM, NULL, NULL, IDBM_TUCUSTOM, NULL, IDBM_TDCUSTOM, NULL, NULL, 0, NULL, NULL, NULL, 0 }, /* * W_DIALOG */ { W_DIALOG, WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | WS_POPUP | DS_SETFONT, WS_DISABLED | DS_SYSMODAL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, DS_SYSMODAL, 0, 160, 100, IC_DIALOG, NULL, FALSE, FALSE, TRUE, TRUE, FALSE, DID_DIALOGSTYLES, (WNDPROC)DialogStylesDlgProc, HELPID_DIALOGSTYLES, IDS_DEFTXTDIALOG, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL, 0, NULL, NULL, NULL, 0 } }; /* * This table maps the BS_* style of a button control into its * appropriate W_* type that is used internally by the editor. * This table assumes that any value used to index into it is * masked by BS_ALL. */ INT rgmpiClsBtnType[] = { W_PUSHBUTTON, /* BS_PUSHBUTTON W_PUSHBUTTON, /* BS_DEFPUSHBUTTON W_CHECKBOX, /* BS_CHECKBOX W_CHECKBOX, /* BS_AUTOCHECKBOX W_RADIOBUTTON, /* BS_RADIOBUTTON W_CHECKBOX, /* BS_3STATE W_CHECKBOX, /* BS_AUTO3STATE W_GROUPBOX, /* BS_GROUPBOX W_PUSHBUTTON, /* BS_USERBUTTON W_RADIOBUTTON, /* BS_AUTORADIOBUTTON W_PUSHBUTTON, /* BS_PUSHBOX W_PUSHBUTTON /* BS_OWNERDRAW }; /* Map low word of Static Control Style to static type. */ /* * This table maps the SS_* style of a static control into its * appropriate W_* type that is used internally by the editor. * This table assumes that any value used to index into it is * masked by SS_ALL. */ INT rgmpiClsStcType[] = { W_TEXT, /* SS_LEFT W_TEXT, /* SS_CENTER W_TEXT, /* SS_RIGHT W_ICON, /* SS_ICON W_RECT, /* SS_BLACKRECT W_RECT, /* SS_GREYRECT W_RECT, /* SS_WHITERECT W_FRAME, /* SS_BLACKFRAME W_FRAME, /* SS_GRAYFRAME W_FRAME, /* SS_WHITEFRAME W_TEXT, /* SS_USERITEM W_TEXT, /* SS_SIMPLE W_TEXT /* SS_LEFTNOWORDWRAP }; /* * * * * * * * Following are the tables with the predefined RC keywords for each class (IC_*). These tables describe each keyword other than the generic "CONTROL" keyword that is possible to use within a dialog template. The style describes the minimum bits that must be set to define the keyword. The mask allows a style to be specified that must have certain bits OFF for a match to occur. The default styles flag specifies style bits that are implicitly turned on */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ * when this keyword is specified in the dialog template in the .DLG * file. These bits are checked against the style flag of the control * that we are trying to match and if any of these default bits are * NOT set for that control, we need to specify them in the .DLG file * with a "NOT" in front of them to explicitly turn them off. * * The "Has Text" flag is set to FALSE in those cases where the syntax * for the keyword does NOT include a text field, like "ICON" and * "LISTBOX". */ /* * Array of the predefined RC keywords for Button styles. */ static RCKEYWORD arckwdButton[] = { /* * RADIOBUTTON */ { BS_RADIOBUTTON, BS_ALL, WS_CHILD | WS_VISIBLE, IDS_KEYRADIOBUTTON, TRUE }, /* * CHECKBOX */ { BS_CHECKBOX, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYCHECKBOX, TRUE }, /* * DEFPUSHBUTTON */ { BS_DEFPUSHBUTTON, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYDEFPUSHBUTTON, TRUE }, /* * PUSHBUTTON */ { BS_PUSHBUTTON, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYPUSHBUTTON, TRUE }, /* * GROUPBOX */ { BS_GROUPBOX, BS_ALL, WS_CHILD | WS_VISIBLE, IDS_KEYGROUPBOX, TRUE }, /* * AUTO3STATE */ { BS_AUTO3STATE, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYAUTO3STATE, TRUE }, /* * AUTOCHECKBOX */ { BS_AUTOCHECKBOX, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYAUTOCHECKBOX, TRUE }, /* * AUTORADIOBUTTON */ { BS_AUTORADIOBUTTON, BS_ALL, WS_CHILD | WS_VISIBLE, IDS_KEYAUTORADIOBUTTON, TRUE }, /* * STATE3 */ { BS_3STATE, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYSTATE3, TRUE }, /* * USERBUTTON */ { BS_USERBUTTON, BS_ALL, WS_CHILD | WS_VISIBLE | WS_TABSTOP, IDS_KEYUSERBUTTON, TRUE } }; /* * Array of the predefined RC keywords for Edit control styles. */ static RCKEYWORD arckwdEdit[] = { /* * EDIT */ { 0L, 0L, WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER, IDS_KEYEDITTEXT, FALSE } }; /* * Array of the predefined RC keywords for Static styles. */ static RCKEYWORD arckwdStatic[] = { /* * ICON */ { SS_ICON, SS_ALL, WS_CHILD | WS_VISIBLE, IDS_KEYICON, TRUE }, /* * RTEXT */ { SS_RIGHT, SS_ALL, WS_CHILD | WS_GROUP | WS_VISIBLE, IDS_KEYRTEXT, TRUE }, /* * CTEXT */ { SS_CENTER, SS_ALL, WS_CHILD | WS_GROUP | WS_VISIBLE, IDS_KEYCTEXT, TRUE }, /* * LTEXT */ { SS_LEFT, SS_ALL, WS_CHILD | WS_GROUP | WS_VISIBLE, IDS_KEYLTEXT, TRUE } }; /* * Array of the predefined RC keywords for ListBox styles. */ static RCKEYWORD arckwdLB[] = { /* * LISTBOX */ { 0L, 0L, WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY, IDS_KEYLISTBOX, FALSE } }; /* * Array of the predefined RC keywords for ComboBox styles. */ static RCKEYWORD arckwdComboBox[] = { /* * COMBOBOX */ { 0L, 0L, WS_CHILD | WS_VISIBLE, IDS_KEYCOMBOBOX, FALSE } }; /* * Array of the predefined RC keywords for ScrollBar styles. */ static RCKEYWORD arckwdScrollBar[] = { /* * SCROLLBAR */ { 0L, 0L, WS_CHILD | WS_VISIBLE, IDS_KEYSCROLLBAR, FALSE } }; /* * Following are the Class Styles structures. These tables define the * styles for the different window classes (IC_*). The first element * is the style flag, followed by an optional style mask. If the style * mask is zero, the style flag becomes the mask also. This is often good * enough, but there are cases where the style depends on certain bits * being off, as well as certain bits being on, to definitively identify * a certain style. An extreme example of this is the BS_PUSHBUTTON * style, which is actually zero (no bits are on). The mask for this * style had to be set to include all four of the lower bits, or all * buttons would be incorrectly figured to have the BS_PUSHBUTTON style. * With the proper mask, only styles that have all four lower bits * OFF will be considered to have the BS_PUSHBUTTON style. */ /* * Button styles. */ static CLASSSTYLE acsButton[] = { {BS_PUSHBUTTON, {BS_DEFPUSHBUTTON, {BS_CHECKBOX, BS_ALL, BS_ALL, BS_ALL, DID_BS_PUSHBUTTON DID_BS_DEFPUSHBUTTON 0 }, }, }, {BS_AUTOCHECKBOX, {BS_RADIOBUTTON, {BS_3STATE, {BS_AUTO3STATE, {BS_GROUPBOX, {BS_USERBUTTON, {BS_AUTORADIOBUTTON, {BS_PUSHBOX, {BS_OWNERDRAW, {BS_LEFTTEXT, BS_ALL, BS_ALL, BS_ALL, BS_ALL, BS_ALL, BS_ALL, BS_ALL, BS_ALL, BS_ALL, 0, 0 0 0 0 0 0 0 0 DID_BS_OWNERDRAW DID_BS_LEFTTEXT }, }, }, }, }, }, }, }, }, } 0 0 0 0 0 0 0 0 0 }, }, }, }, }, }, }, }, } DID_ES_LEFT DID_ES_CENTER DID_ES_RIGHT DID_ES_MULTILINE DID_ES_UPPERCASE DID_ES_LOWERCASE DID_ES_PASSWORD DID_ES_AUTOVSCROLL DID_ES_AUTOHSCROLL DID_ES_NOHIDESEL DID_ES_OEMCONVERT DID_ES_READONLY }, }, }, }, }, }, }, }, }, }, }, } DID_SS_LEFT DID_SS_CENTER DID_SS_RIGHT 0 DID_SS_BLACKRECT DID_SS_GRAYRECT DID_SS_WHITERECT DID_SS_BLACKFRAME DID_SS_GRAYFRAME }, }, }, }, }, }, }, }, }, }; /* * Scroll bar styles. */ static CLASSSTYLE acsSB[] = { {SBS_HORZ, SBS_ALL, {SBS_VERT, SBS_ALL, {SBS_TOPALIGN, 0, {SBS_LEFTALIGN, 0, {SBS_BOTTOMALIGN, 0, {SBS_RIGHTALIGN, 0, {SBS_SIZEBOXTOPLEFTALIGN, 0, {SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, {SBS_SIZEBOX, 0, }; /* * Entry field styles. */ static CLASSSTYLE acsEdit[] {ES_LEFT, {ES_CENTER, {ES_RIGHT, {ES_MULTILINE, {ES_UPPERCASE, {ES_LOWERCASE, {ES_PASSWORD, {ES_AUTOVSCROLL, {ES_AUTOHSCROLL, {ES_NOHIDESEL, {ES_OEMCONVERT, {ES_READONLY, }; = { ES_ALIGN, ES_ALIGN, ES_ALIGN, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* * Static styles. */ static CLASSSTYLE acsStatic[] = { {SS_LEFT, SS_ALL, {SS_CENTER, SS_ALL, {SS_RIGHT, SS_ALL, {SS_ICON, SS_ALL, {SS_BLACKRECT, SS_ALL, {SS_GRAYRECT, SS_ALL, {SS_WHITERECT, SS_ALL, {SS_BLACKFRAME, SS_ALL, {SS_GRAYFRAME, SS_ALL, {SS_WHITEFRAME, {SS_USERITEM, {SS_SIMPLE, {SS_LEFTNOWORDWRAP, {SS_NOPREFIX, SS_ALL, SS_ALL, SS_ALL, SS_ALL, 0, DID_SS_WHITEFRAME DID_SS_USERITEM DID_SS_SIMPLE DID_SS_LEFTNOWORDWRAP DID_SS_NOPREFIX }, }, }, }, } { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, DID_LBS_NOTIFY DID_LBS_SORT DID_LBS_NOREDRAW DID_LBS_MULTIPLESEL DID_LBS_OWNERDRAWFIXED DID_LBS_OWNERDRAWVARIABLE DID_LBS_HASSTRINGS DID_LBS_USETABSTOPS DID_LBS_NOINTEGRALHEIGHT DID_LBS_MULTICOLUMN DID_LBS_WANTKEYBOARDINPUT DID_LBS_EXTENDEDSEL DID_LBS_DISABLENOSCROLL DID_LBS_NODATA }, }, }, }, }, }, }, }, }, }, }, }, }, } DID_CBS_SIMPLE DID_CBS_DROPDOWN DID_CBS_DROPDOWNLIST DID_CBS_OWNERDRAWFIXED DID_CBS_OWNERDRAWVARIABLE DID_CBS_AUTOHSCROLL DID_CBS_OEMCONVERT DID_CBS_SORT DID_CBS_HASSTRINGS DID_CBS_NOINTEGRALHEIGHT DID_CBS_DISABLENOSCROLL }, }, }, }, }, }, }, }, }, }, } /* * Dialog styles. */ static CLASSSTYLE acsDialog[] = { {DS_ABSALIGN, 0, DID_DS_ABSALIGN {DS_SYSMODAL, 0, DID_DS_SYSMODAL {DS_LOCALEDIT, 0, DID_DS_LOCALEDIT {DS_SETFONT, 0, 0 {DS_MODALFRAME, 0, DID_DS_MODALFRAME {DS_NOIDLEMSG, 0, DID_DS_NOIDLEMSG /* * The following two styles are the same bits as WS_GROUP and * WS_TABSTOP, so they must be in this table and there has * to be special case code for writing the appropriate string }, }, }, }, }, }, }; /* * List box styles. */ static CLASSSTYLE acsLB[] = {LBS_NOTIFY, {LBS_SORT, {LBS_NOREDRAW, {LBS_MULTIPLESEL, {LBS_OWNERDRAWFIXED, {LBS_OWNERDRAWVARIABLE, {LBS_HASSTRINGS, {LBS_USETABSTOPS, {LBS_NOINTEGRALHEIGHT, {LBS_MULTICOLUMN, {LBS_WANTKEYBOARDINPUT, {LBS_EXTENDEDSEL, {LBS_DISABLENOSCROLL, {LBS_NODATA, }; /* * Combo Box styles. */ static CLASSSTYLE acsComboBox[] = { {CBS_SIMPLE, CBS_ALL, {CBS_DROPDOWN, CBS_ALL, {CBS_DROPDOWNLIST, CBS_ALL, {CBS_OWNERDRAWFIXED, 0, {CBS_OWNERDRAWVARIABLE, 0, {CBS_AUTOHSCROLL, 0, {CBS_OEMCONVERT, 0, {CBS_SORT, 0, {CBS_HASSTRINGS, 0, {CBS_NOINTEGRALHEIGHT, 0, {CBS_DISABLENOSCROLL, 0, }; * out when writing dialog styles. */ {WS_MINIMIZEBOX, 0, {WS_MAXIMIZEBOX, 0, DID_WS_MINIMIZEBOX DID_WS_MAXIMIZEBOX }, } }; /* * Window styles. */ static CLASSSTYLE acsWindow[] = { {WS_POPUP, 0, DID_WS_POPUP {WS_CHILD, 0, DID_WS_CHILD {WS_MINIMIZE, 0, DID_WS_MINIMIZE {WS_VISIBLE, 0, DID_WS_VISIBLE {WS_DISABLED, 0, DID_WS_DISABLED {WS_CLIPSIBLINGS, 0, DID_WS_CLIPSIBLINGS {WS_CLIPCHILDREN, 0, DID_WS_CLIPCHILDREN {WS_MAXIMIZE, 0, DID_WS_MAXIMIZE {WS_CAPTION, WS_CAPTIONALL, DID_WS_CAPTION {WS_BORDER, WS_CAPTIONALL, DID_WS_BORDER {WS_DLGFRAME, WS_CAPTIONALL, DID_WS_DLGFRAME {WS_VSCROLL, 0, DID_WS_VSCROLL {WS_HSCROLL, 0, DID_WS_HSCROLL {WS_SYSMENU, 0, DID_WS_SYSMENU {WS_THICKFRAME, 0, DID_WS_THICKFRAME {WS_GROUP, 0, DID_WS_GROUP {WS_TABSTOP, 0, DID_WS_TABSTOP }; /* * Resource Flags styles. */ static CLASSSTYLE acsResFlags[] = { {MMF_MOVEABLE, 0, {MMF_PURE, 0, {MMF_PRELOAD, 0, {MMF_DISCARDABLE, 0, }; /* * Extended Styles. */ static CLASSSTYLE acsExStyle[] = { {WS_EX_DLGMODALFRAME, 0, {0x0002 /*WS_EX_DRAGOBJECT*/, 0, {WS_EX_NOPARENTNOTIFY, 0, {WS_EX_TOPMOST, 0, {WS_EX_ACCEPTFILES, 0, {WS_EX_TRANSPARENT, 0, }; /* * * * * * * }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, } DID_MMF_MOVEABLE DID_MMF_PURE DID_MMF_PRELOAD DID_MMF_DISCARDABLE }, }, }, } 0 0 0 0 0 0 }, }, }, }, }, } Array of class style description structures. These are indexed by the IC_* constants and describe each class. They contain pointers to both the class styles array and the predefined keywords array for each class. The last few entries are included in the table for convenience, * and are used to describe things like the various window (WS_*, WS_EX_*) * and resource memory flags (MMF_*) styles, although they don't exactly * map to an IC_* style that a control will have. */ CLASSSTYLEDESC acsd[] = { /* * IC_BUTTON */ { IDS_WCBUTTON, acsButton, sizeof(acsButton) / sizeof(CLASSSTYLE), IDS_IC_BUTTON, arckwdButton, sizeof(arckwdButton) / sizeof(RCKEYWORD), ORDID_BUTTONCLASS }, /* * IC_SCROLLBAR */ { IDS_WCSCROLLBAR, acsSB, sizeof(acsSB) / sizeof(CLASSSTYLE), IDS_IC_SCROLLBAR, arckwdScrollBar, sizeof(arckwdScrollBar) / sizeof(RCKEYWORD), ORDID_SCROLLBARCLASS }, /* * IC_EDIT */ { IDS_WCEDIT, acsEdit, sizeof(acsEdit) / sizeof(CLASSSTYLE), IDS_IC_EDIT, arckwdEdit, sizeof(arckwdEdit) / sizeof(RCKEYWORD), ORDID_EDITCLASS }, /* * IC_STATIC */ { IDS_WCSTATIC, acsStatic, sizeof(acsStatic) / sizeof(CLASSSTYLE), IDS_IC_STATIC, arckwdStatic, sizeof(arckwdStatic) / sizeof(RCKEYWORD), ORDID_STATICCLASS }, /* * IC_LISTBOX */ { IDS_WCLISTBOX, acsLB, sizeof(acsLB) / sizeof(CLASSSTYLE), IDS_IC_LISTBOX, arckwdLB, sizeof(arckwdLB) / sizeof(RCKEYWORD), ORDID_LISTBOXCLASS }, /* * IC_COMBOBOX */ { IDS_WCCOMBOBOX, acsComboBox, sizeof(acsComboBox) / sizeof(CLASSSTYLE), IDS_IC_COMBOBOX, arckwdComboBox, sizeof(arckwdComboBox) / sizeof(RCKEYWORD), ORDID_COMBOBOXCLASS }, /* * IC_CUSTOM */ { IDS_WCCUSTOM, NULL, 0, 0, NULL, 0, 0 }, /* * IC_DIALOG */ { IDS_WCDIALOG, acsDialog, sizeof(acsDialog) / sizeof(CLASSSTYLE), IDS_IC_DIALOG, NULL, 0, 0 }, /* * IC_WINDOW */ { IDS_NULL, acsWindow, sizeof(acsWindow) / sizeof(CLASSSTYLE), IDS_IC_WINDOW, NULL, 0, 0 }, /* * IC_RESFLAGS */ { IDS_NULL, acsResFlags, sizeof(acsResFlags) / sizeof(CLASSSTYLE), 0, NULL, 0, 0 }, /* * IC_EXSTYLE */ { IDS_NULL, acsExStyle, sizeof(acsExStyle) / sizeof(CLASSSTYLE), IDS_IC_EXSTYLE, NULL, 0, 0 } }; /* * Message box messages, for the Message() function. */ MESSAGEDATA gamdMessages[] = { { IDS_DELETEDIALOG, MB_YESNO | MB_ICONEXCLAMATION { IDS_OUTOFMEMORY, MB_OK | MB_ICONHAND { IDS_CANTCREATE, MB_OK | MB_ICONEXCLAMATION { IDS_SYMNOCHANGE, MB_OK | MB_ICONEXCLAMATION { IDS_IDSYMMISMATCH, MB_OK | MB_ICONEXCLAMATION { IDS_CLOSING, MB_YESNOCANCEL | MB_ICONEXCLAMATION }, }, }, }, }, }, { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { IDS_BADRESFILE, MB_OK | MB_ICONEXCLAMATION IDS_INCLCLOSING, MB_YESNOCANCEL | MB_ICONEXCLAMATION IDS_SYMEXISTS, MB_OK | MB_ICONEXCLAMATION IDS_BADSYMBOLID, MB_OK | MB_ICONEXCLAMATION IDS_LABELDUPID, MB_OK | MB_ICONEXCLAMATION IDS_SELECTFIRST, MB_OK | MB_ICONEXCLAMATION IDS_CTRLDUPID, MB_OK | MB_ICONEXCLAMATION IDS_BADCUSTDLL, MB_OK | MB_ICONEXCLAMATION IDS_NOCLIP, MB_OK | MB_ICONEXCLAMATION IDS_INTERNAL, MB_OK | MB_ICONEXCLAMATION IDS_NOMOUSE, MB_OK | MB_ICONEXCLAMATION IDS_NOINIT, MB_OK | MB_ICONEXCLAMATION IDS_GTZERO, MB_OK | MB_ICONEXCLAMATION IDS_ICONNAMEHASBLANKS,MB_OK | MB_ICONEXCLAMATION IDS_IDUPIDS, MB_OK | MB_ICONEXCLAMATION IDS_CREATECTRLERROR, MB_OK | MB_ICONEXCLAMATION IDS_CANTOPENRES, MB_OK | MB_ICONEXCLAMATION IDS_CONFIRMDISCARD, MB_YESNO | MB_ICONEXCLAMATION IDS_SYMNOTFOUND, MB_OK | MB_ICONEXCLAMATION IDS_NOCLASS, MB_OK | MB_ICONEXCLAMATION IDS_POSITIVENUM, MB_OK | MB_ICONEXCLAMATION IDS_MEMERROR, MB_OK | MB_ICONHAND IDS_DLGNAMEHASBLANKS, MB_OK | MB_ICONEXCLAMATION IDS_NODLGNAME, MB_OK | MB_ICONEXCLAMATION IDS_CANTINITDLL, MB_OK | MB_ICONEXCLAMATION IDS_NOICONNAME, MB_OK | MB_ICONEXCLAMATION IDS_RESTOREDIALOG, MB_YESNO | MB_ICONEXCLAMATION IDS_ZEROPOINTSIZE, MB_OK | MB_ICONEXCLAMATION IDS_MINGTMAXSPACE, MB_OK | MB_ICONEXCLAMATION IDS_CUSTCNTLINUSE, MB_OK | MB_ICONEXCLAMATION IDS_CUSTALREADYLOADED,MB_OK | MB_ICONEXCLAMATION IDS_CANTLOADDLL, MB_OK | MB_ICONEXCLAMATION IDS_DLLBADEXPORTS, MB_OK | MB_ICONEXCLAMATION IDS_DLLBADCOUNT, MB_OK | MB_ICONEXCLAMATION }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, } }; /* * Table that maps menu items to help context id's for them. */ HELPMAP gahmapMenu[] = { {MENU_NEWRES, HELPID_FILE_NEWRES {MENU_OPEN, HELPID_FILE_OPEN {MENU_SAVE, HELPID_FILE_SAVE {MENU_SAVEAS, HELPID_FILE_SAVEAS {MENU_SETINCLUDE, HELPID_FILE_SETINCLUDE {MENU_NEWCUST, HELPID_FILE_NEWCUST {MENU_OPENCUST, HELPID_FILE_OPENCUST {MENU_REMCUST, HELPID_FILE_REMCUST {MENU_EXIT, HELPID_FILE_EXIT {MENU_RESTOREDIALOG, {MENU_CUT, {MENU_COPY, {MENU_PASTE, {MENU_DELETE, {MENU_DUPLICATE, {MENU_SYMBOLS, {MENU_STYLES, HELPID_EDIT_RESTOREDIALOG HELPID_EDIT_CUT HELPID_EDIT_COPY HELPID_EDIT_PASTE HELPID_EDIT_DELETE HELPID_EDIT_DUPLICATE HELPID_EDIT_SYMBOLS HELPID_EDIT_STYLES }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, {MENU_SIZETOTEXT, {MENU_NEWDIALOG, {MENU_SELECTDIALOG, HELPID_EDIT_SIZETOTEXT HELPID_EDIT_NEWDIALOG HELPID_EDIT_SELECTDIALOG }, }, }, {MENU_ALIGNLEFT, {MENU_ALIGNVERT, {MENU_ALIGNRIGHT, {MENU_ALIGNTOP, {MENU_ALIGNHORZ, {MENU_ALIGNBOTTOM, {MENU_SPACEHORZ, {MENU_SPACEVERT, {MENU_ARRSIZEWIDTH, {MENU_ARRSIZEHEIGHT, {MENU_ARRPUSHBOTTOM, {MENU_ARRPUSHRIGHT, {MENU_ORDERGROUP, {MENU_ARRSETTINGS, HELPID_ARRANGE_ALIGNLEFT HELPID_ARRANGE_ALIGNVERT HELPID_ARRANGE_ALIGNRIGHT HELPID_ARRANGE_ALIGNTOP HELPID_ARRANGE_ALIGNHORZ HELPID_ARRANGE_ALIGNBOTTOM HELPID_ARRANGE_SPACEHORZ HELPID_ARRANGE_SPACEVERT HELPID_ARRANGE_ARRSIZEWIDTH HELPID_ARRANGE_ARRSIZEHEIGHT HELPID_ARRANGE_ARRPUSHBOTTOM HELPID_ARRANGE_ARRPUSHRIGHT HELPID_ARRANGE_ORDERGROUP HELPID_ARRANGE_ARRSETTINGS }, }, }, }, }, }, }, }, }, }, }, }, }, }, {MENU_TESTMODE, {MENU_HEXMODE, {MENU_TRANSLATE, {MENU_USENEWKEYWORDS, {MENU_SHOWTOOLBOX, HELPID_OPTIONS_TESTMODE HELPID_OPTIONS_HEXMODE HELPID_OPTIONS_TRANSLATE HELPID_OPTIONS_USENEWKEYWORDS HELPID_OPTIONS_SHOWTOOLBOX }, }, }, }, }, {MENU_CONTENTS, HELPID_HELP_CONTENTS {MENU_SEARCH, HELPID_HELP_SEARCH // No help for the About menu command. }, }, {0, } 0 }; /* * Table that maps dialog ids to help context id's for them. */ HELPMAP gahmapDialog[] = { // No help for the About dialog. {DID_ARRSETTINGS, HELPID_ARRSETTINGS {DID_CHECKBOXSTYLES, HELPID_CHECKBOXSTYLES {DID_COMBOBOXSTYLES, HELPID_COMBOBOXSTYLES {DID_CUSTOMSTYLES, HELPID_CUSTOMSTYLES {DID_DIALOGSTYLES, HELPID_DIALOGSTYLES {DID_EDITSTYLES, HELPID_EDITSTYLES {DID_FRAMESTYLES, HELPID_FRAMESTYLES {DID_GROUPBOXSTYLES, HELPID_GROUPBOXSTYLES {DID_ORDERGROUP, HELPID_ORDERGROUP {DID_HORZSCROLLSTYLES, HELPID_HORZSCROLLSTYLES {DID_ICONSTYLES, HELPID_ICONSTYLES {DID_LISTBOXSTYLES, HELPID_LISTBOXSTYLES {DID_NEWCUST, HELPID_NEWCUST {DID_PUSHBUTTONSTYLES, HELPID_PUSHBUTTONSTYLES {DID_RADIOBUTTONSTYLES, HELPID_RADIOBUTTONSTYLES {DID_RECTSTYLES, HELPID_RECTSTYLES {DID_REMCUST, HELPID_REMCUST {DID_SELECTDIALOG, HELPID_SELECTDIALOG {DID_SYMBOLS, HELPID_SYMBOLS {DID_TEXTSTYLES, HELPID_TEXTSTYLES {DID_VERTSCROLLSTYLES, HELPID_VERTSCROLLSTYLES }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, {DID_COMMONFILEOPENINCLUDE, {DID_COMMONFILEOPENRES, {DID_COMMONFILESAVEINCLUDE, {DID_COMMONFILESAVERES, {DID_COMMONFILEOPENDLL, HELPID_COMMONFILEOPENINCLUDE HELPID_COMMONFILEOPENRES HELPID_COMMONFILESAVEINCLUDE HELPID_COMMONFILESAVERES HELPID_COMMONFILEOPENDLL }, }, }, }, }, {DID_TOOLBOX, {DID_STATUS, HELPID_TOOLBOX HELPID_PROPERTIESBAR }, }, {0, 0 } }; /* * Language and Sub Language tables. */ static SUBLANGTABLE aslNeutral[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, { SUBLANG_DEFAULT, IDS_SUBLANG_DEFAULT, }; IDS_SL_NEUTRAL IDS_SL_DEFAULT static SUBLANGTABLE aslChinese[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL { SUBLANG_CHINESE_SIMPLIFIED, IDS_SUBLANG_CHINESE_SIMPLIFIED, IDS_SL_CHINESE_SIMPLIFIED }, { SUBLANG_CHINESE_TRADITIONAL, IDS_SUBLANG_CHINESE_TRADITIONAL, IDS_SL_CHINESE_TRADITIONAL } }; }, } }, static SUBLANGTABLE aslDutch[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, { SUBLANG_DUTCH, IDS_SUBLANG_DUTCH, { SUBLANG_DUTCH_BELGIAN,IDS_SUBLANG_DUTCH_BELGIAN, }; IDS_SL_NEUTRAL }, IDS_SL_DUTCH }, IDS_SL_DUTCH_BELGIAN} static SUBLANGTABLE aslEnglish[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, { SUBLANG_ENGLISH_US, IDS_SUBLANG_ENGLISH_US, { SUBLANG_ENGLISH_UK, IDS_SUBLANG_ENGLISH_UK, { SUBLANG_ENGLISH_AUS, IDS_SUBLANG_ENGLISH_AUS, { SUBLANG_ENGLISH_CAN, IDS_SUBLANG_ENGLISH_CAN, }; IDS_SL_NEUTRAL IDS_SL_ENGLISH_US IDS_SL_ENGLISH_UK IDS_SL_ENGLISH_AUS IDS_SL_ENGLISH_CAN }, }, }, }, } static SUBLANGTABLE aslFrench[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, { SUBLANG_FRENCH, IDS_SUBLANG_FRENCH, IDS_SL_FRENCH }, { SUBLANG_FRENCH_BELGIAN, IDS_SUBLANG_FRENCH_BELGIAN, IDS_SL_FRENCH_BELGIAN }, { SUBLANG_FRENCH_CANADIAN, IDS_SUBLANG_FRENCH_CANADIAN, IDS_SL_FRENCH_CANADIAN }, { SUBLANG_FRENCH_SWISS, IDS_SUBLANG_FRENCH_SWISS, IDS_SL_FRENCH_SWISS } }; static SUBLANGTABLE aslGerman[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, { SUBLANG_GERMAN, IDS_SUBLANG_GERMAN, { SUBLANG_GERMAN_SWISS, IDS_SUBLANG_GERMAN_SWISS, }; static SUBLANGTABLE aslItalian[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, IDS_SL_GERMAN }, IDS_SL_GERMAN_SWISS } IDS_SL_NEUTRAL }, { SUBLANG_ITALIAN, IDS_SUBLANG_ITALIAN, IDS_SL_ITALIAN }, { SUBLANG_ITALIAN_SWISS, IDS_SUBLANG_ITALIAN_SWISS, IDS_SL_ITALIAN_SWISS } }; static SUBLANGTABLE aslNorwegian[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, { SUBLANG_NORWEGIAN_BOKMAL, IDS_SUBLANG_NORWEGIAN_BOKMAL, IDS_SL_NORWEGIAN_BOKMAL }, { SUBLANG_NORWEGIAN_NYNORSK, IDS_SUBLANG_NORWEGIAN_NYNORSK, IDS_SL_NORWEGIAN_NYNORSK } }; static SUBLANGTABLE aslPortuguese[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL { SUBLANG_PORTUGUESE, IDS_SUBLANG_PORTUGUESE, IDS_SL_PORTUGUESE { SUBLANG_PORTUGUESE_BRAZILIAN, IDS_SUBLANG_PORTUGUESE_BRAZILIAN, IDS_SL_PORTUGUESE_BRAZILIAN } }; }, }, static SUBLANGTABLE aslSpanish[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, { SUBLANG_SPANISH, IDS_SUBLANG_SPANISH, IDS_SL_SPANISH }, { SUBLANG_SPANISH_MEXICAN, IDS_SUBLANG_SPANISH_MEXICAN, IDS_SL_SPANISH_MEXICAN }, { SUBLANG_SPANISH_MODERN, IDS_SUBLANG_SPANISH_MODERN, IDS_SL_SPANISH_MODERN } }; LANGTABLE gaLangTable[] = { { LANG_NEUTRAL, IDS_LANG_NEUTRAL, IDS_L_NEUTRAL, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_CHINESE, IDS_LANG_CHINESE, IDS_L_CHINESE, sizeof(aslChinese) / sizeof(SUBLANGTABLE), aslChinese }, { LANG_CZECH, IDS_LANG_CZECH, IDS_L_CZECH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_DANISH, IDS_LANG_DANISH, IDS_L_DANISH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_DUTCH, IDS_LANG_DUTCH, IDS_L_DUTCH, sizeof(aslDutch) / sizeof(SUBLANGTABLE), aslDutch }, { LANG_ENGLISH, IDS_LANG_ENGLISH, IDS_L_ENGLISH, sizeof(aslEnglish) / sizeof(SUBLANGTABLE), aslEnglish }, { LANG_FINNISH, IDS_LANG_FINNISH, IDS_L_FINNISH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_FRENCH, IDS_LANG_FRENCH, IDS_L_FRENCH, sizeof(aslFrench) / sizeof(SUBLANGTABLE), aslFrench }, { LANG_GERMAN, IDS_LANG_GERMAN, IDS_L_GERMAN, sizeof(aslGerman) / sizeof(SUBLANGTABLE), aslGerman }, { LANG_GREEK, IDS_LANG_GREEK, IDS_L_GREEK, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_HUNGARIAN, IDS_LANG_HUNGARIAN, IDS_L_HUNGARIAN, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_ICELANDIC, IDS_LANG_ICELANDIC, IDS_L_ICELANDIC, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_ITALIAN, IDS_LANG_ITALIAN, IDS_L_ITALIAN, sizeof(aslItalian) / sizeof(SUBLANGTABLE), aslItalian }, { LANG_JAPANESE, IDS_LANG_JAPANESE, IDS_L_JAPANESE, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_KOREAN, IDS_LANG_KOREAN, IDS_L_KOREAN, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_NORWEGIAN, IDS_LANG_NORWEGIAN, IDS_L_NORWEGIAN, sizeof(aslNorwegian) / sizeof(SUBLANGTABLE), aslNorwegian }, { LANG_POLISH, IDS_LANG_POLISH, IDS_L_POLISH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_PORTUGUESE, IDS_LANG_PORTUGUESE, IDS_L_PORTUGUESE, sizeof(aslPortuguese) / sizeof(SUBLANGTABLE), aslPortuguese }, { LANG_RUSSIAN, IDS_LANG_RUSSIAN, IDS_L_RUSSIAN, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_SLOVAK, IDS_LANG_SLOVAK, IDS_L_SLOVAK, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_SPANISH, IDS_LANG_SPANISH, IDS_L_SPANISH, sizeof(aslSpanish) / sizeof(SUBLANGTABLE), aslSpanish }, { LANG_SWEDISH, IDS_LANG_SWEDISH, IDS_L_SWEDISH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, { LANG_TURKISH, IDS_LANG_TURKISH, IDS_L_TURKISH, sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral }, }; INT gcLanguages = sizeof(gaLangTable) / sizeof(LANGTABLE); =============================== //////////////////////////////////// //-----------------------------------------------------------// // Netstatp // // Copyright (C) 1998 Mark Russinovich // Systems Internals // http://www.sysinternals.com // // This program implements a subset of the Netstat program's // functionality. Specifically, it enumerates and displays // information about all UDP and TCP endpoints. // //-----------------------------------------------------------#include "windows.h" #include "stdio.h" #include "snmp.h" #include "winsock.h" #define HOSTNAMELEN 256 #define PORTNAMELEN 256 #define ADDRESSLEN HOSTNAMELEN+PORTNAMELEN typedef struct _tcpinfo { struct _tcpinfo struct _tcpinfo UINT UINT UINT UINT UINT } TCPINFO, *PTCPINFO; *prev; *next; state; localip; localport; remoteip; remoteport; BOOL (__stdcall *SnmpExtensionInit)( IN DWORD dwTimeZeroReference, OUT HANDLE *hPollForTrapEvent, OUT AsnObjectIdentifier *supportedView); BOOL (__stdcall *SnmpExtensionQuery)( IN BYTE requestType, IN OUT RFC1157VarBindList *variableBindings, OUT AsnInteger *errorStatus, OUT AsnInteger *errorIndex); // // Possible TCP endpoint states // static char TcpState[][32] = { "???", "CLOSED", "LISTENING", "SYN_SENT", "SEN_RECEIVED", "ESTABLISHED", "FIN_WAIT", "FIN_WAIT2", "CLOSE_WAIT", "CLOSING", "LAST_ACK", "TIME_WAIT" }; // // Lists of endpoints // TCPINFO TcpInfoTable; TCPINFO UdpInfoTable; //-----------------------------------------------------------// // GetPortName // // Translate port numbers into their text equivalent if // there is one // //-----------------------------------------------------------char *GetPortName( UINT port, char *proto, char *name, int namelen ) { struct servent *psrvent; if( psrvent = getservbyport( htons( (USHORT) port ), proto )) { strcpy( name, psrvent->s_name ); } else { sprintf(name, "%d", port); } return name; } //-----------------------------------------------------------// // GetIpHostName // // Translate IP addresses into their name-resolved form // if possible. // //-----------------------------------------------------------char *GetIpHostName( BOOL local, UINT ipaddr, char *name, int namelen ) { struct hostent *phostent; UINT nipaddr; nipaddr = htonl( ipaddr ); if( !ipaddr ) { if( !local ) { sprintf( name, "%d.%d.%d.%d", (nipaddr >> 24) & 0xFF, (nipaddr >> 16) & 0xFF, (nipaddr >> 8) & 0xFF, (nipaddr) & 0xFF); } else { gethostname(name, namelen); } } else if( ipaddr == 0x0100007f ) { if( local ) { gethostname(name, namelen); } else { strcpy( name, "localhost" ); } } else if( phostent = gethostbyaddr( (char *) &ipaddr, sizeof( nipaddr ), PF_INET )) { strcpy( name, phostent->h_name ); } else { sprintf( name, "%d.%d.%d.%d", (nipaddr >> 24) & 0xFF, (nipaddr >> 16) & 0xFF, (nipaddr >> 8) & 0xFF, (nipaddr) & 0xFF); } return name; } //-----------------------------------------------------------// // LoadInetMibEntryPoints // // Load the TCP/IP SNMP extension DLL and locate the entry // points we will use. // //------------------------------------------------------------ BOOLEAN LoadInetMibEntryPoints() { HINSTANCE hInetLib; if( !(hInetLib = LoadLibrary( "inetmib1.dll" ))) { return FALSE; } if( !(SnmpExtensionInit = (void *) GetProcAddress( hInetLib, "SnmpExtensionInit" )) ) { return FALSE; } if( !(SnmpExtensionQuery = (void *) GetProcAddress( hInetLib, "SnmpExtensionQuery" )) ) { return FALSE; } return TRUE; } //-----------------------------------------------------------// // Main // // Do it all. Load and initialize the SNMP extension DLL and // then build a table of TCP endpoints and UDP endpoints. After // each table is built resolve addresses to names and print // out the information // //-----------------------------------------------------------int main( int argc, char *argv[] ) { HANDLE hTrapEvent; AsnObjectIdentifier hIdentifier; RFC1157VarBindList bindList; RFC1157VarBind bindEntry; UINT tcpidentifiers[] = { 1,3,6,1,2,1,6,13,1,1}; UINT udpidentifiers[] = { 1,3,6,1,2,1,7, 5,1,1}; AsnInteger errorStatus, errorIndex; TCPINFO *currentEntry, *newEntry; UINT currentIndex; WORD wVersionRequested; WSADATA wsaData; char localname[HOSTNAMELEN], remotename[HOSTNAMELEN]; char remoteport[PORTNAMELEN], localport[PORTNAMELEN]; char localaddr[ADDRESSLEN], remoteaddr[ADDRESSLEN]; // // Initialize winsock // wVersionRequested = MAKEWORD( 1, 1 ); if( WSAStartup( wVersionRequested, &wsaData ) ) { printf("Could not initialize Winsock.\n"); return 1; } // // Locate and initialize INETMIB1 // if( !LoadInetMibEntryPoints()) { printf("Could not load extension DLL.\n"); return 1; } if( !SnmpExtensionInit( GetCurrentTime(), &hTrapEvent, &hIdentifier )) { printf("Could not initialize extension DLL.\n"); return 1; } // // Initialize the query structure once // bindEntry.name.idLength = 0xA; bindEntry.name.ids = tcpidentifiers; bindList.list = &bindEntry; bindList.len = 1; TcpInfoTable.prev = &TcpInfoTable; TcpInfoTable.next = &TcpInfoTable; // // Roll through TCP connections // currentIndex = 1; currentEntry = &TcpInfoTable; while(1) { if( !SnmpExtensionQuery( ASN_RFC1157_GETNEXTREQUEST, &bindList, &errorStatus, &errorIndex )) { return 1; } // // Terminate when we're no longer seeing TCP information // if( bindEntry.name.idLength < 0xA ) break; // // Go back to start of table if we're reading info // about the next byte // if( currentIndex != bindEntry.name.ids[9] ) { currentEntry = TcpInfoTable.next; currentIndex = bindEntry.name.ids[9]; } // // Build our TCP information table // switch( bindEntry.name.ids[9] ) { case 1: // // Always allocate a new structure // newEntry = (TCPINFO *) malloc( sizeof(TCPINFO )); newEntry->prev = currentEntry; newEntry->next = &TcpInfoTable; currentEntry->next = newEntry; currentEntry = newEntry; currentEntry->state = bindEntry.value.asnValue.number; break; case 2: currentEntry->localip = *(UINT *) bindEntry.value.asnValue.address.stream; currentEntry = currentEntry->next; break; case 3: currentEntry->localport = bindEntry.value.asnValue.number; currentEntry = currentEntry->next; break; case 4: currentEntry->remoteip = *(UINT *) bindEntry.value.asnValue.address.stream; currentEntry = currentEntry->next; break; case 5: currentEntry->remoteport = bindEntry.value.asnValue.number; currentEntry = currentEntry->next; break; } } // // Now print the connection information // printf("%7s %-30s %-30s %s\n", "Proto", "Local", "Remote", "State" ); currentEntry = TcpInfoTable.next; while( currentEntry != &TcpInfoTable ) { sprintf( localaddr, "%s:%s", GetIpHostName( TRUE, currentEntry->localip, localname, HOSTNAMELEN), GetPortName( currentEntry->localport, "tcp", localport, PORTNAMELEN )); sprintf( remoteaddr, "%s:%s", GetIpHostName( FALSE, currentEntry->remoteip, remotename, HOSTNAMELEN), currentEntry->remoteip ? GetPortName( currentEntry->remoteport, "tcp", remoteport, PORTNAMELEN ): "0" ); printf("%7s %-30s %-30s %s\n", "TCP", localaddr, remoteaddr, TcpState[currentEntry->state]); currentEntry = currentEntry->next; } printf("\n"); // // Initialize the query structure once // bindEntry.name.idLength = 0xA; bindEntry.name.ids = udpidentifiers; bindList.list = &bindEntry; bindList.len = 1; UdpInfoTable.prev = &UdpInfoTable; UdpInfoTable.next = &UdpInfoTable; // // Roll through UDP endpoints // currentIndex = 1; currentEntry = &UdpInfoTable; while(1) { if( !SnmpExtensionQuery( ASN_RFC1157_GETNEXTREQUEST, &bindList, &errorStatus, &errorIndex )) { return 1; } // // Terminate when we're no longer seeing TCP information // if( bindEntry.name.idLength < 0xA ) break; // // Go back to start of table if we're reading info // about the next byte // if( currentIndex != bindEntry.name.ids[9] ) { currentEntry = UdpInfoTable.next; currentIndex = bindEntry.name.ids[9]; } // // Build our TCP information table // switch( bindEntry.name.ids[9] ) { case 1: // // Always allocate a new structure // newEntry = (TCPINFO *) malloc( sizeof(TCPINFO )); newEntry->prev = currentEntry; newEntry->next = &UdpInfoTable; currentEntry->next = newEntry; currentEntry = newEntry; currentEntry->localip = *(UINT *) bindEntry.value.asnValue.address.stream; break; case 2: currentEntry->localport = bindEntry.value.asnValue.number; currentEntry = currentEntry->next; break; } } // // Now print the connection information // currentEntry = UdpInfoTable.next; while( currentEntry != &UdpInfoTable ) { printf("%7s %s:%s\n", "UDP", GetIpHostName( TRUE, currentEntry->localip, localname, HOSTNAMELEN), GetPortName( currentEntry->localport, "udp", localport, PORTNAMELEN ) ); currentEntry = currentEntry->next; } printf("\n"); } ///////////////////////////// #if defined(__cplusplus) && !defined(CINTERFACE) //#define interface struct FAR #define interface struct #define STDMETHOD(method) virtual HRESULT __stdcall method #define STDMETHOD_(type,method) virtual type __stdcall method #define PURE = 0 #define THIS_ #define THIS void #define DECLARE_INTERFACE(iface) interface iface #define DECLARE_INTERFACE_(iface, baseiface)\ interface iface:public baseiface #else #define interface struct #define STDMETHOD(method) HRESULT (__stdcall * method) #define STDMETHOD_(type,method) type (__stdcall * method) #ifdef __cplusplus extern "C" { #endif ... ... #ifdef __cplusplus } #endif // Common Library header for DLL and application-- lib1.h #ifdef MAKE_A_DLL #define LINKDLL __declspec( dllexport) #else #define LINKDLL __declspec( dllimport) #endif LINKDLL int libglobal; LINKDLL void libfuncA(char * buffer); LINKDLL int libfuncB(int const * mainint); Was erfolgt beim Laden einer DLL? Das Operating System führt die folgenden Schritte aus: Suche der ( zu ladenden ) DLL auf Platte. Im Adressraum der Applikation wird die Liste der bereits geladenen DLL's durchsucht, ob ein Laden erforderlich ist. Falls erfordelich, wird Speicher für die zu ladende DLL allokiert ( section object ). Die notwendigen vorbereitende Initialisierungen werden durchgeführt ( Adressanpassungen von static-Variablen, fix-up, imports, exports ). ================ TN038: MFC/OLE IUnknown Implementation At the heart of OLE 2 is the "OLE Component Object Model", or COM. COM defines a standard for how cooperating objects communicate to one another. This includes the details of what an "object" looks like, including how methods are dispatched on an object. COM also defines a base class, from which all COM compatible classes are derived. This base class is IUnknown. Although the IUnknown interface is referred to as a C++ class, COM is not specific to any one language — it can be implemented in C, PASCAL, or any other language which can support the binary layout of a COM object. OLE refers to all classes derived from IUnknown as "interfaces." This is an important distinction, since an "interface" such as IUnknown carries with it no implementation. It simply defines the protocol by which objects communicate, not the specifics of what those implementations do. This is reasonable for a system which allows for maximum flexibility. It is MFC's job to implement a default behavior for MFC/C++ programs. To understand MFC's implementation of IUnknown you must first understand what this interface is. A simplified version of IUnknown is defined below: class IUnknown { public: virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0; virtual ULONG AddRef() = 0; virtual ULONG Release() = 0; }; Note Certain necessary calling convention details, such as __stdcall are left out for this illustration. The AddRef and Release member functions control memory management of the object. COM uses a reference counting scheme to keep track of objects. An object is never referenced directly as you would in C++. Instead, COM objects are always referenced through a pointer. To release the object when the owner is done using it, the object's Release member is called (as opposed to using operator delete, as would be done for a traditional C++ object). The reference counting mechanism allows for multiple references to a single object to be managed. An implementation of AddRef and Release maintains a reference count on the object — the object is not deleted until its reference count reaches zero. AddRef and Release are fairly straightforward from an implementation standpoint. Here is a trivial implementation: ULONG CMyObj::AddRef() { return ++m_dwRef; } ULONG CMyObj::Release() { if (--m_dwRef == 0) { delete this; return 0; } return m_dwRef; } The QueryInterface member function is a little more interesting. As you can imagine, it isn't very interesting to have an object whose only member functions are AddRef and Release — it would be nice to tell the object to do more things than IUnknown provides. This is where QueryInterface is useful. It allows you to obtain a different "interface" on the same object. These interfaces are usually derived from IUnknown and add additional functionality by adding new member functions. COM interfaces never have member variables declared in the interface, and all member functions are declared as pure-virtual. For example, class IPrintInterface : public IUnknown { public: virtual void PrintObject() = 0; }; To get an IPrintInterface if you only have an IUnknown, call IUnknown::QueryInterface using the IID of the IPrintInterface. An IID is a 128-bit number that uniquely identifies the interface. There is an IID for each interface that either you or OLE define. If pUnk is a pointer to an IUnknown object, the code to retrieve an IPrintInterface from it might be: IPrintInterface* pPrint = NULL; if (pUnk->QueryInterface(IID_IPrintInterface, (void**)&pPrint) == NOERROR) { pPrint->PrintObject(); pPrint->Release(); // release pointer obtained via QueryInterface } That seems fairly easy, but how would you implement an object supporting both the IPrintInterface and IUnknown interface? In this case it is simple since the IPrintInterface is derived directly from IUnknown — by implementing IPrintInterface, IUnknown is automatically supported. For example: class CPrintObj : public CPrintInterface { virtual HRESULT QueryInterface(REFIID iid, void** ppvObj); virtual ULONG AddRef(); virtual ULONG Release(); virtual void PrintObject(); }; The implementations of AddRef and Release would be exactly the same as those implemented above. CPrintObj::QueryInterface would look something like this: HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj) { if (iid == IID_IUnknown || iid == IID_IPrintInterface) { *ppvObj = this; AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } As you can see, if the interface identifier (IID) is recognized, a pointer is returned to your object; otherwise an error occurs. Also note that a successful QueryInterface results in an implied AddRef. Of course, you'd also have to implement CEditObj::Print. That is simple because the IPrintInterface was directly derived from the IUnknown interface. However if you wanted to support two different interfaces, both derived from IUnknown, consider the following: class IEditInterface : public IUnkown { public: virtual void EditObject() = 0; }; Although there are a number of different ways to implement a class supporting both IEditInterface and IPrintInterface, including using C++ multiple inheritance, this note will concentrate on the use of nested classes to implement this functionality. class CEditPrintObj { public: CEditPrintObj(); HRESULT QueryInterface(REFIID iid, void**); ULONG AddRef(); ULONG Release(); DWORD m_dwRef; class CPrintObj : public IPrintInterface { public: CEditPrintObj* m_pParent; virtual HRESULT QueryInterface(REFIID iid, void** ppvObj); virtual ULONG AddRef(); virtual ULONG Release(); } m_printObj; class CEditObj : public IEditInterface { public: CEditPrintObj* m_pParent; virtual ULONG QueryInterface(REFIID iid, void** ppvObj); virtual ULONG AddRef(); virtual ULONG Release(); } m_editObj; }; The entire implementation is included below: CEditPrintObj::CEditPrintObj() { m_editObj.m_pParent = this; m_printObj.m_pParent = this; } ULONG CEditPrintObj::AddRef() { return ++m_dwRef; } CEditPrintObj::Release() { if (--m_dwRef == 0) { delete this; return 0; } return m_dwRef; } HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj) { if (iid == IID_IUnknown || iid == IID_IPrintInterface) { *ppvObj = &m_printObj; AddRef(); return NOERROR; } else if (iid == IID_IEditInterface) { *ppvObj = &m_editObj; AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } ULONG CEditPrintObj::CEditObj::AddRef() { return m_pParent->AddRef(); } ULONG CEditPrintObj::CEditObj::Release() { return m_pParent->Release(); } HRESULT CEditPrintObj::CEditObj::QueryInterface( REFIID iid, void** ppvObj) { return m_pParent->QueryInterface(iid, ppvObj); } ULONG CEditPrintObj::CPrintObj::AddRef() { return m_pParent->AddRef(); } ULONG CEditPrintObj::CPrintObj::Release() { return m_pParent->Release(); } HRESULT CEditPrintObj::CPrintObj::QueryInterface( REFIID iid, void** ppvObj) { return m_pParent->QueryInterface(iid, ppvObj); } Notice that most of the IUnknown implementation is placed into the CEditPrintObj class rather than duplicating the code in CEditPrintObj::CEditObj and CEditPrintObj::CPrintObj. This reduces the amount of code and avoids bugs. The key point here is that from the IUnknown interface it is possible to call QueryInterface to retrieve any interface the object might support, and from each of those interfaces it is possible to do the same. This means that all QueryInterface functions available from each interface must behave exactly the same way. In order for these embedded objects to call the implementation in the "outer object", a back-pointer is used (m_pParent). The m_pParent pointer is initialized during the CEditPrintObj constructor. Then you would implement CEditPrintObj::CPrintObj::PrintObject and CEditPrintObj::CEditObj::EditObject as well. Quite a bit of code was added to add one feature — the ability to edit the object. Fortunately, it is quite uncommon for interfaces to have only a single member function (although it does happen) and in this case, EditObject and PrintObject would usually be combined into a single interface. That's a lot of explanation and a lot of code for such a simple scenario. The MFC/OLE classes provide a simpler alternative. The MFC implementation uses a technique similar to the way Windows messages are wrapped with Message Maps. This facility is called Interface Maps and is discussed in the next section. MFC Interface Maps MFC/OLE includes an implementation of "Interface Maps" similar to MFC's "Message Maps" and "Dispatch Maps" in concept and execution. The core features of MFC's Interface Maps are as follows: A standard implementation of IUnknown, built into the CCmdTarget class. Maintenance of the reference count, modified by AddRef and Release Data driven implementation of QueryInterface In addition, interface maps support the following advanced features: Support for creating aggregatable COM objects Support for using aggregate objects in the implementation of a COM object The implementation is hookable and extensible For more information on aggregation, see the OLE Programmer's Reference. MFC's interface map support is rooted in the CCmdTarget class. CCmdTarget "has-a" reference count as well as all the member functions associated with the IUnknown implementation (the reference count for example is in CCmdTarget). To create a class that supports OLE COM, you derive a class from CCmdTarget and use various macros as well as member functions of CCmdTarget to implement the desired interfaces. MFC's implementation uses nested classes to define each interface implementation much like the example above. This is made easier with a standard implementation of IUnknown as well as a number of macros that eliminate some of the repetitive code. Interface Map Basics To implement a class using MFC's interface maps follow these steps: Derive a class either directly or indirectly from CCmdTarget. Use the DECLARE_INTERFACE_MAP function in the derived class definition. For each interface you wish to support, use the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros in the class definition. In the implementation file, use the BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros to define the class's interface map. For each IID supported, use the INTERFACE_PART macro between the BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros to map that IID to a specific "part" of your class. Implement each of the nested classes that represent the interfaces you support. Use the METHOD_PROLOGUE macro to access the parent, CCmdTarget-derived object. AddRef, Release, and QueryInterface can delegate to the CCmdTarget implementation of these functions (ExternalAddRef, ExternalRelease, and ExternalQueryInterface). The CPrintEditObj example above could be implemented as follows: class CPrintEditObj : public CCmdTarget { public: // member data and member functions for CPrintEditObj go here // Interface Maps protected: DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(EditObj, IEditInterface) STDMETHOD_(void, EditObject)(); END_INTERFACE_PART(EditObj) BEGIN_INTERFACE_PART(PrintObj, IPrintInterface) STDMETHOD_(void, PrintObject)(); END_INTERFACE_PART(PrintObj) }; The above declaration creates a class derived from CCmdTarget. The DECLARE_INTERFACE_MAP macro tells the framework that this class will have a custom interface map. In addition, the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros define nested classes, in this case with names CEditObj and CPrintObj (the X is used only to differentiate the nested classes from global classes which start with "C" and interface classes which start with "I"). Two nested members of these classes are created: m_CEditObj, and m_CPrintObj, respectively. The macros automatically declare the AddRef, Release, and QueryInterface functions; therefore you only declare the functions specific to this interface: EditObject and PrintObject (the OLE macro STDMETHOD is used such so that _stdcall and virtual keywords are provided as appropriate for the target platform). To implement the interface map for this class: BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget) INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj) INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj) END_INTERFACE_MAP() This connects the IID_IPrintInterface IID with m_CPrintObj and IID_IEditInterface with m_CEditObj respectively. The CCmdTarget implementation of QueryInterface (CCmdTarget::ExternalQueryInterface) uses this map to return pointers to m_CPrintObj and m_CEditObj when requested. It is not necessary to include an entry for IID_IUnknown; the framework will use the first interface in the map (in this case, m_CPrintObj) when IID_IUnknown is requested. Even though the BEGIN_INTERFACE_PART macro automatically declared the AddRef, Release and QueryInterface functions for you, you still need to implement them: ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef() { METHOD_PROLOGUE(CEditPrintObj, EditObj) return pThis->ExternalAddRef(); } ULONG FAR EXPORT CEditPrintObj::XEditObj::Release() { METHOD_PROLOGUE(CEditPrintObj, EditObj) return pThis->ExternalRelease(); } HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface( REFIID iid, void FAR* FAR* ppvObj) { METHOD_PROLOGUE(CEditPrintObj, EditObj) return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj); } void FAR EXPORT CEditPrintObj::XEditObj::EditObject() { METHOD_PROLOGUE(CEditPrintObj, EditObj) // code to "Edit" the object, whatever that means... } The implementation for CEditPrintObj::CPrintObj, would be similar to the above definitions for CEditPrintObj::CEditObj. Although it would be possible to create a macro that could be used to automatically generate these functions (as a matter of fact, earlier in the MFC/OLE development this was the case), it becomes difficult to set break points when a macro generates more than one line of code. For this reason, this code is expanded manually. By using the framework implementation of message maps there are a number of things that weren't necessary to do: Implement QueryInterface Implement AddRef and Release Declare either of these built-in methods on both of your interfaces In addition, the framework uses message maps internally. This allows you to derive from a framework class, say COleServerDoc, that already supports certain interfaces and provides either replacements or additions to the interfaces provided by the framework. This is enabled by the fact that the framework fully supports inheriting an interface map from a base class — that is the reason why BEGIN_INTERFACE_MAP takes as its second parameter the name of the base class. Note It is generally not possible to reuse the implementation of MFC's built-in implementations of the OLE interfaces by inheriting the embedded specialization of that interface from the MFC version. This is not possible because the use of the METHOD_PROLOGUE macro to get access to the containing CCmdTarget-derived object implies a fixed offset of the embedded object from the CCmdTarget-derived object. This means, for example, you cannot derive an embedded XMyAdviseSink from MFC's implementation in COleClientItem::XAdviseSink, because XAdviseSink relies on being at a specific offset from the top of the COleClientItem object. You can, however, delegate to the MFC implementation for all of the functions that you want MFC's default behavior. This is done in the MFC implementation of IOleInPlaceFrame (XOleInPlaceFrame) in the COleFrameHook class (it delegates to m_xOleInPlaceUIWindow for many functions). This design was chosen to reduce the runtime size of objects which implement many interfaces; it eliminates the need for a back-pointer (such as the way m_pParent was used in the previous section). Aggregation and Interface Maps In addition to supporting stand-alone COM objects, MFC also supports aggregation. Aggregation itself is too complex a topic to discuss here; refer to the OLE Programmer's Reference for more information on aggregation. This note will simply describe the support for aggregation built into the framework and interface maps. There are two ways to use aggregation: (1) using a COM object that supports aggregation, and (2) implementing an object that can be aggregated by another. These capabilities can be referred to as "using an aggregate object" and "making an object aggregatable". MFC supports both. Using an Aggregate Object To use an aggregate object, there needs to be some way to tie the aggregate into the QueryInterface mechanism. In other words, the aggregate object must behave as though it is a native part of your object. So how does this tie into MFC's interface map mechanism? In addition to the INTERFACE_PART macro, where a nested object is mapped to an IID, you can also declare an aggregate object as part of your CCmdTarget derived class. To do so, the INTERFACE_AGGREGATE macro is used. This allows you to specify a member variable (which must be a pointer to an IUnknown or derived class), which is to be integrated into the interface map mechanism. If the pointer is not NULL when CCmdTarget::ExternalQueryInterface is called, the framework will automatically call the aggregate object's QueryInterface member function, if the IID requested is not one of the native IIDs supported by the CCmdTarget object itself. To use the INTERFACE_AGGREGATE macro, follow these steps: Declare a member variable (an IUnknown*) which will contain a pointer to the aggregate object. Include an INTERFACE_AGGREGATE macro in your interface map, which refers to the member variable by name. At some point (usually during CCmdTarget::OnCreateAggregates), initialize the member variable to something other than NULL. For example, class CAggrExample : public CCmdTarget { public: CAggrExample(); protected: LPUNKNOWN m_lpAggrInner; virtual BOOL OnCreateAggregates(); DECLARE_INTERFACE_MAP() // "native" interface part macros may be used here }; CAggrExample::CAggrExample() { m_lpAggrInner = NULL; } BOOL CAggrExample::OnCreateAggregates() { // wire up aggregate with correct controlling unknown m_lpAggrInner = CoCreateInstance(CLSID_Example, GetControllingUnknown(), CLSCTX_INPROC_SERVER, IID_IUnknown, (LPVOID*)&m_lpAggrInner); if (m_lpAggrInner == NULL) return FALSE; // optionally, create other aggregate objects here return TRUE; } BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget) // native "INTERFACE_PART" entries go here INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner) END_INTERFACE_MAP() The m_lpAggrInner is initialized in the constructor to NULL. The framework will ignore a NULL member variable in the default implementation of QueryInterface. OnCreateAggregates is a good place to actually create your aggregate objects. You'll have to call it explicitly if you are creating the object outside of the MFC implementation of COleObjectFactory. The reason for creating aggregates in CCmdTarget::OnCreateAggregates as well as the usage of CCmdTarget::GetControllingUnknown will become apparent when creating aggregatable objects is discussed. This technique will give your object all of the interfaces that the aggregate object supports plus its native interfaces. If you only want a subset of the interfaces that the aggregate supports, you can override CCmdTarget::GetInterfaceHook. This allows you very low level hookability, similar to QueryInterface. Usually, you want all the interfaces that the aggregate supports. Making an Object Implementation Aggregatable For an object to be aggregatable, the implementation of AddRef, Release, and QueryInterface must delegate to a "controlling unknown." In other words, for it to be part of the object, it must delegate AddRef, Release, and QueryInterface to a different object, also derived from IUnknown. This "controlling unknown" is provided to the object when it is created, that is, it is provided to the implementation of COleObjectFactory. Implementing this carries a small amount of overhead, and in some cases is not desirable, so MFC makes this optional. To enable an object to be aggregatable, you call CCmdTarget::EnableAggregation from the object's constructor. If the object also uses aggregates, you must also be sure to pass the correct "controlling unknown" to the aggregate objects. Usually this IUnknown pointer is passed to the object when the aggregate is created. For example, the pUnkOuter parameter is the "controlling unknown" for objects created with CoCreateInstance. The correct "controlling unknown" pointer can be retrieved by calling CCmdTarget::GetControllingUnknown. The value returned from that function, however, is not valid during the constructor. For this reason, it is suggested that you create your aggregates only in an override of CCmdTarget::OnCreateAggregates, where the return value from GetControllingUnknown is reliable, even if created from the COleObjectFactory implementation. It is also important adding or releasing artificial ExternalAddRef and ExternalRelease call InternalRelease that the object manipulate the correct reference count when reference counts. To ensure this is the case, always call instead of InternalRelease and InternalAddRef. It is rare to or InternalAddRef on a class that supports aggregation. Reference Material Advanced usage of OLE, such as defining your own interfaces or overriding the framework's implementation of the OLE interfaces requires the use of the underlying interface map mechanism. This section discusses each macro and the APIs which is used to implement these advanced features. CCmdTarget::EnableAggregation — Function Description void EnableAggregation(); Note Call this function in the constructor of the derived class if you wish to support OLE aggregation for objects of this type. This prepares a special IUnknown implementation that is required for aggregatable objects. CCmdTarget::ExternalQueryInterface — Function Description DWORD ExternalQueryInterface(const void FAR* lpIID, LPVOID FAR* ppvObj); lpIID A far pointer to an IID (the first argument to QueryInterface) ppvObj A pointer to an IUnknown* (second argument to QueryInterface) Note Call this function in your implementation of IUnknown for each interface your class implements. This function provides the standard data-driven implementation of QueryInterface based on your object's interface map. It is necessary to cast the return value to an HRESULT. If the object is aggregated, this function will call the "controlling IUnknown" instead of using the local interface map. CCmdTarget::ExternalAddRef — Function Description DWORD ExternalAddRef(); Note Call this function in your implementation of IUnknown::AddRef for each interface your class implements. The return value is the new reference count on the CCmdTarget object. If the object is aggregated, this function will call the "controlling IUnknown" instead of manipulating the local reference count. CCmdTarget::ExternalRelease — Function Description DWORD ExternalRelease(); Note Call this function in your implementation of IUnknown::Release for each interface your class implements. The return value indicates the new reference count on the object. If the object is aggregated, this function will call the "controlling IUnknown" instead of manipulating the local reference count. DECLARE_INTERFACE_MAP — Macro Description DECLARE_INTERFACE_MAP Note Use this macro in any class derived from CCmdTarget that will have an interface map. Used in much the same way as DECLARE_MESSAGE_MAP. This macro invocation should be placed in the class definition, usually in a header (.H) file. A class with DECLARE_INTERFACE_MAP must define the interface map in the implementation file (.CPP) with the BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros. BEGIN_INTERFACE_PART and END_INTERFACE_PART — Macro Descriptions BEGIN_INTERFACE_PART(localClass, iface); END_INTERFACE_PART(localClass) localClass The name of the class that implements the interface iface The name of the interface that this class implements Note For each interface that your class will implement, you need to have a BEGIN_INTERFACE_PART and END_INTERFACE_PART pair. These macros define a local class derived from the OLE interface that you define as well as an embedded member variable of that class. The AddRef, Release, and QueryInterface members are declared automatically. You must include the declarations for the other member functions that are part of the interface being implemented (those declarations are placed between the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros). The iface argument is the OLE interface that you wish to implement, such as IAdviseSink, or IPersistStorage (or your own custom interface). The localClass argument is will automatically be prepended collisions with global classes of the the same as the localClass the name of the local class that will be defined. An 'X' to the name. This naming convention is used to avoid same name. In addition, the name of the embedded member, name except it is prefixed by 'm_x'. For example: BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink) STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM); STDMETHOD_(void,OnViewChange)(DWORD, LONG); STDMETHOD_(void,OnRename)(LPMONIKER); STDMETHOD_(void,OnSave)(); STDMETHOD_(void,OnClose)(); END_INTERFACE_PART(MyAdviseSink) would define a local class called XMyAdviseSink derived from IAdviseSink, and a member of the class in which it is declared called m_xMyAdviseSink.Note: Note The lines beginning with STDMETHOD_ are essentially copied from OLE2.H and modified slightly. Copying them from OLE2.H can reduce errors that are hard to resolve. BEGIN_INTERFACE_MAP and END_INTERFACE_MAP — Macro Descriptions BEGIN_INTERFACE_MAP(theClass, baseClass) END_INTERFACE_MAP theClass The class in which the interface map is to be defined baseClass The class from which theClass derives from. Remarks: The BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros are used in the implementation file to actually define the interface map. For each interface that is implemented there is one or more INTERFACE_PART macro invocations. For each aggregate that the class uses, there is one INTERFACE_AGGREGATE macro invocation. INTERFACE_PART — Macro Description INTERFACE_PART(theClass, iid, localClass) theClass The name of the class which contains the interface map. iid The IID which is to be mapped to the embedded class. localClass The name of the local class (less the 'X') Note This macro is used between the BEGIN_INTERFACE_MAP macro and the END_INTERFACE_MAP macro for each interface your object will support. It allows you to map an IID to a member of the class indicated by theClass and localClass. The 'm_x' will be added to the localClass automatically. Note that more than one IID may be associated with a single member. This is very useful when you are implementing only a "most derived" interface and wish to provide all intermediate interfaces as well. A good example of this is the IOleInPlaceFrameWindow interface. Its hierarchy looks like this: IUnknown IOleWindow IOleUIWindow IOleInPlaceFrameWindow If an object implements IOleInPlaceFrameWindow, a client may QueryInterface on any of these interfaces: IOleUIWindow, IOleWindow, or IUnknown, besides the "most derived" interface IOleInPlaceFrameWindow (the one you are actually implementing). To handle this you can use more than one INTERFACE_PART macro to map each and every base interface to the IOleInPlaceFrameWindow interface: in the class definition file: BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow) in the class implementation file: BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd) INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow) INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow) INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow) END_INTERFACE_MAP The framework takes care of IUnknown since it is always required. INTERFACE_PART — Macro Description INTERFACE_AGGREGATE(theClass, theAggr) theClass The name of the class which contains the interface map, theAggr The name of the member variable which is to be aggregated. Note This macro is used to tell the framework that the class is using an aggregate object. It must appear between the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros. An aggregate object is a separate object, derived from IUnknown. By using an aggregate and the INTERFACE_AGGREGATE macro, you can make all the interfaces that the aggregate supports appear to be directly supported by the object. The theAggr argument is simply the name of a member variable of your class which is derived from IUnknown (either directly or indirectly). All INTERFACE_AGGREGATE macros must follow the INTERFACE_PART macros when placed in an interface map. Technical Notes by Number | Technical Notes by Category ////////////////////////////////////////// /****** Interface Declaration ***********************************************/ /* * * * These are macros for declaring interfaces. They exist so that a single definition of the interface is simulataneously a proper declaration of the interface structures (C++ abstract classes) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * for both C and C++. DECLARE_INTERFACE(iface) is used to declare an interface that does not derive from a base interface. DECLARE_INTERFACE_(iface, baseiface) is used to declare an interface that does derive from a base interface. By default if the source file has a .c extension the C version of the interface declaratations will be expanded; if it has a .cpp extension the C++ version will be expanded. if you want to force the C version expansion even though the source file has a .cpp extension, then define the macro "CINTERFACE". eg. cl -DCINTERFACE file.cpp Example Interface declaration: #undef INTERFACE #define INTERFACE IClassFactory DECLARE_INTERFACE_(IClassFactory, IUnknown) { // *** IUnknown methods *** STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // *** IClassFactory methods *** STDMETHOD(CreateInstance) (THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppvObject) PURE; }; Example C++ expansion: struct FAR IClassFactory : public IUnknown { virtual HRESULT STDMETHODCALLTYPE QueryInterface( IID FAR& riid, LPVOID FAR* ppvObj) = 0; virtual HRESULT STDMETHODCALLTYPE AddRef(void) = 0; virtual HRESULT STDMETHODCALLTYPE Release(void) = 0; virtual HRESULT STDMETHODCALLTYPE CreateInstance( LPUNKNOWN pUnkOuter, IID FAR& riid, LPVOID FAR* ppvObject) = 0; }; NOTE: Our documentation says '#define interface class' but we use 'struct' instead of 'class' to keep a lot of 'public:' lines out of the interfaces. The 'FAR' forces the 'this' pointers to be far, which is what we need. Example C expansion: typedef struct IClassFactory * * * * * * * * * * * * * * * * * * * * * * * */ { const struct IClassFactoryVtbl FAR* lpVtbl; } IClassFactory; typedef struct IClassFactoryVtbl IClassFactoryVtbl; struct IClassFactoryVtbl { HRESULT (STDMETHODCALLTYPE * QueryInterface) ( IClassFactory FAR* This, IID FAR* riid, LPVOID FAR* ppvObj) ; HRESULT (STDMETHODCALLTYPE * AddRef) (IClassFactory FAR* This) ; HRESULT (STDMETHODCALLTYPE * Release) (IClassFactory FAR* This) ; HRESULT (STDMETHODCALLTYPE * CreateInstance) ( IClassFactory FAR* This, LPUNKNOWN pUnkOuter, IID FAR* riid, LPVOID FAR* ppvObject); HRESULT (STDMETHODCALLTYPE * LockServer) ( IClassFactory FAR* This, BOOL fLock); }; MFC MFC ist eine Abkürzung für Microsoft Foundation Class Library. MFC kapselt mit C++ einen Teil der umfangreiche Windows API-Schnittstelle, die in C programmiert wurde. MFC-Klassen-Bibliothek ist eine ( "dünne" ) Software-Schicht über der API-Schnittstelle ( WOSA: Windows Open Services Architecture APIs ) und unterstützt z.B. die ( Framework- ) Programmierung von Windows-Applikationen mit Dialog boxes, Device Contexts, Common GDI Objekte. Das Arbeiten mit dem Gerüst der Die Microsoft Foundation Class Library (MFC) basiert auf einigen Hauptklassen ( CObject, CWnd, ... ). Die Klassen kapseln einen großen Teil des Application Programming Interface (Win32-APIs). Anstelle von HINSTANCE hInst = GetModuleHandle(0) wird nun z.B. HINSTANCE hInst = AfxGetInstanceHandle() verwendet. Anstelle von RegisterClass() wird nun AfxRegisterWndClass (UINT nClassStyle,HCURSOR hCursor,HBRUSH hbrBackground, HICON hIcon) verwendet. Anstelle von WM_CREATE-Einträgen in der CALLBACK-Funktion wird ( automatisch ) PreCreateWindow(CREATESTRUCT& cs) aufgerufen. Andere Klassen kapseln Anwendungskonzepte wie Dokumente, Ansichten und die Anwendung, sowie OLE-Funktionen und ODBC- und DAO-Datenzugriffe. Das Win32-Konzept eines Fensters wird z. B. durch die MFC-Klasse CWnd eingekapselt. ● ● ● ● Die CWnd-Klasse kapselt die internen Win32-API-Daten, -Funktionen für ein Windows-Fenster. Die CDialog-Klasse kapselt die Win32-Dialogfelder. Die Member-Funktionen der Klasse haben meistens ähnliche ( denselben ) Namen wie die Win32-Funktion. Beispiel: LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 ); Wegen der Ausführungsgeschwindigkeit werden zahlreiche Macros benutzt ( z.B. afx.h: DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_SERIAL, IMPLEMENT_SERIAL, usw. ) Für die Entwicklung der Klassen-Bibliothek gab es die folgenden Richtlinien: ● Ausführungsgeschwindigkeit höchstens 5% geringer als bei C-Language Win-API ● Entwickler können Win-API-Functionen ( an bel. Stelle ) direkter aufrufen ( global scoping operator ::, wie z.B. ::GetSystemMetrics ) ● Geringer Nativ-Code-Overhead ● Einfache Konvertierung von existierenden C-Programmen nach C++/MFC ● Quelltext-Generatoren mit Kommentaren für Constructors, Attributes, Operations, Overridables, Implementation. Die //{{...//}} Klammerung dient als Positionsangabe zum Einfügen/Entfernen von Mapping-Makros ( z.B. ON_WM_SETFOCUS() ) durch den Klassen-Assistenten //{{AFX_MSG_MAP(CMainFrame) ON_WM_SETFOCUS() //}}AFX_MSG_MAP ● Vereinfachung der Windows-Programmierung, geringe Einarbeitungszeit ( Achtung! Trotz vieler on-line-Hilfen, Class Library Reference, MFC Technical Notes, MFC-specific articles, Visual C++ Programmer’s Guide, MFC Samples and Tutorials, , Quelltext-Generatoren, Werzeugen, usw. darf die Einarbeitungszeit nicht unterschätzt werden ) MFC hat wenige abstrakte Basis-Klassen ( CObject, CCmdTarget ). MFC benutz 2 klassen-Typen: "value"-Klassen ( kapseln eine Struktur, wie z.B. Strings oder Koordinaten, CPoint vereinfacht die Benutzung der vorhandenen API-Funktionalität ) "framework"-Klassen ( abgeleitet von CObject, z.T. "dünne" Kapselung der Windows-Funktionalität ). Value- gegenüber Framework-Klassen Characteristics Value Framework Hat eine virtual Funktion? Nein Ja Ist eine Basis-Klasse? Nein CObject derived Kann direkt benutzt werden? Ja Maybe Kann abgeleitet werden? Nein Ja Hat einen "="-Operator? meist Nein Hat einen Copy-Konstruktor? meist Nein Wirkt wie ein eingebauter Type? meist Nein Vergleich möglich? Usually Nein Vergleichsreferenz möglich? Nein Ja (Addresse ist identisch) MFC-Schreibweise MFC verwendet eine General Prefix Naming Conventions ( vereinfacht ungarische Notation ). Die Klassen enthalten als Member-Variable u.a. Daten vom Typ HWND. CWnd::m_hWnd, and an accessor function, CWnd::GetSafeHwnd. Static member Variablen ( Klassen-Variablen ) haben einen "global class namespace" und werden ohne Prefix verwendet. Prefix Prefix: C Type: Class or structure Example: CDocument, CPrintInfo Prefix: m_ Type: Member variable Example: m_pDoc, m_nCustomers Gegenüberstellung Value-Objekte Value-Übergabe void Do(CMyValue val); ( wenige Bytes ) Framework-Objekte Referenz-Übergabe void Do( const CMyValue& val ); ( umfangreiche Size ) Value-Objekte Framework-Objekten benutzen void GetSomething( CMyValue* pval ); benutzen void Do( const CMyView* pob ); non-const Zeiger const Zeiger-Übergabe return-Werte eines CMyValue GetCurrentValue(); Value-Objektes return-Werte eines CMyView* GetCurrentView(); Framework-Objektes Hinweise zur Programmierung Overloading-Operatoren und Copy-Konstructoren sollten vermieden werden ( insbesondere bei Framework-Klassen ). Falls dennoch erforderlich, so sollte der CopyKonstructor vom Argument "const classname&" sein. Beispiel für CWND_Member-Funktion Die internen Fensterdaten werden bei der Klasse CWnd mit der API-Funktion CreateEx() angelegt. Die Klasse CWnd entspricht eine "Wrapper"-Funktion Create bzw. CreateEx ( wincore.cpp ): BOOL CWnd:: CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam /* = NULL */) { return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam); } // überladen: BOOL CWnd:: CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) { // allow modification of several common create parameters CREATESTRUCT cs; cs.dwExStyle = dwExStyle; cs.style = dwStyle; cs.lpszClass = lpszClassName; cs.lpszName = lpszWindowName; cs.x = x; cs.cx = nWidth; cs.y = y; cs.cy = nHeight; cs.hwndParent = hWndParent; cs.hMenu = nIDorHMenu; cs.hInstance = AfxGetInstanceHandle(); cs.lpCreateParams = lpParam; if (!PreCreateWindow(cs)){PostNcDestroy();return FALSE;} AfxHookWindowCreate(this); HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); #ifdef _DEBUG if (hWnd==NULL){ TRACE1("Warning: creation failed:GetLastError 0x%8.8X\n",GetLastError()); } #endif if (!AfxUnhookWindowCreate())PostNcDestroy(); if (hWnd == NULL)return FALSE; ASSERT(hWnd == m_hWnd); // should have been set in send msg hook return TRUE; } // auch: BOOL CWnd:: Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { // can't use for desktop or pop-up windows(use CreateEx instead) ASSERT(pParentWnd != NULL); ASSERT((dwStyle & WS_POPUP) == 0); return CreateEx(0, lpszClassName, lpszWindowName, dwStyle | WS_CHILD, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext); } Anstelle von HINSTANCE hInst = GetModuleHandle(0) wird nun HINSTANCE hInst = AfxGetInstanceHandle() verwendet. Anstelle von RegisterClass() wird nun AfxRegisterWndClass (UINT nClassStyle,HCURSOR hCursor,HBRUSH hbrBackground, HICON hIcon) verwendet. Anstelle von WM_CREATE-Einträgen wird PreCreateWindow(CREATESTRUCT& cs) Die folgende, überladene CreateEx-Funktion zeigt, wie sog. "Hooks" eingebaut werden: CArray-Beispiel // Fehlerhaft ist: CArray myarray1; CArray myarray2; ... (insertion of data) myarray1 = myarray2; // erlaubt ist CArray myarray1; CArray myarray2; ... (insertion of data) myarray2.RemoveAll(); myarray2.Append(myarray1); Handles und MFC * Die meisten OLE-Daten-Typen sind als COle-Variant class "gewrapped". Andere MFC Klassen benutzen COleVariant ( COleDateTime, COleDateTimeSpan, COleCurrency ). 1 GDI-Objekte werden meist als lokale Variablen auf dem Stack-Frame angelegt ( z.B. CPen pen; ). 2 Controls werden meist zusammen mit dem Parent-Window angelegt. Enthält z.B. ein CDialog ein CButton-Object, so wird ides als CButton m_button; deklariert. Abhängigkeiten zwischen MFC- und Windows Handles, Controls, Strukturen Windows Type Example Variable MFC Class Example Object HWND hWnd; CWnd* pWnd; HDLG hDlg; CDialog* pDlg; CDC* pDC; CGdiObject* pGdiObj; CPen* pPen;1 HBRUSH hBrush; CBrush* pBrush;1 HFONT hFont; CFont* pFont;1 HBITMAP hBitmap; CBitmap* pBitmap;1 HPALETTE hPalette; CPalette* pPalette;1 CRgn* pRgn;1 HMENU hMenu; CMenu* pMenu;1 HWND hCtl; CStatic* pStatic;2 HWND hCtl; CButton* pBtn;2 HWND hCtl; CEdit* pEdit;2 HWND hCtl; CListBox* pListBox;2 HWND hCtl; CComboBox* pComboBox;2 HWND hCtl; CScrollBar* pScrollbar;2 CString pStr;2 CPoint pt; HDC hDC; HGDIOBJ hGdiObj; HPEN hPen; HRGN hRgn; HSZ hszStr; POINT pt; SIZE size; CSize size; RECT rect; CRect rect; MFC-Klassenhirachie Die MFC-Klassen-Deklarationen sind in stdafx.h enthalten. stdafx.h verwendet als MFC-Kern- und -Standardkomponenten afxwin.h. In afxwin.h sind die folgenden Klassen deklariert: class CSize; class CPoint; class CRect; class CGdiObject; class CPen; class CBrush; class CFont; class CBitmap; class CPalette; class CRgn; // // // // // // // CDC drawing tool a pen / HPEN wrapper a brush / HBRUSH wrapper a font / HFONT wrapper a bitmap / HBITMAP wrapper a palette / HPALLETE wrapper a region / HRGN wrapper class CDC; class CClientDC; class CWindowDC; class CPaintDC; // // // // a Display Context / HDC wrapper CDC for client of window CDC for entire window embeddable BeginPaint struct helper class CMenu; // a menu / HMENU wrapper class CCmdTarget; // a target for user commands class CWnd; class CDialog; // a window / HWND wrapper // a dialog // standard windows controls class CStatic; // Static control class CButton; // Button control class CListBox; // ListBox control class CCheckListBox; // special listbox with checks class CComboBox; // ComboBox control class CEdit; // Edit control class CScrollBar; // ScrollBar control // frame windows class CFrameWnd; class CMDIFrameWnd; class CMDIChildWnd; class CMiniFrameWnd; // // // // // views on a document class CView; class CScrollView; // a view on a document // a scrolling view class CWinThread; class CWinApp; standard SDI frame standard MDI frame standard MDI child half-height caption frame wnd // thread base class // application base class class CDocTemplate; // template for document creation class CSingleDocTemplate;// SDI support class CMultiDocTemplate; // MDI support class CDocument; // main document abstraction //CObject //CException //CSimpleException class CResourceException;// Win resource failure exception class CUserException; // Message Box alert and stop operation // Helper classes: class CCmdUI; // Menu/button enabling class CDataExchange; // Data exchange and validation context class CCommandLineInfo; // CommandLine parsing helper class CDocManager; // CDocTemplate manager object Nachrichten und MFC MFC verwendet Tabellen, um die Funktionszeiger von auszuführenden Funktionen zu hinterlegen. Ein Tabelleneintrag enthält die Nachricht ( z.B. WM_...) und die auszuführenden Funktionen. Mit struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) }; wird BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) aufgelöst gemäss: BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_SETFOCUS(), ON_WM_.... END_MESSAGE_MAP() // AFX_MSGMAP_ENTRY CMainFrame::_messageEntries[] = {{WM_SETFOCUS,0,0,0,AfxSig_vW,(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(CWnd*))&OnSetFocus }, ... //END_MESSAGE_MAP() wird aufgelöst in: {0,0,0,0, AfxSig_end, (AFX_PMSG)0 }}; Eine separate CALLBACK-Funktion ist nicht nötig, weil zum Verteilen der Nachrichten die Klasse CWnd verwendet wird. Die Funktion nWndMsg() ruft z.B. bei WM_COMMAND OnCommand(wParam, lParam)) auf. BOOL CWnd::OnWndMsg (UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { LRESULT lResult = 0; if (message == WM_COMMAND){ if (OnCommand(wParam, lParam)){ lResult = 1; goto LReturnTrue; } return FALSE; } if (message == WM_NOTIFY){ NMHDR* pNMHDR = (NMHDR*)lParam; if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult)) goto LReturnTrue; return FALSE; } if (message == WM_ACTIVATE) _AfxHandleActivate(this,wParam, CWnd::FromHandle((HWND)lParam)); if (message == WM_SETCURSOR && _AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam))){ lResult = 1;goto LReturnTrue; } const AFX_MSGMAP* pMessageMap = GetMessageMap(); UINT iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1); AfxLockGlobals(CRIT_WINMSGCACHE); AFX_MSG_CACHE* pMsgCache = &_afxMsgCache[iHash];... AfxUnlockGlobals(CRIT_WINMSGCACHE); for (pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap) { // Note: catch not so common but fatal mistake!! // BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd) // registered windows message lpEntry = pMessageMap->lpEntries; while ((lpEntry = AfxFindMessageEntry(lpEntry,0xC000,0,0)) != NULL){ UINT* pnID = (UINT*)(lpEntry->nSig); ... lpEntry++; } return FALSE; LDispatch: union MessageMapFunctions mmf; mmf.pfn = lpEntry->pfn; switch (nSig){ // lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam)); case AfxSig_vw: (this->*mmf.pfn_vw)(wParam);break; case AfxSig_bb: ... case AfxSig_bD: ... case AfxSig_bWww: ... case AfxSig_bWCDS: .case AfxSig_bHELPINFO: ... case AfxSig_hDWw: case AfxSig_hDw: case AfxSig_iwWw: ... case AfxSig_iww: case AfxSig_iWww: case AfxSig_is: ... case AfxSig_lwl: case AfxSig_lwwM: case AfxSig_vv:... case AfxSig_vww: case AfxSig_vvii: case AfxSig_vwww: case AfxSig_vwii: case AfxSig_vwl: case AfxSig_vbWW: case AfxSig_vD: case AfxSig_vM: case AfxSig_vMwb: case AfxSig_vW: case AfxSig_vW2: case AfxSig_vWww: case AfxSig_vWp: case AfxSig_vWh: case AfxSig_vwW: case AfxSig_vwWb: case AfxSig_vwwW: case AfxSig_vwwx: case AfxSig_vs: case AfxSig_vws: case AfxSig_vOWNER: case AfxSig_iis: case AfxSig_wp: case AfxSig_wv: case AfxSig_vCALC: case AfxSig_vPOS: case AfxSig_vwwh: case AfxSig_vwp: case AfxSig_vwSIZING:case AfxSig_bwsp: default:break; } goto LReturnTrue; LDispatchRegistered: // for registered windows messages ASSERT(message >= 0xC000); mmf.pfn = lpEntry->pfn; lResult = (this->*mmf.pfn_lwl)(wParam, lParam); LReturnTrue: if (pResult != NULL)*pResult = lResult; return TRUE; } Die DefWindowProc() der Klasse CWnd kann auch Super- und Subclassing von CALLBACK-Funktionen handhaben: LRESULT CWnd:: DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam) { if (m_pfnSuper != NULL) return ::CallWindowProc(m_pfnSuper,m_hWnd,nMsg,wParam,lParam); WNDPROC pfnWndProc; if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL) return ::DefWindowProc(m_hWnd,nMsg,wParam,lParam); else return ::CallWindowProc(pfnWndProc,m_hWnd,nMsg,wParam,lParam); } Hinweise zum Übersezungsvorgang Die folgende Tabelle gibt Konfigurationsmakros ( Linker ) an: Konfigurationsmakros ( Linker ) _AFXDLL Stand-alone dynamic-link library (DLL) version _DEBUG Debug version including diagnostics _MBCS Compilation for multi-byte character sets Macro-Name Macro-Typ _UNICODE Enables Unicode in an application AFXAPI Function provided by MFC WINAPI Function provided by Windows CALLBACK Function called back via pointer Der Linker kann unterschiedliche Bibliotheken ( z.B. Static- Library, Versionen ) binden. NAFXCWD.LIB ist eine Debug version: MFC Static Link Library UAFXCWD.LIB ist eine Debug version: MFC Static Link Library with Unicode support NAFXCW.LIB ist eine Release version: MFC Static Link Library UAFXCW.LIB ist eine Release version: MFC Static Link Library with Unicode support Mit der #pragma comment(lib, "...") -Präprozessor-Direktive kann der Übersetzungsvorgang gesteuert werden: #ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, #else #pragma comment(lib, #endif #else #ifdef _DEBUG #pragma comment(lib, #else #pragma comment(lib, #endif #endif "nafxcwd.lib") "nafxcw.lib") "uafxcwd.lib") "uafxcw.lib") 1. Praktikum Diese Aufgabe besteht aus den folgenden Teilen. 1. Es ist eine einfache Console-Applikation zu erstellen, mit der einige Tests durchzuführen sind. 2. Die Definition von Windows-Datentypen ist mit Hilfe einer Console-Applikation und freopen() zu untersuchen 3. Es sind die unten angegebenen Tests durchzuführen und die Macros, Datentypen, Zeiger zu verstehen: ❍ windows.h definiert zahlreiche Typen ( siehe z.B. windef.h ). Welche typedef's sind richtig? typedef typedef typedef typedef typedef typedef typedef char *LPSTR; unsigned int *PUINT; long BOOL; unsigned char BYTE; unsigned long DWORD; unsigned short WORD; unsigned int UINT; 4. Wieviele Byte belegen im Win32-Programmiermodell die Datentypen long, unsigned long, float, double, signed short, unsigned short, char, signed char, bool? Erklären sie dies bitte im Zusammenhang mit der Hardware-Archtektur von Dadatypen. 5. Welche Änderungen ergeben sich mit #define UNICODE für String und Char? 6. Das Windows-System ist im Überblick zu quantifizieren ( *.exe, *.dll-Files, *.dll-Funktionen ) ❍ In welchem absoluten Pfad befinden sich *.dll-Files des Betriebssystems? ❍ Wieviele *.exe-Files gehören etwa zu dem benutzten Windows-System? ❍ Wieviele *.dll-Files gehören etwa zu dem benutzten Windows-System? ❍ Wieviele Funktionen enthält eine *.dll im Mittel? ❍ Für die C,C++-Programmentwicklung werden *.h-Files benötigt. In welchem Verzeichnis befinden sich die *.h-Files? ❍ Wieviele *.h-Files gehören zu der verwendeten C++-Entwicklungsumgebung? Hinweise Hinweise zum MS-Studio-Bedienung 1. Studie-Menu: Datei Neu Projekt Win32ConsoleAnwendung Projetname: myauf01 Pfad : d:\temp\my... (x) Neuen Arbeitsbereich erstellen 2. Studie-Menu: Datei Neu Dateien C++-Quellcodedatei [x] dem Projekt hinzufügen Dateiname: myauf01 Pfad : d:\temp\my... Mit der rechten Maustaste auf dem grauen Fenster-Rand können die benötigten Hilfsfenster aktiviert werden: Ausgabe-Fenster ( für die Übersetzungsfehler ) Minileiste-Erstellen ( zum Compilieren, Linken, Starten ) Arbeitsbereich ( für Klassen und Dateien ) Console-Applikation Zum Ausführen von Tests ist eine Console-Applikation zu erstellen. #include <stdio.h> #include <windows.h> void main() { printf("sizeof(PSZ) } =%d\n", sizeof(PSZ)); Tests zu Macros,Datentypen, Zeigern Macros können z.B. definiert werden gemäss: #define my_tolower(_c) ( (_c)-'A'+'a' ) #define my_toupper(_c) ( (_c)-'a'+'A' ) #define my_isascii(_c) ( (unsigned)(_c) < 0x80 ) #define my_toascii(_c) ( (_c) & 0x7f ) #define my_isspace(_c) (_c==' ' || _c=='\t' || _c=='\n') #define my_seterror( api, retstring ) \ sprintf(retstring,"%s: Error %d from %s on line %d\n",\ __FILE__, GetLastError(), api, __LINE__); Das folgende User-Macro stdout_to(f) #define stdout_to(f) if((freopen(f,"at",stdout)) == NULL) \ {fprintf(stderr,"\nredir-err\n");exit(-1);} kann definiert und für die Umleitung der Ausgabe auf die Console oder die Umleitung der Ausgabe in den Quelltext-File verwendet werden: Macro-Aufrufe z.B. stdout_to("CON"); stdout_to(__FILE__); In windows.h, windef.h sind zahlreiche Macros definiert. Testen Sie die folgenden Macros: #define MAKELONG(a, b) #define LOWORD(l) #define HIWORD(l) #define LOBYTE(w) #define HIBYTE(w) Welche Werte ( Bitmuster ) gehören zu: LOWORD (0x123456789), HIWORD(0x123456789), MAKELONG(0xBCDEF,0x56789A) ? Es sei char a=(char)0xff; LPSTR p="ABC"; Welche Werte haben die BOOLschen Ausdrücke: FALSE TRUE ( a < *p ) ( (BYTE) a < (BYTE) *p ) *(p+3) hat hat hat hat hat den den den den den Wert Wert Wert Wert Wert ... ... ... ... ... Welche Änderungen ergeben sich, wenn #define UNICODE #include <windows.h> TCHAR a=(char)0xff; LPSTR p="ABC"; LPTSTR pt=... verwendet wird? Etwas Wiederholung: // Gegeben: int x[] = { 8, 1, 7, 2, 6, 3, 5, 4, 0, -1, 1, -2, 2, -3 }; int k = 2, *z = &x[5]; // Gesucht: Welche Werte haben damit die folgenden Ausdrücke: 1 *z+k ergibt ..... 2 *(z+k) ergibt ..... 3 z-x ergibt ..... 4 *(z-k) ergibt ..... 5 x[2]-*(z+2) ergibt ..... 6 x[2]-(*z+2) ergibt ..... 7 x[k+1] << *z ergibt ..... 8 x[*z+k] ergibt ..... 9 x[k**z] 11 x[x[k]] ergibt ..... 10 x[k**z+3]**z+3 ergibt ..... ergibt ..... 12 x[x[k]] ergibt ..... Machen sie sich bitte mit dem folgenden Programm das Prinzip von CALLBACK-Funktionen klar. Welchen Typ haben die meisten Windows-CALLBACK-Funktionen? #include <stdio.h> #include <conio.h> void system_func( int (*user_func)(int) ) { static int first=0; char ch=' '; while ((ch=getch()) != 27) user_func (++first); return; } int myfunction(int wert) { printf("... myfunction: system_call_wert =%d\n", wert); return (wert); } int main () { system_func(myfunction); return 0 ; } Testen Sie das eigene Macro ACHAR2WCHAR mit ihren Initialen. Welche Bytefolge steht im w-Speicher? #define ACHAR2WCHAR(pa,buf,cb) MultiByteToWideChar(CP_ACP,0,pa,-1,buf,cb) CHAR a[3]="BW"; WCHAR w[3]; ACHAR2WCHAR(a,w,sizeof(w)); Der Aufbau von Windows-Header-Files ist zu untersuchen ( windows.h ) ● Warum beginnt windows.h mit #ifndef _WINDOWS_ #define _WINDOWS_ //und endet mit #endif / * _WINDOWS_ */ ● *.h-Files ( z.B. windef.h ) enthalten oft die Klammerungen #ifdef __cplusplus extern "C" { ...... } #endif Wozu dient diese Klammerung? Betrachten Sie bitte den Windows.h-File. Welche Nachrichten können nicht verwendet werden, wenn in einem C-Quelltext-File steht: #define NOWINOFFSETS #include <windows.h> Windows definiert zahlreiche Macros ( siehe z.B. windoswx.h ). Welche Werte liefert z.B. LOWORD (0x123456789) HIWORD(0x123456789) MAKELONG(0xBCDEF,0x56789A) Der System-Begriff ist zu verstehen ( siehe Script ). Hier einige Fragen: 1. Warum werden soviele neue Typen (z.B. typedef unsigned short WORD;) gebraucht? 2. Wieviele Byte hat ein double und wie ist eine double-Zahl intern aufgebaut? 3. Wieviele Byte hat ein UNICODE-Char und mit wievielen 0-Bytes wird ein UNICODE-String beendet? 4. Was enthält ein dll-File? 5. Worin unterscheiden sich Console-Applikation/Win32-Applikation/AFC-Applikation? 6. Wozu dienen die folgenden Zeilen? #include #define WIDEN2(x) L ## x #define WIDEN(x) WIDEN2(x) #define __WFILE__ WIDEN(__FILE__) wchar_t *pwsz = __WFILE__; 7. Welches (Entwicklungs-Übersetzungs-) Programm verwendet *.h/*.lib/*.res? 8. Überlegen Sie, welchen Wert der Ausdruck (bei 1, 2, ...., 12) hat: int x[] = { 8, 1, 7, 2, 6, 3, 5, 4, 0, -1, 1, -2, 2, -3 }; int k = 2, *z = &x[5];Ausgabe: ======== 1: *z+k =....| 2: *(z+k) =....3: z-x =....| 4: *(z-k) =....5: x[2]-*(z+2) =....| 6: x[2]-(*z+2) =....7: x[k+1] <<*z =....| 8: x[*z+k] =....9: x[k**z] =....| 10: x[k**z+3]**z+3 =....11: x[x[k]] =....| 12: x[x[k]] =.... IA-32 architecture datatypes integer datatype formats signed byte signed word signed dword 7 6..0 S integer 15 14..0 S integer 31 30..0 S integer 7..0 unsigned byte integer 15..0 unsigned word integer 31..0 unsigned dword integer 63..0 unsigned qword integer BCD packed BCD 7..4 3..0 res. BCD 7..4 3..0 BCD BCD pointer datatype formats 31..0 near pointer offset or virtual address far pointer 47..32 31..0 segment or selector offset FP datatype formats single real double real extended 79 real S 31 30..23 22..0 S exp. fraction 63 62..52 51..0 S exp. fraction 78..64 63 62..0 exp. I fraction word integer short integer long integer packed 79 BCD S res. 14..0 S integer 31 30..0 S integer 63 62..0 S integer 78..72 15 71..0 D17 D16 D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 MMX datatype formats 63..56 55..48 47..40 39..32 31..24 23..16 15..8 packed byte byte packed word byte byte byte byte byte byte 7..0 byte 63..48 47..32 31..16 15..0 word word word word packed dword 63..32 31..0 dword dword 63..0 qword qword packed 127..120 119..112 111..104 103..96 95..88 87..80 79..72 71..64 63..56 55..48 47..40 39..32 31..24 23..16 15..8 7..0 byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte packed word packed dword 127..112 111..96 95..80 79..64 63..48 47..32 31..16 15..0 word word word word word word word word 127..96 95..64 63..32 31..0 dword dword dword dword packed qword 127..64 63..0 qword qword SSE datatype format scalar single FP packed single FP 127..96 95..64 63..32 31..0 reserved reserved reserved single FP 127..96 95..64 63..32 31..0 single FP single FP single FP single FP SSE2 datatype format scalar double FP packed double FP 127..64 63..0 reserved double FP 127..64 63..0 double FP double FP 2.Praktikum Diese Aufgabe besteht aus den Teilen 1, 2, 3, ..., usw. Es soll ein erste "Hallo Welt"-Windows-Applikation geschrieben werden. Zur Reduzierung der Tipp-Tätigkeit soll das unten angegebene Rahmen-Programm benutzt werden. Das Rahmen-Programm ist zu erweitern. Zum besseren Verstehen sind einige Tests durchzuführen, wie z.B. aktuelle Maus-Position in der Titelzeile ausgeben, eine MessageBox() angezeigen, die verwendeten Windows-Datenstrukturen mit dem Debugger schrittweise anschauen, die Nachrichten mit dem Spy-Werkzeug ( Spy ) verfolgen ( MausNachrichten, Tasten-Nachrichten, Fenstervergrößerung, usw. ). 1. Mit WinMain() ist eine Windows-Applikation zu schreiben. Ein Programm "Hallo Welt" ist mit WinMain() und WndProc() zu erstellen. 2. Der Text in der Titelzeile ist bei WM_RBUTTONDOWN zu ändern 3. Die Maus-Position ( bei Klick mit der linke Maus-Taste ) ist in die in Titelzeile zu schreiben. 4. Bei Klick mit der rechten Maus-Taste soll eine MessageBox() angezeigt werden. 5. Mit einer Windows-Applikation ist die MessageBox()-Funktion zu untersuchen 6. Es ist eine einfache Grafik zu erstellen, die die Funktionen MoveToEx(), LineTo(), Ellipse(), Rectangle(), RoundRect(), Polyline(), PolyPolyline() verwendet. 7. Das "Hallo Welt"-Beispiel ist zu debuggen. 8. Die Nachrichten sind mit einem geeigneten Werkzeug ( Spy ) zu verfolgen. Hallo Welt Es ist ein einfaches, kleines Beispiel mit WinMain() und einer WndProc() - CALLBACK - Funktion sorgfältig zu durchdenken. In ein Hauptfenster soll ( testweise ) Text zentriert hinein geschrieben und die Funktionen MoveToEx(), LineTo(), Ellipse(), Rectangle(), RoundRect(), Polyline(), PolyPolyline() verwendet werden. GetClientRect( hwnd, & rect ) ; DrawText ( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; Mit dem Debugger ist das Programm schrittweise durchzugehen. Die Window-Daten-Strukturen sind zu entnehmen und am Programm-Anfang als Kommentar in den Quelltext einzufügen. #include <windows.h> //======================= LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { //======================= switch ( iMsg ) { case WM_CREATE : break ;//return 0; case WM_PAINT : { RECT rect ; PAINTSTRUCT ps ; HDC hDC = BeginPaint( hwnd, & ps ) ; // hier Zeichen-Func einfügen EndPaint ( hwnd, & ps ) ; } break ; //return 0; case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0; } return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wndclass = { 0 } ; wndclass.cbSize wndclass.style wndclass.lpfnWndProc wndclass.cbClsExtra wndclass.cbWndExtra wndclass.hInstance wndclass.hIcon wndclass.hCursor wndclass.hbrBackground wndclass.lpszMenuName wndclass.lpszClassName wndclass.hIconSm = = = = = = = = = = = = sizeof( WNDCLASSEX ) ; CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; WndProc ; 0 ; 0 ; hInstance ; LoadIcon ( NULL, IDI_APPLICATION ) ; LoadCursor ( NULL, IDC_ARROW ) ; ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; NULL ; "my_class" ; LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wndclass ) ) return -1 ; HWND hwndMain = CreateWindowEx( WS_EX_LEFT, "my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow ( hwndMain ) ; MSG msg ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1 TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return msg.wParam ; } Das "Hallo Welt"-Beispiel ist zu debuggen und zu kommentieren. Die verwendeten Windows-Datenstrukturen sind einzufügen. Text in Titelzeile Ändern Sie das Programm so, dass das Windows-Programm die eigene hg-Nummer in der Titelzeile beim WM_RBUTTONDOWN-Ereignis anzeigt. Verwenden Sie SetWindowText (hwnd, szText); Der Text in der Titelzeile ist bei WM_RBUTTONDOWN zu ändern. Maus-Pos in Titelzeile Die Position ( xPos, yPos ) der Maus soll bei einem Klick in der Titelzeile erscheinen. Verwenden Sie in der CALLBACK-Funktion Maus-Nachrichten, wie z.B. case case case case case case case case case case WM_LBUTTONUP: WM_RBUTTONUP: WM_MBUTTONUP: WM_LBUTTONDOWN: WM_RBUTTONDOWN: WM_MBUTTONDOWN: WM_LBUTTONDBLCLK: WM_MBUTTONDBLCLK: WM_RBUTTONDBLCLK: WM_MOUSEMOVE: break; break; break; break; break; break; break; break; break; break; char MouseMsgStrings[][20] = { " ", "WM_LBUTTONUP ", "WM_RBUTTONUP ", "WM_MBUTTONUP ", "WM_LBUTTONDOWN ", "WM_RBUTTONDOWN ", "WM_MBUTTONDOWN ", "WM_LBUTTONDBLCLK ", "WM_MBUTTONDBLCLK ", "WM_RBUTTONDBLCLK ", }; In lParam ist die Maus-Position enthalten. Hinweis: char szBuffer[???]; char * p=szBuffer; p += wsprintf ( p, "...wie printf: x=%04d", xPos ); SetWindowText ( hwnd, szBuffer ); MessageBox() Die MessageBox() ist zu testen, indem bei einem Tasten-Anschlag ( siehe WM_CHAR ) eine "Hallo-Welt"MessageBox() angezeigt wird. case WM_CHAR : { switch ( LOWORD(wParam) ) { case ‘\b’ : Rücktaste; break; case ‘\t’ : Tabulatortaste; break; case ‘\n’ : LF-Taste; break; default : //normales Zeichen bearbeiten } } Für die MessageBox() testen Sie bitte a )die Flags MB_OK MB_OKCANCEL MB_YESNO MB_DEFBUTTON2 MB_ICONHAND MB_ICONERROR MB_ICONASTERISK MB_ICONWARNING MB_ABORTRETRYIGNORE MB_RETRYCANCEL MB_YESNOCANCEL MB_DEFBUTTON3 MB_ICONSTOP MB_ICONQUESTION MB_ICONEXCLAMATION MB_ICONINFORMATION b ) Bitte beachten Sie den Rückgabewert von MessageBox() c ) Ändern Sie bitte den Default-Button der MessageBox() d ) Verwenden Sie bitte verschiedene Icons MB_ICONHAND MB_ICONERROR MB_ICONASTERISK MB_ICONWARNING MB_ICONSTOP MB_ICONQUESTION MB_ICONEXCLAMATION MB_ICONINFORMATION e ) Erstellen Sie eine MessageBox(), die den eigenen Quelltext-Aufruf ( mit den \"-Zeichen ) im Client-Bereich anzeigt Hier einige Fragen: 1. Was bedeutet CALLBACK? Was bedeutet typedef __int32 LRESULT; ? 2. Welche Bedeutung haben die WindowProc()-Parameter HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam? Welche übergebene Nachricht kündigt das Schließen des Fensters an? 3. Was hat BeginPaint() mit sizing, moving, creating, scrolling und der Clipping-Region zu tun? Welche Nachrichten sendet BeginPaint()? 4. Wozu dient der Device-Context? Welche Funktionen benutzen den Device-Context? 5. Wozu dient WNDCLASSEX wc = { 0 }; ? 6. Wozu braucht ein mit CreateWindowEx() erstelltes Fenster eine Fensterklasse, die mit RegisterClassEx() erstellt wurde? 7. Wodurch werden die folgenden Nachrichten ausgelöst? a) WM_LBUTTONDOWN, b) WM_CHAR, c) WM_PAINT, d) WM_DESTROY #include <windows.h> //======================= LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { //======================= switch ( iMsg ) { case WM_PAINT : { PAINTSTRUCT ps ; HDC hDC = BeginPaint( hwnd, & ps ); //... EndPaint( hwnd, & ps ) ; } break; case WM_DESTROY : PostQuitMessage( 0 ) ; break; } return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow ( hwndMain ) ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return msg.wParam ; } 3.Praktikum Diese Aufgabe besteht darin, das "Hallo Welt" - Windows - Programm schrittweise zu erweitern und das Programm sicher zu beenden, einfache Menu-Möglichkeiten ( ohne externe Ressource ) in das das Window-Gerüst zu integrieren. Die verwendeten Windows-Datenstrukturen sind sorgfältig mit dem Debugger zu betrachten. Die Nachrichten sind mit einem geeigneten Werkzeug ( Spy++ ) zu verfolgen ( Fenstervergrößerung, Maus-Nachrichten, Tasten-Nachrichten, usw. ). 1. Mit einer MessageBox() ist vor dem Beenden des Programmes eine Sicherheits - Rückfrage ( "Do you want to Exit?" ) auszulösen 2. Es ist ein System - Menu - Erweiterung durchzuführen, um eine MessageBox(hwnd,"Dies war ein System-Menu-Klick","Test",MB_...) anzuzeigen 3. Für die rechte Maus-Taste ist ein Popup - Menu zu programmieren und zu testen. Ein Menu-Auswahl-Klick ruft dann die CALLBACK-Funktion mit WM_COMMAND auf. 4. Es ist ein Menu mit LoadMenuIndirect() zu programmieren (siehe menu.cpp). 5. Mit Hilfe von i=0... können das i-te Icon aus Shell32.dll geholt und angezeigt werden: HICON hIcon = ExtractIcon(GetModuleHandle(0),"Shell32.dll",i); if(!hIcon) break; DrawIcon(hDC, x, y, hIcon); DestroyIcon(hIcon); Stellen Sie alle Icons dar, indem sie die Funktion BOOL draw_icons(HWND hwnd, int idx_start, /*Start-Index des Icons*/ int anz ) /*Anzahl der anzuzeigenden Icons*/ schreiben und testen. WM_CLOSE Beim Schliessen des Fensters wird in der CALLBACK-Funktion durch einen x-Mausklick auf die iMsg = WM_CLOSE - Nachricht und damit der Aufruf von LRESULT CALLBACK WndProc ( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) ausgelöst, Beim Schliessen des Fensters ist unter WM_CLOSE mit char buf[256]; GetWindowText( hwnd, buf, 256 ); der Text der Titelzeile in char buf[256] zu kopieren. Dann ist mit MessageBox ( hwnd, "Do you want to Exit?", buf, ??? | MB_YESNO) eine MessageBox anzuzeigen. Ist der Rückgabewert der MessageBox IDYES, so darf nicht DefWindowProc() aufgerufen werden, denn dann würde nach der WM_CLOSE-Nachricht durch Windows die WM_DESTROY-Nachricht gesendet. Ist der Rückgabewert der MessageBox IDYES, so kann z.B. mit DestroyWindow( hwnd ) die WM_DESTROY-Nachricht gesendet werden. System - Menu Das System-Menu soll erweitert werden. Dazu wird zunächst z.B. in WM_CREATE eingefügt: HMENU hSysMenu = GetSystemMenu( hwnd, FALSE ); if ( hSysMenu ) { InsertMenu ( hSysMenu, SC_RESTORE, MF_STRING, IDM_SYS_MENU_HELP, "&Help" ); InsertMenu ( hSysMenu, SC_RESTORE, MF_SEPARATOR, 0, NULL ); } Dann wird vor der CALLBACK-Funktion ein User-define ergänzt, wie z.B. #define IDM_SYS_MENU_HELP 4711 case WM_SYSCOMMAND: switch ( LOWORD(wParam ) ) { case IDM_SYS_MENU_HELP: MessageBox(hwnd, "IDM_SYS_MENU_HELP",NULL, MB_OK ) ; break ; } } break; Popup-Menu Ein PopupMenu soll bei einem Klick mit der rechten Maustaste an der Mausposition erscheinen. Was ist zu tun, wenn das KontextMenü ( nicht mit Resourcen, sondern ) per Programm "zusammen-gebastelt" werden soll? Unter WM_CREATE: //( PopupMenu wird unsichtbar erstellt ) soll per Programm ein Menu hMenu zusammengestellt werden, das Einzelpunkte ( Menu-Items, hPopup ) enthält: hMenu = CreateMenu (); hPopup = CreateMenu (); AppendMenu ( hPopup, MF_STRING, IDM_STATE0, "Menu-Text0" ); AppendMenu ( hPopup, MF_STRING, IDM_STATE1, "Menu-Text1" ); ... // Menu-Items zusammenfügen: AppendMenu ( hMenu, MF_POPUP, (???)hPopup, "Popup-Menu"); // und falls error DestroyMenu( hMenu ); IDM_... sind eindeutige WORD-Identifizierer z.B. zwischen 1000-5000. Unter WM_RBUTTONUP: //PopupMenu wird sichtbar u. benutzbar POINT mouse; GetCursorPos ( & mouse ); TrackPopupMenu ( hPopup, ???, mouse.x, mouse.y, 0, hwnd, NULL); Achtung! hMenu, hPopup wird in mehreren cases der CALLBACK-Funktion verwendet ... Bitte nicht vergessen, unter WM_DESTROY : den Windowinternen Speicher frei zu geben durch DestroyMenu( hMenu ); Unter WM_COMMAND: soll LOWORD( wParam ) in der Titelzeile angezeigt werden. Hallo Welt GetClientRect( hwnd, & rect ) ; DrawText ( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; Mit dem Debugger ist das Programm schrittweise durchzugehen. Die Window-Daten-Strukturen sind zu entnehmen und am Programm-Anfang als Kommentar in den Quelltext einzufügen. #include <windows.h> //======================= LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { //======================= PAINTSTRUCT ps ; HDC hDC ; RECT rect ; switch ( iMsg ) { case WM_CREATE : break ;//return 0; case WM_PAINT : hDC = BeginPaint( hwnd, & ps ) ; //hier einfügen EndPaint ( hwnd, & ps ) ; break ; //return 0; case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0; } return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wndclass = { 0 } ; HWND hwndMain ; MSG msg ; wndclass.cbSize wndclass.style wndclass.lpfnWndProc wndclass.cbClsExtra wndclass.cbWndExtra wndclass.hInstance wndclass.hIcon wndclass.hCursor wndclass.hbrBackground wndclass.lpszMenuName wndclass.lpszClassName wndclass.hIconSm = = = = = = = = = = = = sizeof( WNDCLASSEX ) ; CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; WndProc ; 0 ; 0 ; hInstance ; LoadIcon ( NULL, IDI_APPLICATION ) ; LoadCursor ( NULL, IDC_ARROW ) ; ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; NULL ; "my_class" ; LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wndclass ) ) return -1 ; hwndMain = CreateWindowEx( WS_EX_LEFT, "my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow ( hwndMain ) ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1 TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return msg.wParam ; } Menu mit LoadMenuIndirect() Normalerweise werden Ressourcen mit dem Ressourcen-Work-Shop erstellt. Hier soll nun mit Hilfe von HMENU hMenu = LoadMenuIndirect(buf); das Menue zusammen gebaut werden. Weil die Bit-Operationen zunächst recht unverständlich sind, verwenden sie bitte das Programm menu.cpp, dessen Aufbau etwa folgender Idee folgt: Der User schreibt Funktionen, wie z.B. BOOL menu_1(HWND hwnd) { ... return TRUE; } und legt eine Tabelle menu_struct mit Menu-Item-Text und auszuführende Funktion menu_1 an. Der Aufruf von MENU_CLASS(hwndMain, menu_struct) aktiviert das Menue und vergibt (duch hochzählen) automatisch die MENUE-ID's: MENU_STRUCT menu_struct[] = { //-------------------------------------------------// Menutext Funktion //-------------------------------------------------{L"Einstelungen", 0 },///////////////// {L"menu_1", menu_1 }, {L"menu_2", menu_2 }, {L"beenden", menu_ende }, {L"Zeichnen", 0 },///////////////// {L"Icons aus Shell32.dll 0.. 99", menu_4 }, {L"Icons aus Shell32.dll 100..199", menu_5 }, {L"Icons aus Shell32.dll 200..299", menu_6 }, {L"\0\0",0}}; // <== Endekriterium ist Pflicht! MENU_CLASS(hwndMain, menu_struct); Fügen Sie bitte einen Punkt L"beenden" hinzu. Bemerkung: Durch ein Sub-Classing wird CALLBACK new_wnd_proc() automatisch VOR der WndProc() ausgeführt und dort werden automatisch die WM_COMMAND-Nachrichten ausgeführt. Icons anzeigen Die folgenden Icons können Shell32.dll entnommen und verwendet werden. Schreiben Sie die Funktion BOOL draw_icons(HWND hwnd, int idx_start, /*Start-Index des Icons*/ int anz ) /*Anzahl der anzuzeigenden Icons*/ Shell32.dll 0.. 99 Shell32.dll 100..199 Shell32.dll 200..299 Fragen 1. 2. 3. 4. 5. Wozu dient der Rückgabewert von MessageBox()? Enthält eine MessageBox() eine eigene Hauptnachrichtenschleife? Was bedeutet modal? Was enthält wParam bei einem Aufruf der CALLBACK-Funktion infolge eines Menu-Item-Klick? Was würden Sie anstelle von GetClientRect() verwende, wenn die äußeren Abmessungen des Fensters gebraucht werden? 6. Wieviele Pixel enthält ein Icon? #include <windows.h> //======================= LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { //======================= switch ( iMsg ) { case WM_PAINT : { PAINTSTRUCT ps ; HDC hDC = BeginPaint( hwnd, & ps ); //... EndPaint( hwnd, & ps ) ; } break; case WM_DESTROY : PostQuitMessage( 0 ) ; break; } return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow ( hwndMain ) ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return msg.wParam ; } /////////////////////////////////////////////// // Menue mit LoadMenuIndirect() /////////////////////////////////////////////// #include <windows.h> #define err_if(e,errStr) if(e) MessageBox(NULL,(errStr),0,\ MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); typedef BOOL (* DRAWPROC)(HWND); typedef struct _MENU_STRUCT { //für das Menue WCHAR * pMenu; union { DRAWPROC drawProc; int length; }; WORD id; } MENU_STRUCT; MENU_STRUCT * pMenuStruc; //für das Menue void MENU_CLASS(HWND hwnd_main, MENU_STRUCT pMenuStruct[]); WNDPROC old_wnd_proc; //für das Menue /////////////////////////////////////////////// // Funktionen, die beiMenue-Klick ausgeführt werden /////////////////////////////////////////////// BOOL menu_1(HWND hwnd) { MessageBox(0,"Hallo1","Titel1",MB_OK); return TRUE; } BOOL menu_2(HWND hwnd) { MessageBox(hwnd,"Hallo2","Titel2",MB_OK); return TRUE; } BOOL menu_3(HWND hwnd) { RECT rect ; GetClientRect( hwnd, & rect ) ; HDC hDC = GetDC(hwnd); DrawText( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; ReleaseDC(hwnd, hDC); return TRUE; } BOOL draw_icons(HWND hwnd, int idx_start, //Start-Index des Icons int anz //Anzahl der anzuzeigenden Icons ) { ... ... ... return TRUE; } BOOL menu_4(HWND hwnd) { return draw_icons(hwnd, 0, 100); } BOOL menu_5(HWND hwnd) { return draw_icons(hwnd, 100,100); } BOOL menu_6(HWND hwnd) { return draw_icons(hwnd, 200,100); } /////////////////////////////////////////////// // Normale (nachgeschaltete CALLBACK-Funktion) /////////////////////////////////////////////// LRESULT CALLBACK WndProc( HWND hwnd , UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch ( uMsg ) { case WM_COMMAND: //MessageBox(0,"WM_COMMAND","WM_COMMAND",MB_OK); break; case WM_PAINT: { PAINTSTRUCT ps; HDC hDC = BeginPaint( hwnd, & ps ); //... EndPaint( hwnd, & ps ); } break; case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hwnd, uMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wc = { 0 } ; MSG msg ; HWND hwndMain; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = "my_class" ; //wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 20,20,420,320, // x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow ( hwndMain ) ; MENU_STRUCT menu_struct[] = { //-------------------------------------------------// Menutext Funktion //-------------------------------------------------{L"Einstelungen", 0 }, // 0 für Popup {L"menu_1", menu_1 }, {L"menu_2", menu_2 }, {L"Zeichnen", 0 }, // 0 für Popup {L"Icons aus Shell32.dll 0.. 99", menu_4 }, {L"Icons aus Shell32.dll 100..199", menu_5 }, {L"Icons aus Shell32.dll 200..299", menu_6 }, {L"\0\0",0}}; // <== Endekriterium ist Pflicht! MENU_CLASS(hwndMain, menu_struct); while ( GetMessage ( & msg, NULL, 0, 0 ) ) { TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } return 0; } /////////////////////////////////////////////// // ACHTUNG! HIER BITTE NICHTS ÄNDERN!!! /////////////////////////////////////////////// LRESULT CALLBACK new_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { err_if((old_wnd_proc==NULL),"ERR:new_wnd_proc"); if(iMsg==WM_COMMAND) if(!(HIWORD(wParam))) { WORD id = LOWORD(wParam); WORD n = pMenuStruc[0].length; for(WORD k=0;k<n;k++){ if(id==pMenuStruc[k].id) { if(pMenuStruc[k].drawProc) { BOOL ok = pMenuStruc[k].drawProc(hwnd); if(!ok){ InvalidateRect(hwnd,NULL,TRUE); UpdateWindow(hwnd); }}}}} if(old_wnd_proc)return CallWindowProc( old_wnd_proc,hwnd,iMsg,wParam,lParam); else return DefWindowProc( hwnd,iMsg,wParam,lParam ) ; }; /////////////////////////////////////////////// // ACHTUNG! HIER BITTE NICHTS ÄNDERN!!! /////////////////////////////////////////////// size_t AddMenuItem( // Bitweise die Menue-Resource zusammenbauen LPVOID MenuTemplate, WCHAR* MenuString, WORD MenuID, BOOL IsPopup, BOOL LastItem) { MENUITEMTEMPLATE* pItem = (MENUITEMTEMPLATE*) MenuTemplate; size_t bytes_used = 0; if (IsPopup) { // for popup menu if (LastItem) pItem->mtOption = MF_POPUP | MF_END; else pItem->mtOption = MF_POPUP; bytes_used += sizeof (pItem->mtOption); pItem = (MENUITEMTEMPLATE*) ((BYTE*) MenuTemplate + bytes_used); // a popup doesn't have mtID!!! wcscpy((WCHAR*) pItem, MenuString); bytes_used += sizeof (WCHAR) * (wcslen(MenuString) + 1); // include '\0' } else { // for command item pItem->mtOption = LastItem ? MF_END : 0; pItem->mtID = MenuID; wcscpy(pItem->mtString, MenuString); bytes_used += sizeof (pItem->mtOption ) + sizeof (pItem->mtID) + sizeof (WCHAR) * (wcslen(MenuString) + 1); // include '\0' } return bytes_used; } /////////////////////////////////////////////// // ACHTUNG! HIER BITTE NICHTS ÄNDERN!!! /////////////////////////////////////////////// void OnCreate_SetCallBackFunc(HWND hwnd, MENU_STRUCT pMenuStruct[]) { BYTE buf[4000]; memset(buf, 0, 4000); int k,j=0,m = -1, id=9100; BOOL letzteSpalte = TRUE, IsPopup[256], LastItem[256]; size_t bytes_used = sizeof(MENUITEMTEMPLATEHEADER); MENUITEMTEMPLATEHEADER* p = (MENUITEMTEMPLATEHEADER*) buf; p->versionNumber = 0; //WORD p->offset = 0; //WORD pMenuStruc = pMenuStruct; //global while (*pMenuStruct[++m].pMenu){ if( pMenuStruc[m].drawProc==NULL ) { pMenuStruct[m].id = 0; } else { id++; pMenuStruct[m].id = id; } } err_if((m<1),"kein Menue"); pMenuStruct[0].length = m; for(k=0;k<m;k++) { IsPopup[k]=FALSE; LastItem[k]=FALSE; if(pMenuStruct[k].id == 0) { j = k; IsPopup[k]=TRUE; if(k>0)LastItem[k-1]=TRUE; } } LastItem[j]=TRUE; LastItem[m-1]=TRUE; for(k=0;k<m;k++) { // baue Ressource zusammen bytes_used += AddMenuItem(buf + bytes_used, pMenuStruct[k].pMenu, pMenuStruct[k].id, IsPopup[k], LastItem[k]); } HMENU hMenu = LoadMenuIndirect(buf); err_if(!hMenu,"LoadMenuIndirect"); HMENU hMenuOld = GetMenu(hwnd); SetMenu(hwnd, NULL); DestroyMenu(hMenuOld); BOOL ok = SetMenu(hwnd, hMenu); err_if(!ok,"SetMenu"); HICON hIcon = ExtractIcon(GetModuleHandle(0),"Shell32.dll",43); SetClassLong(hwnd, GCL_HICON, (LONG)hIcon ); DestroyIcon(hIcon); } /////////////////////////////////////////////// // ACHTUNG! HIER BITTE NICHTS ÄNDERN!!! /////////////////////////////////////////////// void MENU_CLASS(HWND hwnd_main, MENU_STRUCT pMenuStruct[]){ //Konstruktor OnCreate_SetCallBackFunc(hwnd_main, pMenuStruct); old_wnd_proc =(WNDPROC)SetWindowLong(hwnd_main,GWL_WNDPROC,(long)new_wnd_proc); err_if(!old_wnd_proc,"OnCreate_SetCallBackFunc:old_wnd_proc"); } /////////////////////////////////////////////// // ACHTUNG! HIER BITTE NICHTS ÄNDERN!!! /////////////////////////////////////////////// 4.Praktikum Diese Aufgabe besteht darin, das "Hallo Welt" - Windows - Programm zu erweitern und Ressourcen zu benutzen. Zunächst sollen einfache Ressource von Hand (resource.rc) erstellt und in dem Window-Gerüst genutzt werden. Später werden wir (gewöhnlich immer) den Ressourcen-Workshop für die Erstellung eines Ressourcenskript verwenden. Durch die Verwendung des Ressourcen-Compilers kann dann auf das bitweise Zusammenbasteln der Ressourcen im C++Programm (wie im früheren Quelltext menu.cpp, der LoadMenuIndirect() verwendete) verzichtet werden. 1) Die Ressourcen-Erstellung von Hand besteht im folgenden: ● ● ● Von Hand ist eine ( User - ) Menu - Ressource ( als ASCII-File resource.rc ) zu erstellen und im Window - Projekt zu nutzen. resource.h soll die IDM_-Konstanten enthalten. resource.h soll in die Files *.cpp und resource.rc includiert werden. In resource.rc soll eine einfache ( User-) Menue - Ressource erstellt und mit dem *.cpp getestet werden Verwenden Sie für das Menu Beschleuniguungs-Tasten ( Alt-Hot-Keys ). Es sind Beschleunigungs - Tasten ( HotKeys ) zu verwenden. In resource.rc soll eine einfache ( User-) Ressourcen - String - Table angelegt und Strings geladen werden. Legen Sie eine String-Tabelle an. Die Strings sind nach dem Laden anzuzeigen. Verwenden Sie diese Texte z.B. für die FensterTitelzeile. 2) Die Ressourcen-Erstellung mit dem Ressourcen-Workshop besteht im folgenden: ● Wiederholen Sie den Teil 1 der Übung in einem neuen Projekt, indem NUN der Ressourcen-Workshop verwendet wird. 3) Es ist eine kleiner "HTML-Code-Generierer" zu schreiben, der folgendes leisten soll: ● ● ● Erweitern Sie das Menu, indem Edit-Fenster sichtbar/unsichtbar gemacht werden können. Eine Anleitung ist unten. Jedes Edit-Fenster soll bereits ein HTML-Struktur-Element enthalten. In ein "Haupt"-Text-Fenster soll eine HTML-Page "halb-automatisch" zusammengestellt werden, indem das jeweilige HTML-Element aus dem vorbelegten Fenstern geholt und in das "Haupt"-Text-Ergebnis-Fenster eingefügt wird. 1. Menu-Resource von Hand Für Anfänger ist wohl günstig, ein neues Win32-Projekt anzulegen. Diese Aufgabe besteht darin, eine "Resource von Hand" zu erstellen und zu testen. Gehen Sie bitte von dem Grundgerüst aus. Fügen Sie dem Projekt ASCII-Files hinzu ( mit dem Dev-Studio-Menu: Neu - Textdatei und mit dem Namen resource.h und resource.rc ) a) In der Entwicklungsumgebung (im Projekt-Fenster auf Header-Files) kann ein neuer File resource.h -File leer hin-zu-zu-fügt werden (rechte Maustaste im Projekt-Fenster auf Header-Dateien, Element hinzufügen). In resource.h sind die RessourcenIDentifizierer einzufügen: #define #define #define #define #define IDM_MAIN_MENU IDM_MAIN_EXIT IDM_MAIN_NEW IDM_MAIN_EXAMPLE_1 IDM_MAIN_EXAMPLE_2 101 4001 4002 4003 4004 #define IDM_MAIN_ABOUT 4005 b) In der Entwicklungsumgebung (im Projekt-Fenster auf Ressourcen-Dateien, rechte Maustaste im Projekt-Fenster, Element hinzufügen) kann ein neuer resource.rc - File hinzugefügt werden. resource.rc - File ist mit dem Ascii-Quellcode-Editor und alles (automatisch beim Erstellen bereits eingetragene) zu löschen (außer #include "resource.h"). Dort hinein wird der folgende rcQuelltext kopiert. Dann soll diese Ressource (für sich allein) kopiliert werden. #include "???.h" IDM_MAIN_MENU MENU DISCARDABLE { POPUP "&File" { MENUITEM "&New", IDM_MAIN_NEW, GRAYED MENUITEM SEPARATOR MENUITEM "&Exit", IDM_MAIN_EXIT } POPUP "&Examples" { MENUITEM "Example&1 F1", IDM_MAIN_EXAMPLE_1 MENUITEM "Example&2 F2", IDM_MAIN_EXAMPLE_2 } POPUP "&Help" { MENUITEM "&About", IDM_MAIN_ABOUT } } c) Um das Menu anzuzeigen, wird in der WinMain()-Funktion die RegisterClass()-Struktur ergänzt durch den Eintrag: WNDCLASS wc.lpszMenuName = MAKEINTRESOURCE( IDM_MAIN_MENU ); d) Nun sollte das Projekt komplett neu erstelle (build) werden und das Menu im Hauptfenster sichtbar sein. Ein Mausklick auf einen Menu-Item hat keine Wirkung. d) Menu-Ereignisse rufen die CALLBACK-Funktion mit der WM_COMMAND-Nachricht auf und übergeben in wParam den Menu-Ressourcen-IDentifizierer (genauer: LOWORD(wParam) enthält den IDentifizierer). Um die Ausführung nach Menu-Klick zu testen muss die WndProc-CALLBACK-Funktion (bei WM_COMMAND) ergänzt werden. Tragen Sie bitte in die CALLBACK-Funktion WndProc ein: case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDM_MAIN_EXAMPLE_1: { MessageBox( NULL, "IDM_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION | MB_YESNO ) ; } break ; case IDM_MAIN_EXAMPLE_2: { // ... } break ; } break; // Ende von WM_COMMAND e) Ein Menu kann dynamisch geladen und gewechselt werden. Legen Sie bitte im resource.rc - File durch Kopieren des 1.MenuEintrages eine 2.Menu-Ressource an, die auch einen Eintrag "BITTE 2. MENU LADEN" enthalten soll und fügen Sie im WM_COMMAND-Switch das Laden des 2.Menu ein (case IDM_...???:) ein etwa gemäss: HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE( IDM_??? )); SetMenu( hwnd, h??? ); Das 1. Menu und 2. Menu sollen gewechselt werden können. Beschleunigungs-Tasten f) Mit Beschleuniguungs - Tasten ( Alt - Hot - Keys ) kann das Menu schneller bedient werden. Hierzu wird im Menu - Text das '&' Markierungs - Zeichen verwendet. Es können aber auch andere Tasten einem Menu - Punkt zugeordnet werden. Dem resource.rc File kann z.B. von Hand hinzugefügt werden: ID_MAIN_ACCEL ACCELERATORS LOADONCALL MOVEABLE VK_F1, IDM_MAIN_EXAMPLE_1, VIRTKEY VK_F2, IDM_MAIN_EXAMPLE_2, VIRTKEY "?", IDM_..., ASCII, ALT } { Vor der Haupt - Nachrichten - Schleife wird dieAccelerator - Tabelle mit LoadAccelerators(...) geladen. HACCEL hAccel = LoadAccelerators ( hInstance, MAKEINTRESOURCE( ID_MAIN_ACCEL ) ); hAccel == NULL signalisiert einen Ladungsfehler, d.h. meist ist ID_MAIN_ACCEL falsch. In der Haupt-Nachrichten-Schleife wird unmittelbar nach while zuerst geprüft, ob eine Beschleunigungstaste gedrückt wurde: if ( ( hAccel != NULL ) && ( ! TranslateAccelerator ( msg.hwnd, hAccel, & msg ) ) ) { ... String-Table g) Im *.cpp soll ein Text - Hinweis mit LoadString() aus *.rc ( IDS_MAIN_STRING1 ) geladen werden und als MessageBox( GetFocus(), "...", "...", MB_OK) vor dem Main - Window angezeigt werden. Die in *.rc mit dem Resourcen - Werkzeug erstellte STRINGTABLE sieht etwa wie folgt aus: STRINGTABLE DISCARDABLE BEGIN IDS_MAIN_STRING1, "Copyright - MessageBox" IDS_MAIN_STRING2, "Error in Runtime 1" .... IDS_MAIN_STRING16, "Wert = %d" END Es ist eine Resourcen - String - Table und LoadString() zu verwenden. Der LoadString( hInstance, IDS_..., buf, sizeof(buf) ) - Rueckgabe - Wert muss > 0 sein. 2. Menu-Resource mit Ressourcen-Workshop Für Anfänger ist wohl günstig, ein NEUES Win32-Projekt anzulegen. Die obige Aufgabe soll nun mit dem Ressourcen-Workshop erstellt werden. Wenn Sie die Identifizierer von vorher verwenden, so braucht das C++-Programm kaum geändert werden. 3. "Quellcode-Generierung" a) Es sollen nun MEHRER Fenster verwendet werden, deren Handle im globalen Array HWND ghwnd[] gespeichert werden. Die Fenster werden NICHT zerstört, sondern lediglich sichtbar bzw. unsichtbar gemacht. Dadurch "behält sich" Windows auch die zu einem Fenster gehörenden Daten auch dann, wenn das Fenster nicht sichtbar ist. Alle Fenster verwenden die CALLCACK-Funktion WndProc(). Um ein Fenster sichtbar zu machen kann verwendet werden: void show_window(HWND hwnd) { SetForegroundWindow( hwnd ); ShowWindow ( hwnd, SW_RESTORE); UpdateWindow ( hwnd ) ; } Beim Klick auf (X) der Titelzeile wird ein WM-CLOSE gesendet. Dann soll das Fenster unsichtbar werden, aber nur dann, wenn es nicht das Haupt-Fenster ghwnd[0] ist. Ergänzen Sie bei WM_CLOSE: for(int i=1;i<sizeof(ghwnd)/sizeof(ghwnd[0]);i++) { if(hwnd == ghwnd[i]) { ShowWindow ( hwnd, SW_HIDE); UpdateWindow( hwnd ); return 0; } } break; Die folgende Funktion create_edit_window(hwndMain, lpWindowName,x,y,cx,cy) erstellt eine Klasse lpWindowName und hinterlegt immer die CALLBACK-Funktion WndProc. Dann wird ein Parent-Fenster erzeugt, in das ein "EDIT" (bereits verfügbar) "eingehängt" wird. Schauen Sie sich create_edit_window() bitte einmal sorgfältig an! Unmittelbar vor WinMain() sollt hinkopiert werden: HWND create_edit_window(HWND hwndMain, LPCTSTR lpWindowName, int x,int y,int cx,int cy) { // create (m)odeless_(w)indow HINSTANCE hInst = GetModuleHandle(0); WNDCLASSEX wc = { 0 } ; if (cx<=0) cx = CW_USEDEFAULT; if (cy<=0) cy = CW_USEDEFAULT; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.lpfnWndProc = WndProc ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.hInstance = hInst; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = lpWindowName; if (!RegisterClassEx(&wc)) return 0 ; HWND hwndParent = CreateWindowEx(WS_EX_TOOLWINDOW, wc.lpszClassName, lpWindowName, WS_POPUPWINDOW | WS_CHILD | WS_CAPTION, x,y,cx,cy,hwndMain,0,hInst,0); // zusätzlich ein Editchild ins obige hwndParent WNDCLASS wcMS ={0}; GetClassInfo(hInst, "EDIT", &wcMS); RECT rc; GetClientRect( hwndParent, & rc ) ; int ID_EDIT = (int) hwndParent; HWND hwndEdit = CreateWindowEx( WS_EX_CLIENTEDGE, wcMS.lpszClassName, 0, WS_CHILD | WS_VISIBLE | WS_VSCROLL //| WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | ES_OEMCONVERT, rc.left,rc.top,rc.right,rc.bottom, hwndParent, (HMENU)ID_EDIT, hInst,0); return hwndParent; } In WinMain() hinein und dort vor die Hauptnachrichtenschleife soll hin: // ghwnd[0] vom Haupt-Fenster ghwnd[1] = create_edit_window(ghwnd[0], "[1] mein Edit 1", 0,300, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 ); ghwnd[2] = create_edit_window(ghwnd[0], "[2] mein Edit 2", 20,320, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 ); ghwnd[3] = create_edit_window(ghwnd[0], "[3] mein Edit 3", 40,340, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 ); show_window(ghwnd[0]); show_window(ghwnd[1]); show_window(ghwnd[2]); show_window(ghwnd[3]); Nun sollten die Fenster erscheinen und sichtbar sein. Die Edit-Fenster haben ein Kontext-Menue. In ein Edit[i]-Fenster kann Text auch per Programm geschrieben werden, etwa gemäss: HWND hEdit = GetTopWindow(ghwnd[i]); // i > 0 SetWindowText(hEdit, "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" "\r\n<html><head>\r\n <title>...</title>\r\n</head><body>\r\n" "\r\n<h1>...</h1>\r\n<p>\r\n...\r\n</p>\r\n\r\n</body></head>"); Mit SetWindowText() kann Text in ein Fenster geschrieben werden. Mit GetWindowText() kann Text aus einem Fenster geholt werden. Für umfangreichen Text ist der Virtual-Mem-Speicher geeignet: // Virtual-Mem-Speicher auch für SEHR umfangreichen Text: HWND hSrc = GetTopWindow(ghwnd[i]); // i > 0 int anz = GetWindowTextLength(hSrc); // hSrc ist Quelle anz += 1000; //zusätzlicher Bedarf 1000 Byte PSTR p = (PSTR) VirtualAlloc((LPVOID)NULL, (DWORD)(anz+1),MEM_COMMIT,PAGE_READWRITE); int n = GetWindowText(hSrc, p, anz+1); // p zeigt auf Heap-Text // Verarbeite den Text ... wsprintf(p+n,"\r\nGEHOLT\r\nUND\r\nGESCHRIEBEN"); SetWindowText(hDst, p); //hDst ist Ziel VirtualFree(p,0,MEM_RELEASE); Holen Sie den aktuellen Text aus dem einen Edit-Fenster und schreiben Sie diesen in ein anderes Edit-Fenster. Es ist eine kleiner "HTML-Code-Generierer" zu schreiben, der folgendes leistet: Jedes Edit-Fenster soll bereits ein HTML-StrukturElement enthalten. In ein "Haupt"-Text-Fenster soll eine HTML-Page "halb-automatisch" zusammengestellt werden, indem das jeweilige HTML-Element aus dem vorbelegten Fenstern geholt und in das "Haupt"-Text-Ergebnis-Fenster eingefügt wird. Window Sub-Classing Um alle Nachrichten einer vorhandenen MS-Edit-CALLBACK-Funktion zu erhalten, wird das Sub-Classing-Verfahren verwendet. Damit können Nachrichten umgeleitet werden. Beim Sub-Classing einer MS-Edit-CALLBACK-Funktion wird eine eigene EditProc vor die MS-Edit-CALLBACK-Funktion "gehängt". Die eigene EdtProc erhält dann erst die Nachrichten und muss am Ende die alte MS-Edit-CALLBACK-Funktion aufrufen. /////////////////////////////////////////////// // SUB-CLASSING // OldEdtProc ist die Orginal-"EDIT"-CALLBACK-Funktion, // die nach dem Erzeugen von // HWND hEdit = CreateWindowEx( WS_EX_CLIENTEDGE, ... // durch // WNDPROC OldEdtProc = (WNDPROC)SetWindowLong(hEdit,GWL_WNDPROC,(DWORD)NewEdtProc); // // zurück-gegeben wurde. Mit // // SetWindowLong(hEdit,GWL_USERDATA,(DWORD)OldEdtProc); // // wird in den Windows-GWL_USERDATA-Fenster OldEdtProc aufgehoben // und kann in der CALLBACK NewEdtProc( HWND hwnd,... durch // // WNDPROC OldEdtProc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA); // if(!OldEdtProc) return DefWindowProc(hwnd,uMsg,wParam,lParam); // // geholt werden. Am Ende von CALLBACK NewEdtProc( HWND hwnd,... // wird dann die alte MS-OldEdtProc aufgerufen durch // // return CallWindowProc(OldEdtProc,hwnd,uMsg,wParam,lParam); /////////////////////////////////////////////// LRESULT CALLBACK NewEdtProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { WNDPROC OldEdtProc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA); if(!OldEdtProc) return DefWindowProc(hwnd,uMsg,wParam,lParam); switch ( uMsg ) { case WM_CONTEXTMENU: {//1. rM-Taste, Menu will aufgehen if(0xffffffff==(DWORD)lParam) break;//Orginal-Kontex-Menu gpMenuStruc = (MENU_STRUCT *)GetWindowLong(GetParent(hwnd),GWL_USERDATA); if(!gpMenuStruc) break; err_if(!gpMenuStruc,"kein hPopupmenu"); if(gpMenuStruc){ HMENU hKM = gpMenuStruc[0].hMenu; err_if(!hKM,"kein hPopupmenu"); if (hKM) { POINT m; GetCursorPos( & m ); TrackPopupMenu(hKM, TPM_LEFTALIGN, m.x,m.y,0,GetParent(hwnd),0); return 0; }} break; } case WM_KEYUP: case WM_LBUTTONUP: { // Edit sendet bei jeder WM_KEYUP oder // WM_LBUTTONUP-Nachricht an Parent // die folgende Notify-Nachricht: SendMessage(GetParent(hwnd),WM_COMMAND, (WPARAM)MAKELONG(wParam,0xFFFF),(LPARAM)hwnd); break; } } return CallWindowProc(OldEdtProc,hwnd,uMsg,wParam,lParam); } Und (z.B.) die WndProc empfängt die die Notify-Nachricht: // Dies ist die Parent-CALLBACK-Funktion, die // die Notify-Nachricht erhält und verarbeitet. case WM_COMMAND: { if(HIWORD(wParam)) {//==0xffff user-notify HWND hEdit = (HWND)lParam; edit_caret_teste_pos_anzeige(hEdit); } break; } Die folgende Test-Funktion edit_caret_teste_pos_anzeige() zeigt lediglich, wie mit der "EDIT"-Klasse gearbeitet wird (Betrachten Sie das Fenster [5] des *.exe bei Caret-Bewegungen): void edit_caret_teste_pos_anzeige(HWND hEdit) { DWORD iLineBeg, iLineEnd, iLineLen; DWORD iSelBeg, iSelEnd; DWORD cxPos, cyPos; //30000 = SendMessage(hEdit,EM_GETLIMITTEXT,0,0); DWORD iAnz = GetWindowTextLength(hEdit); //aktuelle Selektierung geht von [iSelBeg] bis [iSelEnd] SendMessage(hEdit,EM_GETSEL,(WPARAM)&iSelBeg,(LPARAM)&iSelEnd); //aktuelle Zeile geht von [iLineBeg] bis [iLineEnd] iLineBeg = SendMessage(hEdit, EM_LINEINDEX,-1,0); iLineLen = SendMessage(hEdit,EM_LINELENGTH,iLineBeg,0); iLineEnd = iLineBeg + iLineLen; cyPos = iSelBeg - iLineBeg; cxPos = SendMessage(hEdit, EM_LINEFROMCHAR,-1,0); char buf[512],*p=buf; p+=wsprintf(p,"iSel:(%02d,%02d)", iSelBeg, iSelEnd); p+=wsprintf(p,"xyCar:(%02d,%02d)", cxPos,cyPos); p+=wsprintf(p,"iLine:(%02d,%02d)",iLineBeg, iLineEnd); p+=wsprintf(p,"iAnz:(%02d)",iAnz); p+=wsprintf(p,"\r\n"); //SetWindowText(ghwnd[5], buf); SetWindowText(GetTopWindow(ghwnd[5]), buf); } Fragen 1. 2. 3. 4. 5. 6. 7. 8. 9. Wann wird in der CALLBACK-Funktion return 0; verwendet? Warum wird ein DestroyWindow(ghwnd[0]) aber kein DestroyWindow(ghwnd[1]) benötigt? Welche Prä-Zeichen (??_...) verwendet die "EDIT"-Klasse für Edit-Nachrichten? Anstelle von ❍ HWND hEdit = GetTopWindow(ghwnd[1]); kann auch verwendet werden: ❍ HWND hEdit = GetDlgItem(ghwnd[1],(int)ghwnd[1]); Warum "funktioniert die Dlg-Funktion GetDlgItem()? Welche alternativen Möglichkeiten gibt es anstelle der Verwendung von Virtual-Mem-Speicher? Wozu dient LoadAccelerators()? Wodurch wird ein WS_CHILD-Fenster zerstört? Wie kann CreateWindowEx() eine vorhandene Klasse von MS verwenden? Was bedeutet Window Sub-Classing? #include <windows.h> HWND ghwnd[20]; // globale Handle für die Fenster void show_window(HWND hwnd) { SetForegroundWindow( hwnd ); ShowWindow ( hwnd, SW_RESTORE); UpdateWindow ( hwnd ) ; } //======================= LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) { //======================= switch ( iMsg ) { ////////////////////////////////////////////////////// case WM_COMMAND: { } break; // Ende von WM_COMMAND ////////////////////////////////////////////////////// case WM_PAINT : { PAINTSTRUCT ps ; HDC hDC = BeginPaint( hwnd, & ps ); EndPaint( hwnd, & ps ) ; } break; case WM_CLOSE : { } break; case WM_DESTROY : PostQuitMessage( 0 ) ; return 0; } return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { //=================== WNDCLASSEX wc = { 0 } ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = 0; //MAKEINTRESOURCE( IDM_MAIN_MENU ); wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; ghwnd[0] = CreateWindowEx( WS_EX_LEFT, "my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, // window style 0,0,GetSystemMetrics(SM_CXFULLSCREEN),300,//x,y,dx,dy NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL ) ; // creation parameters show_window(ghwnd[0]); show_window(ghwnd[1]); show_window(ghwnd[2]); show_window(ghwnd[3]); MSG msg ; while ( GetMessage ( & msg, NULL, 0, 0 ) ) { TranslateMessage ( & msg ) ; DispatchMessage ( & msg ) ; } DestroyWindow(ghwnd[0]); return msg.wParam ; } ////////////////////////////////////////////// // File: menu.cpp // Einfaches Menu ////////////////////////////////////////////// #ifndef _MYMENU_ #define _MYMENU_ ////////////////////////////////////////////// #include <windows.h> // wird immer gebraucht #include <wchar.h> // für das Menu #define err(errStr) MessageBox(0,(errStr),0,MB_OK) ////////////////////////////////////////////// // global verfügbar ////////////////////////////////////////////// typedef BOOL (* DRAWPROC)(void); typedef struct _MENU_STRUCT { WORD _id; // Menu-Identifizierer WCHAR * _txt; // Menu-Item-Text DRAWPROC _fn; // auzurufende Funktion //union { DRAWPROC _fn; int _length; }; } MENU_STRUCT; static WNDPROC g_wnd_proc_old;//EINE alte ////////////////////////////////////////////// class MENU_CLASS { ////////////////////////////////////////////// static LRESULT CALLBACK wnd_proc_new ( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam ) { int k; static HWND g_hwnd_main; //EIN aktiv static DRAWPROC g_fn_aktiv; //EINE fn aktiv static MENU_STRUCT * g_menu_struc;//WM_ACTIVATE switch ( iMsg ) { case WM_COMMAND: { if(HIWORD(wParam)) break; // alle Menu-Tabellen-Einträge durchgehen: for( k=0; g_menu_struc[k]._txt; k++) { if( LOWORD(wParam) == g_menu_struc[k]._id ) { //Menu-ausgewählte Funktion aufrufen: g_fn_aktiv = g_menu_struc[k]._fn; if ( g_fn_aktiv ) g_fn_aktiv(); //SetFocus(hwnd); //InvalidateRect(hwnd,NULL,TRUE); //UpdateWindow(hwnd); } } // for } break; //ende WM_COMMAND case WM_ACTIVATE: { if(0==wParam) { g_hwnd_main = 0; } else { g_menu_struc = (MENU_STRUCT *) ::GetWindowLong(hwnd,GWL_USERDATA); if(!g_menu_struc) err("g_menu_struc"); g_hwnd_main = hwnd; g_hwnd_main = (HWND)g_menu_struc[0]._fn; } } break; case WM_CLOSE: { if(IDNO==MessageBox(hwnd,"Exit?", "Programm",MB_ICONQUESTION|MB_YESNO)) return 0; } break; case WM_DESTROY: { PostQuitMessage(0); } break; } //ende switch ( iMsg ) if(g_wnd_proc_old) { return CallWindowProc((WNDPROC)g_wnd_proc_old,hwnd,iMsg,wParam,lParam); } else { return err("ERR:g_wnd_proc_old"); } }; ////////////////////////////////////////////// UINT AddMenuItem(LPVOID pBuf, MENU_STRUCT *pMenu, BOOL IsPopup, BOOL LastItem) { WORD MenuID = pMenu->_id; WCHAR * MenuString = pMenu->_txt; MENUITEMTEMPLATE* pM = (MENUITEMTEMPLATE*) pBuf; UINT cb = 0; if (IsPopup) { // for popup menu if (LastItem) pM->mtOption = MF_POPUP | MF_END; else pM->mtOption = MF_POPUP; cb += sizeof (pM->mtOption); pM = (MENUITEMTEMPLATE*) ((BYTE*)pBuf + cb); wcscpy((WCHAR*) pM, MenuString); cb += sizeof(WCHAR)*(wcslen(MenuString)+1); } else { // for command item pM->mtOption = LastItem ? MF_END : 0; pM->mtID = MenuID; wcscpy(pM->mtString, MenuString); cb += sizeof(pM->mtOption) + sizeof(pM->mtID) + sizeof(WCHAR)*(wcslen(MenuString)+1); } return cb; } ////////////////////////////////////////////// void BAUE_DAS_MENU_ZUSAMMEN( HWND hwnd, MENU_STRUCT * pMenu ) { BYTE buf[4000]={0};// memset(buf, 0, 4000); BYTE * p = buf; p += sizeof(MENUITEMTEMPLATEHEADER); HMENU hMenu=NULL; int i,k,j,m=-1; BOOL letzteSpalte=TRUE,IsPopup[100],LastItem[100]; while (*pMenu[++m]._txt){ i=pMenu[m]._id; if( i == 0 ) pMenu[m]._id = 0; } for(k=0;k<m;k++) { IsPopup[k]=FALSE; LastItem[k]=FALSE; } for(k=0;k<m;k++) { if(pMenu[k]._id==0){ IsPopup[k]=TRUE; j=k-1; IsPopup[j]=FALSE; LastItem[j]=TRUE; j=k; } } LastItem[j]=TRUE; LastItem[m-1]=TRUE; for(k=0;k<m;k++) { MENU_STRUCT mmm = pMenu[k]; p += AddMenuItem(p,&mmm,IsPopup[k],LastItem[k]); } hMenu = LoadMenuIndirect(buf);if(!hMenu) err("createEdit"); SetMenu(hwnd, hMenu); } ////////////////////////////////////////////// public: //Konstruktor MENU_CLASS(HWND hwnd, MENU_STRUCT * pMenu) { pMenu[0]._fn = (DRAWPROC)hwnd; ::SetWindowLong(hwnd,GWL_USERDATA,(LONG)pMenu); g_wnd_proc_old = (WNDPROC)::SetWindowLong(hwnd, GWL_WNDPROC,(LONG)wnd_proc_new); if(!g_wnd_proc_old) err("g_wnd_proc_old"); BAUE_DAS_MENU_ZUSAMMEN(hwnd, pMenu); } }; // Ende MENU_CLASS ////////////////////////////////////////////// #endif _MYMENU_ ////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////// // File: main.cpp // Hauptprogramm für GDI-Tests //////////////////////////////////////////////////// #include <windows.h> ??? // #include "menu.cpp" HWND g_hwnd_main; //////////////////////////////////////////////////// // GDI-Vereinfachungen //////////////////////////////////////////////////// class GDI_OBJ { //global: HWND g_hwnd_main; HWND _hwnd; HDC _hdc; HPEN _hPenOld, _hPenNew; HBRUSH _hBrushOld, _hBrushNew; COLORREF _text_color, _bktext_color; public: ////////////////////////////////////////////// GDI_OBJ(void){ //Konstruktor if(!g_hwnd_main) err("g_hwnd_main==0"); _hwnd = g_hwnd_main; _hdc = GetDC(_hwnd); } //////////////////////////////////////////////////// ~GDI_OBJ(void){ //Destruktor ReleaseDC(_hwnd, _hdc); } //////////////////////////////////////////////////// void begin_pen(int fnPenStyle,int nWidth,COLORREF crColor) { _hPenNew = (HPEN) CreatePen(fnPenStyle,nWidth,crColor); _hPenOld = (HPEN) SelectObject(_hdc, _hPenNew ); } //////////////////////////////////////////////////// void end_pen(void) { SelectObject( _hdc, _hPenOld ); DeleteObject( _hPenNew ); } //////////////////////////////////////////////////// void begin_textcolor( COLORREF color, COLORREF bkcolor ){ _text_color = SetTextColor(_hdc, color); _bktext_color = SetBkColor (_hdc, bkcolor); } //////////////////////////////////////////////////// void end_textcolor( void ){ SetBkColor(_hdc,_bktext_color); SetTextColor(_hdc, _text_color); } //////////////////////////////////////////////////// void begin_brush( COLORREF color ){ //LOGBRUSH * pLB HBRUSH _hbrush = (HBRUSH) GetCurrentObject(_hdc, OBJ_BRUSH); _hBrushNew = (HBRUSH) CreateSolidBrush( color ); if(!_hBrushNew){err("!_hBrushNew");exit(-1);} _hBrushOld = (HBRUSH) SelectObject(_hdc, _hBrushNew ); } //////////////////////////////////////////////////// void end_brush( void ){ SelectObject( _hdc, _hBrushOld ); DeleteObject( _hBrushNew ); } //////////////////////////////////////////////////// void draw_rect( int xLeft,int yTop,int xRight,int yBottom ){ Rectangle(_hdc, xLeft,yTop,xRight,yBottom ); } //////////////////////////////////////////////////// void draw_polyline( CONST POINT *pt, int cPoints ) { Polyline( _hdc, pt, cPoints ); } //////////////////////////////////////////////////// void draw_text( int x, int y, char * str ){ TextOut( _hdc, x, y, str, lstrlen(str)); } //////////////////////////////////////////////////// void erase(){ SendMessage(_hwnd,WM_ERASEBKGND,(UINT)_hdc,0); } }; //////////////////////////////////////////////////// //////////////////////////////////////////////////// // Lösche den Viewport //////////////////////////////////////////////////// BOOL loesche() { GDI_OBJ g = GDI_OBJ(); g.erase(); return FALSE; } //////////////////////////////////////////////////// // Schreibe Text an Position //////////////////////////////////////////////////// BOOL draw_test1() { GDI_OBJ g = GDI_OBJ(); g.begin_textcolor( RGB(0,0,255), RGB(255,255,0) ); g.draw_text( 180,140, "Hallo"); g.end_textcolor(); return FALSE; } //////////////////////////////////////////////////// // Zeichne Rechteck mit pen: draw_rect //////////////////////////////////////////////////// BOOL draw_test2() { GDI_OBJ g = GDI_OBJ(); // PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT g.begin_pen(PS_SOLID,3,RGB(0,0,0)); g.draw_rect(50,10, 300,250); g.end_pen(); return FALSE; } //////////////////////////////////////////////////// // Zeichne Rechteck mit pen: draw_polyline //////////////////////////////////////////////////// BOOL draw_test3() { POINT Points[] = { { 200,100} ,{ 250,150} ,{ 200,200} ,{ 150,150} ,{ 200,100} }; int cPoints = sizeof(Points)/sizeof(Points[0]); GDI_OBJ g = GDI_OBJ(); //////////////////////////////////////////////////// // fnPenStyle: PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT // crColor : RGB(00, 00, 0xff) //////////////////////////////////////////////////// g.begin_pen(PS_SOLID,13, RGB(255,0,0)); g.draw_polyline( Points, cPoints ); g.end_pen(); return FALSE; } //////////////////////////////////////////////////// // Zeichne Rechteck mit brush: BS_SOLID //////////////////////////////////////////////////// BOOL draw_test4() { GDI_OBJ g = GDI_OBJ(); g.begin_brush( RGB(0,0,255) ); g.draw_rect(80,80, 120,120); g.end_brush( ); return FALSE; } //////////////////////////////////////////////////// // Zeichne Rechteck mit brush: BS_HATCHED //////////////////////////////////////////////////// BOOL draw_test5() { GDI_OBJ g = GDI_OBJ(); g.begin_brush( RGB(0,255,0) ); g.draw_rect(80,140, 120,180); g.end_brush( ); return FALSE; } //////////////////////////////////////////////////// // Gib Info mit MessageBox aus //////////////////////////////////////////////////// BOOL show_msg() { MessageBox( g_hwnd_main, "Hallo", "Hallo", MB_OK); return FALSE; } //========================================================= int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { WNDCLASSEX wc = { 0 } ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = DefWindowProc; //WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInstance ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = NULL ; wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon ( NULL, IDI_APPLICATION ) ; if ( ! RegisterClassEx( & wc ) ) return -1 ; g_hwnd_main = CreateWindowEx( WS_EX_LEFT,"my_class", "Main-Titel-Zeile", WS_OVERLAPPEDWINDOW, 20,20,420,320, NULL,NULL,hInstance, NULL ); MENU_STRUCT menu_struct[] = { { 0, L"allgemein", { 100, L"loesche", { 120, L"MessageBox()", 0 loesche show_msg }, }, }, { 0, L"einige Tests", 0 }, { 220, L"draw test1", draw_test1 }, { 230, L"pen test rect2", draw_test2 }, { 235, L"pen test polyline", draw_test3 }, { 240, L"brush test1", draw_test4 }, { 250, L"brush test2", draw_test5 }, {0,L"\0\0",0}}; // <== Endekriterium ist Pflicht! MENU_CLASS mc = MENU_CLASS(g_hwnd_main, menu_struct); ShowWindow (g_hwnd_main,iShowMain) ; UpdateWindow(g_hwnd_main) ; MSG msg; while ( GetMessage(&msg,NULL,0,0 ) ) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam ; } 5.Praktikum Diese Aufgabe besteht darin, mit einer modalen DialogBox das Hauptprogramm zu gestalten und weitere DialogBoxen zu erstellen und die zugehörigen CALLBACK-Funktionen zu schreiben. 1. DialogBox() soll in WinMain() benutzt werden. 2. Diese DialogBox soll ein Menu erhalten. 3. Es ist eine Dialog-CALLBACK-Funktion zu schreiben, die die Klick-Nachricht eines OK-Button bearbeitet. 4. Es sind Button's einzufügen, die den Notepad starten. 5. Per Button-Klick sind *.exe-Programme zu starten. 6. Es ist eine Prototyp füer einen Hex-Taschenrechner zu programmieren. Es sind Verbesserungen und Erweiterungen ( ComboBox, Edit ) vorzunehmen. 7. Mit einem neuen Projekt ( für But.cpp ) ist der Taschenrechner ohne Ressourcen-Script zu schreiben. WinMain-DialogBox Es ist in einem neuen ( leeren ) Projekt ein einfacher Dialog zu erstellen ( z.B. 2 Buttons, Eingabe-Zeile, Menu, Icon ). Ist die IDD_DIALOGDialog-Resource ( resource.rc ) verfügbar, so kann mit der dlgProc-CALLBACK-Funktion ein Dialog gemaess int ret = DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE( IDD_DIALOG), hwnd, (DLGPROC)dlgProc); erzeugt werden. Das Windows-Hauptprogramm enthält DialogBox() und in dieser ist die Nachrichten-Schleife. Die DialogBox() erzeugt implizit die while-Schleife des Hauptprogrammes. Die Dialog-Resource ( resource.rc ) soll den Identifizierer IDD_DIALOG haben. Ein IDD_DIALOGDialog und die dlg-CALLBACK-Funktion dlgProc) sollen mit dem Ressourcen-Workshop erstellt werden. //Hauptprogramm int APIENTRY WinMain( HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain) { return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)dlgProc); } dlgProc-CALLABCK Bekanntlich senden MenuItem-Klicks und Button-Klicks Nachrichten iMsg=WM_COMMAND mit LOWORD(wParam) = IDB_... , IDM_, usw. ... case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDB_...: break; case IDM_...: break; } break; an die CALLBACK-Funktion: dlgProc, die etwa folgenden Aufbau hat: //dlgProc-CALLBACK-Funktion #include <windows.h> #include "resource.h" BOOL CALLBACK dlgProc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { switch ( iMsg ) { case WM_INITDIALOG : { // statt WM_CREATE break; } case WM_CLOSE : { char buf[256]; int ret; GetWindowText( hwnd, buf, sizeof(buf) ) ; ret = MessageBox( hwnd,"Exit?","Exit?",MB_ICONQUESTION|MB_YESNO); if ( IDNO == ret ) return TRUE; EndDialog( hwnd, ret ); //wParam=IDNO wird der ret-Value von DialogBox() break; } /* spaeter: case WM_COMMAND: { switch ( LOWORD(wParam) ) { //MenuItems, Buttons case IDB_...: break; case IDM_...: MessageBox( hwnd, "Hallo","ID...",MB_OK); break; case IDOK : //(OK)-Button zum beenden SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), lParam ); return TRUE; } } break; //Ende von WM_COMMAND */ } //Ende von switch(iMsg) return FALSE; } Menu für DialogBox Die Main-DialogBox soll ein Menu IDM_MENU erhalten. Das Ressourcen-Script soll mit dem Resourcen-Workshop erstellt werden. Der Resourcen-Workshop kann unmittelbar das Menu einfügen. Alternativ kann z.B. das Menu IDM_MENU ( zur Laufzeit ) unter case WM_INITDIALOG mit SetMenu() geladen und angezeigt werden. SetMenu(hwnd, LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDM_MENU))); DialogBox mit Button's Die DialogBox von Main soll einen Button IDB_... erhalten. Die Button-Beschriftung soll starte IDD_DIALOG1 sein. Ein Button-Klick von IDB_... soll einen weiteren Dialog IDD_DIALOG1 anzeigen. Starten von *.exe-Programmen Als Beispiel wird beschrieben, wie das Notepad.exe-Programm gestartet werden kann. Am einfachsten ist die alte WinExec().Funktion. UINT ui = WinExec("Notepad", SW_SHOW); if(ui > 31) ... Experimentieren und untersuchen Sie nützliche Anwendungen von UINT ui = WinExec("cmd /K dir \r\n", SW_SHOW); WinExec() wurde zu CreateProcess() erweitert, ist aufwendiger und wird empfohlen. Create.. braucht eine "saubere" Freigabe! Hier ein Muster, wenn "BuildLog.htm" im gleichen Verzeichnis ist, wie unser entwickelter sp2aufxx.exe-File. Grob ausgedrückt entspricht dies etwa dem Aufruf von WinExec("Notepad.exe FULLPATH\\BuildLog.htm", SW_SHOW)). CHAR * programm = "Notepad.exe"; CHAR * filename = "BuildLog.htm"; CHAR drive[256]; CHAR dir[256]; CHAR fname[256]; CHAR ext[256]; CHAR path[512]; CHAR aufruf[512]; STARTUPINFO si; ZeroMemory(&si,sizeof(si)); GetStartupInfo(&si); _splitpath(si.lpTitle, drive, dir, fname, ext); _makepath(path, drive, dir,"",""); wsprintf(aufruf,"%s %s%s",programm,path,filename); PROCESS_INFORMATION pi; ZeroMemory(&pi,sizeof(pi)); BOOL ok = CreateProcess (0,aufruf, 0,0,0,NORMAL_PRIORITY_CLASS,0,0,&si,&pi); if(!ok){ //Process konnte nicht gestartet werden err_if(!ok,"KEIN PROCESS"); } else { //befreie, falls nicht mehr benötigt CloseHandle(pi.hThread); // WaitForSingleObject(pi.hProcess, INFINITE); // der Process terminierte DWORD dwExitCode; // wie wurde er beendet? GetExitCodeProcess(pi.hProcess, &dwExitCode); //befreie, falls nicht mehr benötigt: CloseHandle(pipi.hProcess); } Wozu kann GetFullPathName(filename,sizeof(path),path,?); nützlich sein? Taschenrechner mit Ressourcenscript Es ist ein Prototyp für einen Hex-Taschenrechner zu gestalten ( mit Verbesserungen und Erweiterungen ). Um einem Control eine Nachricht zu schicken kann anstelle von HWND hCtl = GetDlgItem ( HWND hDlg, int idRes ); LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam); kürzer auch verwendet werden: LONG SendDlgItemMessage( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam, LPARAM lParam); Für das Edit- und ComboBox-Control sollen die Macros ( wie z.B. Edit_SetText() ) aus WindosX.h verwendet werden. Bei der Erstellung des Ressourcen-Scripts kann zunächst ein "leeres grosses Dialog-Rechteck" angelegt werden und in diesen rcQuelltext wird der untere rc-Quelltext hinein kopiert ( ID-Konstanten beachten ). BEGIN //RESOURCE COMBOBOX IDC_COMBO1,5,5,115,125,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "0",48, 6,117,14,14,NOT WS_TABSTOP PUSHBUTTON "1",49, 6, 99,14,14,NOT WS_TABSTOP PUSHBUTTON "2",50,24, 99,14,14,NOT WS_TABSTOP PUSHBUTTON "3",51,42, 99,14,14,NOT WS_TABSTOP PUSHBUTTON "4",52, 6, 81,14,14,NOT WS_TABSTOP PUSHBUTTON "5",53,24, 81,14,14,NOT WS_TABSTOP PUSHBUTTON "6",54,42, 81,14,14,NOT WS_TABSTOP PUSHBUTTON "7",55, 6, 64,14,14,NOT WS_TABSTOP PUSHBUTTON "8",56,24, 64,14,14,NOT WS_TABSTOP PUSHBUTTON "9",57,42, 64,14,14,NOT WS_TABSTOP PUSHBUTTON "A",65,42, 47,14,14,NOT WS_TABSTOP PUSHBUTTON "B",66,24, 47,14,14,NOT WS_TABSTOP PUSHBUTTON "C",67, 6, 47,14,14,NOT WS_TABSTOP PUSHBUTTON "D",68,42, 30,14,14,NOT WS_TABSTOP PUSHBUTTON "E",69,24, 30,14,14,NOT WS_TABSTOP PUSHBUTTON "F",70, 6, 30,14,14,NOT WS_TABSTOP PUSHBUTTON "+",43,64, 81,14,14,NOT WS_TABSTOP PUSHBUTTON "-",45,64, 99,14,14,NOT WS_TABSTOP PUSHBUTTON "*",42,82, 81,14,14,NOT WS_TABSTOP PUSHBUTTON "/",47,82, 99,14,14,NOT WS_TABSTOP PUSHBUTTON "%",37,64, 30,14,14,NOT WS_TABSTOP PUSHBUTTON "=",61,24,117,31,14,NOT WS_TABSTOP PUSHBUTTON "&&",38,82, 63,14,14,NOT WS_TABSTOP PUSHBUTTON "|",124,64, 63,14,14,NOT WS_TABSTOP PUSHBUTTON "^",94,64, 46,14,14,NOT WS_TABSTOP PUSHBUTTON "<",60,82, 30,14,14,NOT WS_TABSTOP PUSHBUTTON ">",62,82, 46,14,14,NOT WS_TABSTOP PUSHBUTTON "M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP PUSHBUTTON "M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP PUSHBUTTON "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP PUSHBUTTON "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP PUSHBUTTON "BS",8,64,117,31,14,NOT WS_TABSTOP PUSHBUTTON "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,98,30,6,101 CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,5,21,116,6 CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,58,29,6,101 CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,7,132,116,6 EDITTEXT IDC_EDIT1,7,141,113,45,ES_MULTILINE |WS_TABSTOP|ES_WANTRETURN|WS_VSCROLL|WS_HSCROLL DEFPUSHBUTTON "Schliessen",IDOK,37,193,50,14,NOT WS_TABSTOP END Achtung! Es ist sinnvoll, die folgenden KonstantenBezeichner zu verwenden: IDC_COMBO1 IDC_EDIT1 IDC_BUTTON0 IDC_BUTTON1 IDC_BUTTON2 IDC_BUTTON3 IDC_BUTTON4 IDC_BUTTON5 Windows kenn bereits: IDC_STATIC IDOK Hier ein Anfang für die CALLBACK dlgHexCalcProc() und hex_show_number() zum Anzeigen von iNum in IDC_COMBO1 und der Funktion hex_calc_it(), die abhängig von dem geklickten Button ( siehe default: iAsc = LOWORD( wParam ); ... ) auf die alte Zahl iFirstNum die aktuelle iNum "drauf-rechnet" und das Ergebnis zurück gibt. //C-Quelltext #include <limits.h> void hex_show_number ( HWND hwnd, INT idRes, UINT iNum ) { CHAR buf[256] ; HWND hCombo1 = GetDlgItem( hwnd, IDC_COMBO1 ) ; strupr( ltoa( iNum, buf, 16 )); ComboBox_SetText( hCombo1, buf ) ; if ( idRes == IDC_COMBO1 ) { if ( ComboBox_GetCount ( hCombo1 ) >= 15 ) ComboBox_DeleteString( hCombo1, 15 ) ; ComboBox_InsertString ( hCombo1, 0, buf ); } } DWORD hex_calc_it ( UINT iFirstNum, INT iOperation, UINT iNum ) { switch ( iOperation ) { default : return 0 ; case '=' : return iNum ; case '+' : return iFirstNum + iNum ; case '-' : return iFirstNum - iNum ; case '*' : return iFirstNum * iNum ; case '&' : return iFirstNum & iNum ; case '|' : return iFirstNum | iNum ; case case case case case } '^' '<' '>' '/' '%' : : : : : return return return return return iFirstNum ^ iNum ; iFirstNum << iNum ; iFirstNum >> iNum ; iNum ? iFirstNum / iNum : UINT_MAX ; iNum ? iFirstNum % iNum : UINT_MAX ; } BOOL CALLBACK dlgHexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL bNewNumber = TRUE ; static INT iOperation = '=' ; static UINT iAsc,iNumber, iFirstNum ; static CHAR * pCombo1; static HWND hCombo1; switch ( iMsg ) { case WM_INITDIALOG: if ( pCombo1 != NULL ) { free( pCombo1 ); pCombo1 = NULL; } pCombo1 = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); strcpy( pCombo1, "0" ); hCombo1 = GetDlgItem( hwnd, IDC_COMBO1 ) ; ComboBox_SetText ( hCombo1, pCombo1 ); break; case WM_COMMAND : if(HIWORD(wParam)) break; //Notifications switch ( LOWORD( wParam ) ) { case IDOK: SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; case IDC_BUTTON0://M+ case IDC_BUTTON1://Mcase IDC_BUTTON2://MR case IDC_BUTTON3://MC case IDC_BUTTON4://AC case IDC_BUTTON5://BS break ; default: iAsc = LOWORD( wParam ); if ( isxdigit( iAsc ) ) { // hex digit if ( bNewNumber == TRUE ) { iFirstNum = iNumber ; iNumber = 0; } if ( iNumber <= (UINT_MAX >> 4) ) { iNumber = 16 * iNumber + iAsc - ( isdigit( iAsc ) ? '0' : 'A' - 10 ) ; hex_show_number ( hwnd, 0, iNumber ) ; } else { MessageBeep( 0 ) ; // MessageBeep(MB_ICONHAND); } bNewNumber = FALSE ; } else { // operation if ( bNewNumber == FALSE ) { iNumber = ( UINT ) hex_calc_it ( iFirstNum, iOperation, iNumber ) ; hex_show_number ( hwnd, IDC_COMBO1, iNumber ) ; } iOperation = iAsc ; bNewNumber = TRUE ; } break; // ende von switch ( LOWORD( wParam ) } break; // ende von WM_COMMAND case WM_CLOSE: if(pCombo1) free( pCombo1 ); pCombo1 = NULL; EndDialog ( hwnd, wParam ); // DestroyWindow( hwnd ); ... ist bei modal unnötig break; } return FALSE ; } Taschenrechner Ohne Ressourcen-Script Empfehlung: Neues Projekt anlegen. Durch den Aufruf von CreateWindowEx() kann ein Button mit der Klasse "BUTTON" erzeugt werden. Der Identifizierer (HMENU)idRes wird bei HMENU hMenu ( mit geeignetem Casten ) eingetragen. Der Style sollte auch WS_CHILD enthalten, damit eine automatische Freigabe beim Schliessen des Parent-Fensters erfolgt. _hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON", pText,WS_VISIBLE | WS_CHILD, x,y,dx,dy, hParent,(HMENU)idRes,GetModuleHandle(0),0); Als ein Anfang kann die class my_button { ... } verwendet werden, die CreateWindowEx() mit der Window-Fenster-Klasse "BUTTON" und den Identifizierer idRes nutzt. Die Klasse my_button { ... } ist in dem Rahmenprogramm But.cpp enthalten. Ein Aufruf erfolgt etwa gemäss: // mit static my_button * pButtton[256]; //max 256 Button's // können Child-Button ( Zeichen entspricht // dem Identifizierer ) in das Haupt-Fenster // platziert werden, etwa gemäss: WM_CREATE : ... pButton[255] = new my_button(hwnd,255,"255", 200,100,80,80); WM_DESTROY: ... if(pButton[255]) delete pButton[255]; Fragen 1. 2. 3. 4. 5. 6. Enthält die Funktion DialogBox() eine Hauptnachrichtenschleife? Nennen Sie unterschiedliche Möglichkeiten, wie DialogBox() mit einem Menu versehen werden kann. Wozu dient der ret-Parameter bei EndDialog(hwnd,ret)? Welche Nachricht wird durch einen Button-Klick ausgelöst? Wie heißt die Klasse, die Button's erstellt und die MS-CALLBACK-Funktion enthält? Was ist zu tun, wenn alle Nachrichten ZUERST an eine eigene CALLBACK-Funktion geschickt werden sollen und erst danach an die "vorhandene, unsichtbare" MS-CALLBACK-Funktion weiter gereicht werden sollen? 7. Was bewirkt der Aufruf: ShellExecute(hwnd,"explore",0,0,0,SW_SHOWNORMAL)? Fragen 1. Welches Programm übersetzt einen *.rc-File in einen *.res-File? 2. Welches Programm bindet *.res-Files in das *.exe-File ein? 3. Welche CALLBACK-Funktion gehört zu der eingebauten Klasse "#32770" und welche Nachrichten (Beispiele angeben) verarbeitet dies CALLBACK-Funktion? 4. Wozu dienen die Aufrufe: WNDCLASSEX wc = { 0 }; GetClassInfoEx(hInst,"#32770",&wc);? 5. Eine CALLBACK-Funktion soll unter WM_COMMAND nur Menu und Button-Nachrichten verarbeiten, aber keine NotifyNachrichten von Controls. Wie würden Sie (unmittelbat nach WM_COMMAND) die Notify-Nachrichten "abblocken"? Lösung durch: case WM_COMMAND: if(HIWORD(wParam)) ....; 6. Eine modless Dialog liefere mit CreateDialog() das HWND hDlg zurück. Der Dialog enthalte eine ComboBox. Wie kann mit Hilfe von hDlg das Handle hCombo erhalten werden, wenn ID_COMBO der Identifizierer für die ComboBox ist? 7. Eine modale DialogBox() liefert kein HWND zurück. Der Dialog enthalte eine ComboBox. Wie wird per Programm in die Edit-Eingabezeile der ComboBox ein Text geschrieben? Wie werden in die List-Zeile der ComboBox Texte geschrieben? 8. CreateWindowEx() gehört zu einer der folgenden Klassen. a) "EDIT" b) "BUTTON" c) "COMBOBOX" Wie würden Sie die folgenden Styles 1), 2), 3) zu a), b), c) zuordnen? 1) WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP 2) WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN 3) WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN #include <windows.h> #include <windowsx.h> #include <limits.h> #define err_if(e,str) \ if(e)MessageBox(0,(str),0,MB_OK|MB_ICONSTOP); ///////////////////////////////////////////////// // ... NOTIFY-TEST ... // Ausgabe von Hilfetext als Notify-Hinweis: // if(CBN_EDITCHANGE==HIWORD(wParam)) ... ///////////////////////////////////////////////// char * helpCBN_EDITCHANGE = "\r\nWenn Sie die Texteingabe in die Combo-Edit-Zeile" "\r\nProgrammieren möchten, so können die" "\r\nCombobox-Notify-Nachrichten CBN_ ..." "\r\nverwendet werden, die kommen unter:" "\r\n\r\nWM_COMMAND:" "\r\n if(HIWORD(wParam))" "\r\n if(hCombo==(HWND)lParam)" "\r\n if(CBN_EDITCHANGE==HIWORD(wParam))" "\r\n { // es wurde was in Combo getippt" "\r\n\tmemset(buf,0,sizeof(buf));" "\r\n\tGetWindowText(hCombo,buf,sizeof(buf));" "\r\n\tchar *p = buf; UINT uNum=0;" "\r\n\twhile(*p)" "\r\n\t\{ // Zahl zeichenweise:" "\r\n\t\tchar asc = *p; p++;" "\r\n\t\terr_if(!isxdigit(asc),\"Bitte nur Hex-Digit!\")" "\r\n\t\tuNum = 16 * uNum + asc - (isdigit(asc)?\'0\':\'A\'-10) ;" "\r\n\t} uNum2 = ...; isNewNum = ... ; \r\n}"; // err_if(1,helpCBN_EDITCHANGE); ///////////////////////////////////////////////// // globales ///////////////////////////////////////////////// const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText() const UINT MAX_COMBO_CHAR = 8;//ComboBox_LimitText() const UINT USE_CE = 1; // Ziel Combo-Edit const UINT USE_CL = 2; // Ziel Combo-Liste const UINT USE_EM = 4; // Ziel Edit-Multiline // UINT (M)em(SUM)men-Speicher MSUM // MSUM hält den Summenwert ('M+','M-') //'MR' für Anzeige, 'MC' setzt MSUM=0 UINT MSUM; // Verwendet werden hCombo, hEdit dadurch entfällt: // HWND hCombo = GetDlgItem(hwnd,IDC_COMBO); // HWND hEdit = GetDlgItem(hwnd,IDC_EDIT); HWND hCombo; //hCombo anstelle von IDC_COMBO HWND hEdit; //hEdit anstelle von IDC_EDIT ///////////////////////////////////////////////// // print_append() kann aus den hSrc-Fenster Text holen // und gemäss "printf-ähnlichem" Formats Text "anhängen" // und den gesamten Text in das hDst-Fenster schreiben. // Dadurch entsteht ein "append" von Text // // Anstelle der Aufruffolge: // print_append(hEdit,hEdit, "\r\n"); // print_append(hEdit,hEdit, "%u ", u1); // print_append(hEdit,hEdit, "%u ", u2); // // ist günstiger: // print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2); ///////////////////////////////////////////////// int CDECL print_append(HWND hDst, HWND hSrc, LPTSTR pFormat, ...) { static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048 err_if(!hDst,"print_append(): hDst?"); memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf; va_list argList; va_start( argList, pFormat ) ; if(hSrc) // hole Text aus hSrc pBuf += GetWindowText(hSrc,Buf,sizeof(Buf)); // bei Speichermangel pBuf auf Buf[0] if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf; pBuf += wvsprintf( pBuf, pFormat, argList ) ; va_end( argList ) ; // schreibe erweiterten Text in hDest SetWindowText( hDst, Buf ); return (pBuf-Buf); } ///////////////////////////////////////////////// // show_hex() schreibt uNum in das ziel. // Beispiel: show_hex(10,USE_CE); // Ziel kann sein (USE_CE|USE_CL|USE_EM) ///////////////////////////////////////////////// void show_hex(UINT uNum, int ziel ) { char buf[256]; int radix = 16; //global sind hCombo, hEdit //schreibe uNum als hex-String (basis 16) in buf strupr( ltoa(uNum, buf, radix) ); //Ausgabe von buf in ziel if (USE_CE & ziel) {//in Combo-Liste eintragen: ComboBox_SetText(hCombo, buf ) ; } if (USE_CL & ziel) { //in Combo-Liste eintragen: if ( ComboBox_GetCount(hCombo) >= 30) ComboBox_DeleteString(hCombo,30); ComboBox_InsertString(hCombo, 0, buf ); } if (USE_EM & ziel) { //in Edit-Journal eintragen: print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum); } } ///////////////////////////////////////////////// // Beispiel: UINT erg = berechne(6,'+',4); // Schreibt auch in hEdit ///////////////////////////////////////////////// UINT berechne(UINT uNum1, char Op, UINT uNum2 ) { UINT erg; switch ( Op ) { default : erg = 0; return erg; case '=' : erg = uNum2 ; return erg; case '+' : erg = uNum1 + uNum2 ; break; case '-' : erg = uNum1 - uNum2 ; break; case '*' : erg = uNum1 * uNum2 ; break; case '&' : erg = uNum1 & uNum2 ; break; case '|' : erg = uNum1 | uNum2 ; break; case '^' : erg = uNum1 ^ uNum2 ; break; case '<' : erg = uNum1 << uNum2 ; break; case '>' : erg = uNum1 >> uNum2 ; break; case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ; break; case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ; break; } print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n", uNum1,Op,uNum2,erg); print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n", uNum1,Op,uNum2,erg); return erg; } ///////////////////////////////////////////////// // CALLBACK ///////////////////////////////////////////////// LRESULT CALLBACK HexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL isNewNum = FALSE ; char buf[1024]; static char Op = '=' ; static UINT uNum1, uNum2, uNum ; //1.2.-Zahl switch ( iMsg ) { case WM_COMMAND : { WORD hwp = HIWORD(wParam); if(hwp)//NOTIFY von Combo oder Edit { if(hEdit==(HWND)lParam) // EDIT-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify EN_: 0x%",hwp); } if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp); if(CBN_SELCHANGE==HIWORD(wParam)) { //etwas wird in Comboliste ausgewählt memset(buf,0,sizeof(buf)); int index = ComboBox_GetCurSel(hCombo); ComboBox_GetLBText(hCombo,index,buf); isNewNum = TRUE; char *p = buf; while(*p) { // Zeichenweise: WPARAM wp =(WPARAM)(char)*p++; SendMessage(hwnd,WM_COMMAND,wp,0); } } if(CBN_EDITCHANGE==HIWORD(wParam)) { // es wurde was in Combo getippt ComboBox_SetText(hCombo, "0") ; isNewNum=TRUE; uNum1=uNum2=0; err_if(1,helpCBN_EDITCHANGE); return 0; } } break; } ///////////////////////////////////////////////////// switch ( LOWORD( wParam ) ) { default:{ if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;} if (uNum2 <= UINT_MAX >> 4 ) { uNum2 = 16 * uNum2 + wParam - (isdigit(wParam)?'0':'A'-10) ; } else MessageBeep( 0 ) ; show_hex(uNum2, USE_CE|USE_CL); isNewNum = FALSE ; } else { // operation if ( isNewNum == FALSE ) { uNum2 = berechne(uNum1, Op, uNum2) ; show_hex(uNum2, USE_CE); } Op = LOWORD(wParam); isNewNum = TRUE ; } break;}// Ende von default case VK_ESCAPE: show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break ; case 1000:show_hex(uNum2/=16, USE_CE);//"BS"; break; case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+"; isNewNum = TRUE ; break; case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-" isNewNum = TRUE ; break; case 1003://zeige MSUM in Combo an: "MR" show_hex(uNum2=MSUM, USE_CE|USE_CL); isNewNum = TRUE ; print_append(hEdit,hEdit, "MR=%u MR=0x%X\r\n",MSUM,MSUM); break; case 1004: MSUM=0;//Clear MSUM: "MC" break; case 1005: // Clear Combo: "AC" show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break; case 1006: // Clear Edit: "EC" SetWindowText(hEdit, ""); break; } break; } case WM_DESTROY : PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,iMsg,wParam,lParam); } ///////////////////////////////////////////////// void my_button(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) { if(idRes<=0)idRes=(WORD)*txt; CreateWindowEx(0,"BUTTON",txt, WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP, x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); } ///////////////////////////////////////////////// HWND my_combo(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) { HWND hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN, x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); //RECT rc; //SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc); return hCombo; } ///////////////////////////////////////////////// HWND my_edit(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) { HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT |ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0); return hEdit; } ///////////////////////////////////////////////// //Hauptprogramm ///////////////////////////////////////////////// int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain) { // HINSTANCE hInst = GetModuleHandle(0); // Nutze die vorhandene Desktop-Klasse // für die Registrierung: WNDCLASSEX wc = { 0 }; GetClassInfoEx(hInst,"#32769",&wc);//Desktop-Window wc.cbSize = sizeof(wc); wc.lpszClassName = "my_class" ; // eigener Class-Name: wc.lpfnWndProc = HexCalcProc; // eigene CALLBACK einfügen: wc.hIcon = ExtractIcon(hInst,"Shell32.dll",12); if (!RegisterClassEx(&wc)) err_if(1,"RegisterClassEx()"); // HEX-Rechner als Haupt-Fenster: int X = 100, Y = 100, DX = 204, DY = 380; HWND hwnd = CreateWindowEx(WS_EX_LEFT,wc.lpszClassName,"HEX-Rechner", WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME, X,Y,DX,DY,0,0,hInst,0); // anzeigen: ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd); // alle Button's per Programm "createn" int cx=24, cy=24, dx=26, dy=26, x,y, x0= 4, y0= 5, //für ComboBox x1= 4, y1=40, //1.Button-Spalte x2= 34, y2=40, //2.Button-Spalte x3= 64, y3=40, //3.Button-Spalte x4=100, y4=40, //4.Button-Spalte x5=130, y5=40, //5.Button-Spalte x6=168, y6=40; //6.Button-Spalte x=x0; y=y0; WORD IDC_COMBO = 1000; hCombo = my_combo(hwnd,x,y,188,180,"COMBO",IDC_COMBO); ComboBox_LimitText(hCombo, MAX_COMBO_CHAR); ComboBox_SetText (hCombo, "0"); // keine Hand-Eingabe, falls // ComboBox_Enable(hCombo, FALSE); x=x1; y=y1; my_button(hwnd,x,y,dx,cy,"F",0);y+=dy; my_button(hwnd,x,y,dx,cy,"C",0);y+=dy; my_button(hwnd,x,y,dx,cy,"7",0);y+=dy; my_button(hwnd,x,y,dx,cy,"4",0);y+=dy; my_button(hwnd,x,y,dx,cy,"1",0);y+=dy; my_button(hwnd,x,y,dx,cy,"0",0); x=x2; y=y2; my_button(hwnd,x,y,dx,cy,"E",0);y+=dy; my_button(hwnd,x,y,dx,cy,"B",0);y+=dy; my_button(hwnd,x,y,dx,cy,"8",0);y+=dy; my_button(hwnd,x,y,dx,cy,"5",0);y+=dy; my_button(hwnd,x,y,dx,cy,"2",0);y+=dy; my_button(hwnd,x,y,2*dx+4,cy,"=",0); x=x3; y=y3; my_button(hwnd,x,y,dx,cy,"D",0);y+=dy; my_button(hwnd,x,y,dx,cy,"A",0);y+=dy; my_button(hwnd,x,y,dx,cy,"9",0);y+=dy; my_button(hwnd,x,y,dx,cy,"6",0);y+=dy; my_button(hwnd,x,y,dx,cy,"3",0); x=x4; y=y4; my_button(hwnd,x,y,dx,cy,"%",0);y+=dy; my_button(hwnd,x,y,dx,cy,"^",0);y+=dy; my_button(hwnd,x,y,dx,cy,"|",0);y+=dy; my_button(hwnd,x,y,dx,cy,"+",0);y+=dy; my_button(hwnd,x,y,dx,cy,"-",0);y+=dy; my_button(hwnd,x,y,2*dx+4,dy,"BS",1000); x=x5; y=y5; my_button(hwnd,x,y,dx,cy,"<",0);y+=dy; my_button(hwnd,x,y,dx,cy,">",0);y+=dy; my_button(hwnd,x,y,dx,cy,"&&",0);y+=dy; my_button(hwnd,x,y,dx,cy,"*",0);y+=dy; my_button(hwnd,x,y,dx,cy,"/",0); x=x6; y=y6; my_button(hwnd,x,y,dx,cy,"M+",1001);y+=dy; my_button(hwnd,x,y,dx,cy,"M-",1002);y+=dy; my_button(hwnd,x,y,dx,cy,"MR",1003);y+=dy; my_button(hwnd,x,y,dx,cy,"MC",1004);y+=dy; my_button(hwnd,x,y,dx,cy,"AC",1005);y+=dy; my_button(hwnd,x,y,dx,cy,"EC",1006);y+=dy; char * pInfo = "MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n" "EC löscht diese Anzeige\r\nMR zeigt M an\r\n" "M+ addiert zu M \r\nM- subtr. von M\r\n"; WORD IDC_EDIT = 2000; hEdit = my_edit(hwnd,x0,y+4,188,140,pInfo,IDC_EDIT); Edit_LimitText(hEdit, MAX_EDIT_CHAR); // Hauptnachrichtenschleife BOOL bRet; MSG msg; while (bRet=GetMessage(&msg, NULL,0,0)){ err_if(-1==bRet,"GetMessage()"); TranslateMessage(&msg); DispatchMessage (&msg); } return 0; } #include <windows.h> #include <windowsx.h> #include <limits.h> Unten ist bei ??? ein Programmierfehler ... /////////////////////////////////////////////////////////////////////////// // Globales: /////////////////////////////////////////////////////////////////////////// typedef struct _DLG_STRUCT {//für das DlgTemplate WORD buf[2048]; // Speicher für das DlgTemplate-Aufbau int idxBuf; // idx, wo weiter geschrieben wird DLGPROC dlgProc;// Dialog CALLBACK-Funktion !!! } DLG_STRUCT; HWND ghwnd[10]; // [0]=aktuelles Window, [1]=Main-Window WORD IDC_COMBO = 1000; WORD IDC_EDIT = 2000; /////////////////////////////////////////////////////////////////////////// // Prototypen: /////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK wnd_default_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); BOOL CALLBACK dlg_default_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); #define err_if(e,errStr) if(e) MessageBox(0,(errStr),0,\ MB_OK|MB_ICONSTOP|MB_SETFOREGROUND); /////////////////////////////////////////////////////////////////////////// // dlg_...- Funktionen für "RAM-Dlg-Templates" /////////////////////////////////////////////////////////////////////////// int nCopyAnsiToWideChar (LPWORD lpWCStr, LPSTR lpAnsiIn) { // lediglich eine Hilfsfunktionen: return MultiByteToWideChar(CP_ACP,0,lpAnsiIn,-1,lpWCStr,256); } BOOL dlg_init(DLG_STRUCT *dlgStruct, WORD x,WORD y,WORD cx,WORD cy,char * szTitelStr) { PWORD p = dlgStruct->buf; memset(p,0,sizeof(dlgStruct->buf)); char * font= "Times New Roman"; WORD FontSize = 9; DWORD lStyle = WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_SETFONT; DWORD lExStyle = WS_EX_DLGMODALFRAME; *p++ = 1; // DlgVer *p++ = 0xFFFF; // Signature *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = 0; // NumberOfItems, buf[8]=3; *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = 0; // Menu *p++ = 0; // Class p += nCopyAnsiToWideChar (p,szTitelStr); if(FontSize < 6) FontSize = 9; *p++ = FontSize; //z.B. 9 *p++ = FW_DONTCARE; // Weight *p++ = MAKEWORD(FALSE,DEFAULT_CHARSET );// italic flag and charset. if(font)p+=nCopyAnsiToWideChar(p,font);// Face name else p+=nCopyAnsiToWideChar(p,"Courier New"); ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /////////////////////////////////////////////////////////////////////////// BOOL dlg_editM(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, char * szInitStr, WORD idRes) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | SS_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_WANTRETURN; DWORD lExStyle = WS_EX_CLIENTEDGE; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"EDIT"); if(szInitStr)p += nCopyAnsiToWideChar(p,szInitStr); else p += nCopyAnsiToWideChar(p,""); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /////////////////////////////////////////////////////////////////////////// int dlg_button(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, char * szStr, WORD idRes) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP; DWORD lExStyle = 0;//WS_EX_CLIENTEDGE; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"BUTTON"); if(szStr)p += nCopyAnsiToWideChar(p,szStr); else p += nCopyAnsiToWideChar(p,"?"); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /////////////////////////////////////////////////////////////////////////// BOOL dlg_combo(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, WORD idRes) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_GROUP|WS_VSCROLL |CBS_SORT|CBS_AUTOHSCROLL|CBS_DROPDOWN; DWORD lExStyle = WS_EX_CLIENTEDGE; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p, "COMBOBOX"); p += nCopyAnsiToWideChar(p,""); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /* /////////////////////////////////////////////////////////////////////////// int dlg_but_check(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, char * szStr, WORD idRes) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; //DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP| WS_GROUP | BS_AUTORADIOBUTTON ; DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | BS_AUTOCHECKBOX; DWORD lExStyle = WS_EX_CLIENTEDGE; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"BUTTON"); if(szStr)p += nCopyAnsiToWideChar(p,szStr); else p += nCopyAnsiToWideChar(p,"?"); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } */ /////////////////////////////////////////////////////////////////////////// /* BOOL dlg_edit(DLG_STRUCT *dlgStruct, WORD x,WORD y,WORD cx,WORD cy,char * szInitStr,WORD idRes) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP|SS_LEFT|ES_AUTOHSCROLL; DWORD lExStyle = WS_EX_CLIENTEDGE; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"EDIT"); if(szInitStr)p +=nCopyAnsiToWideChar(p,szInitStr); else p +=nCopyAnsiToWideChar(p,""); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /////////////////////////////////////////////////////////////////////////// int dlg_static(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, char * szStr) { PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_CHILD | WS_VISIBLE | SS_LEFT; DWORD lExStyle = 0;//WS_EX_CLIENTEDGE; WORD idRes = 0xffff; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"STATIC"); if(szStr)p += nCopyAnsiToWideChar(p,szStr); else p += nCopyAnsiToWideChar(p,""); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } /////////////////////////////////////////////////////////////////////////// int dlg_black(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy) {// schwarzes Rechteck PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++; DWORD lStyle = WS_CHILD | WS_VISIBLE |SS_BLACKRECT| SS_LEFT; DWORD lExStyle = WS_EX_CLIENTEDGE; WORD idRes = 0xffff; *p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID) *p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle); *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = x; *p++ = y; *p++ = cx; *p++ = cy; *p++ = idRes; // LOWORD (Control ID) *p++ = 0; // HOWORD (Control ID) p += nCopyAnsiToWideChar(p,"STATIC"); p += nCopyAnsiToWideChar(p,""); *p++ = 0; // Advance pointer over nExtraStuff WORD. ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE; } */ ///////////////////////////////////////////////// // Hex-Rechner: globales ///////////////////////////////////////////////// const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText() const UINT MAX_COMBO_CHAR = 8;//ComboBox_LimitText() const UINT USE_CE = 1; // Ziel Combo-Edit const UINT USE_CL = 2; // Ziel Combo-Liste const UINT USE_EM = 4; // Ziel Edit-Multiline // UINT (M)em(SUM)men-Speicher MSUM // MSUM hält den Summenwert ('M+','M-') //'MR' für Anzeige, 'MC' setzt MSUM=0 UINT MSUM; // Verwendet werden hCombo, hEdit dadurch entfällt: // HWND hCombo = GetDlgItem(hwnd,IDC_COMBO); // HWND hEdit = GetDlgItem(hwnd,IDC_EDIT); HWND hCombo; //hCombo anstelle von IDC_COMBO HWND hEdit; //hEdit anstelle von IDC_EDIT ///////////////////////////////////////////////// // print_append() kann aus den hSrc-Fenster Text holen // und gemäss "printf-ähnlichem" Formats Text "anhängen" // und den gesamten Text in das hDst-Fenster schreiben. // Dadurch entsteht ein "append" von Text // // Anstelle der Aufruffolge: // print_append(hEdit,hEdit, "\r\n"); // print_append(hEdit,hEdit, "%u ", u1); // print_append(hEdit,hEdit, "%u ", u2); // // ist günstiger: // print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2); ///////////////////////////////////////////////// int CDECL print_append(HWND hDst, HWND hSrc, LPTSTR pFormat, ...) { static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048 err_if(!hDst,"print_append(): hDst?"); memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf; va_list argList; va_start( argList, pFormat ) ; if(hSrc) // hole Text aus hSrc pBuf += GetWindowText(hSrc,Buf,sizeof(Buf)); // bei Speichermangel pBuf auf Buf[0] if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf; pBuf += wvsprintf( pBuf, pFormat, argList ) ; va_end( argList ) ; // schreibe erweiterten Text in hDest SetWindowText( hDst, Buf ); return (pBuf-Buf); } ///////////////////////////////////////////////// // show_hex() schreibt uNum in das ziel. // Beispiel: show_hex(10,USE_CE); // Ziel kann sein (USE_CE|USE_CL|USE_EM) ///////////////////////////////////////////////// void show_hex(UINT uNum, int ziel ) { char buf[256]; int radix = 16; //global sind hCombo, hEdit //schreibe uNum als hex-String (basis 16) in buf strupr( ltoa(uNum, buf, radix) ); //Ausgabe von buf in ziel if (USE_CE & ziel) {//in Combo-Liste eintragen: ComboBox_SetText(hCombo, buf ) ; } if (USE_CL & ziel) { //in Combo-Liste eintragen: if ( ComboBox_GetCount(hCombo) >= 30) ComboBox_DeleteString(hCombo,30); ComboBox_InsertString(hCombo, 0, buf ); } if (USE_EM & ziel) { //in Edit-Journal eintragen: print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum); } } ///////////////////////////////////////////////// // Beispiel: UINT erg = berechne(6,'+',4); // Schreibt auch in hEdit ///////////////////////////////////////////////// UINT berechne(UINT uNum1, char Op, UINT uNum2 ) { UINT erg; switch ( Op ) { default : erg = 0; return erg; case '=' : erg = uNum2 ; return erg; case '+' : erg = uNum1 + uNum2 ; break; case '-' : erg = uNum1 - uNum2 ; break; case '*' : erg = uNum1 * uNum2 ; break; case '&' : erg = uNum1 & uNum2 ; break; case '|' : erg = uNum1 | uNum2 ; break; case '^' : erg = uNum1 ^ uNum2 ; break; case '<' : erg = uNum1 << uNum2 ; break; case '>' : erg = uNum1 >> uNum2 ; break; case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ; break; case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ; break; } print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n", uNum1,Op,uNum2,erg); print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n", uNum1,Op,uNum2,erg); return erg; } ///////////////////////////////////////////////// // CALLBACK ///////////////////////////////////////////////// BOOL CALLBACK HexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL isNewNum = FALSE ; char buf[1024]; static char Op = '=' ; static UINT uNum1, uNum2, uNum ; //1.2.-Zahl switch ( iMsg ) { case WM_INITDIALOG: { if(!hCombo) hCombo = GetDlgItem(hwnd,IDC_COMBO); if(!hEdit) hEdit = GetDlgItem(hwnd,IDC_EDIT); ComboBox_LimitText(hCombo,MAX_COMBO_CHAR);// 8 ComboBox_SetText (hCombo, "0"); char * pInfoText = "MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n" "EC löscht diese Anzeige\r\nMR zeigt M an\r\n" "M+ addiert zu M \r\nM- subtr. von M\r\n"; Edit_LimitText(hEdit,MAX_EDIT_CHAR);//=2048 Edit_SetText(hEdit, pInfoText ); break; } case WM_COMMAND : { WORD hwp = HIWORD(wParam); if(hwp)//NOTIFY von Combo oder Edit { if(hEdit==(HWND)lParam) // EDIT-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify EN_: 0x%",hwp); } if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY { //nur für Notify-Tests (Titelzeile): print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp); if(CBN_SELCHANGE==HIWORD(wParam)) { //etwas wird in Comboliste ausgewählt memset(buf,0,sizeof(buf)); int index = ComboBox_GetCurSel(hCombo); ComboBox_GetLBText(hCombo,index,buf); isNewNum = TRUE; char *p = buf; while(*p) { // Zeichenweise: WPARAM wp =(WPARAM)(char)*p++; SendMessage(hwnd,WM_COMMAND,wp,0); } } if(CBN_EDITCHANGE==HIWORD(wParam)) { // es wurde was in Combo getippt ComboBox_SetText(hCombo, "0") ; isNewNum=TRUE; uNum1=uNum2=0; char * helpCBN_EDITCHANGE = "\r\nWenn Sie die Texteingabe in die Combo-Edit-Zeile" "\r\nProgrammieren möchten, so können die" "\r\nCombobox-Notify-Nachrichten CBN_ ..." "\r\nverwendet werden, die kommen unter:" "\r\n\r\nWM_COMMAND:" "\r\n if(HIWORD(wParam))" "\r\n if(hCombo==(HWND)lParam)" "\r\n if(CBN_EDITCHANGE==HIWORD(wParam))" "\r\n { // es wurde was in Combo getippt" "\r\n\tmemset(buf,0,sizeof(buf));" "\r\n\tGetWindowText(hCombo,buf,sizeof(buf));" "\r\n\tchar *p = buf; UINT uNum=0;" "\r\n\twhile(*p)" "\r\n\t\{ // Zahl zeichenweise:" "\r\n\t\tchar asc = *p; p++;" "\r\n\t\terr_if(!isxdigit(asc),\"Bitte nur Hex-Digit!\")" "\r\n\t\tuNum = 16 * uNum + asc - (isdigit(asc)?\'0\':\'A\'-10) ;" "\r\n\t} uNum2 = ...; isNewNum = ... ; \r\n}"; MessageBox(0,helpCBN_EDITCHANGE,0,MB_OK|MB_ICONSTOP); return TRUE; } } break; } // Ende von if(hwp) ///////////////////////////////////////////////////// switch ( LOWORD( wParam ) ) { default:{ if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;} if (uNum2 <= UINT_MAX >> 4 ) { uNum2 = 16 * uNum2 + wParam - (isdigit(wParam)?'0':'A'-10) ; } else MessageBeep( 0 ) ; show_hex(uNum2, USE_CE|USE_CL); isNewNum = FALSE ; } else { // operation if ( isNewNum == FALSE ) { uNum2 = berechne(uNum1, Op, uNum2) ; show_hex(uNum2, USE_CE); } Op = LOWORD(wParam); isNewNum = TRUE ; } break;}// Ende von default case IDOK: SendMessage(hwnd,WM_CLOSE,0,0);return TRUE; case IDHELP: MessageBox(hwnd, "Quelltext-Beschreibung ist im Skript" "\r\nim Kapitel über Dialoge ...", "Hilfetext",MB_OK); break ; case VK_ESCAPE: show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break ; case 1000:show_hex(uNum2/=16, USE_CE);//"BS"; break; case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+"; isNewNum = TRUE ; break; case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-" isNewNum = TRUE ; break; case 1003://zeige MSUM in Combo an: "MR" show_hex(uNum2=MSUM, USE_CE|USE_CL); isNewNum = TRUE ; print_append(hEdit,hEdit, "MR=%u MR=0x%X\r\n",MSUM,MSUM); break; case 1004: MSUM=0;//Clear MSUM: "MC" break; case 1005: // Clear Combo: "AC" show_hex(uNum2=0, USE_CE); isNewNum = TRUE ; break; case 1006: // Clear Edit: "EC" SetWindowText(hEdit, ""); break; } break; } case WM_ACTIVATE: if ( WA_INACTIVE == LOWORD(wParam) ) { ghwnd[0] = NULL;//becoming inactive } else {ghwnd[0] = hwnd; }//becoming active break; case WM_CLOSE: PostQuitMessage(0); //beende modeless break; } return FALSE; } void hex_rechner_indirect() { HWND ghwnd =0; // keins bekannt // Ressource für CreateDialogIndirect() // des HEX-Rechners zusammenbauen: int X = 100, Y = 100, DX = 100, DY = 200; // alle Button's per Programm "createn" int cx=12, cy=12, dx=13, dy=13, x,y, x0= 2, y0= 4, //für ComboBox x1= 2, y1=20, //1.Button-Spalte x2= 17, y2=20, //2.Button-Spalte x3= 32, y3=20, //3.Button-Spalte x4= 50, y4=20, //4.Button-Spalte x5= 65, y5=20, //5.Button-Spalte x6= 84, y6=20; //6.Button-Spalte ////////////////// DLG_STRUCT ds; ds.dlgProc = HexCalcProc; /////////////////// // in ds werden die Controls zusammengebaut x=x0; y=y0; dlg_init (&ds,X,Y,DX,DY, "HEX_RECHNER"); dlg_combo (&ds, x,y,94,90,IDC_COMBO); x=x1; y=y1; dlg_button(&ds,x,y,dx,cy,"F",'F');y+=dy; dlg_button(&ds,x,y,dx,cy,"C",'C');y+=dy; dlg_button(&ds,x,y,dx,cy,"7",'7');y+=dy; dlg_button(&ds,x,y,dx,cy,"4",'4');y+=dy; dlg_button(&ds,x,y,dx,cy,"1",'1');y+=dy; dlg_button(&ds,x,y,dx,cy,"0",'0'); x=x2; y=y2; dlg_button(&ds,x,y,dx,cy,"E",'E');y+=dy; dlg_button(&ds,x,y,dx,cy,"B",'B');y+=dy; dlg_button(&ds,x,y,dx,cy,"8",'8');y+=dy; dlg_button(&ds,x,y,dx,cy,"5",'5');y+=dy; dlg_button(&ds,x,y,dx,cy,"2",'2');y+=dy; dlg_button(&ds,x,y,2*dx+2,cy,"=",'='); x=x3; y=y3; dlg_button(&ds,x,y,dx,cy,"D",'D');y+=dy; dlg_button(&ds,x,y,dx,cy,"A",'A');y+=dy; dlg_button(&ds,x,y,dx,cy,"9",'9');y+=dy; dlg_button(&ds,x,y,dx,cy,"6",'6');y+=dy; dlg_button(&ds,x,y,dx,cy,"3",'3'); x=x4; y=y4; dlg_button(&ds,x,y,dx,cy,"%",'%');y+=dy; dlg_button(&ds,x,y,dx,cy,"^",'^');y+=dy; dlg_button(&ds,x,y,dx,cy,"|",'|');y+=dy; dlg_button(&ds,x,y,dx,cy,"+",'+');y+=dy; dlg_button(&ds,x,y,dx,cy,"-",'-');y+=dy; dlg_button(&ds,x,y,2*dx+2,cy,"BS",1000); x=x5; y=y5; dlg_button(&ds,x,y,dx,cy,"<",'<');y+=dy; dlg_button(&ds,x,y,dx,cy,">",'>');y+=dy; dlg_button(&ds,x,y,dx,cy,"&&",'&&');y+=dy; ??? Hier ist ein Programmierfehler! Bei "&&",'&&' ist "&&" richtig aber das nochfolgende '&&' falsch. Warum? dlg_button(&ds,x,y,dx,cy,"*",'*');y+=dy; dlg_button(&ds,x,y,dx,cy,"/",'/'); x=x6; y=y6; dlg_button(&ds,x,y,dx,cy,"M+",1001);y+=dy; dlg_button(&ds,x,y,dx,cy,"M-",1002);y+=dy; dlg_button(&ds,x,y,dx,cy,"MR",1003);y+=dy; dlg_button(&ds,x,y,dx,cy,"MC",1004);y+=dy; dlg_button(&ds,x,y,dx,cy,"AC",1005);y+=dy; dlg_button(&ds,x,y,dx,cy,"EC",1006);y+=dy; dlg_editM(&ds,x0,y+4,95,70, "", IDC_EDIT); dlg_button(&ds, x0,DY-27,43,dy," Beenden ",IDOK); dlg_button(&ds,DX/2,DY-27,43,dy,"Quelltext",IDHELP); ///////////////////////////////////////////////// // jetzt kommt der spannende Create-Moment ... DialogBoxIndirect(GetModuleHandle(0), (LPDLGTEMPLATE)ds.buf,ghwnd,(DLGPROC)ds.dlgProc); } //Hauptprogramm int APIENTRY WinMain (HINSTANCE hInst,HINSTANCE hiPr,PSTR pCmd,int iShow) { hex_rechner_indirect(); return 0; } #include <windows.h> #include <windowsx.h> /////////////////////////////////////////////////////////// // class my_button zum // Erzeugen von Buttons /////////////////////////////////////////////////////////// class my_button { HWND _hBut,_hParent; public: my_button(HWND hParent,WORD idRes,LPSTR pText, int x,int y,int dx,int dy) { _hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON", pText,WS_VISIBLE | WS_CHILD, x,y,dx,dy, hParent,(HMENU)idRes,GetModuleHandle(0),0); _hParent = hParent; } my_button(HWND hParent, char ch, int x,int y,int dx,int dy) { char txt[2]; txt[1]='\0'; txt[0] = ch; WORD idRes = MAKEWORD(txt[0],txt[1]); _hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON", txt,WS_VISIBLE | WS_CHILD, x,y,dx,dy, hParent,(HMENU)idRes,GetModuleHandle(0),0); _hParent = hParent; } ~my_button(void){ DestroyWindow(_hBut); } }; /////////////////////////////////////////////////////////// // class my_edit zum // Erzeugen von Edit-Fenstern /////////////////////////////////////////////////////////// class my_edit { HWND _hEdt,_hParent; public: my_edit(HWND hParent,WORD idRes,LPSTR pText, int x,int y,int dx,int dy) { _hEdt = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT",pText, WS_VISIBLE | WS_CHILD, x,y,dx,dy, hParent, (HMENU)idRes, GetModuleHandle(0),0); _hParent = hParent; } my_edit(HWND hParent,WORD idRes,LPSTR pText, int x,int y,int dx,int dy,BOOL multiline) { if(multiline){ _hEdt = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", pText, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_OEMCONVERT, x,y,dx,dy,hParent,(HMENU)idRes,GetModuleHandle(0),0); _hParent = hParent; } else my_edit(hParent, idRes,pText,x,y,dx,dy); } HWND get_hwnd(void) { return _hEdt; } ~my_edit(void){ DestroyWindow(_hEdt); } }; /////////////////////////////////////////////////////////// // class my_combo zum // Erzeugen von ComboBox-Controls /////////////////////////////////////////////////////////// class my_combo { HWND _hCombo,_hParent; public: my_combo(HWND hParent,WORD idRes,int x,int y,int dx,int dy) { _hCombo = CreateWindowEx( WS_EX_CLIENTEDGE,"COMBOBOX","", WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_BORDER |CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS ,x,y,dx,dy,hParent,(HMENU)idRes,GetModuleHandle(0),0); //EnableWindow(_hCombo,TRUE); _hParent = hParent; } HWND get_hwnd(void) { return _hCombo; } BOOL set_text( LPSTR lpsz ) { return SetWindowText(_hCombo,lpsz); } BOOL get_text( LPSTR Buf, int sizBuf ) { return GetWindowText(_hCombo,Buf,sizBuf); } int add_text( LPSTR lpsz ) { return ((int)(DWORD)SendMessage( _hCombo,CB_ADDSTRING,0L,(LPARAM)(LPCTSTR)(lpsz))); } int get_text(int idx, LPSTR Buf, int sizBuf ) { return ((int)(DWORD)SendMessage( _hCombo,CB_GETLBTEXT,(WPARAM)idx,(LPARAM)(LPCTSTR)Buf)); } ~my_combo(void){ DestroyWindow(_hCombo); } }; //////////////////////////////////////////////////////// #define IDC_EDIT0 1000 #define IDC_EDIT1 1001 //////////////////////////////////////////////////////// LRESULT CALLBACK WndProc( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { int i; static my_button * pBut[256]; static my_edit * pEdt[2]; static my_combo * pCombo[1]; switch ( iMsg ) { case WM_CREATE : { int x,y, dx=19, dy=19; x=2; y=10; pEdt[0] = new my_edit(hwnd,IDC_EDIT0,"0",x,y,100,dy); pEdt[1] = new my_edit(hwnd,IDC_EDIT1,"Append:",x,y+150,100,100,TRUE); pCombo[0] = new my_combo(hwnd,4711,x,300,100,100); pCombo[0]->add_text("2"); pCombo[0]->add_text("1"); pCombo[0]->add_text("3"); pCombo[0]->set_text("Hallo ComboBox"); x=2; y=30; pBut['F'] = new my_button(hwnd,'F', x,y,dx,dy);y+=20; pBut['C'] = new my_button(hwnd,'C', x,y,dx,dy);y+=20; pBut['7'] = new my_button(hwnd,'7', x,y,dx,dy);y+=20; pBut['4'] = new my_button(hwnd,'4', x,y,dx,dy);y+=20; pBut['1'] = new my_button(hwnd,'1', x,y,dx,dy);y+=20; pBut['0'] = new my_button(hwnd,'0', x,y,dx,dy);y+=20; x=32; y=30; pBut['E'] = new my_button(hwnd,'E', x,y,dx,dy);y+=20; pBut['B'] = new my_button(hwnd,'B', x,y,dx,dy);y+=20; pBut['8'] = new my_button(hwnd,'8', x,y,dx,dy);y+=20; pBut['5'] = new my_button(hwnd,'5', x,y,dx,dy);y+=20; pBut['2'] = new my_button(hwnd,'2', x,y,dx,dy);y+=20; pBut['='] = new my_button(hwnd,'=', x,y,dx+dx+1,dy); x=52; y=30; pBut['D'] = new my_button(hwnd,'D', x,y,dx,dy);y+=20; pBut['A'] = new my_button(hwnd,'A', x,y,dx,dy);y+=20; pBut['9'] = new my_button(hwnd,'9', x,y,dx,dy);y+=20; pBut['6'] = new my_button(hwnd,'6', x,y,dx,dy);y+=20; pBut['3'] = new my_button(hwnd,'3', x,y,dx,dy);y+=20; // ... x=72; y=30; pBut['?'] = new my_button(hwnd,'?', x,y,dx,dy);y+=20; break ; } case WM_COMMAND: { // keine Notify-Nachrichten: if(HIWORD(wParam)) break; // aber Button- und Menu-Nachrichten in LOWORD(wParam): int idButton = LOWORD(wParam); //////////////////////////////////////////////////// // hier sind die Klick-Nachrichten zu verarbeiten //////////////////////////////////////////////////// // obere einzeilige hEdt0 char buf[256]; HWND hEdt0 = pEdt[0]->get_hwnd(); // schreibe formatiert in buf: int len0 = wsprintf(buf,"Button:%i",idButton); // gib buf in hEdt0 aus Edit_SetText( hEdt0, buf); ////////////////////////////////////////// // untere mehrzeilige hEdt1 int cBuf = 4000; char pBuf [ 4000 ]; HWND hEdt1 = pEdt[1]->get_hwnd(); // tue Text aus hEdt1 in pBuf Edit_GetText( hEdt1, pBuf, cBuf ); int len1 = Edit_GetTextLength(hEdt1); if( cBuf > len0 + len1 ) { strcat( pBuf, "\r\n"); strcat( pBuf, buf); } else { // bei Überlauf strcpy( pBuf, buf); } Edit_SetText( hEdt1, pBuf); Edit_Scroll(hEdt1, cBuf,0); break; } case WM_DESTROY : { int anz = sizeof(pBut)/sizeof(pBut[0]); for( i=0; i<anz; i++) if(pBut[i]) delete pBut[i]; PostQuitMessage( 0 ) ; break; } } // ende von switch ( iMsg ) return DefWindowProc( hwnd, iMsg, wParam, lParam ) ; } 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; } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.hInstance = GetModuleHandle(0); wc.hCursor = LoadCursor ( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "my_dlgclass" ; if ( ! RegisterClassEx( & wc ) ) return -1 ; hwndMain = CreateWindowEx(WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE, "my_dlgclass", "Hex-Taschenrechner", WS_CAPTION|WS_VISIBLE|WS_SYSMENU, 120,120,120,420, 0,0,GetModuleHandle(0),0); ShowWindow ( hwndMain, iShowMain ) ; UpdateWindow( hwndMain ) ; while ( GetMessage ( &msg,NULL,0,0)){ TranslateMessage( &msg ); DispatchMessage ( &msg ); } return msg.wParam ; } 6.Praktikum 1. Eine Win 32 - Applikation ist als neues Projekt zu schreiben. Die Anwendung soll als "Taskbar-Icon" starten. Hierzu wird BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid ); verwendet ( NIM_... Nachrichten ). Das beigelegte Programm soll auf "richtige" Ressourcen Icon, Menu und ein weiterer Dialog umgestellt werden. Erstellen Sie mit dem Resourcen-Workshop-Tool ein eigenes Icon IDI_ICON und ein Menu IDR_TRAYMENU und ändern Sie das Rahmenprogramm an den passenden Stellen. 2. Es ist ein Standard-File-Open-Dialog mit GetOpenFileName(&ofn)) zu verwenden. Das angefuegte Muster hat "Schwachstellen" ( auch logische! ). Diese sind zu beseitigen. Es ist eine "bessere" Routine zu schreiben. 3. Aus der eigenen Applikation sind *.exe-Programme ( wie z.B. notepad.exe ) zu starten. 4. Mit dem Resourcen-Workshop-Tool sind aus einem *.exe-File die Resourcen zu extrahieren und anzusehen ( verwenden Sie z.B. notepad.exe, comdlg32.dll, shell32.dll ) 5. Bei modalen Dialogen soll je Dialog bei Windows ein 4 Byte Wert ( Zeiger auf Instanz ) hinterlegt werden. Hierzu dienen die ...param()-Funktionen. Bitte testen. 6. Im Client-Bereich des Hauptfenster ist ein anderes Icon anzuzeigen und mit der Maus zu bewegen. Um mehrere Icons mit der Maus zu steuern, soll eine Klasse bIcon geschrieben werden. 7. OPTIONAL: Es ist mit der Windows-Klasse "BUTTON" eine C++-Klasse zu erstellen, die einen Button erzeugt und zu verschieben gestattet. 8. OPTIONAL: Das Icon soll in der Titelzeile Hauptfenster angezeigt werden. Im *cpp-Quelltext wird die String-Resource mit WNDCLASS wndclass.hIcon = LoadIcon ( hInstance,MAKEINTRESOURCE(IDI_MAIN)); geladen. Achten Sie bitte darauf, dass auch das "kleine" Icon in WNDCLASS gesetzt wird. StandardFile-Open-Dialog Es ist ein File-Open-Dialog gemaess dem angefuegten Muster eines Standard-Dialoges zu verwenden. #include <commdlg.h> // includes common dialog functionality char * get_Open_File_Name ( HWND hwnd, CHAR * pFilt, CHAR * pTitle ) { ??? char buf[MAX_PATH] ; buf[0] = '\0' ; OPENFILENAME ofn = { 0 } ; //ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof( OPENFILENAME ); ofn.hwndOwner = hwnd ; ofn.hInstance = GetModuleHandle( NULL ); ofn.lpstrTitle = pTitle ; ofn.lpstrFile = buf ; ofn.nMaxFile = sizeof( buf ) ; ofn.lpstrFilter = (pFilt) ? pFilt : "Alle Files (*.*)\000*.*\000" ; ofn.lpstrDefExt = "*" ; ofn.nFilterIndex = 1L ; ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) return buf;//(char*)ofn.lpstrFile; else return NULL ; } Achtung! Der String pFilt enthält Stringpaare mit \000 als Trennzeichen. Im Speicher ist pFilt durch \000\000 beendet. Der Aufruf von get_Open_File_Name() liefert den ausgewählten File-Namen. char * pFilNam = get_Open_File_Name( hwnd, "C-Dateien (*.c;*.cpp;)\000*.c;*.cpp;\000" "H-Dateien (*.h;*.hpp;)\000*.h;*.hpp;\000" "Text-Dateien (*.txt)\000*.txt\000" "Alle Files (*.*)\000*.*\000", "Titel von get_Open_File_Name" ); Programme starten Um z.B. notepad.exe mit dem ausgewählten File zu starten kann //Hinweis: case IDC_...: //Edit-Button strcpy( buf, "notepad " ) ; strcat( buf, pPfad ) ; WinExec( buf, SW_SHOW ) ; break ; ..param()-Funktionen Bei modalen Dialogen soll ( bei Windows ) je Dialog ein 4 Byte Wert ( Zeiger auf Instanz ) hinterlegt werden. LONG set_user_long (HWND hwnd, LPARAM val) { return SetWindowLong(hwnd,GWL_USERDATA,(LONG)val); } LONG get_user_long (HWND hwnd) { return GetWindowLong(hwnd,GWL_USERDATA); } Wird zum Aufruf des modalen Dialoges ret = DialogBoxParam( GetModuleHandle(NULL), MAKEINTRESOURCE(idDlg),hwnd, (DLGPROC) dlgProc, (LPARAM) this); } ( nicht DialogBox() ) verwendet, so wird der this-Zeiger bei case WM_INITDIALOG an die CALLBACK-Funktion durchgereicht und kann mit set_user_long() bei Windows hinterlegt werden. Hierdurch können Dialog-Daten zwischen CALLBACK-Funktion und Aufruf-Ebene übergeben werden. Dies ist zu testen //ACHTUNG! NICHT GESTESTET class bDLG { public: bDLG (HWND hwnd, int bDLG (HWND hwnd, int HWND _hwnd; CREATESTRUCT void * _buf; void * _bufOld; int _bufSize; int _idDlg, _ret; } ; ... idDlg, DLGPROC dlgProc); idDlg, DLGPROC dlgProc, void * buf, int sizebuf); _cs; bDLG::bDLG(HWND hwnd, int idDlg, DLGPROC dlgProc){ _bufSize = 0; _buf = NULL; _idDlg = idDlg; _hwnd = hwnd; _ret = DialogBoxParam( GetModuleHandle(NULL), MAKEINTRESOURCE(idDlg),hwnd, (DLGPROC) dlgProc, (LPARAM) this); } bDLG::bDLG(HWND hwnd, int idDlg, DLGPROC dlgProc, void * buf, int sizebuf){ _bufSize = sizebuf; _buf = buf; _idDlg = idDlg; _hwnd = hwnd; _ret = DialogBoxParam( GetModuleHandle(NULL), MAKEINTRESOURCE(idDlg),hwnd, (DLGPROC) dlgProc, (LPARAM) this); } optional: Button ( dynamisch) Es ist mit der Windows-Klasse "BUTTON" eine C++-Klasse class bBUTTON { ...} mit Hilfe von CreateWindow() zu erstellen, die einen Button erzeugt und mit SetWindowPos() positioniert. Dieser Button soll mit der Maus verschiebbar sein. optional: C++-bBUTTON-Klasse //Aufruf :bBUTTON pB = new bBUTTON(hwnd,"Hallo",100,10,80,20); //Zeichnen : pB->drawButton(LOWORD(lParam),HIWORD(lParam)); //Freigeben:delete pB; #include <windows.h> class bBUTTON { public: bBUTTON(HWND hParent, LPSTR pText, int x, int y, int dx, int dy ); //??virtual void setPos( x, y); virtual void drawButton( void); int _x, _y, _dx, _dy; HWND _hButton, _hParent; LPSTR _pText; }; bBUTTON::bBUTTON(HWND hParent, LPSTR pText, int x, int y, int dx, int dy ){ _hParent = hParent; _pText = pText; _x = x; _y = y; _dx = dx; _dy = dy; _hButton = CreateWindow( "BUTTON",_pText,WS_VISIBLE | WS_CHILD, _x,_y,_dx,_dy,hParent,NULL,GetModuleHandle(NULL),NULL); } void bBUTTON::drawButton( void ){ SetWindowPos(_hButton,HWND_TOP,_x,_y,_dx,_dy,SWP_SHOWWINDOW); } optional: Icon Einem neuen Projekt ( "Hallo Welt" ) wird nun ein Resourcenskript hinzugefügt. Die resource.rc - Erstellung mit dem Resourcen-Workshop-Tool ( hier Icon ) hat etwa folgende Schritte: Datei Neu Resourcenskript auf resource.rc rechte Maustaste und einfügen... Icon neu Das Icon soll den Identifizierer IDI_MAIN erhalten ( Doppelklick und Eigenschaften ). resource.h und resource.rc sind dem Projekt hinzuzufügen. Zum Laden von Resourcen werden im *.cpp-File sogenannte Load-Funktionen benötigt. Load-Funktionen haben einen hInstance-Parameter. HINSTANCE hInstance = GetModuleHandle( NULL ); //oder durch //HINSTANCE hInstance = (HINSTANCE) GetWindowLong( hwnd, GWL_HINSTANCE ); //statisch in Windows-Klasse eintragen z.B. durch WNDCLASS wndclass.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN) ); //dynamisch in Windows-Fenster-Klasse eintragen z.B. durch HICON hIconOld = (HICON)SetClassLong(hwnd,GCL_HICONSM, (LONG)LoadIcon(NULL,IDI_HAND)); optional: Icon (dynamisch) Um mehrere Icons mit der Maus zu steuern, soll eine Klasse bIcon geschrieben werden: ● ● ● ● ● ● Der Konstruktor z.B. bIcon * pIcon = new bIcon(10,20,IDI_MAIN); ❍ erzeugt die Instanz ❍ läd das IDI_MAIN - Icon ❍ speichert die x,y - Positionswerte Um auch verfügbares Icons des Systems ( z.B. IDI_ASTERISK ) verwenden zu können ist LoadIcon(NULL,MAKEINTRESOURCE(idIcon)) zu verwenden. Der Konstruktor kann gemäß bIcon(int x, int y, LPCTSTR idIcon ) überladen werden. pIcon->drawIcon(hDC) zeichnet das Icon, wenn durch pIcon->setOn() das Zeichenflag gesetzt ist. pIcon->setOn() bzw. pIcon->setOff() setzen die Zeichenflags auf TRUE bzw. FALSE. Durch delete pIcon; wird die Klasse freigegeben Um bei WM_PAINT einen eingeschränktes Rechteck neu zu zeichnen kann x1=x; x=dx=LOWORD(lParam); x0=x1+x; if(x < x1)dx=x1; y1=y; y=dy=HIWORD(lParam); y0=y1+y; if(y < y1)dy=y1; SetRect( & rc, x0-dx,y0-dy, dx+32,dy+32 ); InvalidateRect(hwnd, & rc, TRUE); durchdacht und berücksichtigt werden optional: C++-bIcon-Klasse //bIcon pI = new bIcon(10,10,IDI_MAIN); pIcon->setOn(); // pI->setOn(); pI->setOff(); // pI->setPos(LOWORD(lParam),HIWORD(lParam)); // pI->drawIcon(hDC); //delete pI; //InvalidateRect(hwnd,NULL,TRUE); #include <windows.h> class bIcon { public: bIcon(int x, int y, WORD idIcon ); virtual void drawIcon(HDC hDC ); virtual void setPos( int x, int y); virtual void setOn(void); virtual void setOff(void); HICON hIcon; int _x, _y; BOOL fDraw; }; bIcon::bIcon(int x, int y, WORD idIcon){ //User hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(idIcon)); setPos ( x, y ); setOn(); } void bIcon::setOn (void){ fDraw=TRUE; } void bIcon::setOff(void){ fDraw=FALSE; } void bIcon::setPos ( int x, int y ){ _x=x; _y=y; } void bIcon::drawIcon(HDC hDC ){ if(fDraw) DrawIconEx(hDC,_x,_y,hIcon,32,32,0,NULL,DI_NORMAL); } Die mittige Zentrierung etwa wie folgt: RECT rc ; 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 ) ; #include <windows.h> typedef BOOL (* MENUFUNC)(HWND hwnd); ////////////////////////////////////////////////// // Prototypen ////////////////////////////////////////////////// BOOL fn_tray_create (HWND hwnd); BOOL fn_tray_destroy (HWND hwnd); BOOL fn_tray_notifcation(HWND hwnd); BOOL fn_tray_hide (HWND hwnd); BOOL fn_tray_show (HWND hwnd); BOOL fn_tray_about (HWND hwnd); ////////////////////////////////////////////////// // von Hand erstelltes Menu ////////////////////////////////////////////////// typedef struct _MENU_STRUCT { WORD _id; // Menu-Id's, etwa ab 100 LPSTR _txt; // Menu-Popup/Item-Text MENUFUNC _fn; // auzurufende Funktion } MENU_STRUCT; HMENU my_set_menu(HWND hwnd, MENU_STRUCT * pMenu) { HMENU hMenu=CreateMenu(), hPopup = NULL; LPSTR pSave=NULL; int j,k=0; if((!hwnd)||(!pMenu))return NULL; while(pMenu[k]._txt){ hPopup = CreateMenu(); for(j=k+1; pMenu[j]._id; j++){ AppendMenu(hPopup,MF_STRING,pMenu[j]._id,pMenu[j]._txt); } AppendMenu(hMenu, MF_POPUP,(UINT_PTR)hPopup,pMenu[k]._txt); k = j; } //if(!hMenu)DestroyMenu(hMenu); SetMenu(hwnd,hMenu); return hMenu; } ////////////////////////////////////////////////// // Shell_NotifyIcon() bringts ... ////////////////////////////////////////////////// BOOL my_tray_message(HWND hwnd, DWORD iMsg, HICON hIcon, PSTR pszTip){ NOTIFYICONDATA tnd = {0}; tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = hwnd; tnd.uID = ID_TRAYICON; tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; tnd.uCallbackMessage = WM_TRAY_NOTIFICATION; tnd.hIcon = hIcon; lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip)); BOOL res = Shell_NotifyIcon(iMsg, &tnd); if (hIcon) DestroyIcon(hIcon); return res; } ////////////////////////////////////////////////// // Menu-Aufrufe ... ////////////////////////////////////////////////// BOOL fn_tray_hide(HWND hwnd){ ShowWindow(hwnd, SW_HIDE);return TRUE;} BOOL fn_tray_show(HWND hwnd){ ShowWindow(hwnd, SW_SHOW);return TRUE;} BOOL fn_tray_about(HWND hwnd) { MessageBox(hwnd,"","Tray-Icon",MB_OK|MB_ICONINFORMATION); return TRUE; } HMENU my_menu1(HWND hwnd) { // alternativ mit Ressourcen: // HMENU hMenu = LoadMenu(GetModuleHandle(0),MAKEINTRESOURCE(IDR_TRAYMENU)),0); // SetMenu(hwnd,hMenu); MENU_STRUCT menu_struct[] = { { 0, "Tray-App", 0 }, { 110, "anzeigen", fn_tray_show }, { 120, "verstecken",fn_tray_hide }, { 130, "Info", fn_tray_about }, { 140, "beenden", fn_tray_destroy }, { 0, "Pop2", 0 }, { 4718, "Item 4718", 0 }, {0,NULL,0}};// <== Endekriterium ist Pflicht! HMENU hMenu = my_set_menu(hwnd, menu_struct); return hMenu; } BOOL fn_tray_create(HWND hwnd) { HICON hIcon = LoadIcon(NULL, IDI_APPLICATION); HMENU hMenu = my_menu1(hwnd); SetMenu(hwnd,hMenu); my_tray_message(hwnd, NIM_ADD, NULL, NULL); my_tray_message(hwnd, NIM_MODIFY, hIcon, "Kurzinfo"); return TRUE; } BOOL fn_tray_destroy(HWND hwnd) { my_tray_message(hwnd, NIM_DELETE, NULL, NULL); PostQuitMessage( 0 ); return TRUE; } BOOL fn_tray_notifcation(HWND hwnd) { HMENU hMenu = my_menu1(hwnd); POINT mouse; GetCursorPos(&mouse); HMENU hMenuSub = GetSubMenu(hMenu,0); TrackPopupMenu(hMenuSub,0,mouse.x,mouse.y,0,hwnd,NULL); return TRUE; } ////////////////////////////////////////////////// // CALLBACK-Funktion ////////////////////////////////////////////////// LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch( iMsg ) { case WM_TRAY_NOTIFICATION: switch (lParam ){ case WM_RBUTTONUP: fn_tray_notifcation(hwnd); break; case WM_LBUTTONDBLCLK: break; //hat Klasse Doppeklicks? } // ende switch (lParam ) break; case WM_CREATE: { //hIcon = (HICON)LoadImage(GetModuleHandle(0),MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,0); HICON hIcon = LoadIcon(NULL, IDI_APPLICATION); my_tray_message(hwnd, NIM_ADD, NULL, NULL); my_tray_message(hwnd, NIM_MODIFY, hIcon, "Kurzinfo"); break;} case WM_COMMAND: { switch(LOWORD(wParam)) { case 110: fn_tray_show(hwnd); break;//{ 110, "anzeigen", fn_tray_show }, case 120: fn_tray_hide(hwnd); break;//{ 120, "verstecken",fn_tray_hide }, case 130: fn_tray_about(hwnd); break;//{ 130, "Info", fn_tray_about }, case 140: fn_tray_destroy(hwnd); break;//{ 140, "beenden", fn_tray_destroy }, //case xxx: // DialogBox(GetModuleHandle(0),MAKEINTRESOURCE(IDD_ABOUT), // hwnd,(DLGPROC)DlgProc); break; } // ende switch(LOWORD(wParam)) break; } // ende von WM_COMMAND case WM_DESTROY: fn_tray_destroy(hwnd); break; } // ende von switch( iMsg ) return DefWindowProc( hwnd, iMsg, wParam, lParam ); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); //alternativ LoadIcon(hInstance, (LPCTSTR)IDI_ICON); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); //alternativ LoadIcon(wc.hInstance, (LPCTSTR)IDI_ICON); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground= (HBRUSH) (COLOR_WINDOW); wc.lpszMenuName = 0;//alternativ (LPTSTR) IDR_WINMENU; wc.lpszClassName= "my_class"; RegisterClassEx(&wc); HWND hwnd = CreateWindow("my_class", "TrayIcon Beispiel", WS_OVERLAPPEDWINDOW, 50,50,200,60, NULL,NULL,hInstance,NULL); if( !hwnd ) return FALSE; HMENU hMenu = my_menu1(hwnd); ShowWindow( hwnd, SW_HIDE ); UpdateWindow( hwnd ); MSG msg; while( GetMessage(&msg,NULL,0,0)) { TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; } 7. Praktikum Diese Aufgabe besteht im darin, mit Modeless-Dialogen zu arbeiten. ● Zum Üben und besseren Verstehen beginnen Sie bitte mit einem "Hallo Welt"-Programm und fügen ein Menü ( für Dialog-Aufrufe ) ein, erstellen 2 einfache Dialog-Rssourcen, wie z.B. und die Callback-Funktion mit Dialog-Aufrufen ( zunächst für modale Dialoge ) unter WM_COMMAND, switch (LOWORD(wParam)), case IDM_...: DialogBox(hwnd, IDD_..., (DLGPROC)myDlgProc) unter WM_CLOSE: EndDialog(hwnd, bel_return_zahl); unter WM_DESTROY: PostQuitMessage(0); BOOL CALLBACK my_dlgProc //Muster ( HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam){ switch ( iMsg ) { case WM_INITDIALOG: ... break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDM_...:{ break; } case IDM_...:{ break; } } break; } case WM_CLOSE: EndDialog(hwnd,...); // DestroyWindow(hwnd); break; } return FALSE; } ● Unter WM_INITDIALOG werden nun die benötigten Control-Handles hCtrl... in static-Variablen geholt ( ggf. können die hCtrl... auch ohne static benutzt werden, müssen dann aber jeweils bei Bedarf vor der Verwendung neu geholt werden ). HWND hCtl... = GetDlgItem(hwnd, ID_CTRL...); //int idCtrl = GetDlgCtrlID(hCtl...); Mit diesen hCtl... können nun Nachrichten an die "EDIT"-, COMBOBOX"-, usw. CALLBACK-Funktionen der Controls geschickt werden. SendMessage(hCtl,iMsg,wParam,lParam); günstiger sind oft die "gecasteten SendMessage-Macros" aus "windowsx.h", wie z.B. Edit_SetText(hCtl..., "mein Text" ); Initialisieren Sie bitte unter WM_INITDIALOG die Controls wie gewünscht. ● ● ● Lesen Sie z.B. per Butten-Klick aus einem Control einen Text aus und schreiben diesen in ein anderes Control. Wenn dies funktioniert, stellen Sie bitte auf Modeless-Dialoge um, indem static HWND hDlg; CALLBACK-intern angelegt wird und unter WM_CLOSE: EndDialog() durch DestroyWindow() ersetzt wird und unter WM_COMMAND, switch (LOWORD(wParam)) bei case IDM_...: anstelle DialogBox() nun hDlg = CreateDialog(GetModuleHandle(0),MAKEINTRESOURCE(IDD_...), hwnd,(DLGPROC)myDlgProc); verwendet wird. Wenn dies funktioniert, ersetzen Sie bitte CreateDialog() durch CreateDialogParam() und beobachten mit dem Debugger das "Reinkommen" des Parameters bei WM_INITDIALOG. ● Überlegen Sie, wie Sie es erreicht können, dass z.B. bei den sichtbaren Dialogen 1,2,3 der Modeless Dialog 1 nicht zusätzlich ( unnötig ) geöffnet werden kann. ● Nun wrd das globale HWND hDlgModeless für den einen, aktiven Modeless-Dialog angelegt. ● Nun wird für Modeless-Dialoge die Haupnachrichten-Schleife ergänzt: while ( GetMessage( & msg, NULL, 0, 0 ) ) { if ( NULL == hDlgModeless || ! IsDialogMessage( hDlgModeless, & msg ) ) { TranslateMessage( & msg ); DispatchMessage ( & msg ); } } ● In jeder Modeless-Dialog-CALLBACK-Funktion wird die WM_ACTIVATE-Nachricht zum Umschalten des hDlgModeless benutzt. ... switch ( iMsg ) { case WM_ACTIVATE: { if ( 0 == wParam ) hDlgModeless = NULL; // wird inactive else hDlgModeless = hWnd; // wird active return FALSE; break; } case WM_CLOSE: { // ggf. Heap-freigeben if( hDlgModeless == hWnd ) DestroyWindow( hWnd ) ; break; } ... ● Erstellen Sie einen zusätzlichen Edit-Dialog möglichst nach den folgenden Vorgaben: ... mit Resourcen-Workshop erstellen: IDC_COMBO_FIND IDC_BUTTON_FIND IDC_COMBO_REPL IDC_BUTTON_REPL Dialog Edit-Control Allgemein: Allgemein: ID: IDC_EDIT ID: IDD_ ... [x] Sichtbar Titel: ... [x] Tabstop Formate: Formate: Stil: Kontextmenü Text ausrichten: links Rand: Größe ändern [x] Mehrzeilig [x] Titelleiste [x] Auto Hor. Bildlauf [x] Systemmenü [x] Auto Vert. Bildlauf [x] Minimieren Schaltfläche [x] Return möglich [x] Maximieren Schaltfläche [x] Rand Weitere Formate: Weitere Formate: [x] Sichtbar [x] Sichtbar [x] Vordergrund setzen [x] Vordergrund setzen [x] Zentriert [x] Zentriert Schreiben Sie eine CALLBACK-Funktionen dlg_edit() für diesen Dialog ( siehe mitgelieferte Quelltexte ) Betrachten Sie den mitgelieferten Quelltext, der ohne externe Ressourcen auskommt. ● ● Nun soll in einen Dialog ein bmp-Bild eigefügt werden. Ein Bild kann eingefügt werden etwa durch: case WM_INITDIALOG : { HBITMAP bild = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP1)); HWND hbmp = CreateWindowEx( WS_EX_LEFT, "static", NULL, WS_CHILD | SS_BITMAP, 0,0,GetSystemMetrics(SM_CXMAXIMIZED),GetSystemMetrics(SM_CYMAXIMIZED), hwnd, (HMENU)NULL, GetModuleHandle(NULL), NULL); SendMessage(hbmp,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)bild); SetWindowPos( hbmp, HWND_BOTTOM, 0,0,GetSystemMetrics(SM_CXMAXIMIZED),GetSystemMetrics(SM_CYMAXIMIZED), SWP_SHOWWINDOW );//oder ShowWindow(hbmp,SW_SHOWNORMAL ) ; } break; ● Nun ist eine Kofigurationsdatei zu verwenden. Windows-Applikationen benutzen *.INI - Files, in die zahlreiche Informationen ( Start-Parameter, Treiber-Programme, usw. ) fuer die Applikation eingetragen werden können. Die Profile-Funktionen sind auf die Benutzung der INI-Files ( Kofigurationsdatei wie z.B. my App.ini ) abgestimmt. Die folgenden Anweisungen zeigen die Nutzung: #define err(errStr) if(MessageBox(0,(errStr),0, \ MB_OKCANCEL)-1){*((void **)0)=0;} ------------------------- dies kann eine init-Func fuer *.ini werden: // hole Pfad-fileNamen.EXE der Applikation char fileName[MAX_PATH]; HANDLE hFile; DWORD n2,n1 = GetModulefileName(GetModuleHandle(0),fileName,sizeof(fileName)); // ersetze EXE durch INI lstrcpy(fileName+lstrlen(fileName)-3, "ini"); // prüfe, ob dieser INI-File bereits existiert: hFile = CreateFile(fileName,GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); // falls der INI-File noch nicht existiert, erstelle diesen INI-File: if (GetLastError()!=0) {// s. WINERROR.H hFile = CreateFile(fileName,GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); if (GetLastError()!=0) err("CreateFile"); char * pInitStr = "[TOOLDIR]\r\n" "BcLib=d:\\bc\\BC45\\LIB\r\n" "BcInclude=d:\\bc\\BC45\\INCLUDE\r\n\r\n" "[IDE]\r\n" "DefaultDesktopDir=d:\\bc\\BC45\\BIN\r\n" "HelpDir=d:\\bc\\BC45\\BIN\r\n" "[START]\r\n" "Status=TRUE\r\n" "Links=4\r\n" "Rechts=2\r\n" "Breite=-550\r\n" "Höhe=608\r\n"; n1 = lstrlen(pInitStr); // schreibe die pInitStr-Initialisierung in den INI-File if(!WriteFile(hFile,pInitStr,n1,&n2,NULL))if(n1!=n2)err("diskFull"); } CloseHandle(hFile); ----------------------------------------------Beispiele fuer das Arbeiten mit ProfileString's: // hole HelpDir aus INI, schreibe nach buf char buf[512]; GetPrivateProfileString("IDE","HelpDir","?", buf,sizeof(buf),fileName); // hinterlege einen Text in INI WritePrivateProfileString("START","Status","FALSE",fileName ) ; // hinterlege eine int-Zahl in INI int breite=+1234; wsprintf(buf, "%d", val ) ; WritePrivateProfileString("START","Breite", buf,fileName ) ; // hole eine int-Zahl aus INI GetPrivateProfileString("START","Breite","0", buf,sizeof(buf),fileName); breite = atoi(buf) ; Schreiben Sie einfach zu benutzende Profile-Funktionen, die das Arbeiten mit solchen privaten Profile Strings erleichtern. Wie können Einträge gelöscht werden? //Modeless-Dialoge #include <windows.h> #include "resource.h" HINSTANCE hInst; HWND hDlgModeless; HWND h_ML[10]; //Handles auf ModlessDlg's BOOL CALLBACK my_dlgProc1 //Muster ( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam){ switch ( iMsg ) { case WM_INITDIALOG:{ }break; case WM_CLOSE:{ }break; case WM_ACTIVATE: if ( WA_INACTIVE == LOWORD(wParam) ) { _hModeless = NULL;//becoming inactive } else { _hModeless = hwnd;//becoming active } return FALSE; } return FALSE; } //...BOOL CALLBACK my_dlgProc2 ... wie oben //...BOOL CALLBACK my_dlgProc3 ... wie oben LRESULT CALLBACK WndProc //Muster ( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam){ switch ( iMsg ) { case WM_CREATE: break; case WM_COMMAND: { switch (LOWORD(wParam)) { case ID_DLG1: ShowWindow( h_ML[1],SW_SHOW);break; case ID_DLG2: ShowWindow( h_ML[2],SW_SHOW);break; case ID_HIDE1:ShowWindow( h_ML[1],SW_HIDE);break; case ID_HIDE2:ShowWindow( h_ML[2],SW_HIDE);break; } break; } case WM_CLOSE: { char buf[256]; int ret; GetWindowText(hwnd,buf,sizeof(buf) ) ; ret=MessageBox(hwnd,"Exit?","Exit?",MB_ICONQUESTION|MB_YESNO); if ( IDNO == ret ) return TRUE; DestroyWindow(hwnd); } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd,iMsg,wParam,lParam); } int APIENTRY WinMain( HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain) { hInst = hInstance; //=GetModuleHandle(0); WNDCLASSEX wc = { 0 } ; MSG msg ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.cbClsExtra = 0 ; wc.cbWndExtra = 0 ; wc.hInstance = hInst ; wc.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wc.hCursor = LoadCursor( NULL, IDC_ARROW ) ; wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wc.lpszMenuName = (LPSTR) IDR_MENU1 ; wc.lpszClassName = "my_class" ; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION ); //auch bei: //WM_CREATE, WM_INITDIALOG: //HMENU hMenu = LoadMenu(hInst,(LPSTR)ID_..); // SetMenu(hwnd,hMenu); //HICON hIcon = ExtractIcon(hInst,"Shell32.dll",41); //SetClassLong(hwnd,GCL_HICON,(long)hIcon); if ( ! RegisterClassEx( & wc ) ) return -1 ; h_ML[0]= CreateWindowEx(WS_EX_LEFT,"my_class", "Hauptfenster-Titel", WS_OVERLAPPEDWINDOW,//window style 20,20,420,240, //x,y,dx,dy NULL, NULL,hInst,NULL); //WM_NCCREATE,WM_NCCALCSIZE,WM_CREATE ShowWindow (h_ML[0], SW_SHOW) ; UpdateWindow(h_ML[0]) ; h_ML[1]= CreateDialog(hInst,(LPSTR)IDD_DLG1,h_ML[0],my_dlgProc1); h_ML[2]= CreateDialog(hInst,(LPSTR)IDD_DLG2,h_ML[0],my_dlgProc2); while ( GetMessage( & msg, NULL,0,0)) { if ( NULL == hDlgModeless || ! IsDialogMessage(hDlgModeless,&msg)) { TranslateMessage( & msg ); DispatchMessage ( & msg ); } } DestroyWindow(h_ML[0]); DestroyWindow(h_ML[1]); DestroyWindow(h_ML[2]); return 0; } ///////////////////////////////////////////////////// // dlg_modeless.cpp ///////////////////////////////////////////////////// #ifndef _MYMODELESS_ #define _MYMODELESS_ #include <windows.h> // wird immer gebraucht #include <windowsx.h> #include <wchar.h> // für das Menu #define err(errStr) MessageBox(0,(errStr),0,MB_OK) #define err_if(p,errStr) if(p)MessageBox(0,(errStr),0,MB_OK) #define get_pDlg(hwnd) (DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA); ////////////////////////////////////////////// // global verfügbar ////////////////////////////////////////////// typedef BOOL (* MENUFUNC)(HWND hwnd); static HWND _hModeless; //global static HINSTANCE _hInst; //global static MENUFUNC _mfunc;//EINE fn aktiv typedef struct _MENU_STRUCT { WORD _id; // Menu-Identifizierer, etwa ab 100 LPSTR _txt; // Menu-Item-Text MENUFUNC _fn; // auzurufende Funktion } MENU_STRUCT; typedef struct _DLG_STRUCT { HWND hwnd; LPSTR pKlasse; LPSTR pText; WORD x,y,cx,cy; } DLG_STRUCT; /////////////////////////////////////////// // class CREATE_DLG_INDIRECT /////////////////////////////////////////// class DLG_INDIRECT { MENU_STRUCT *_pMenu; //_pMenu muss immer zuerst sein int _nCtrl; HWND _hParent; DLG_STRUCT *_pFirst, *_pLast; int nCopyAnsiToWideChar (LPWORD p, LPSTR lpAnsiIn) { int nChar = 0; do { *p++ = (WORD)*lpAnsiIn; nChar++; } while (*lpAnsiIn++); return nChar; } public: ~DLG_INDIRECT() { HWND hWnd = this->get_hwnd(); if(hWnd) { HMENU hMenu = GetMenu(hWnd); if(hMenu)DestroyMenu(GetMenu(hWnd)); DestroyWindow(hWnd); } } DLG_INDIRECT(HWND hParent, DLG_STRUCT * pDlg, DLGPROC dlgProc) { _nCtrl = 0; _pMenu = NULL; _pFirst = _pLast = NULL; _hParent= hParent; HWND hDlg = create_dlg_indirect(pDlg,dlgProc); if(!hDlg||(hDlg!=this->get_hwnd())) err("ERR: pDlg??, dlgProc??"); } MENU_STRUCT * get_pMenu() { return _pMenu; } DLG_STRUCT * get_pFirst() { return _pFirst;} DLG_STRUCT * get_pLast() { return _pLast; } int get_nCtrl() { return _nCtrl; } HWND get_parent() { return _hParent; } HWND get_hwnd() { if(!_pFirst)return NULL; return _pFirst->hwnd; } HWND get_hwnd(int i) { if(i>get_nCtrl())return NULL; return (_pFirst+i)->hwnd; } HWND set_hwnd(HWND hwnd) { if(!_pFirst) return NULL; HWND hwnd_old = _pFirst->hwnd; _pFirst->hwnd = hwnd; return hwnd_old; } HMENU create_menu(MENU_STRUCT * pMenu) { HMENU hMenu = CreateMenu(), hPopup = NULL; int j,k=0; if(!pMenu)return NULL; LPSTR pSave=NULL; while(pMenu[k]._txt) { hPopup = CreateMenu(); for(j=k+1; pMenu[j]._id; j++){ AppendMenu(hPopup,MF_STRING, pMenu[j]._id, pMenu[j]._txt); } AppendMenu(hMenu,MF_POPUP, (UINT_PTR)hPopup,pMenu[k]._txt); k = j; } return hMenu; } BOOL set_menu(MENU_STRUCT * pMenu) { HWND hwnd = get_hwnd(); if(!hwnd) return FALSE; HMENU hMenu = create_menu(pMenu); if(!hMenu)return FALSE; DestroyMenu(GetMenu(hwnd)); if(!SetMenu(hwnd,hMenu)) return FALSE; _pMenu = pMenu; return TRUE; } BOOL do_wm_command_func(DLG_INDIRECT *pDlg,WPARAM wParam ) { if(!pDlg) return FALSE; MENU_STRUCT *p = pDlg->_pMenu; if(!p) return FALSE; HWND hwnd = get_hwnd(); if(!hwnd ) return FALSE; while ( p->_txt ) { if ( p->_id == LOWORD(wParam) ) { if( p->_fn ) return p->_fn(hwnd); } p++; } return FALSE; } HWND create_dlg_indirect( DLG_STRUCT * pDlg, DLGPROC dlgProc) { #define es_ist(str) (CSTR_EQUAL==CompareString(\ LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,(str),-1,pD->pKlasse,-1)) DWORD lStyle, lExtStyle; DLG_STRUCT * pD; WORD pDlgStruct[8000] = {0}, *p = pDlgStruct; int i; _nCtrl=0; if(!pDlg)return NULL; while((pDlg+_nCtrl)->pKlasse) _nCtrl++; _pFirst = pDlg; _pLast = pDlg + _nCtrl; _nCtrl--; // Dialog: ///////////////////////////////////////////// pD = _pFirst; //pD zeigt auf den 0-ten DLG_STRUCT-Eintrag if(!es_ist("DIALOG"))return NULL; lStyle = WS_OVERLAPPEDWINDOW|DS_MODALFRAME|DS_SETFOREGROUND|DS_SETFONT; //|WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX //WS_VISIBLE lExtStyle = WS_EX_DLGMODALFRAME;//|WS_EX_TOPMOST;//|WS_EX_CONTROLPARENT|WS_EX_NOPARENTNOTIFY;//WS_EX_CLIENTEDGE *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = _nCtrl; *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = 0; // Menu *p++ = 0; // Class p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 10; // point size; braucht DS_SETFONT p += nCopyAnsiToWideChar(p,TEXT("Times New Roman")); // p += nCopyAnsiToWideChar(p,TEXT("Courier New")); for ( i=1; i<=_nCtrl; i++){ p = (WORD*)(((DWORD)p + 3) & ~3); // WORD align pD = _pFirst + i; //pD zeigt auf den i-ten DLG_STRUCT-Eintrag if(es_ist("STATIC")){ lStyle = WS_VISIBLE|WS_CHILD |SS_NOPREFIX|SS_LEFTNOWORDWRAP; lExtStyle = 0;//WS_EX_CLIENTEDGE|WS_EX_STATICEDGE; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = 0xffff; //IDOK; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0082;// alternativ: //p += nCopyAnsiToWideChar(p,TEXT("STATIC")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("BUTTON")){ lExtStyle = 0;//WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab0 //; lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP |BS_PUSHBUTTON; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; //IDOK; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0080;//alternativ: //p += nCopyAnsiToWideChar(p,TEXT("BUTTON")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("LISTBOX")){ lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab ; lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_TABSTOP |LBS_DISABLENOSCROLL |LBS_HASSTRINGS|LBS_STANDARD; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0083;//alternativ: //p += nCopyAnsiToWideChar(p,TEXT("LISTBOX")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("EDIT")){ lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT;//tab ;//WS_EX_DLGMODALFRAME lStyle = WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_CLIPSIBLINGS|WS_TABSTOP |ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0081;// alternativ: //p += nCopyAnsiToWideChar(p,TEXT("EDIT")); p += nCopyAnsiToWideChar(p,TEXT(pD->pText)); *p++ = 0; } else if(es_ist("COMBOBOX")){ lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab ; lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_TABSTOP |CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS; *p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle); *p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle); *p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy; *p++ = i; // ID *p++ = (WORD)0xffff; *p++ = (WORD)0x0085; //alternativ: //p += nCopyAnsiToWideChar(p,TEXT("COMBOBOX")); p += nCopyAnsiToWideChar(p,TEXT(""));//pD->pText)); *p++ = 0; } } // ende for HWND hDlg = CreateDialogIndirectParam(_hInst, (LPDLGTEMPLATE)pDlgStruct,_hParent,(DLGPROC)dlgProc,(LONG)this); return hDlg; } #undef es_ist /////////////////////////////////////////// // ende class CREATE_DLG_INDIRECT /////////////////////////////////////////// }; static BOOL def_modeless_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { //Achtung! Haupt-CALLBACK braucht: //case WM_DESTROY: PostQuitMessage(0); break; static HICON hIcon; switch ( iMsg ) { case WM_ACTIVATE:{ if ( WA_INACTIVE == LOWORD(wParam) ) { _hModeless = NULL;//wird inactive } else { _hModeless = hwnd;//wird active } break; } case WM_INITDIALOG: { DLG_INDIRECT *pDlg = (DLG_INDIRECT*)lParam; if(pDlg)if(pDlg->get_hwnd()) { SendMessage(hwnd,WM_CLOSE,0,0);break; } pDlg->set_hwnd(hwnd); DLG_STRUCT * pLast = pDlg->get_pLast(); DLG_STRUCT * pFirst = pDlg->get_pFirst(); DLG_STRUCT * p = pFirst; for ( int i=1; i <= pDlg->get_nCtrl(); i++) { //Ctrl's p = pFirst + i; p -> hwnd = GetDlgItem(hwnd, i); // !!! if(CSTR_EQUAL==CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,"COMBOBOX",-1,p->pKlasse,-1)){ SetWindowText(p->hwnd,p->pText); } else if(CSTR_EQUAL==CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,"LISTBOX",-1,p->pKlasse,-1)){ SendMessage(p->hwnd,LB_ADDSTRING,0L,(LPARAM)p->pText); } } //ende for RECT rc; GetWindowRect(hwnd, &rc); pLast->x = (WORD) rc.left; pLast->y = (WORD) rc.top; pLast->cx = (WORD) (rc.right - rc.left); pLast->cy = (WORD) (rc.bottom- rc.top); SetWindowLong(hwnd,GWL_USERDATA,(LONG)pDlg); HICON hIcon = ExtractIcon(_hInst,"Shell32.dll",41); SetClassLong(hwnd,GCL_HICON,(long)hIcon ); break; } case WM_ERASEBKGND: if(IsIconic(hwnd)&&hIcon) { SendMessage(hwnd,WM_ICONERASEBKGND,wParam,0L);return TRUE; break; } case WM_QUERYDRAGICON: return (BOOL)hIcon; case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); if(IsIconic(hwnd)) { // If iconic, paint the icon. if(hIcon) { RECT rc; GetClientRect(hwnd,&rc) ; rc.left = (rc.right - GetSystemMetrics(SM_CXICON))>>1; rc.top = (rc.bottom - GetSystemMetrics(SM_CYICON))>>1; DrawIcon(ps.hdc,rc.left,rc.top,hIcon); } } EndPaint( hwnd, &ps ); break;} case WM_GETMINMAXINFO:{ if (IsIconic(hwnd))return FALSE; //DLG_INDIRECT *pDlg=(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA); DLG_INDIRECT *pDlg = get_pDlg(hwnd); if(!pDlg)if(!pDlg->get_pFirst())break; HWND h = pDlg->get_hwnd(); if(h) if( h != hwnd ){SendMessage(hwnd,WM_CLOSE,0,0);break;} LPMINMAXINFO lpmmi= (LPMINMAXINFO)lParam; DLG_STRUCT * pLast = pDlg->get_pLast(); lpmmi->ptMinTrackSize.x =3*GetSystemMetrics(SM_CXHTHUMB); lpmmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION); lpmmi->ptMaxPosition.x = pLast->x; lpmmi->ptMaxPosition.y = pLast->y; lpmmi->ptMaxSize.x = lpmmi->ptMaxTrackSize.x = pLast->cx; lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y = pLast->cy; break; } case WM_WINDOWPOSCHANGED: { LPWINDOWPOS lpwp =(LPWINDOWPOS) lParam; //DLG_INDIRECT *pDlg=(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA); DLG_INDIRECT *pDlg = get_pDlg(hwnd); if(!pDlg)if(!pDlg->get_pFirst())break; DLG_STRUCT * pLast = pDlg->get_pLast(); pLast->x =(WORD) lpwp->x; pLast->y =(WORD) lpwp->y; break; } case WM_CLOSE: { ShowWindow(hwnd,SW_HIDE); break;} // falls jeder Modeless immer wieder neu // durch CreateDialog erzeugt wird, ist zu durchdenken ... // case WM_CLOSE: { // DLG_INDIRECT *pDlg = get_pDlg(hwnd); // if(pDlg)if(pDlg->get_hwnd())pDlg->set_hwnd(NULL); // DestroyWindow(hwnd); oder ggf. // if( pDlg ) delte pDlg; // break; } // case WM_DESTROY: { PostQuitMessage(0); break; } // ausgewählte Menu-Func aufrufen, // alle Menu-Tabellen-Einträge durchgehen: case WM_COMMAND:{ if(HIWORD(wParam))break; //DLG_INDIRECT *pDlg =(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA); DLG_INDIRECT *pDlg = get_pDlg(hwnd); pDlg->do_wm_command_func(pDlg,wParam); break; } //ende WM_COMMAND } // ende switch(iMsg) return FALSE; } static BOOL do_wm_command_func( HWND hwnd, MENU_STRUCT * pMenu, WPARAM wParam ) { MENU_STRUCT *p = pMenu; if(!p) return FALSE; while ( p->_txt ) { if ( p->_id == LOWORD(wParam) ) { if( p->_fn ) return p->_fn(hwnd); } p++; } return FALSE; } #endif _MYMODELESS_ ///////////////////////////////////////////////////// ende von dlg_modeless.cpp ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // my_application.cpp ///////////////////////////////////////////////////// #include <windows.h> #include <windowsx.h> #include "dlg_modeless.cpp" ///////////////////////////////////////////////////// // Zusammenstellung der CALLBACK-Funktionen ///////////////////////////////////////////////////// static BOOL CALLBACK dlg0_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); BOOL CALLBACK dlg1_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); BOOL CALLBACK dlg2_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); ///////////////////////////////////////////////////// // Eintragen der CALLBACK-Funktionen in den Globalen Array ///////////////////////////////////////////////////// #define MAX_ANZ_MODELESS 20 static DLG_INDIRECT *g_dlg_ptr [MAX_ANZ_MODELESS]; void do_post_quit_message(void) // alles freigeben { int i; HWND hwnd; DLG_INDIRECT *pDlg; for ( i=0; i<MAX_ANZ_MODELESS;i++) { pDlg = g_dlg_ptr[i]; if(!pDlg)continue; hwnd = pDlg->get_hwnd();if(!hwnd)continue; DestroyWindow(hwnd); if(pDlg) delete g_dlg_ptr[i]; } PostQuitMessage(0); } HMENU create_menu(MENU_STRUCT * pMenu) { HMENU hMenu = CreateMenu(), hPopup = NULL; int j,k=0; if(!pMenu)return NULL; LPSTR pSave=NULL; while(pMenu[k]._txt) { hPopup = CreateMenu(); for(j=k+1; pMenu[j]._id; j++){ AppendMenu(hPopup,MF_STRING, pMenu[j]._id, pMenu[j]._txt); } AppendMenu(hMenu,MF_POPUP, (UINT_PTR)hPopup,pMenu[k]._txt); k = j; } return hMenu; } BOOL set_menu(HWND hwnd, MENU_STRUCT * pMenu) { if(!IsWindow(hwnd))return FALSE; HMENU hMenuNew = create_menu(pMenu); if(!hMenuNew)return FALSE; HMENU hMenuOld = GetMenu(hwnd);if(hMenuOld) DestroyMenu(hMenuOld); BOOL ok = SetMenu(hwnd,hMenuNew); if(!ok)return FALSE; //hinterlege pMenu im Dialog-Window: MENU_STRUCT *pMenuOld = (MENU_STRUCT*)GetWindowLong(hwnd,GWL_USERDATA); if(!pMenuOld)return FALSE; pMenuOld = pMenu; return TRUE; } BOOL show_popup_menu_spalte(HWND hwnd, int pos ) { HMENU hMenu = GetMenu(hwnd); HMENU hPopup = GetSubMenu(hMenu, pos); POINT P; GetCursorPos ( &P ); return TrackPopupMenu(hPopup,TPM_LEFTALIGN,P.x,P.y,0,hwnd,NULL); } ///////////////////////////////////////////////////// // Zusammenstellung der Menu-Funktionen ///////////////////////////////////////////////////// BOOL menu_fn100(HWND hwnd) { if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless); MessageBox(0,buf,"info",MB_OK); return TRUE; } BOOL menu_fn110(HWND hwnd) { if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless); MessageBox(0,buf,"info",MB_OK); return TRUE; } BOOL menu_fn120(HWND hwnd) { if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless); MessageBox(0,buf,"info",MB_OK); return TRUE; } BOOL menu_fn200(HWND hwnd) { if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless); MessageBox(0,buf,"info",MB_OK); return TRUE; } BOOL menu_fn210(HWND hwnd) { if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK); char buf[256]; wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless); MessageBox(0,buf,"info",MB_OK); return TRUE; } ///////////////////////////////////////////////////// // Zusammenstellung der modeless-Dialoge ///////////////////////////////////////////////////// DLG_INDIRECT *create_dlg0(HWND hwnd, DLGPROC dlg_prog ) { static // static ist Pflicht! DLG_STRUCT dlg_struct[] = {// x, y, cx, cy {0,"DIALOG", "Editor", 100, 35,370,260},//[0] {0,"BUTTON", "beende", 5,230, 50, 14},//[1] {0,"BUTTON", "Dlg-Neu2", 315,230, 50, 14},//[2] {0,"BUTTON", "Suche", 135, 5, 40, 14},//[3] {0,"BUTTON", "Ersetze", 325, 5, 40, 14},//[4] {0,"EDIT", "dlg-Edit", 5, 50,360,170},//[5] {0,"COMBOBOX","Suche", 5, 5,125,150},//[6] {0,"COMBOBOX","Ersetze", 195, 5,125,150},//[7] {0,"BUTTON", "Dlg-Neu1", 80,230, 50, 14},//[8] {0,NULL,0,0,0,0}};//Endekriterium ist Pflicht DLG_INDIRECT *pDlg = new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog); static // static ist Pflicht! MENU_STRUCT menu_struct[] = { { 0, "Pop1", 0 }, { 100, "Item 100", menu_fn100 }, { 110, "Item 110", menu_fn110 }, { 120, "Item 120", menu_fn120 }, { 0, "Pop2", 0 }, { 200, "Item 200", menu_fn200 }, { 210, "Item 210", menu_fn210 }, { 220, "Hallo an Curso-Stelle einfügen", 0 }, {0,NULL,0}}; // <== Endekriterium ist Pflicht! pDlg->set_menu(menu_struct); return pDlg; } ///////////////////////////////////////////////////// DLG_INDIRECT *create_dlg1(HWND hwnd, DLGPROC dlg_prog ) { //int i_dlg = 1; // i_dlg = 0,1,...MAX_ANZ_MODELESS ///////////////////////////////////////////////////// static // static ist Pflicht! DLG_STRUCT dlg_struct[] = { // x, y, cx, cy {0,"DIALOG", "dlg1-Titel", 40, 20,100,145},//[0] {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] {0,"EDIT", "dlg-Edit", 10, 85, 80, 40},//[3] {0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4] {0,"BUTTON", "OK", 10,130, 80, 12},//[5] {0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht ///////////////////////////////////////////////////// return new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog); } ///////////////////////////////////////////////////// DLG_INDIRECT *create_dlg2(HWND hwnd, DLGPROC dlg_prog ) { static // static ist Pflicht! DLG_STRUCT dlg_struct[] = { // x, y, cx, cy {0,"DIALOG", "dlg2-Titel", 50, 40,100,155},//[0] {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] {0,"EDIT", "dlg-Edit", 10, 85, 80, 40},//[3] {0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4] {0,"BUTTON", "OK", 10,130, 80, 12},//[5] {0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht DLG_INDIRECT *pDlg = new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog); static // static ist Pflicht! MENU_STRUCT menu_struct[] = { { 0, "Test1", 0 }, { 100, "100", menu_fn100 }, { 120, "120", menu_fn120 }, { 0, "Test2", 0 }, { 200, "200", menu_fn100 }, { 210, "210", menu_fn120 }, {0,NULL,0}}; // <== Endekriterium ist Pflicht! pDlg -> set_menu(menu_struct); ///////////////////////////////////////////////////// // einige Einträge in Ctrl's: ///////////////////////////////////////////////////// // {0,"LISTBOX", "dlg-List", 10,20, 80,40},//[2] HWND hCtrl2 = pDlg->get_hwnd(2); // [2] SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"1"); SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"2"); SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"3"); // {0,"COMBOBOX","dlg-Combo",10,60, 80,60},//[4] HWND hCtrl4 = pDlg->get_hwnd(4); // [4] SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"1"); SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"2"); SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"3"); ///////////////////////////////////////////////////// err_if(!pDlg,"In g_dlg_proc[MAX_ANZ_MODELESS]\nist keine dlg_proc"); return pDlg; } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// //////////////////////////////////////////////////// // Zusammenstellung der CALLBACK-Funktionen //////////////////////////////////////////////////// BOOL CALLBACK dlg0_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam ) { if(def_modeless_proc(hwnd,iMsg,wParam,lParam))return TRUE; static static static static HWND hFind, hRepl, hEdit; int idxSelStart, idxSelEnd, nChar; char buf[256], *pBuf,*pFind; DLG_INDIRECT *pDlg = g_dlg_ptr[0]; switch ( iMsg ) { case WM_CLOSE: do_post_quit_message();//PostQuitMessage(0); // DestroyWindow(hwnd); break; case WM_DESTROY: //do_post_quit_message();//PostQuitMessage(0); break; case WM_RBUTTONDOWN: { show_popup_menu_spalte(hwnd,0); break;} case WM_INITDIALOG : { /////////////////////////////////////////////////////// // Zugriff auf Ctrl-Handle mit der DLG_INDIRECT-Klasse // {0,"EDIT", "dlg-Edit", 5, 50,360,170},//[5] // {0,"COMBOBOX","Suche", 5, 5,125,150},//[6] // {0,"COMBOBOX","Ersetze", 195, 5,125,150},//[7] // {0,"", 0,0,0,0}};//Endekriterium ist Pflicht // Alternative 1: // wegen create...param()-Aufruf kommt // lParam als this-Zeiger nur bei WM_INITDIALOG pDlg = (DLG_INDIRECT *)lParam; /////////////////////////////////////////////////////// // allg. Alternative 2: // pDlg (=this-Zeiger) holen vom GWL_USERDATA pDlg = get_pDlg(hwnd); /////////////////////////////////////////////////////// // Zugriff auf Ctrl-Handle unter // WM_INITDIALOG mit GetDlgItem() // Windows-Standard-Alternative: hEdit = GetDlgItem(hwnd, 5); //5.Ctrl hFind = GetDlgItem(hwnd, 6); //6.Ctrl hRepl = GetDlgItem(hwnd, 7); //7.Ctrl Edit_SetText(hEdit, "5.Ctrl Edit\r\n2 2 \r\n2 2 \r\n"); ComboBox_SetText (hRepl, "7.Ctrl Ersetze" ) ; ComboBox_SetText (hFind, "6.Ctrl Suche" ) ; ComboBox_AddString(hFind, "1" ) ; ComboBox_AddString(hFind, "2" ) ; break; } case WM_SETCURSOR: if (hEdit==(HWND)wParam) idxSelStart=idxSelEnd=Edit_LineIndex(hEdit,-1); break; case WM_COMMAND: { switch (HIWORD(wParam)) { case EN_ERRSPACE: { break; } case EN_MAXTEXT: { break; } case EN_KILLFOCUS: { break; } case EN_SETFOCUS: { break; } case CBN_KILLFOCUS: { if ( 6 == LOWORD(wParam)) { //err("CBN_KILLFOCUS:"); // {0,"EDIT","dlg-Edit", 5, 50,360,170},//[5] // {0,"COMBOBOX","Suche",5, 5,125,150},//[6] //SendMessage(hwnd,WM_COMMAND,MAKELPARAM(5,EN_SETFOCUS),(WPARAM)hEdit); } break; } break; } // ende switch (HIWORD(wParam)) switch (LOWORD(wParam)) {//Buttons, Edit, Combo case 8: { // {0,"BUTTON", "Dlg-Neu1", 80,230, 50, 14},//[8] HWND htemp = g_dlg_ptr[1]->get_hwnd(); ShowWindow(htemp,SW_SHOW); SetForegroundWindow(htemp); break;} case 2: { //{0,"BUTTON", "Dlg-Neu2", 315,230, 50, 14},//[2] HWND htemp = g_dlg_ptr[2]->get_hwnd(); ShowWindow(htemp,SW_SHOW); SetForegroundWindow(htemp); break;} case 1: { //{0,"BUTTON","beende", 13,233, 50, 14},//[1] //SendMessage(hwnd,WM_CLOSE,0,0); break; } case 4: //Replace-Button //{0,"BUTTON","Repl",337, 7, 34, 14},//[4] ComboBox_GetText( hRepl, buf, sizeof(buf)); if ( idxSelStart < idxSelEnd ) Edit_ReplaceSel(hEdit, buf); //fallend in Find-Button case 3: { //Find-Button //{0,"BUTTON","Find",134, 7, 43, 14},//[3] ComboBox_GetText( hFind, buf, sizeof(buf)); nChar = Edit_GetTextLength(hEdit); if ( pBuf ) { free(pBuf); pBuf=NULL; } else { pBuf = (char *) calloc( nChar+1, sizeof(char) ); } nChar = Edit_GetText(hEdit, pBuf, nChar); pFind = strstr( pBuf + idxSelEnd, buf ); if (pFind) { idxSelStart = pFind - pBuf; idxSelEnd = idxSelStart + strlen(buf); } else { idxSelEnd = idxSelStart = 0; } SetFocus( hEdit ); Edit_SetSel( hEdit, idxSelStart, idxSelEnd); Edit_ScrollCaret( hEdit); if (pBuf) { free(pBuf); pBuf=NULL;} break; } // ende Find-Button case 220: { //Test: an Cursor-Stelle "Hallo" einfügen: int curPos = Edit_LineIndex(hEdit,-1); Edit_SetSel( hEdit,curPos,curPos); Edit_ReplaceSel(hEdit,"Hallo\r\n"); break; } } // ende switch ( LOWORD( wParam ) ) break; }// ende WM_COMMAND } // ende switch ( iMsg ) return FALSE; } BOOL CALLBACK dlg1_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam ) { if(def_modeless_proc(hwnd,iMsg,wParam,lParam)) return TRUE; switch ( iMsg ) { case WM_RBUTTONDOWN: { show_popup_menu_spalte(hwnd, 0); break;} case WM_CLOSE: { break; } //case WM_DESTROY: { PostQuitMessage(0); break; } } return FALSE; } BOOL CALLBACK dlg2_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam ) { if(def_modeless_proc(hwnd,iMsg,wParam,lParam)) return TRUE; switch ( iMsg ) { case WM_CLOSE: { break; } case WM_DESTROY:{ break; } } return FALSE; } LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { static MENU_STRUCT * pMenu; switch ( iMsg ) { case WM_CREATE: pMenu=(MENU_STRUCT*)((LPCREATESTRUCT)lParam)->lpCreateParams; break; case WM_RBUTTONDOWN: show_popup_menu_spalte(hwnd, 0); break; case WM_COMMAND: { if(HIWORD(wParam))break; do_wm_command_func(hwnd,pMenu,wParam ); break;}//ende WM_COMMAND case WM_DESTROY: PostQuitMessage(0); break; } // ende switch ( iMsg ) return DefWindowProc(hwnd,iMsg,wParam,lParam ); } BOOL show_dlg1(HWND hwnd) { HWND htemp = g_dlg_ptr[1]->get_hwnd(); if(!htemp) return FALSE; ShowWindow(htemp,SW_SHOW); return SetForegroundWindow(htemp); } BOOL show_dlg2(HWND hwnd) { HWND htemp = g_dlg_ptr[2]->get_hwnd(); if(!htemp) return FALSE; ShowWindow(htemp,SW_SHOW); return SetForegroundWindow(htemp); } //=================== int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev, PSTR pCmdMain, int sw_show ) { HWND hwnd = 0; _hInst = hInstance; /* WNDCLASSEX wc = { 0 } ; wc.cbSize = sizeof( WNDCLASSEX ) ; wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = WndProc ; wc.hInstance = _hInst; wc.cbWndExtra = DLGWINDOWEXTRA; wc.hCursor = LoadCursor ( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "my_class" ; if ( ! RegisterClassEx( & wc ) ) return -1 ; static MENU_STRUCT menu_struct[] = { 0, "ML-Dialoge", 0 { 10, "dlg1", show_dlg1 { 20, "dlg2", show_dlg2 { { { { { { { 0, 100, 110, 120, 0, 200, 210, "Pop1", "Item 100", "Item 110", "Item 120", "Pop2", "Item 200", "Item 210", { }, }, }, 0 menu_fn100 menu_fn110 menu_fn120 0 menu_fn200 menu_fn210 }, }, }, }, }, }, }, {0,NULL,0}}; // <== Endekriterium ist Pflicht! hwnd = CreateWindowEx( WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE, "my_class", "Main-Window", WS_CAPTION|WS_VISIBLE|WS_SYSMENU, 120,120,120,420, 0,0,_hInst,menu_struct); HICON hIcon = ExtractIcon(_hInst,"Shell32.dll",41); SetClassLong(hwnd,GCL_HICON,(long)hIcon ); set_menu(hwnd, menu_struct ); ShowWindow ( hwnd, sw_show ) ; UpdateWindow( hwnd ) ; */ g_dlg_ptr[0] = create_dlg0(hwnd, dlg0_proc); g_dlg_ptr[1] = create_dlg1(hwnd, dlg1_proc); g_dlg_ptr[2] = create_dlg2(hwnd, dlg2_proc); HWND hwnd0 = g_dlg_ptr[0]->get_hwnd(); ShowWindow(hwnd0, sw_show); MSG msg ; while ( GetMessage( &msg,NULL,0,0) ) { if ( NULL==_hModeless|| !IsDialogMessage(_hModeless,& msg)){ TranslateMessage( &msg ); DispatchMessage ( &msg ); } } return msg.wParam ; } ///////////////////////////////////////////////////// // ende von my_application.cpp ///////////////////////////////////////////////////// 8. Praktikum Diese Aufgabe besteht darin, das Erstellen von DLL's zu üben. In der Entwicklungsumgebung sind 2 Projekte anzulegen. ● ● 1.Projekt: auf_08 ( Windows-Applikation ) 2.Projekt: myDll ( Windows-DLL ). In das Projekt myDll ( 2.Projekt ) sind zunächst die beiden Files myDll.h, myDll.cpp einzufügen. Die Übersetzung soll die Files myDll.dll und myDll.lib erstellen. Später soll die Anwendung ( 1. Projekt: auf_08 ) diese erstellten Files ( myDll.dll und myDll.lib ) nutzen. Hinweise DLL's haben Import/Export-Tabellen, d.h. der Linker braucht Hilfe-Stellungen ( storage-class modifiers ). Beispiele sind: // // // // // // // // // // // // // // #define DLL_IMPORT __declspec( dllimport ) #define DLL_EXPORT __declspec( dllexport ) #ifdef __cplusplus #define EXTERN_C extern "C" #else #define EXTERN_C extern #endif #ifdef _DLLBUILD_ #define DLL_API EXTERN_C __declspec( dllexport ) #else #define DLL_API EXTERN_C __declspec( dllimport ) #endif DLL's können auch "SHARED"-Daten verwalten. Hierzu benötigt der Linker ebenfalls Hilfe-Stellungen. Der Aufbau ist etwa wie folgt: #pragma data_seg("SHARED") // Definition von einfachen Variablen, // wie z.B. int, char[] arrays, zeiger // Keine Klassen verwenden, die einen // tiefen Copy Constructors brauchen // Ende des "shared data segment" // Zurück zum normalen Daten-Segment-Bereich #pragma data_seg() // Das folgende Linker-Pragma veranlasst den Linker // die notwendigen initialisierungen für das // "shared data segment" zu erzeugen #pragma comment(linker, "/section:SHARED,RWS") DLL-Erstellung Hier kommt ein einführendes Beispiel, das als erste Grundlage zum Erstellen der DLL und der LIB verwendet werden soll. Zunächst sind die myDll.dll und die myDll.lib zu erstellen. Im Header-File myDll.h werden infolge von #ifdef _DLLBUILD_ die storage-class modifiers ( automatisch ) umgeschalten, denn was für die DLL ein EXPORT ( #define _DLLBUILD_ ), ist für die Applikation ein IMPORT ( #undef _DLLBUILD_ ). File: myDll.h #ifndef MYDLL_H #define MYDLL_H /////////////////// #include <windows.h> File: myDll.cpp #define _DLLBUILD_ #include "myDll.h" /////////////////////////////////// // DllMain ist Pflicht #ifdef _DLLBUILD_ /////////////////////////////////// #define DLL_API __declspec( dllexport ) BOOL APIENTRY #else DllMain(HANDLE hModule, #define DLL_API __declspec( dllimport ) DWORD ul_reason_for_call, #endif LPVOID lpReserved) { /////////////////////////////////// switch (ul_reason_for_call) { // Referenz: case DLL_PROCESS_ATTACH: /////////////////////////////////// case DLL_THREAD_ATTACH: extern DLL_API int myDllInt; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: /////////////////////////////////// break; // Funktions-Prototyp: } return TRUE; /////////////////////////////////// } DLL_API int myDllFunc( int i ); /////////////////////////////////// // einige Tests /////////////////////////////////// /////////////////////////////////// // C++-Klasse: DLL_API void func(); // ohne tiefen Copy-Konstruktor! DLL_API int i = 10; /////////////////////////////////// DLL_API int j; class DLL_API myDllClass { DLL_API int n; public: myDllClass(void); //Konstruktor /////////////////////////////////// }; // Konstruktor der Klasse /////////////////////////////////// /////////////////////////////////// #endif //MYDLL_H myDllClass::myDllClass() { /////////////////////////////////// return; } #pragma data_seg("SHARED") //exportierte Variable DLL_API int myDllInt=1; //exportierte Funktion. DLL_API int myDllFunc(int i) { char buf[256]; int j = i + myDllInt; myDllInt += 10; wsprintf( buf, "i + myDllInt = %d", j ); MessageBox(0,buf,0,MB_OK); return j; } #pragma data_seg() #pragma comment(linker, "/section:SHARED,RWS") Applikation-Erstellung Das 1.Projekt: auf_08 enthält die Windows-Applikation. Weil der auf_08.exe-File die Dll zunächst im eigenen Direktory sucht, so ist es günstig die Linker-Ausgabe in das Debug-Verzeichnis des DLL-Projektes umzuleiten. Dort befinden sich bereits myDll.dll und myDll.lib. Dem Linker muss noch die benötigte LIB ( myDll.lib ) mitgeteilt werden. Dies kann erfolgen mit: #include "myDll.h" #pragma comment(lib, "myDll.lib") Ein Test ist: /////////////////// // hier folgt myApp.cpp // // Teste z.B. // int i1 = myDllInt; // i1 = ??? // int i2 = myDllFunc(i1); // i2 = ??? // int i3 = myDllInt; // i3 = ??? Erweiterungen Die DLL ist sinnvoll zu erweitern, wie z.B. durch void heap_size( void ) { CHAR Buf [1024]; LPSTR pp = Buf; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionEx(&os)) return; switch(os.dwPlatformId){ case VER_PLATFORM_WIN32s: pp += wsprintf(pp, "Win32s or Windows 3.1 \tVers: %ld.%ld", os.dwMajorVersion,os.dwMinorVersion); break; case VER_PLATFORM_WIN32_WINDOWS: if(0 == os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 95"); if(0 < os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 98"); break; case VER_PLATFORM_WIN32_NT: pp += wsprintf(pp, "Win32 or NT \tVers: %ld.%ld", os.dwMajorVersion,os.dwMinorVersion); break; default: pp += wsprintf(pp, "unbekannt"); break; } pp += wsprintf(pp, " \tServicePack: %s",os.szCSDVersion); MEMORYSTATUS ms; ms.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus( &ms ) ; pp += wsprintf(pp,"\nmemory in use\t:%12ld %%",ms.dwMemoryLoad); pp += wsprintf(pp,"\nphys mem free/total\t:%12ld \t%12ld" , ms.dwAvailPhys , ms.dwTotalPhys ) ; pp += wsprintf(pp,"\npaging file free/total\t:%12ld \t%12ld" , ms.dwAvailPageFile , ms.dwTotalPageFile ) ; pp += wsprintf(pp,"\nuser space free/total\t:%12ld \t%12ld" , ms.dwAvailVirtual , ms.dwTotalVirtual ) ; pp += wsprintf(pp,"\n_______________________________________________" ) ; MessageBox(auxGetHWND(),Buf,"Heap-Size",MB_OK); } 9. Praktikum Diese Aufgabe besteht darin, in die MFC einzuführen. Der Anwendungs-Assistent ( Datei==< Projekt ==< ... ) unterstützt Applikationen für SDI ( = Single-Document Interface ) und MDI ( = Multiple-Document Interface). Für einen einfacheren "MFC-Durchblick" soll mit Hilfe der automatischen textgenerierung eine möglichst kleine mfcApp-SDI-Anwendung ( Single Document Interface, mfc.h, mfc.cpp ) erstellt werden. Die mfcApp soll keine externe MFC42DEU.DLL verwenden. Erzeugt werden CMainFrame ( MainFrm.h, MainFrm.cpp ) und CChildView ( ChildView.h, ChildView.cpp ) ● ● ● ● ● ● Schauen Sie sich im Arbeitsbereich die erstellten Ressourcen an. Welche sind es? Schauen Sie sich im Arbeitsbereich die erstellten Klassen an. Welche sind es? Schauen Sie sich im Arbeitsbereich die erstellten Files an. Welche sind es? Schauen Sie sich die cwl-Datei an ( Header-File-Namen, Klassen-Namen, Resourcen-Namen ) Schauen Sie sich das Erstellungsprotokoll *.plg an ( html ). Schauen Sie sich den File readme.txt ( Zusammenfassung, z.B. *.dsp: Projektdatei; *.clw: enthält Infos für Klassen-Assistenten ) Wozu dient *.pch? Schauen Sie sich den MFC-Quelltext an ( z.B. werden Member-Variablen durch ein m_-Präfix gekennzeichnet, wie m_hDC ). Von welcher Klasse ist CAboutDlg abgeleitet? Von welcher Klasse ist CChildView abgeleitet? Von welcher Klasse ist mfcApp abgeleitet? Schauen Sie sich den Quelltext von einfachen MFC-Klassen an ( z.B. class CSize; class CPoint; class CRect; ) Was bedeutet bei einer Console-Applikation ( wie bei OpenGL ) #pragma comment(linker, "/defaultlib:kernel32.lib") #pragma comment(linker, "/entry:mainCRTStartup") #pragma comment(linker, "/subsystem:windows") Wie können Warnunge unterdrückt werden? #pragma ... Wozu dient #define ASSERT(f) ((void)0) ? Wozu dient #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif Wozu dient #ifndef _DEBUG ... #define ASSERT(f) ((void)0) ... #end ? ASSERT() dient der Prüfung von Variablen und der Anzeige von Fehler-Hinweisen. Schreiben und testen Sie ein einfaches, eigenes MY_ASSERT(boolBed,AusgabeTxt)-Macro. Was bedeutet: #if !defined(AFX_MAINFRM_H__7850FD27_9D7F_11D7_BDB2_00F944C10000__INCLUDED_) #define AFX_MAINFRM_H__7850FD27_9D7F_11D7_BDB2_00F944C10000__INCLUDED_ Die //{{...//}} Klammerung dient als Positionsangabe zum Einfügen/Entfernen von MappingMakros ( z.B. ON_WM_SETFOCUS() ) durch den Klassen-Assistenten //{{AFX_MSG_MAP(CMainFrame) ON_WM_SETFOCUS() //}}AFX_MSG_MAP Weitere Untersuchungen Versuchen Sie die Tabelle herauszufinden, die die WM_Nachrichten den Funktionen zuordnet. Ein Anfang ist: struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) }; DECLARE_MESSAGE_MAP() fügt ein: private: static const AFX_MSGMAP_ENTRY _messageEntries[]; protected: static AFX_DATA const AFX_MSGMAP messageMap; virtual const AFX_MSGMAP* GetMessageMap() const;