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 Computer- System nachgebildet. Es besteht aus den Komponenten: Memory, Prozessor, Receptor, Effektor, Enviroment.

Memory Prozessor Wandler Enviroment

enthält: führt aus: wandelt um: Übertragungs- 1. Nutzdaten, elementare Verarbeitungsschritte, <== medium: 2. Daten für den Prozessor: Verzweigungen, Rececptor( Weiterleitung Programm - Code, kurzzeitige Speicherung von Sensor ) von Signalfolgen Umschaltungen und Zwischenwerten, ==> Steuerungen Prozess - Umschaltung Effektor( Aktor )

Memory Prozessor 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, SQL- Abfragen, 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-Aided- Manufacturing )

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: 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 abstrakt: 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 gegenständlich, dinglich, fassbar, wirklich, tatsächlich, anschaulich, sinnlich wahrnehmbar; konkret: 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, Transportsystem Bahn: faltbaren Verdeck, ICE T der Baureihe 415 Innenausstattung aus Leder 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 ). Software- Schnittstellen 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 Soll- Wert 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 Modell- Identitä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.

Masse 1 t = 1000 kg Zeit 1 h = 60 min = 3600 s Temperatur- Volumen 1 l = 103 m3 differenz 1 °C = 1 K

Druck 1 bar = 105 Pa Winkel 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/CENELEC- Mitglieder ü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 An international message-handling standard for connecting e-mail networks and for connecting users to e- mail networks. X.400 is published by the International Telegraph and Telephone Consultative Committee ( X.400 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 message- handling 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 9241- Richtlinien zur Gebrauchstauglichkeit 11 ISO/DIS 9241- Informationsdarstellung 12 ISO/DIS 9241- Benutzerfü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 Beschreibt einen benutzerorientierten Entwicklungszyklus ( 1998 verabschiedet ). Unter dem Titel 13407 "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 E- Mail-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) File Structure and Labelling of Magnetic Tapes for Information Interchange, 4th edition (December ECMA-13 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) Measurement of Airborne Noise Emitted by Information Technology and Telecommunications ECMA-74 Equipment, 6th edition (December 1999) 8-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabets No. 1 to No. 4, 2nd edition (June ECMA-94 1986) Data Interchange on 130 mm Flexible Disk Cartridges Using MFM Recording at 13 262 ftprad on Both ECMA-99 Sides, 3,8 Tracks per mm (September 1985) Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 7 958 ftprad on ECMA-100 80 Tracks on Each Side - ISO Type 301, 2nd edition (December 1988) Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point - Circuit ECMA-106 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) Measurement of High-Frequency Noise emitted by Information Technology and Telecommunications ECMA-108 Equipment, 3rd edition (December 1996) Declared Noise Emission Values of Information Technology and Telecommunications Equipment, 4th ECMA-109 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) Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 15 916 ftprad on ECMA-125 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) Private Integrated Services Network (PISN) - Reference Configurations for PISN Exchanges (PINX), ECMA-133 2nd edition (December 1998) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS ECMA-139 Format (June 1990) Private Integrated Services Network (PISN) - Circuit Mode 64kbit/s Bearer Services - Service ECMA-142 Description, Functional Capabilities and Information Flows (BCSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Circuit Mode Bearer Services - Inter-Exchange Signalling ECMA-143 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) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording (December ECMA-145 1990) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - ECMA-146 DATA/DAT Format (December 1990) Data Interchange on 90 mm Flexible Disk Cartridges using MFM Recording at 31 831 ftprad on ECMA-147 80 Tracks on Each Side - ISO Type 303 (December 1990) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-148 Identification Supplementary Services (ISSD), 3rd edition (June 1997) ECMA-149 Portable Common Tool Environment (PCTE) - Abstract Specification, 4th edition (December 1997) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS- ECMA-150 DC Format using 60 m and 90 m Length Tapes, 2nd edition (June 1992) Data Compression for Information Interchange - Adaptive Coding with Embedded Dictionary - DCLZ ECMA-151 Algorithm (June 1991) Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges - Extended Format, 2nd edition ECMA-152 (December 1993) Information Interchange on 130 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) ECMA-153 Type, using the Magneto-Optical Effect, 2nd edition (June 1994) Data Interchange on 90 mm Optical Disk Cartridges, Read only and Rewritable, M.O., 2nd edition (June ECMA-154 1994) ECMA-155 Private Integrated Services Networks - Addressing, 2nd edition (June 1997) Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Keypad ECMA-156 Protocol for the Support of Supplementary Services (SSIG-KP), 2nd edition (June 1993) Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point - ECMA-157 Identification Supplementary Services (SSIG-ID), 2nd edition (June 1993) Portable Common Tool Environment (PCTE) - C Programming Language Binding, 4th edition ECMA-158 (December 1997) ECMA-159 Data Compression for Information Interchange - Binary Arithmetic Coding Algorithm (December 1991) Determination of Sound Power Levels of Computer and Business Equipment Using Sound Intensity ECMA-160 Measurements; Scanning Method in Controlled Rooms, 2nd edition (December 1992) Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Feature Key ECMA-161 Management Protocol for the Control of Supplementary Services (SSIG-FK), 2nd edition (June 1993) Portable Common Tool Environment (PCTE) - Ada Programming Language Binding, 4th edition ECMA-162 (December 1997) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-163 Name Identification Supplementary Services (NISD), 3rd edition (September 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Name Identification ECMA-164 Supplementary Services (QSIG-NA), 3rd edition (September 1997) Private Integrated Services Network (PISN) - Generic Functional Protocol for the Support of ECMA-165 Supplementary Services - Inter-Exchange Signalling Procedures and Protocol (QSIG-GF), 4th edition(June 2001) Volume and File Structure for Write-Once and Rewritable Media using Non-Sequential Recording for ECMA-167 Information Interchange, 3rd edition(June 1997) Volume and File Structure of Read-Only and Write-Once Compact Disk Media for Information ECMA-168 Interchange, 2nd edition (December 1994) 8 mm Wide Magnetic Tape Cartridge Dual Azimuth Format for Information Interchange - Helical Scan ECMA-169 Recording (June 1992) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS ECMA-170 Format Using 60 m and 90 m Length Tapes (June 1992) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - ECMA-171 DATA/DAT-DC Format Using 60 m and 90 m Length Tapes (June 1992) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-173 Call Diversion Supplementary Services (CFSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Diversion ECMA-174 Supplementary Services (QSIG-CF), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-175 Path Replacement Additional Network Feature (ANF-PRSD), 3rd edition (December 1998) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Path Replacement ECMA-176 Additional Network Feature (QSIG-PR), 3rd edition (December 1998) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-177 Call Transfer Supplementary Service (CTSD), 2nd edition (September 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Transfer ECMA-178 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) Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1 Gigabyte per Cartridge (December ECMA-183 1992) Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1,3 Gigabytes per Cartridge (December ECMA-184 1992) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-185 Call Completion Supplementary Services (CCSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Completion ECMA-186 Supplementary Services (QSIG-CC), 3rd edition (February 2000) Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) ECMA-189 Type using the SSF Method (June 1993) Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) ECMA-190 Type using the CCS Method (June 1993) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-191 Call Offer Supplementary Service (COSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Offer ECMA-192 Supplementary Service (QSIG-CO), 3rd edition (June 1997) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-193 Do Not Disturb and Do Not Disturb Override Supplementary Services (DND(O)SD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Do Not Disturb and ECMA-194 Do Not Disturb Override Supplementary Services (QSIG-DND(O)), 3rd edition (June 1997) Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 2 Gigabytes per Cartridge, 2nd edition ECMA-195 (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) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-2 ECMA-198 Format using 120 m Length Tapes, 2nd edition (June 1995) Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 230 Megabytes per Cartridge, 2nd ECMA-201 edition (December 1994) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-202 Call Intrusion Supplementary Service (CISD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Intrusion ECMA-203 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) Data Interchange on 90 mm Flexible Disk Cartridges - 326 Data Tracks on each Side - Capacity: 21 ECMA-207 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) 12,65 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DATA- ECMA-210 D3-1 Format, 2nd edition (December 1995) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-211 Advice of Charge Supplementary Services (AOCSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Advice of Charge ECMA-212 Supplementary Services (QSIG-AOC), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-213 Recall Supplementary Service (RESD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Recall Supplementary ECMA-214 Service (QSIG-RE), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange ECMA-215 Signalling Protocol - Cordless Terminal Incoming Call Additional Network Feature (QSIG-CTMI), 2nd edition (September 1997) Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange ECMA-216 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) Authentication and Priviledge Attribute Security Application with Related Key Distribution Functions - ECMA-219 Part 1, 2 and 3, 2nd edition (March 1996) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-220 Call Interception Additional Network Feature (ANF-CINTSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Interception ECMA-221 Additional Network Feature (QSIG-CINT), 2nd edition (June 1997) ECMA-222 Adaptive Lossless Data Compression Algorithm(June 1995) Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 385 Megabytes per Cartridge (June ECMA-223 1995) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-224 Transit Counter Additional Network Feature (ANF-TCSD), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Transit Counter ECMA-225 Additional Network Feature (QSIG-TC), 2nd edition (June 1997) Private Integrated Services Network (PISN) - Mapping Functions for the Employment of Dedicated ECMA-226 Circuit Mode Connections as Inter-PTNX Connections (MAPPING-CM-STATIC) (June 1995) Portable Common Tool Environment (PCTE) - IDL Binding (Interface Definition Language), 2nd edition ECMA-230 (December 1997) ECMA-231 Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 4 Format (December 1995) Private Integrated Services Network (PISN) - Profile Standard for the Connection of Radio Paging ECMA-232 Equipment (RPE) to a PISN (December 1995) Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange ECMA-233 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) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-3 ECMA-236 Format using 125 m Length Tapes (June 1996) Data Interchange on 130 mm Optical Disk Cartridge of Type WORM (Write Once Read Many) using ECMA-238 Irreversible Effects - Capacity: 2,6 Gbytes per Cartridge (June 1996) Data Interchange on 90 mm Optical Disk Cartridges - HS-1 Format - Capacity: 650 Megabytes per ECMA-239 Cartridge (June 1996) Data Interchange on 120 mm Optical Disk Cartridges using Phase Change PD Format - Capacity: 650 ECMA-240 Mbytes per Cartridge (June 1996) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-241 Message Waiting Indication Supplementary Service (MWISD), 4th edition (February 2002) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Message Waiting ECMA-242 Indication Supplementary Service (QSIG-MWI), 3rd edition (December 1998) Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange ECMA-243 Signalling Protocol - Cordless Terminal Authentication Supplementary Services (QSIG-CTAU), 2nd edition (September 1997) Private Integrated Services Network (PISN) - Mapping Functions for the Employment of a Circuit Mode ECMA-244 Basic Service and the Supplementary Service User-to-User Signalling as a pair of On-demand Inter- PINX Connections (Mapping-UUS), 2nd edition (September 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - PINX Clock ECMA-245 Synchronization (SYNC-SIG), 2nd edition (September 1997) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-1 ECMA-246 Format, 2nd edition(June 1998) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - HH-1 ECMA-247 Format, 2nd edition(June 1998) 12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-1 ECMA-248 Format, 2nd edition (June 1998) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DA-2 ECMA-249 Format, 2nd edition (June 1998) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-250 Common Information Additional Network Feature (ANF-CMNSD), 2nd edition (December 1998) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Common Information ECMA-251 Additional Network Feature (QSIG-CMN), 2nd edition (December 1998) Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Transit ECMA-252 Counter Additional Network Feature (B-QSIG-TC) (December 1996) Private Integrated Services Network (PISN) - Mapping Functions for the Employement of 64 kbit/s ECMA-253 Circuit Mode Connection with 16 kbit/s Sub-multiplexing (Mapping/16), 2nd edition (September 2000) Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Generic ECMA-254 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) Data Interchange on 356 mm Optical Disk Cartridges - WORM, using Phase Change Technology ECMA-260 Capacity: 14,8 and 25 Gbytes per Cartridge (June 1997) Broadband Private Integrated Services Network (B-PISN) - Service Description - Broadband Connection ECMA-261 Oriented Bearer Services (B-BCSD) (June 1997) ECMA-262 ECMAScript Language Specification, 3rd edition (December 1999) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-263 Call Priority Interruption and Call Priority Interruption Protection Supplementary Services (CPI(P)SD), 2nd edition (December 1998) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Priority ECMA-264 Interruption and Call Priority Interruption Protection Supplementary Services (QSIG-CPI(P)), 2nd edition (December 1998) Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - ECMA-265 Signalling ATM Adaptation Layer (B-QSIG-SAAL) (September 1997) Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Basic ECMA-266 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) Services for Computer Supported Telecommunications Applications (CSTA) Phase III, 4th edition (June ECMA-269 2000) Portable Common Tool Environment (PCTE) - Mapping from CASE Data Interchange Format (CDIF) to ECMA-270 PCTE (December 1997) Extended Commercially Oriented Functionality Class for Security Evaluation (E - COFC), 2nd edition ECMA-271 (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) Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes, ECMA-274 2nd edition (June 1999) ECMA-275 Measurement of structure-borne vibration induced by small air moving devices (AMDs) (June 1998) Private Integrated Services Network (PISN) - Reference Configuration for PINX Extension Lines (June ECMA-276 1998) Private Integrated Services Network (PISN) - Circuit Emulation Specification - Emulation of Basic ECMA-277 Access by ATM Networks (June 1998) Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridge - Parallel Serpentine Format, 2nd ECMA-278 edition (June 2000) 80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) ECMA-279 (December 1998) Data Interchange on 130 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using ECMA-280 Irreversible Effects - Capacity: 5,2 Gbytes per Cartridge (December 1998) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-281 Private User Mobility (PUM) - Registration Supplementary Service (PUMRSD), 2nd edition(June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility ECMA-282 (PUM) - Registration Supplementary Service (QSIG-PUMR), 2nd edition (June 2000) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-283 Private User Mobility (PUM) - Call Handling Additional Network Features (PUMCHSD), 2nd edition (June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility ECMA-284 (PUM) - Call Handling Additional Network Features (QSIG-PUMCH), 2nd edition (June 2000) Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III, 2nd edition (June ECMA-285 2000) Data Interchange on 12,7 mm 208-Track Magnetic Tape Cartridges - DLT 6 Format, 2nd edition (June ECMA-286 2000) ECMA-287 Safety of electronic equipment (June 1999) 3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-4 ECMA-288 Format (June 1999) Private Integrated Services Network (PISN) - Mapping Functions for the Employment of 64 kbit/s ECMA-289 Circuit Mode Connections with 8 kbit/s Sub-Multiplexing (Mapping/8), 2nd edition (September 2000) ECMA-290 ECMAScript Components Specification (June 1999) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-1 with ECMA-291 MIC Format (December 1999) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-2 with ECMA-292 MIC Format (December 1999) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - ECMA-293 MammothTape-2 Format (December 1999) B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange ECMA-294 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) 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 ECMA-295 Control Environment - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999) B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange ECMA-296 Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 1: Protocol Specification (December 1999) B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange ECMA-297 Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999) Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - ECMA-298 Separated Bearer Control (SBC) (B-QSIG-SBC) (December 1999) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-299 Single Step Call Transfer Supplementary Service (SSCT-SD) (February 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Single Step Call ECMA-300 Transfer Supplementary Service (QSIG-SSCT) (February 2000) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-301 Wireless Terminal Location Registration Supplementary Service and Wireless Terminal Information Exchange Additional Network Feature (WTMLR-SD) (June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal ECMA-302 Location Registration Supplementary Service and Wireless Terminal Information Exchange Additional Network Feature (QSIG-WTMLR) (June 2000) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-303 Wireless Terminal Call Handling Additional Network Features (WTMCH-SD) (June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal ECMA-304 Call Handling Additional Network Features (QSIG-WTMCH) (June 2000) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-305 Wireless Terminal Authentication Supplementary Services (WTMAU-SD) (June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal ECMA-306 Authentication Supplementary Services (QSIG-WTMAU) (June 2000) Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Generic ECMA-307 Functional Protocol for the Support of Supplementary Services (June 2000) Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call ECMA-308 Transfer Supplementary Services, 2nd edition (June 2001) Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call ECMA-309 Diversion Supplementary Services, 2nd edition (June 2001) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-310 Simple Dialog Supplementary Service (SDSD) (June 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Simple Dialog ECMA-311 Supplementary Service (QSIG-SD) (June 2000) Private Integrated Services Network (PISN) - Profile Standard for the Use of PSS1 (QSIG) in Air Traffic ECMA-312 Services Networks, 2nd edition (June 2001) Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-313 Call Identification and Call Linkage Additional Network Feature (CIDLSD) (September 2000) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Identification ECMA-314 and Call Linkage Additional Network Feature (QSIG-CIDL) (September 2000) 12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-2 ECMA-315 (December 2000) 8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - VXA-1 ECMA-316 Format (December 2000) Data Interchange on 300 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using ECMA-317 Irreversible Effects - Capacity: 30 Gbytes per Cartridge (December 2000) Private Integrated Services Network (PISN) - Use of QSIG at the C Reference Point between a PINX and ECMA-318 an Interconnecting Network (December 2000) Data Interchange on 12,7 mm - 384- Track Magnetic Tape Cartridges - Ultrium-1 Format (June 2001) ECMA-319

Data Interchange on 12,7 mm - 448-Track Magnetic Tape Cartridges - SDLT1 Format (June 2001) ECMA-320

Streaming Lossless Data Compression Algorithm (SLDC) (June 2001) ECMA-321

Data Interchange on 130 mm Magneto-Optical Disk Cartridges - Capacity: 9,1 Gbytes per Cartridge ECMA-322 (June 2001) XML Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III (June 2001) ECMA-323

Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - ECMA-324 Short Message Service (SMSSD) (June 2001) Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Short Message ECMA-325 Service (QSIG-SMS) (June 2001) Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call ECMA-326 Completion Supplementary Services (June 2001) ECMAScript 3rd Edition Compact Profile (June 2001) ECMA-327

Detection and measurement of chemical emissions from electronic equipment (August 2001) ECMA-328

8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-3 ECMA-329 Format (December 2001) 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) ECMA-330 (December 2001) Case for 120 mm and 80 mm DVD-RAM Disks (December 2001) ECMA-331

Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Basic ECMA-332 Services (December 2001) Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through ECMA-333 H.323 Networks (December 2001) C# Language Specification (December 2001) ECMA-334

Common Language Infrastructure (CLI) (December 2001) ECMA-335

Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through IP ECMA-336 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 Mehrbenutzer- Betriebssystem 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 Computer- Zeitschriften. 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 MS- DOS 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 Online- Komprimierer 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 UNIX- Derivaten 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 Boot- Routine 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 Kommando- prozessor (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

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 PDP- 11 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 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, Sicherheit, Erweiterbarkeit, Stabilität und Skalierbarkeit, zentrale Administration, NT-Server tritt in Konkurrenz zu Novell, Banyan oder UNIX 1995 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, 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

NT-Design Ziele NT-Server

● Kompatibilität: Durch seine Submodule ist Windows NT in der Lage, ● Die Server - Version unterstützt beliebig viele gleichzeitige Datei- Applikationen für die Betriebssyteme Windows 3.x, Windows 95, MS- und Druckerverbindungen, Datei- und Druckerserver auch für DOS, OS/2 und POSIX zu betreiben. Macintosh, ● Portierbarkeit: Windows NT ist fast vollständig in C geschrieben. Für ● Die Benutzerinformationen stehen allen Servern zur Verfügung eine neue Hardware Architektur muß deswegen lediglich eine neue (Domänen Konzept), HAL (Hardware Abstraction Layer) geschrieben werden und ein NT- ● NT-Server ermöglicht eine zentrale Benutzeradministration, komformer Compiler verfügbar sein. Verzeichnis-Replikation, ● Skalierbarkeit: Windows NT unterstützt das symmetrische ● TCP/IP Unterstützung ( DHCP, WINS, DNS, etc.), Multiprocessing. ● NetWare Unterstützung ( GSNW, Migration Tool, FPNW ● Sicherheit: Windows NT beinhaltet ein durchgängiges kompatibel ), Sicherheitskonzept, das darauf ausgelegt ist, die ● fehlertolerante Plattenkonzepte werden unterstützt ( Parity, RAID Sicherheitsanforderungen des Amerikanischen 5 ), Verteidungsministeriums zu erfüllen (C2). ● Multiuser Remote Access Service ● 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 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-Bit- Programmen. ● OS/2: OS/2 2.x Subsystem. ● POSIX: Zeichenorientiertes POSIX-Subsystem. ● Sicherheit: Subsystem zur Überwachung der Sicherheit der anderen Subsysteme

NT-Objekte NT-Objekte NT-Objekte Resourcen als Objekte: Ein NT-Thread: Unterschiedliche Objekte sind:

● Dateien ● teilt sich das Code- und Daten- ● Executive Objects ● Gemeinsam benutzter Speicher Segment eines Prozesses mit anderen ● hat bereits Windows NT 3.5 mit Service Pack 3 die C2- ● Physikalische Geräte jeder Art Threads, Zertifizierung für NT-Rechner ohne ● Prozesse/Threads ● hat seine eigenen CPU-Register, Stack- Netzwerkanbindung erhalten. Raum und einen eigenen Instruktions - ● NT ist für B1-Security ausgelegt. Zähler, ● Für jedes Objekt gibt es ein Zugriffstoken ● erhält vom System eine gewisse CPU - Zeit, so daß alle Threads des Prozesses gleichzeitig ausgeführt werden.

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: , 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 3 2 1 0 9 8 7 6 5 4 3 2 1 0 0 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 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 )

0 1 0 0 0 0 0 0 1 1 0 1 1 0 0 1 0 0 0 1 0 0 1 1 1 0 0 1 0 1 0 1 1 1 0 0 ...... 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 ). Bitmapped- Fonts 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. ).

C++ garantiert die folgenden Relationen: 1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(float) <= sizeof(double) Typ Beispiel Typen für Integer char entspricht bei vielen Maschinen einem 8-Bit-signed-Wert;

char t = '\t'; /* 0x09 */ char c0 = ( char ) 0x61;/* 'a' */ char *p = ∓ c0; /* pStr -> c0 */ char c[5] = {'A', 'B', 'C'}; // 0x41 0x42 0x43 0x00 0x00 char *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 char *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 bitset.h for defining a template class that administers sets of bits algorithms cassert.h for enforcing assertions when functions execute cctype.h for classifying characters cerrno.h for testing error codes reported by library functions cfloat.h for testing floating-point type properties ciso646.h for programming in ISO 646 variant character sets climits.h for testing integer type properties clocale.h for adapting to different cultural conventions cmath.h for computing common mathematical functions complex.h for defining a template class that supports complex arithmetic csetjmp.h for executing nonlocal goto statements csignal.h for controlling various exceptional conditions cstdarg.h for accessing a varying number of arguments cstddef.h for defining several useful types and macros cstdio.h for performing input and output cstdlib.h for performing a variety of operations cstring.h for manipulating several kinds of strings ctime.h for converting between various time and date formats cwchar.h for manipulating wide streams and several kinds of strings cwctype.h for classifying wide characters deque.h for defining a template class that implements a deque container exception.h for defining several functions that control exception handling fstream.h for defining several iostreams template classes that manipulate external files functional.h for defining several templates that help construct predicates iomanip.h for declaring several iostreams manipulators that take an for the templates defined in algorithm.h and numeric.h argument ios.h for defining the template class that serves as the base for many iosfwd.h for declaring several iostreams template classes before they are iostreams classes necessarily defined iostream.h for declaring the iostreams objects that manipulate the standard iso646.h.h for programming in ISO 646 variant character sets streams istream.h for defining the template class that performs extractions iterator.h for defining several templates that help define and manipulate iterators limits.h for testing numeric type properties list.h for defining a template class that implements a list container locale.h for defining several classes and templates that control locale- map.h for defining template classes that implement associative specific containers behavior, as in the iostreams classes memory.h for defining several templates that allocate and free storage for new.h for declaring several functions that allocate and free storage various container classes numeric.h for defining several templates that implement useful numeric ostream.h for defining the template class that performs insertions functions queue.h for defining a template class that implements a queue container set.h for defining template classes that implement associative containers with unique elements sstream.h for defining several iostreams template classes that manipulate stack.h for defining a template class that implements a stack container string containers stdexcept.h for defining several classes useful for reporting exceptions streambuf.h for defining template classes that buffer iostreams operations string.h for defining a template class that implements a string container strstream.h for defining several iostreams classes that manipulate in- memory character sequences typeinfo.h for defining class type_info, the result of the typeid operator utility.h for defining several templates of general utility valarray.h for defining several classes and template classes vector.h for defining a template class that implements a vector container that support value-oriented arrays

Windows-Standard Typen

Ein Betriessystem ( im Gegensatz zur C++-Definition ) arbeitet mit ( exakt ) festgelegten Typen, Strukturen und Speicherabbildern.

Windows-Standard Typen der RTL ( Run-Time Library ) Typ Beschreibung deklariert in clock_t structure Stores time values; used by clock. TIME.H _complex structure Stores real and imaginary parts of complex numbers; used by _cabs. MATH.H _dev_t short or unsigned Represents device handles. SYS\TYPES.H integer div_t, ldiv_t structures Store values returned by div and ldiv, respectively. STDLIB.H _exception structure Stores error information for _matherr. MATH.H FILE structure Stores information about current state of stream; used in all stream I/O STDIO.H operations. _finddata_t, _finddata_t stores file-attribute information returned by _findfirst and _finddata_t: IO.H _wfinddata_t _findnext. _wfinddata_t stores file-attribute information returned by _wfinddata_t: IO.H, WCHAR.H _wfinddatai64_t _wfindfirst and _wfindnext. _wfinddatai64_t stores file-attribute information _wfinddatai64_t: IO.H, WCHAR.H structures returned by _wfindfirsti64 and _wfindnexti64. _FPIEEE_RECORD Contains information pertaining to IEEE floating-point exception; passed to FPIEEE.H structure user-defined trap handler by _fpieee_flt. fpos_t Used by fgetpos and fsetpos to record information for uniquely specifying STDIO.H (long integer, __int64, every position within a file. or structure, depending on the target platform) _HEAPINFO structure Contains information about next heap entry for _heapwalk. MALLOC.H jmp_buf array Used by setjmp and longjmp to save and restore program environment. SETJMP.H lconv structure Contains formatting rules for numeric values in different countries. LOCALE.H _off_t long integer Represents file-offset value. SYS\TYPES.H _onexit_t pointer Returned by _onexit. STDLIB.H _PNH pointer to function Type of argument to _set_new_handler. NEW.H ptrdiff_t integer Result of subtraction of two pointers. STDDEF.H sig_atomic_t integer Type of object that can be modified as atomic entity, even in presence of SIGNAL.H asynchronous interrupts; used with signal. size_t unsigned integer Result of sizeof operator. STDDEF.H and other include files _stat structure Contains file-status information returned by _stat and _fstat. SYS\STAT.H time_tlong integer Represents time values in mktime and time. TIME.H _timeb structure Used by _ftime to store current system time. SYS\TIMEB.H tm structure Used by asctime, gmtime, localtime, mktime, and strftime to store and TIME.H retrieve time information. _utimbuf structure Stores file access and modification times used by _utime to change file- SYS\UTIME.H modification dates. va_list structure Used to hold information needed by va_arg and va_end macros. Called STDARG.H function declares variable of type va_list that can be passed as argument to another function. wchar_t internal Useful for writing portable programs for international markets. STDDEF.H, STDLIB.H type of a wide character wctrans_t integer Represents locale-specific character mappings. WCTYPE.H wctype_t integer Can represent all characters of any national character set. WCHAR.H wint_t integer Type of data object that can hold any wide character or wide end-of-file WCHAR.H value.

Die Typen und Strukturen eines Betriessystems sind vielfältig und umfangreich. Windows-Typen werden u.a. für Funktions - Parameter, Funktions-Rückgabe- Werte, und für Nachrichten benötigt.

Handles werden benutzt, um mit einer Deskriptor-Tabelle auf geladenen Resourcen oder einen benötigten globalen Kontext zuzugreifen. Ein Handle entspricht dem Index der Deskriptor-Tabelle. Ein 8-Byte Deskriptor-Eintrag enthält die Ziel-Byte-Adresse, den Byte-Umfang, die Zugriffsrechte.

In der folgenden Tabelle sind Daten-Typen für Character, Integer, Boolean, Pointer und Handles enthalten. Die meisten Pointer-Typen beginnen mit dem Prefix P oder LP.

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 ENUMRESNAMEPROC Pointer to an application-defined callback function that enumerates resource languages that enumerates resource names ENUMRESTYPEPROC Pointer to an application-defined callback function FARPROC Pointer to a callback function that enumerates resource types FLOAT Floating-point variable FONTENUMPROC Pointer to an application-defined callback function that enumerates fonts GOBJENUMPROC Pointer to an application-defined callback function GRAYSTRINGPROC Pointer to an application-defined callback function that enumerates graphics device interface (GDI) that draws gray text objects HACCEL Handle of an accelerator table HANDLE Handle of an object HBITMAP Handle of a bitmap HBRUSH Handle of a brush HCONV Handle of a dynamic data exchange (DDE) HCONVLIST Handle of a DDE conversation list conversation HCURSOR Handle of a cursor HDC Handle of a device context (DC) HDDEDATA Handle of DDE data HDWP Handle of a deferred window position structure HENHMETAFILE Handle of an enhanced metafile HFILE Handle of a file HFONT Handle of a font HGDIOBJ Handle of a GDI object HGLOBAL Handle of a global memory block HHOOK Handle of a hook HICON Handle of an icon HINSTANCE Handle of an instance HKEY Handle of a registry key HLOCAL Handle of a local memory block HMENU Handle of a menu HMETAFILE Handle of a metafile HOOKPROC Pointer to an application-defined hook function HPALETTE Handle of a palette HPEN Handle of a pen HRGN Handle of a region HRSRC Handle of a resource HSZ Handle of a DDE string HWINSTA Handle of a workstation HWND Handle of a window INT Signed integer LANGID Language identifier LCID Locale identifier LCTYPE Locale type LINEDDAPROC Pointer to a callback function that processes line LONG 32-bit signed value coordinates LP Pointer to a null-terminated Unicode™ string LPARAM 32-bit message parameter LPBOOL Pointer to a Boolean variable LPBYTE Pointer to a byte LPCCH Pointer to a constant Windows character LPCCHOOKPROC Pointer to an application-defined hook function LPCFHOOKPROC Pointer to an application-defined hook function LPCH Pointer to a Windows character LPCOLORREF Pointer to a COLORREF value LPCRITICAL_SECTION Pointer to a critical-section object LPCSTR Pointer to a constant null-terminated Windows LPCTSTR Pointer to a constant null-terminated Unicode or character string Windows character string LPCWCH Pointer to a constant null-terminated Unicode LPCWSTR Pointer to a constant null-terminated Unicode character character string LPDWORD Pointer to an unsigned doubleword (32 bits) LPFRHOOKPROC Pointer to an application-defined hook function LPHANDLE Pointer to a handle LPHANDLER_FUNCTION Pointer to a handler function LPINT Pointer to a signed integer LPLONG Pointer to a signed long (32 bits) LPOFNHOOKPROC Pointer to an application-defined hook function LPPRINTHOOKPROC Pointer to an application-defined hook function LPSETUPHOOKPROC Pointer to an application-defined hook function LPSTR Pointer to a null-terminated Windows character string LPTCH Pointer to a Unicode character or a Windows LPTSTR Pointer to a null-terminated Windows or Unicode character character string LRESULT Signed result of message processing LPVOID Pointer to any type LPWCH Pointer to a Unicode character LPWORD Pointer to an unsigned word (16 bits) LPWSTR Pointer to a null-terminated Unicode character LUID Locally unique identifier string MFENUMPROC Pointer to an application-defined callback function NPSTR Pointer to a null-terminated Windows character that enumerates metafile records string NWPSTR Pointer to a null-terminated Unicode string PBOOL Pointer to a Boolean variable PBOOLEAN Pointer to a Boolean variable PBYTE Pointer to a byte PCCH Pointer to a constant Windows character PCH Pointer to a Windows character PCHAR Pointer to a Windows character PCRITICAL_SECTION Pointer to a critical-section object PCSTR Pointer to a constant null-terminated Windows PCWCH Pointer to a constant Unicode character character string PCWSTR Pointer to a constant null-terminated Unicode PDWORD Pointer to an unsigned doubleword (32 bits) character string PFLOAT Pointer to a floating-point variable PFNCALLBACK Pointer to a callback function PHANDLE Pointer to a handle PHANDLER_ Pointer to a handler routine ROUTINE PHKEY Pointer to a registry key PINT Pointer to a signed integer PLONG Pointer to a signed long (32 bits) PLUID Pointer to a locally unique identifier (LUID) PROPENUMPROC Pointer to an application-defined callback function PROPENUMPROCEX Pointer to an application-defined callback function that enumerates window properties. See that enumerates window properties. See PropEnumProc for information on functions of this PropEnumProcEx for information on functions of type. this type. PSHORT Pointer to a signed short (16 bits) PSID Pointer to a security identifier (SID) PSTR Pointer to a null-terminated Windows character PSZ Pointer to a null-terminated Windows character string string PTCH Pointer to a Windows or Unicode character PTCHAR Pointer to a Windows or Unicode character PTSTR Pointer to a null-terminated Windows or Unicode PUCHAR Pointer to an unsigned Windows character character string PUINT Pointer to an unsigned integer PULONG Pointer to an unsigned long (32 bits) PUSHORT Pointer to an unsigned short (16 bits) PVOID Pointer to any type PWCH Pointer to a Unicode character PWCHAR Pointer to a Unicode character PWORD Pointer to an unsigned word (16 bits) PWSTR Pointer to a null-terminated Unicode character string REGSAM Security access mask for registry key SC_HANDLE Handle of a service SENDASYNCPROC Pointer to an application-defined callback function SERVICE_STATUS_ Handle of a service status value that the operating system calls when the HANDLE 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 SPHANDLE Pointer to a handle TCHAR Unicode character or Windows character TIMERPROC Pointer to an application-defined timer callback function UCHAR Unsigned Windows character UINT Unsigned integer ULONG Unsigned long integer (32 bits) USHORT Unsigned short integer (16 bits) VOID Any type WCHAR Unicode character WNDENUMPROC Pointer to an application-defined callback function WNDPROC Pointer to an application-defined window that enumerates windows procedure WORD Unsigned word (16 bits) WPARAM 32-bit message parameter YIELDPROC Pointer to a yield callback function

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 Delete a file. rename Rename a file or directory. rewind Reposition file pointer to the beginning of a stream. scanf Read formatted data from stdin. setbuf Change stream buffering. setvbuf Change stream buffering. sprintf Format data to a string. sscanf Read formatted data from a string. tmpfile Open a temporary file. tmpnam Generate a unique temporary filename. ungetc 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))) #define GlobalUnlockPtr(lp) \ GlobalUnlock(GlobalPtrHandle(lp))

#define GlobalAllocPtr(flags, cb) \ (GlobalLock(GlobalAlloc((flags), (cb)))) #define GlobalReAllocPtr(lp, cbNew, flags) \ (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags)))) #define GlobalFreePtr(lp) \ (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))

/****** GDI Macro APIs *******************************************************/

#define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen)) #define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen))) #define GetStockPen(i) ((HPEN)GetStockObject(i))

#define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr)) #define SelectBrush(hdc, hbr) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr))) #define GetStockBrush(i) ((HBRUSH)GetStockObject(i))

#define DeleteRgn(hrgn) DeleteObject((HGDIOBJ)(HRGN)(hrgn))

#define CopyRgn(hrgnDst, hrgnSrc) CombineRgn(hrgnDst, hrgnSrc, 0, RGN_COPY) #define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND) #define SubtractRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_DIFF) #define UnionRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_OR) #define XorRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_XOR)

#define DeletePalette(hpal) DeleteObject((HGDIOBJ)(HPALETTE)(hpal))

#define DeleteFont(hfont) DeleteObject((HGDIOBJ)(HFONT)(hfont)) #define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont))) #define GetStockFont(i) ((HFONT)GetStockObject(i))

#define DeleteBitmap(hbm) DeleteObject((HGDIOBJ)(HBITMAP)(hbm)) #define SelectBitmap(hdc, 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 GetWindowStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_STYLE)) #define GetWindowExStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_EXSTYLE))

#define GetWindowOwner(hwnd) GetWindow(hwnd, GW_OWNER)

#define GetFirstChild(hwnd) GetTopWindow(hwnd) #define GetFirstSibling(hwnd) GetWindow(hwnd, GW_HWNDFIRST) #define GetLastSibling(hwnd) GetWindow(hwnd, GW_HWNDLAST) #define GetNextSibling(hwnd) GetWindow(hwnd, GW_HWNDNEXT) #define GetPrevSibling(hwnd) GetWindow(hwnd, GW_HWNDPREV)

#define GetWindowID(hwnd) GetDlgCtrlID(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 IsMinimized(hwnd) IsIconic(hwnd) #define IsMaximized(hwnd) IsZoomed(hwnd) #define IsRestored(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 message is in Windows 3.1 only */ /* void Cls_OnSystemError(HWND hwnd, int errCode) */ #define HANDLE_WM_SYSTEMERROR(hwnd, wParam, lParam, fn) 0L #define 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) GetWindowText((hwndCtl), (lpch), (cchMax)) #define Static_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl) #define Static_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

#define Static_SetIcon(hwndCtl, hIcon) ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_SETICON, (WPARAM)(HICON)(hIcon), 0L)) #define Static_GetIcon(hwndCtl, hIcon) ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_GETICON, 0L, 0L))

/****** Button control message APIs ******************************************/

#define Button_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))

#define Button_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax)) #define Button_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl) #define Button_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

#define Button_GetCheck(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), BM_GETCHECK, 0L, 0L)) #define Button_SetCheck(hwndCtl, check) ((void)SendMessage((hwndCtl), BM_SETCHECK, (WPARAM)(int)(check), 0L))

#define Button_GetState(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), BM_GETSTATE, 0L, 0L)) #define Button_SetState(hwndCtl, state) ((UINT)(DWORD)SendMessage((hwndCtl), BM_SETSTATE, (WPARAM)(int)(state), 0L))

#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) GetWindowText((hwndCtl), (lpch), (cchMax)) #define Edit_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl) #define Edit_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

#define Edit_LimitText(hwndCtl, cchMax) ((void)SendMessage((hwndCtl), EM_LIMITTEXT, (WPARAM)(cchMax), 0L))

#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) ((void)SendMessage((hwndCtl), EM_GETRECT, 0L, (LPARAM)(RECT *)(lprc))) #define Edit_SetRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECT, 0L, (LPARAM)(const RECT *)(lprc))) #define Edit_SetRectNoPaint(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECTNP, 0L, (LPARAM)(const RECT *)(lprc)))

#define Edit_GetSel(hwndCtl) ((DWORD)SendMessage((hwndCtl), EM_GETSEL, 0L, 0L)) #define Edit_SetSel(hwndCtl, ichStart, ichEnd) ((void)SendMessage((hwndCtl), EM_SETSEL, (ichStart), (ichEnd))) #define Edit_ReplaceSel(hwndCtl, lpszReplace) ((void)SendMessage((hwndCtl), EM_REPLACESEL, 0L, (LPARAM)(LPCTSTR)(lpszReplace)))

#define Edit_GetModify(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_GETMODIFY, 0L, 0L)) #define Edit_SetModify(hwndCtl, fModified) ((void)SendMessage((hwndCtl), EM_SETMODIFY, (WPARAM)(UINT)(fModified), 0L))

#define Edit_ScrollCaret(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_SCROLLCARET, 0, 0L))

#define Edit_LineFromChar(hwndCtl, ich) ((int)(DWORD)SendMessage((hwndCtl), EM_LINEFROMCHAR, (WPARAM)(int)(ich), 0L)) #define Edit_LineIndex(hwndCtl, line) ((int)(DWORD)SendMessage((hwndCtl), EM_LINEINDEX, (WPARAM)(int)(line), 0L)) #define Edit_LineLength(hwndCtl, line) ((int)(DWORD)SendMessage((hwndCtl), EM_LINELENGTH, (WPARAM)(int)(line), 0L))

#define Edit_Scroll(hwndCtl, dv, dh) ((void)SendMessage((hwndCtl), EM_LINESCROLL, (WPARAM)(dh), (LPARAM)(dv)))

#define Edit_CanUndo(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_CANUNDO, 0L, 0L)) #define Edit_Undo(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_UNDO, 0L, 0L)) #define Edit_EmptyUndoBuffer(hwndCtl) ((void)SendMessage((hwndCtl), EM_EMPTYUNDOBUFFER, 0L, 0L))

#define Edit_SetPasswordChar(hwndCtl, ch) ((void)SendMessage((hwndCtl), EM_SETPASSWORDCHAR, (WPARAM)(UINT)(ch), 0L))

#define Edit_SetTabStops(hwndCtl, cTabs, lpTabs) ((void)SendMessage((hwndCtl), EM_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(const int *)(lpTabs)))

#define Edit_FmtLines(hwndCtl, fAddEOL) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_FMTLINES, (WPARAM)(BOOL)(fAddEOL), 0L))

#define Edit_GetHandle(hwndCtl) ((HLOCAL)(UINT)(DWORD)SendMessage((hwndCtl), EM_GETHANDLE, 0L, 0L)) #define Edit_SetHandle(hwndCtl, h) ((void)SendMessage((hwndCtl), EM_SETHANDLE, (WPARAM)(UINT)(HLOCAL)(h), 0L))

#if (WINVER >= 0x030a) #define Edit_GetFirstVisibleLine(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), EM_GETFIRSTVISIBLELINE, 0L, 0L))

#define Edit_SetReadOnly(hwndCtl, fReadOnly) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_SETREADONLY, (WPARAM)(BOOL)(fReadOnly), 0L))

#define Edit_GetPasswordChar(hwndCtl) ((TCHAR)(DWORD)SendMessage((hwndCtl), EM_GETPASSWORDCHAR, 0L, 0L))

#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) ShowWindow((hwndCtl), (fShow) ? SW_SHOWNORMAL : SW_HIDE)

#define ScrollBar_SetPos(hwndCtl, pos, fRedraw) SetScrollPos((hwndCtl), SB_CTL, (pos), (fRedraw)) #define ScrollBar_GetPos(hwndCtl) GetScrollPos((hwndCtl), SB_CTL)

#define ScrollBar_SetRange(hwndCtl, posMin, posMax, fRedraw) SetScrollRange((hwndCtl), SB_CTL, (posMin), (posMax), (fRedraw)) #define ScrollBar_GetRange(hwndCtl, lpposMin, lpposMax) GetScrollRange((hwndCtl), SB_CTL, (lpposMin), (lpposMax))

/****** ListBox control message APIs *****************************************/

#define ListBox_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))

#define ListBox_GetCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCOUNT, 0L, 0L)) #define ListBox_ResetContent(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), LB_RESETCONTENT, 0L, 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), LB_DELETESTRING, (WPARAM)(int)(index), 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCURSEL, 0L, 0L)) #define ListBox_SetCurSel(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_SETCURSEL, (WPARAM)(int)(index), 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSEL, (WPARAM)(int)(index), 0L)) #define ListBox_GetSelCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELCOUNT, 0L, 0L)) #define ListBox_GetTopIndex(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTOPINDEX, 0L, 0L)) #define ListBox_GetSelItems(hwndCtl, cItems, lpItems) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int *)(lpItems)))

#define ListBox_SetTopIndex(hwndCtl, indexTop) ((int)(DWORD)SendMessage((hwndCtl), LB_SETTOPINDEX, (WPARAM)(int)(indexTop), 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), LB_SETCARETINDEX, (WPARAM)(int)(index), 0L)) #define ListBox_GetCaretIndex(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCARETINDEX, 0L, 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), CB_LIMITTEXT, (WPARAM)(int)(cchLimit), 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), CB_GETCOUNT, 0L, 0L)) #define ComboBox_ResetContent(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_RESETCONTENT, 0L, 0L))

#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) ((int)(DWORD)SendMessage((hwndCtl), CB_DELETESTRING, (WPARAM)(int)(index), 0L))

#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, index) ((LRESULT)(DWORD)SendMessage((hwndCtl), CB_GETITEMDATA, (WPARAM)(int)(index), 0L)) #define ComboBox_SetItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMDATA, (WPARAM)(int)(index), (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) ((int)(DWORD)SendMessage((hwndCtl), CB_GETCURSEL, 0L, 0L)) #define ComboBox_SetCurSel(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_SETCURSEL, (WPARAM)(int)(index), 0L))

#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) ((BOOL)(DWORD)SendMessage((hwndCtl), CB_SHOWDROPDOWN, (WPARAM)(BOOL)(fShow), 0L))

#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) ((UINT)(DWORD)SendMessage((hwndCtl), CB_GETEXTENDEDUI, 0L, 0L)) #define ComboBox_SetExtendedUI(hwndCtl, flags) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L)) #endif /* WINVER >= 0x030a */

/****** Alternate porting layer macros ****************************************/

/* USER MESSAGES: */

#define GET_WPARAM(wp, lp) (wp) #define GET_LPARAM(wp, lp) (lp)

#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) #define GET_WM_ACTIVATE_STATE(wp, lp) LOWORD(wp) #define GET_WM_ACTIVATE_FMINIMIZED(wp, lp) (BOOL)HIWORD(wp) #define GET_WM_ACTIVATE_HWND(wp, lp) (HWND)(lp) #define GET_WM_ACTIVATE_MPS(s, fmin, hwnd) \ (WPARAM)MAKELONG((s), (fmin)), (LONG)(hwnd)

#define GET_WM_CHARTOITEM_CHAR(wp, lp) (TCHAR)LOWORD(wp) #define GET_WM_CHARTOITEM_POS(wp, lp) HIWORD(wp) #define GET_WM_CHARTOITEM_HWND(wp, lp) (HWND)(lp) #define GET_WM_CHARTOITEM_MPS(ch, pos, hwnd) \ (WPARAM)MAKELONG((pos), (ch)), (LONG)(hwnd)

#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) #define GET_WM_COMMAND_MPS(id, hwnd, cmd) \ (WPARAM)MAKELONG(id, cmd), (LONG)(hwnd)

#define WM_CTLCOLOR 0x0019

#define GET_WM_CTLCOLOR_HDC(wp, lp, msg) (HDC)(wp) #define GET_WM_CTLCOLOR_HWND(wp, lp, msg) (HWND)(lp) #define GET_WM_CTLCOLOR_TYPE(wp, lp, msg) (WORD)(msg - WM_CTLCOLORMSGBOX) #define GET_WM_CTLCOLOR_MSG(type) (WORD)(WM_CTLCOLORMSGBOX+(type)) #define GET_WM_CTLCOLOR_MPS(hdc, hwnd, type) \ (WPARAM)(hdc), (LONG)(hwnd)

#define GET_WM_MENUSELECT_CMD(wp, lp) LOWORD(wp) #define GET_WM_MENUSELECT_FLAGS(wp, lp) (UINT)(int)(short)HIWORD(wp) #define GET_WM_MENUSELECT_HMENU(wp, lp) (HMENU)(lp) #define GET_WM_MENUSELECT_MPS(cmd, f, hmenu) \ (WPARAM)MAKELONG(cmd, f), (LONG)(hmenu)

/* 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 GET_WM_MENUCHAR_CHAR(wp, lp) (TCHAR)LOWORD(wp) #define GET_WM_MENUCHAR_HMENU(wp, lp) (HMENU)(lp) #define GET_WM_MENUCHAR_FMENU(wp, lp) (BOOL)HIWORD(wp) #define GET_WM_MENUCHAR_MPS(ch, hmenu, f) \ (WPARAM)MAKELONG(ch, f), (LONG)(hmenu)

#define GET_WM_PARENTNOTIFY_MSG(wp, lp) LOWORD(wp) #define GET_WM_PARENTNOTIFY_ID(wp, lp) HIWORD(wp) #define GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp) (HWND)(lp) #define GET_WM_PARENTNOTIFY_X(wp, lp) (int)(short)LOWORD(lp) #define GET_WM_PARENTNOTIFY_Y(wp, lp) (int)(short)HIWORD(lp) #define 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)

#define GET_WM_VKEYTOITEM_CODE(wp, lp) (int)(short)LOWORD(wp) #define GET_WM_VKEYTOITEM_ITEM(wp, lp) HIWORD(wp) #define GET_WM_VKEYTOITEM_HWND(wp, lp) (HWND)(lp) #define GET_WM_VKEYTOITEM_MPS(code, item, hwnd) \ (WPARAM)MAKELONG(item, code), (LONG)(hwnd) #define GET_EM_SETSEL_START(wp, lp) (INT)(wp) #define GET_EM_SETSEL_END(wp, lp) (lp) #define GET_EM_SETSEL_MPS(iStart, iEnd) \ (WPARAM)(iStart), (LONG)(iEnd)

#define GET_EM_LINESCROLL_MPS(vert, horz) \ (WPARAM)horz, (LONG)vert

#define GET_WM_CHANGECBCHAIN_HWNDNEXT(wp, lp) (HWND)(lp)

#define GET_WM_HSCROLL_CODE(wp, lp) LOWORD(wp) #define GET_WM_HSCROLL_POS(wp, lp) HIWORD(wp) #define GET_WM_HSCROLL_HWND(wp, lp) (HWND)(lp) #define GET_WM_HSCROLL_MPS(code, pos, hwnd) \ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd)

#define GET_WM_VSCROLL_CODE(wp, lp) LOWORD(wp) #define GET_WM_VSCROLL_POS(wp, lp) HIWORD(wp) #define GET_WM_VSCROLL_HWND(wp, lp) (HWND)(lp) #define GET_WM_VSCROLL_MPS(code, pos, hwnd) \ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd)

/****** C runtime porting macros ****************************************/

#define _ncalloc calloc #define _nexpand _expand #define _ffree free #define _fmalloc malloc #define _fmemccpy _memccpy #define _fmemchr memchr #define _fmemcmp memcmp #define _fmemcpy memcpy #define _fmemicmp _memicmp #define _fmemmove memmove #define _fmemset memset #define _fmsize _msize #define _frealloc realloc #define _fstrcat strcat #define _fstrchr strchr #define _fstrcmp strcmp #define _fstrcpy strcpy #define _fstrcspn strcspn #define _fstrdup _strdup #define _fstricmp _stricmp #define _fstrlen strlen #define _fstrlwr _strlwr #define _fstrncat strncat #define _fstrncmp strncmp #define _fstrncpy strncpy #define _fstrnicmp _strnicmp #define _fstrnset _strnset #define _fstrpbrk strpbrk #define _fstrrchr strrchr #define _fstrrev _strrev #define _fstrset _strset #define _fstrspn strspn #define _fstrstr strstr #define _fstrtok strtok #define _fstrupr _strupr #define _nfree free #define _nmalloc malloc #define _nmsize _msize #define _nrealloc realloc #define _nstrdup _strdup #define hmemcpy 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 ), ● *.asm für Assembler - Quelltexte, *.c für C-Quell-Texte, ● Quelltext-Generierung ( Assistenten ), *.cpp für C++-Quell-Texte, ● Assembler ( übersetzt von Assembler nach Maschinencode ● *.obj für binärer OpCode nach dem Compilieren, ), ● *.lib für Bibliotheks-Routinen und Dll-Zuordnungen, ● Compiler ( übersetzt in Assembler bzw. Maschinencode ), ● *.rc für Resourcen - Quelltexte, ● Linker ( fügt compilierte Files zusammen ), ● *.res für binärere Resourcen - Files, ● Projektverwaltung ( überwacht den Build-Prozess ), ● *.map für die DLL - Adressen, ● Resourcen - Tools ( erstellt, übersetzt Properties ), ● *.exe für den executierbarer File, ● Debugger ( schrittweiser Programmablauf ) , ● *.rtf für ASCII-Rich-Text-File incl. Formatierung, ● Nachrichten - Verfolgung ( Spy - Tools ), ● *.hlp für binärer HeLP-Files ● On-Line-Hilfe ( Dokumentation )

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, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // 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_ COMMON CONTROL STYLES CS_ Class styles TCS_ ACS_

CF_ Predefined Clipboard Formats DS_ Dialog Styles

ES_ Edit Control Styles HELP_ Commands to pass to WinHelp()

WM_NCHITTEST, HT ID Dialog Box Command IDs MOUSEHOOKSTRUCT Mouse Pos

IDI_ Standard Icon IDs LANG_ language IDs.

LBS_ Listbox Styles MA_ WM_MOUSEACTIVATE Return Codes

Menu flags for Menu flags for MF_ MFS_ Add/Check/EnableMenuItem() Add/Check/EnableMenuItem()

MK_ Key State Masks for Mouse Messages OBM_ OEM Resource Ordinal Numbers

PWR_ wParam for WM_POWER SBS_ Scroll Bar Styles SC_ System Menu Command Values SIZE_ WM_SIZE message wParam values

SORT_ Sorting IDs. SS_ Static Control Constants

SW_ ShowWindow() Commands TBS_ Tab style

VK_ Virtual Keys, Standard Set WA_ WM_ACTIVATE state values

WM_ Window Messages WM_DDE_ DDE - Mesages

WS_ Window Styles WS_EX_ Extended Window Styles

WVR_ WM_NCCALCSIZE return values

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 user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.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.

Linker- Fehler- Diagnose Anzeige

myFkt$int$int Es wurde mit C++ compiliert, bzw. eine C++ Bibliothek wird verwendet.

Es wurde mit PASCAL deklariert compiliert, bzw. Linkerschalter auf Großbuchstaben, bzw. Win16 - Bibliothek wird MYFKT 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 #include #include

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 ===> Compiler ===> *.OBJ *.H, *.RC ===> Resourcen-Compiler ===> *.RES *.OBJ, *.DEF ===> Linker ===> (*.EXE) (*.EXE), *.RES ===> Resourcen-Compiler ===> *.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 Object Creator function Destroyer function Change notification FindFirstChangeNotification FindCloseChangeNotification device GetStdHandle CloseHandle Communications OpenEventLog, CreateEvent, Event CloseHandle Event log RegisterEventSource, CloseEventLog OpenEvent OpenBackupEventLog CloseHandle, File CreateFileMapping, File CreateFile CloseHandle DeleteFile mapping OpenFileMapping Find file FindFirstFile FindClose Heap HeapCreate HeapDestroy LoadLibrary, Mailslot CreateMailslot CloseHandle Module FreeLibrary GetModuleHandle CreateMutex, CreateNamedPipe, CloseHandle, Mutex CloseHandle Pipe OpenMutex CreatePipe DisconnectNamedPipe CreateProcess, CloseHandle, CreateSemaphore, Process OpenProcess, Semaphore CloseHandle TerminateProcess OpenSemaphore GetCurrentProcess CreateThread, CloseHandle, CreateWaitableTimer, Thread CreateRemoteThread, Timer CloseHandle TerminateThread OpenWaitableTimer GetCurrentThread Update resource BeginUpdateResource EndUpdateResource

USER.EXE

Der File USER.EXE ist eine DLL, die die auf dem Bildschirm die Fenster erzeugt und manipuliert ( create, move, size, remove), die Icons und andere Komponenten des Benutzer-Interface behandelt, die Eingaben ( dispatch ) von Keyboard, Mause und anderen Eingabe-Geräten an die zugehörige Applikation verteilt. Mit den Funktionen von USER.EXE können interaktive Fenster ( desktop - shell ) erstellt werden. Die User Interface Services

● erzeugen und manipulieren Bildschirm - Fenster ( Screen Windows ), ● behandeln Icons und andere Komponenten des Benutzerinterfaces, ● verteilen die Eingabe von Keyboard, Maus und anderen Geräten an die zugehörigen Applikationen USER.EXE enthält Funktionen für die Programmierschnittstelle lesbare Daten ( Resources Benutzer-Eingaben Fensternhirachie ( Dialogelemente ( Controls ( Shell and Common ) sind: ( User Input ) Windowing ) ): Controls ): Auslöseknöpfe ( Buttons ), Textcursor ( Carets ), Windows Shell API, Nachrichtenzugriff ( Fensterbehandlung ( Textboxen ( List Boxes ), Mauscursor ( Cursors ), standardisierter Accessibility ), Windows ) Datenzuordnung aufklappbare Textboxen ( kleines Symbolbild ( Icons Dialogelemente ( Common Mauseingaben ( Mouse zu Fenstern ( Window Combo Boxes ), Text - ), Menus, benutzerdefinierte Controls ), Wizard97 Input ), Tasten - Code der Properties ), mehrere Editor ( Edit Controls ), Resourcen-Daten Specifications Tastatur ( Keyboard Input ), Fenster mit gleichen RTF - Text - Bearbeitung ( standardisierter Tastencode Eigenschhaften ( Window Rich Edit Controls ), ( Virtual-Key Codes ), Alt- Classes ), Rollbalken ( Scroll Bars ), Tasten ( Keyboard Nachrichtenbearbeitung ( feste Texte ( Static Controls Accelerators ), fertige Message and Message ) Dialoge ( Common Dialog Queues ), Box Library ) 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 AnimateWindow ArrangeIconicWindows BeginDeferWindowPos BringWindowToTop CascadeWindows ChildWindowFromPoint ChildWindowFromPointEx CloseWindow CreateWindow CreateWindowEx DeferWindowPos DestroyWindow EnableWindow EndDeferWindowPos EnumChildProc EnumChildWindows EnumThreadWindows EnumThreadWndProc EnumWindows EnumWindowsProc FindWindow FindWindowEx GetClientRect GetDesktopWindow GetForegroundWindow GetLastActivePopup GetNextWindow GetParent GetTopWindow GetWindow GetWindowPlacement GetWindowRect GetWindowText GetWindowTextLength GetWindowThreadProcessId IsChild IsIconic IsWindow IsWindowUnicode IsWindowVisible IsZoomed MoveWindow OpenIcon SetForegroundWindow SetParent SetWindowLong SetWindowPlacement SetWindowPos SetWindowText ShowOwnedPopups ShowWindow ShowWindowAsync TileWindows WindowFromPoint WinMain

GDI.EXE

GDI ist eine Abkürzung für (G)raphic (D)evice (I)nterface. Der File GDI.EXE ist eine DLL, die das Graphics Device Interface ( GDI ) mit den Funktionen zur Bild - Erzeugung und Bild - Anzeige ( nicht nur Screen ) enthält. Hierher gehören z.B. auch Fonts und Device - Kontext.

● Bilderzeugung und Bildanzeige ( nicht nur auf dem Bildschirm, auch auf z.B. Druckern ). ● Fonts ● Device - Kontext

Den Device Kontext benutzen die folgenden Funktionen.

CancelDC ChangeDisplaySettings CreateCompatibleDC CreateDC CreateIC DeleteDC DeleteObject DeviceCapabilities DrawEscape EnumDisplayDevices EnumDisplaySettings EnumObjects EnumObjectsProc GetCurrentObject GetDC GetDCBrushColor GetDCEx GetDCOrgEx GetDCPenColor GetDeviceCaps GetGraphicsMode GetObject GetObjectType GetStockObject ReleaseDC ResetDC RestoreDC SaveDC SelectObject SetDCBrushColor SetDCPenColor

Mit Fonts und Texten werden die folgenden Funktionen benutzt: AddFontResource CreateFont CreateFontIndirect CreateScalableFontResource DrawText DrawTextEx EnumFontFamiliesEx EnumFontFamExProc ExtTextOut GetAspectRatioFilterEx GetCharABCWidths GetCharABCWidthsFloat GetCharacterPlacement GetCharWidth32 GetCharWidthFloat GetFontData GetFontLanguageInfo GetFontUnicodeRanges GetGlyphIndices GetGlyphOutline GetKerningPairs GetOutlineTextMetrics GetRasterizerCaps GetTabbedTextExtent GetTextAlign GetTextCharacterExtra GetTextColor GetTextExtentExPoint GetTextExtentPoint32 GetTextFace GetTextMetrics PolyTextOut RemoveFontResource SetMapperFlags SetTextAlign SetTextCharacterExtra SetTextColor SetTextJustification TabbedTextOut TextOut

Nicht mehr benutzt werden sollten: EnumFontFamilies EnumFontFamProc EnumFonts EnumFontsProc GetCharWidth GetTextExtentPoint

Im Zusammenhang mit der Paint - Nachricht werden die folgenden Funktionen benutzt:

BeginPaint DrawAnimatedRects DrawCaption DrawEdge DrawFocusRect DrawFrameControl DrawState DrawStateProc DrawTextEx EndPaint ExcludeUpdateRgn GdiFlush GdiGetBatchLimit GdiSetBatchLimit GetBkColor GetBkMode GetBoundsRect GetROP2 GetUpdateRect GetUpdateRgn GetWindowDC GetWindowRgn GrayString InvalidateRect InvalidateRgn LockWindowUpdate OutputProc PaintDesktop RedrawWindow SetBkColor SetBkMode SetBoundsRect SetRectRgn SetROP2 SetWindowRgn UpdateWindow ValidateRect ValidateRgn WindowFromDC

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. CURVECAPS Value that indicates the curve capabilities of the device: TECHNOLOGY Device technology: CC_NONE Device does not support curves. DT_PLOTTER Vector plotter, CC_CHORD Device can draw chord arcs. DT_RASDISPLAY Raster display, CC_CIRCLES Device can draw circles. DT_RASPRINTER Raster printer, CC_ELLIPSES Device can draw ellipses. DT_RASCAMERA Raster camera, CC_INTERIORS Device can draw interiors. DT_CHARSTREAM Character stream, CC_PIE Device can draw pie wedges. DT_METAFILE Metafile und GetObjectType(), CC_ROUNDRECT Device can draw rounded rectangles. DT_DISPFILE Display file CC_STYLED Device can draw styled borders. HORZSIZE Width, in millimeters, of the physical screen. CC_WIDE Device can draw wide borders. VERTSIZE Height, in millimeters, of the physical screen. CC_WIDESTYLED Device can draw borders that are wide and styled. HORZRES Width, in pixels, of the screen. LINECAPS Value that indicates the line capabilities of the device: VERTRES Height, in raster lines, of the screen. LC_NONE Device does not support lines. LOGPIXELSX Number of pixels per logical inch along the screen width. LC_INTERIORS Device can draw interiors. LOGPIXELSY Number of pixels per logical inch along the screen height. LC_MARKER Device can draw a marker. BITSPIXEL Number of adjacent color bits for each pixel. LC_POLYLINE Device can draw a polyline. PLANES Number of color planes. LC_POLYMARKER Device can draw multiple markers. NUMBRUSHES Number of device-specific brushes. LC_STYLED Device can draw styled lines. NUMPENS Number of device-specific pens. LC_WIDE Device can draw wide lines. NUMFONTS Number of device-specific fonts. LC_WIDESTYLED Device can draw lines that are wide and styled. NUMCOLORS Number of entries in the device's color table, POLYGONALCAPS Value that indicates the polygon capabilities of the device: ASPECTX Relative width of a device pixel used for line drawing. PC_NONE Device does not support polygons. ASPECTY Relative height of a device pixel used for line drawing. PC_INTERIORS Device can draw interiors. ASPECTXY Diagonal width of the device pixel used for line drawing. PC_POLYGON Device can draw alternate-fill polygons. PDEVICESIZE Reserved. PC_RECTANGLE Device can draw rectangles. CLIPCAPS Flag that indicates the clipping capabilities of the device. PC_SCANLINE Device can draw a single scanline. SIZEPALETTE Number of entries in the system palette. PC_STYLED Device can draw styled borders. NUMRESERVED Number of reserved entries in the system palette. PC_WIDE Device can draw wide borders. COLORRES Actual color resolution of the device, in bits per pixel. PC_WIDESTYLED Device can draw borders that are wide and styled. PHYSICALWIDTH For printing devices: the width of the physical page, in device units. PC_WINDPOLYGON Device can draw winding-fill polygons. PHYSICALHEIGHT For printing devices: the height of the physical page, in device units. TEXTCAPS Value that indicates the text capabilities of the device: PHYSICALOFFSETX For printing devices: the distance from the left edge of the TC_OP_CHARACTER Device is capable of character output precision. physical page to the left edge of the printable area, in device units. TC_OP_STROKE Device is capable of stroke output precision. PHYSICALOFFSETY For printing devices: the distance from the top edge of the TC_CP_STROKE Device is capable of stroke clip precision. physical page to the top edge of the printable area, in device units. TC_CR_90 Device is capable of 90-degree character rotation. VREFRESH Windows NT only: For display devices: the current vertical refresh TC_CR_ANY Device is capable of any character rotation. rate of the device, in cycles per second (Hz). 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. DESKTOPHORZRES Windows NT only: Width, in pixels, of the virtual desktop. TC_SA_INTEGER Device uses integer multiples only for character scaling. DESKTOPVERTRES Windows NT only: Height, in pixels, of the virtual desktop. TC_SA_CONTIN Device uses any multiples for exact character scaling. BLTALIGNMENT Windows NT only: Preferred horizontal drawing alignment, expressed TC_EA_DOUBLE Device can draw double-weight characters. as a multiple of pixels. TC_IA_ABLE Device can italicize. RASTERCAPS Value that indicates the raster capabilities of the device: TC_UA_ABLE Device can underline. RC_BANDING Requires banding support. TC_SO_ABLE Device can draw strikeouts. RC_BITBLT Capable of transferring bitmaps. TC_RA_ABLE Device can draw raster fonts. RC_BITMAP64 Capable of supporting bitmaps larger than 64K. TC_VA_ABLE Device can draw vector fonts. RC_DI_BITMAP Capable of supporting the SetDIBits and GetDIBits functions. TC_RESERVED Reserved; must be zero. RC_DIBTODEV Capable of supporting the SetDIBitsToDevice function. TC_SCROLLBLT Device cannot scroll using a bit-block transfer. 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. 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 //======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 WinMain- Funktion 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 = Stack-Grösse, CX = Heap-Grösse, DI = Instanz-Handle, SI = vorherige Instanz, ES = 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, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // 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_CAPTION, WS_CHILD, WS_CHILDWINDOW, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_DISABLED, WS_DLGFRAME, WS_GROUP, WS_HSCROLL, WS_ICONIC, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX,WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_POPUPWINDOW, WS_SIZEBOX, WS_SYSMENU, WS_TABSTOP, WS_THICKFRAME, WS_TILED, WS_TILEDWINDOW, WS_VISIBLE, WS_VSCROLL

Alle Fenster haben bereits die WS_CLIPSIBLINGS und WS_CLIPCHILDREN Styles. lpParam kann in der CREATESTRUCT - Struktur unter WM_CREATE an die CALLBACK - Funktion weitergereicht werden.

In CreateWindowEx() können für die horizontale/vertikale Fenster - Position anstelle von festen int x-, y-, nWidth-, nHeight- Werten auch Bildschirm - bezogene Werte ( z.B. GetSystemMetrics(SM_CXSCREEN)*1/8, GetSystemMetrics(SM_CYSCREEN)*1/5, GetSystemMetrics(SM_CXSCREEN)*6/8, GetSystemMetrics(SM_CYSCREEN)*6/5 ) verwendet werden. Nachrichtenschleife

// Die Nachrichtenschleife enthält: while ( GetMessage( & msg, NULL, 0, 0 ) ) { TranslateMessage( & msg ) ; DispatchMessage ( & msg ) ; }

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, // address of structure with message HWND hWnd, // handle of window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // 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.

Das Update- Rechteck wird in einer BeginPaint() und EndPaint() benutzen PAINTSTRUCT RECT- Struktur gespeichert

typedef struct tagPAINTSTRUCT { // ps HDC hdc; typedef struct _RECT { // rc BOOL fErase; // TRUE: erase background LONG left; // with hbrBackground of WNDCLASSEX LONG top; RECT rcPaint; // painting rectangle LONG right; BOOL fRestore; // Reserved; used internally LONG bottom; BOOL fIncUpdate; // Reserved; used internally } RECT; BYTE rgbReserved[32];// Reserved; used internally } PAINTSTRUCT;

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 Child- Windows. PostQuitMessage( 0 ); return 0;

ausgeführt. Falls der MessageBox - Rückgabewert TRUE ist, so wurde der "YES" - Button gedrück. Dann wird durch DestroyWindow( hWnd ) die WM_DESTROY - Nachricht gesendet, d.h. die

● LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam )

Funktion wird mit iMsg = WM_DESTROY aufgerufen. Infolge von PostQuitMessage( 0 ) wird das Fenster geschlossen.

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_GETTEXTLENGTH, WM_PAINT, WM_PAINTICON, WM_ERASEBKGND, WM_ICONERASEBKGND, WM_SYNCPAINT, WM_SYSCOMMAND, WM_ACTIVATE, WM_SETREDRAW, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED,WM_CTLCOLOR, WM_SETCURSOR, WM_MOUSEACTIVATE, WM_SHOWWINDOW, WM_NCLBUTTONDOWN, WM_NCLBUTTONUP, WM_NCLBUTTONDBLCLK, WM_NCMOUSEMOVE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP, WM_SYSCHAR, WM_CLOSE, WM_QUERYOPEN, WM_QUERYENDSESSION, WM_ISACTIVEICON, WM_CHARTOITEM, WM_VKEYTOITEM, WM_DRAWITEM, WM_GETHOTKEY, WM_SETHOTKEY, WM_QUERYDRAGICON, WM_QUERYDROPOBJECT, WM_DROPOBJECT,

/*** *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

/* * 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; /* points to wide command line */ #else /* WPRFLAG */ char *_acmdln; /* points to command line */ #endif /* WPRFLAG */ 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 exit via ExitProcess */

/* * _error_mode and _apptype, together, determine how error messages are * written out. */ int __error_mode = _OUT_TO_DEFAULT; #ifdef _WINMAIN_ int __app_type = _GUI_APP; #else /* _WINMAIN_ */ int __app_type = _CONSOLE_APP; #endif /* _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 WPRFLAG void wWinMainCRTStartup( #else /* WPRFLAG */ void WinMainCRTStartup( #endif /* WPRFLAG */

#else /* _WINMAIN_ */

#ifdef WPRFLAG void wmainCRTStartup( #else /* WPRFLAG */ void mainCRTStartup( #endif /* 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) ) /* initialize heap */ #else /* _MT */ if ( !_heap_init(0) ) /* initialize heap */ #endif /* _MT */ fast_error_exit(_RT_HEAPINIT); /* write message and die */

#ifdef _MT if( !_mtinit() ) /* initialize multi-thread */ fast_error_exit(_RT_THREAD); /* write message and die */ #endif /* _MT */

/* * 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();

_wsetargv(); _wsetenvp(); #else /* WPRFLAG */ /* get cmd line info */ _acmdln = (char *)GetCommandLineA();

/* get environ info */ _aenvptr = (char *)__crtGetEnvironmentStringsA();

_setargv(); _setenvp(); #endif /* 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); /* write message */ _aexit_rtn(255); /* 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); /* write message */ ExitProcess(255); /* normally _exit(255) */ }

#ifndef WPRFLAG

#endif /* WPRFLAG */

#endif /* CRTDLL */

#else /* _WIN32 */

#include #include #include #include #include #include #include #include #include #include #include #include #include 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; /* force ExitToShell */ #endif /* _M_MPPC */ } #ifndef _M_MPPC else { _shellStack = _GetShellStack(); //return current a6, or first a6 _shellStack += 4; //a6 + 4 is the stack pointer we want __argc = _pMPWBlock->argc; __argv = _pMPWBlock->argv;

Inherit(); /* Inherit file handles - env is set up by _envinit if needed */ } #endif /* _M_MPPC */

/* * 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 00 00 50 FC 8C C8 Mnemonics: PUSH DS MOV AX, 0 PUSH AX CLD 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 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 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 * src, void * dst, int anz_byte) { asm push ds // asm lds si, src // asm les di, dst // asm mov cx, anz_byte // asm cld // aufsteigend asm shr cx,1 // cx = Anzahl der Worte, cx-- asm rep movsw // bis cx != 0 asm adc cx,cx // cx = carry => Anzahl der Worte gerade oder ungerade ? asm pop ds }

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.

Ein eindeutiger Funktionsname Zuerst wird j dann i auf den Stack Zuerst wird i dann j auf den Stack von int fkt ( int i, int j ) wird gelegt, dann die gelegt, dann die durch das aneinander fügen von Rücksprungadresse. Weil die int fkt ( Rücksprungadresse. Weil die fkt$int$int gebildet. Ein int i, Stackkorrektur im aufrufenden Stackkorrektur in der aufgerufenen Überladen des Funktionsnamen int j Programm erfolgt, kann die Funktion erfolgt, kann die fkt bedeutet, daß zwar der gleiche ) Parameter - Anzahl variieren ( ... ). Parameteranzahl nicht variieren. Name fkt aber andere Der Assembler-Name der Funktion Der Assembler-Name der Funktion Parametertypen oder andere ist _fkt ist FKT 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 [bx+2], 3 ; 2 is a displacement, 3 is immediate mov mem1, 4 ; 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 ES:[bx], mov eax, [si] ; 32-bit operand in 16-bit code segment mov ax, [esi] ; 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 ebx, 2 ; writes to EBX add ecx, ebx ; reads EBX and ECX, writes to ECX ; EBX is read after being written, no pairing mov ebx, 1 ; writes to EBX mov 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 al, 0 ; CMP modifies the flags je addr ; JE reads the flags, but pairs dec cx ; DEC modifies the flags jnz loop1 ; 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 reg inc ax inc eax INC mem inc var1 inc [eax] DEC reg dec bx dec ebx DEC mem dec [bx] dec var2 PUSH reg push ax push eax POP reg pop ax pop eax LEA reg, mem lea ax, [si+2] lea eax, [eax+4*esi+8] JMP near jmp label jmp lable2 CALL near call proc call proc2 Jcc near jz lbl jnz 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 nop nop shift reg, 1 shl ax, 1 rcl eax, 1 shift mem, 1 shr [bx], 1 rcr [ebx], 1 shift reg, imm sal ax, 2 rol esi, 2 shift mem, imm sar ax, 15 ror [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) If imm8 is blank uses 10. AH = 0 AAD is almost always slower, but only 2 bytes long. aam (imm8) all AH = AL/imm8 Same as AAD. AL = AL MOD imm8 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 286+ push offset dest2 When CALL is followed by jmp dest2 jmp dest1 a JMP, change the return address to the JMP destination. call dest1 all jmp dest1 When a CALL is followed by a ret 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.

disadvantage: modifies flags

Pent mov edx, eax When EAX value could be sar edx, 31 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 8088 shr accum, 1 When resolves to 2, use shift for division. (use CL for 4, 8, etc.) div 186+ shr accum, n When resolves to a power of 2 use shifts for division. enter imm16, 0 286+ push bp ENTER is always slower mov bp, sp and 4 bytes in length sub sp, imm16 if imm16 = 0 then push/mov is smaller

386+ push ebp 32-bit mov ebp, esp sub esp, imm16 inc reg16 lea reg16, [reg16 + 1] Use to preserve flags for BX, BP, DI, SI inc reg32 lea reg32, [reg32 + 1] Use to preserve flags for EAX, EBX, ECX, EDX EDI, ESI, EBP jcxz : 486+ test cx, cx JCXZ is faster and je : smaller on 8088-286. On the 386 it is the about the same speed

486+ test ecx, ecx Never use JCXZ on 486 je : or Pentium except for compactness lea reg, mem 8088-286 mov reg, OFFSET mem MOV reg, imm is faster on 8088 - 286. 386+ they are the same.

Note: There are many uses for LEA, see: add, inc, dec, mov, mul leave 486+ mov sp, bp LEAVE is only 1 byte pop bp long and is faster on the 186-386. The mov esp, ebp MOV/POP is much faster pop ebp on 486 and Pentium lodsb 486+ mov al, [si] LODS is only 1 byte long inc si 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] see lodsb add si, 2 lodsd 486+ mov eax, [esi] see lodsb add esi, 4 loop : 386+ dec cx LOOP is faster and jnz : smaller on 8088-286. on 386+ DEC/JNZ is loopd : dec ecx much faster. On the Pentium jnz : the DEC/JNZ instructions pair taking only 1 cycle. loopXX : 486+ je $+5 The 3 replacement instructions ( XX = e,ne,z or nz) dec cx are much faster on the 486+. jnz : LOOPxx is smaller and faster on 8088-286 loopdXX : 486+ je $+5 The speed is about the dec ecx same on the 386. jnz : mov reg2, reg1 286+ lea reg2, [reg1+n] LEA is faster, smaller and followed by: preserves flags. This is a inc/dec/add/sub reg2 way to do a MOV and ADD/SUB of a constant, n.

mov acc, reg all xchg acc, reg Use XCHG for smaller code when one of the registers final value can be ignored. Note that acc = AL, AX or EAX. mov mem, 1 Pent lea bx, mem Displacement/immediate does mov [bx], 1 not pair. LEA/MOV can be used if other code can be placed inbetween to prevent AGI's. mov ax, 1 MOV/MOV may be easier to pair. mov mem, ax mov [bx+2], 1 Pent mov ax, 1 Better pairing because mov [bx+2], ax displacement/immediate instructions do not pair.

lea bx, [bx+2] mov [bx], 1 movsb 486+ mov al, [si] MOVS is faster and inc si smaller to move a single mov [di], al byte, word or dword inc di 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 ax, [si] see MOVSB add si, 2 mov [di], ax add di, 2 movsd 486+ mov eax, [esi] see MOVSB add esi, 4 mov [edi], eax add edi, 4 movzx r16, rm8 486+ xor bx, bx MOVZX is faster and mov bl, al smaller on the 386. On the 486+ XOR/MOV movzx r32, rm8 486+ xor ebx, ebx is faster. Possible mov bl, al pairing on the Pentium. (source can be reg or mem) movzx r32, rm16 486+ xor ebx, ebx disadvantage: modifies flags 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

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 Faster on 486+ mov mem, reg Better pairing on Pentium push mem 486+ mov reg, mem Faster on 486 push reg Better pairing on Pentium pushf 486+ rcr reg, 1 To save only the carry flag use a rotate (RCR or RCL) or into a register. RCR and RCL are pairiable (U pipe only) rcl reg, 1 and take 1 cycle. PUSHF is slow and not pairable. popf 486+ rcl reg, 1 To restore only the carry flag. See PUSHF. or

rcr reg, 1 rep scasb Pent loop1: REP SCAS is faster and mov al, [di] smaller on 8088-486. inc di Expanded code is faster cmp al, reg2 on Pentium due to pairing. je exit dec cx jnz loop1 exit: shl reg, 1 Pent add reg, reg ADD pairs better. SHL only pairs in the U pipe. stosb 486+ mov [di], al STOS is faster and smaller inc di on the 8088-286, and the same speed on the 386. On the 486+ stosw 486+ mov [di], ax the MOV/INC is slightly add di, 2 faster. stosd 486+ mov [edi], eax REP STOS is faster on 8088-386. add edi, 4 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 Use xchg acc, reg to do a 1 byte MOV when one register can be ignored. xchg reg1, reg2 Pent push reg1 pushes and pops are 1 cycle push reg2 faster on Pentium due to pop reg1 pairing. pop reg2

disadvantage: uses stack

Pent mov reg3, reg1 Faster and better pairing mov reg1, reg2 if reg3 is available. mov reg2, reg3 xlatb 486+ mov bh, 0 XLAT is faster and smaller mov bl, al on 8088-386. MOV's are faster mov al, [bx] on 486+. Best to rearrange instructions to prevent AGI's xlatb 486+ xor ebx, ebx and get pairing on Pentium. mov bl, al Force high part of BX/EBX mov al, [ebx] to zero outside of loop.

disadvantage: modifies flags

80x86 Integer Instruction Set (8088 - Pentium)

Legend:

General acc = AL, AX or EAX unless specified otherwise reg = any general register r8 = any 8-bit register r16 = any general purpose 16-bit register r32 = any general purpose 32-bit register imm = immediate data imm8 = 8-bit immediate data imm16 = 16-bit immediate data mem = memory address mem8 = address of 8-bit data item mem16 = address of 16-bit data item mem32 = address of 32-bit data item mem48 = address of 48-bit data item dest = 16/32-bit destination short = 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 Pentium: NP = not pairable UV = pairable in the U pipe or V pipe PU = pairable in the U pipe only PV = pairable in the V pipe only

Instruction formats, clock cycles and Pentium® Pairing info

AAA ASCII adjust after addition

bytes 8088 186 286 386 486 Pentium 1 8 8 3 4 3 3 NP

Example: aaa

AAD ASCII adjust AX before division (second byte is divisor)

bytes 8088 186 286 386 486 Pentium 2 60 15 14 19 14 10 NP

Example: aad

AAM ASCII adjust AX after multiply (second byte is divisor)

bytes 8088 186 286 386 486 Pentium 2 83 19 16 17 15 18 NP

Example: aam

AAS ASCII adjust AL after subtraction

bytes 8088 186 286 386 486 Pentium 1 8 7 3 4 3 3 NP

Example: aas

ADC Integer add with carry

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 PU mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 PU reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 PU reg, imm 2+i(1,2) 4 4 3 2 1 1 PU mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 PU* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 PU

* = not pairable if there is a displacement and immediate

Example: adc eax, ebx

ADD Integer addition

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 UV reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: add eax, ebx

AND Logical AND

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 UV reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: and eax, ebx

ARPL Adjust RPL field of selector (286+)

operands bytes 286 386 486 Pentium reg, reg 2 10 20 9 7 NP mem, reg 2+d(0-2) 11 21 9 7 NP

Example: arpl ax, bx

BOUND Check array index against bounds (186+)

operands bytes 186 286 386 486 Pentium reg, mem 4 35 13 10 7 8 NP

Example: bound bx, array

BSF Bit scan forward (386+)

operands bytes 386 486 Pentium r16, r16 3 10+3n 6-42 6-34 NP r32, r32 3 10+3n 6-42 6-42 NP r16, m16 3+d(0,1,2) 10+3n 7-43 6-35 NP r32, m32 3+d(0,1,2,4) 10+3n 7-43 6-43 NP

Example: bsf eax, [esi]

BSR Bit scan reverse (386+)

operands bytes 386 486 Pentium r16, r16 3 10+3n 6-103 7-39 NP r32, r32 3 10+3n 7-104 7-71 NP r16, m16 3+d(0,1,2) 10+3n 6-103 7-40 NP r32, m32 3+d(0,1,2,4) 10+3n 7-104 7-72 NP

Example: bsr eax, [esi]

BSWAP Byte swap (486+)

operand bytes 486 Pentium r32 2 1 1 NP

Example: bswap eax

BT Bit test (386+)

operands bytes 386 486 Pentium reg, reg 3 3 3 4 NP mem, reg 3+d(0,1,2,4) 12 8 9 NP reg, imm8 3+i(1) 3 3 4 NP mem, imm8 3+d(0,1,2,4)+i(1) 6 3 4 NP

Example: bt eax, 4

BTC Bit test and complement (386+)

operands bytes 386 486 Pentium reg, reg 3 6 6 7 NP mem, reg 3+d(0,1,2,4) 13 13 13 NP reg, imm8 3+i(1) 6 6 7 NP mem, imm8 3+d(0,1,2,4)+i(1) 8 8 8 NP Example: btc eax, 4

BTR Bit test and reset (386+)

operands bytes 386 486 Pentium reg, reg 3 6 6 7 NP mem, reg 3+d(0,1,2,4) 13 13 13 NP reg, imm8 3+i(1) 6 6 7 NP mem, imm8 3+d(0,1,2,4)+i(1) 8 8 8 NP

Example: btr eax, 4

BTS Bit test and set (386+)

operands bytes 386 486 Pentium reg, reg 3 6 6 7 NP mem, reg 3+d(0,1,2,4) 13 13 13 NP reg, imm8 3+i(1) 6 6 7 NP mem, imm8 3+d(0,1,2,4)+i(1) 8 8 8 NP

Example: bts eax, 4

CALL Call subroutine

operand bytes 8088 186 286 386 486 Pentium near 3 23 14 7+m 7+m 3 1 PV reg 2 20 13 7+m 7+m 5 2 NP mem16 2+d(0-2) 29+EA 19 11+m 10+m 5 2 NP far 5 36 23 13+m 17+m 18 4 NP mem32 2+d(0-2) 53+EA 38 16+m 22+m 17 4 NP

Protected Mode

operand bytes 286 386 486 Pentium far 5 26+m 34+m 20 4-13 NP mem32 2+d(0-2) 29+m 38+m 20 5-14 NP

cycles not shown for calls through call and task gates

Example: call my_function

CBW Convert byte to word (AL --> AX)

bytes 8088 186 286 386 486 Pentium 1 2 2 2 3 3 3 NP

Example: cbw

CWDE Convert word to dword (386+) (AX --> EAX)

bytes 386 486 Pentium 1 3 3 3 NP

Example: cwde

CWD Convert word to double (AX --> DX:AX)

bytes 8088 186 286 386 486 Pentium 1 5 4 2 2 3 2 NP

Example: cwd

CDQ Convert double to quad (EAX --> EDX:EAX)

bytes 386 486 Pentium 1 2 3 2 NP

Example: cdq

CLC Clear the carry flag

bytes 8088 186 286 386 486 Pentium 1 2 2 2 2 2 2 NP

Example: clc

CLD Clear the direction flag (set to forward direction)

bytes 8088 186 286 386 486 Pentium 1 2 2 2 2 2 2 NP

Example: cld CLI Clear the interrupt flag (disable interrupts)

bytes 8088 186 286 386 486 Pentium 1 2 2 3 3 5 7 NP

Example: cli

CLTS Clear task switched flag in CR0 (286+)

bytes 286 386 486 Pentium 2 2 5 7 10 NP

Example: clts

CMC Complement carry flag

bytes 8088 186 286 386 486 Pentium 1 2 2 2 2 2 2 NP

Example: cmc

CMP Compare two operands

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 13+EA 10 7 5 2 2 UV reg, mem 2+d(0,2) 13+EA 10 6 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 14+EA 10 6 5 2 2 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: cmp eax, 3

CMPS/CMPSB/CMPSW/CMPSD Compare string operands

variations bytes 8088 186 286 386 486 Pentium cmpsb 1 30 22 8 10 8 5 NP cmpsw 1 - - - 10 8 5 NP cmpsd 1 - - - 10 8 5 NP repX cmpsb 2 9+30n 5+22n 5+9n 5+9n 7+7n* 9+4n NP repX cmpsw 2 9+30n 5+22n 5+9n 5+9n 7+7n* 9+4n NP repX cmpsd 2 - - - 5+9n 7+7n* 9+4n NP

repX = repe, repz, repne or repnz * : 5 if n = 0

Example: repne cmpsb

CMPXCHG Compare and Exchange (486+)

operands bytes 486 Pentium reg, reg 3 6 5 NP mem, reg 3+d(0-2) 7-10 6 NP

Example: cmpxchg ebx, edx

CMPXCHG8B Compare and Exchange 8 bytes (Pentium+)

operands bytes Pentium mem, reg 3+d(0-2) 10 NP

Example: cmpxchg8b [ebx], edx

CPUID CPU identification (Pentium+)

bytes Pentium 2 14 NP

Example: cpuid

DAA Decimal adjust AL after addition

bytes 8088 186 286 386 486 Pentium 1 4 4 3 4 2 3 NP

Example: daa

DAS Decimal adjust AL after subtraction

bytes 8088 186 286 386 486 Pentium 1 4 4 3 4 2 3 NP

Example: das DEC Decrement

operand bytes 8088 186 286 386 486 Pentium r8 2 3 3 2 2 1 1 UV r16 1 3 3 2 2 1 1 UV r32 1 3 3 2 2 1 1 UV mem 2+d(0,2) 23+EA 15 7 6 3 3 UV

Example: dec eax

DIV Unsigned divide

operand bytes 8088 186 286 386 486 Pentium r8 2 80-90 29 14 14 16 17 NP r16 2 144-162 38 22 22 24 25 NP r32 2 - - - 38 40 41 NP mem8 2+d(0-2) 86-96+EA 35 17 17 16 17 NP mem16 2+d(0-2) 150-168+EA 44 25 25 24 25 NP mem32 2+d(0-2) - - - 41 40 41 NP

implied operand quotient remainder dividend AX / byte = AL AH DX:AX / word = AX DX EDX:EAX / dword = EAX EDX

Example: div ebx

ENTER Make stack frame for procedure parameters (186+)

operands bytes 8088 186 286 386 486 Pentium imm16, 0 3 - 15 11 10 14 11 NP imm16, 1 4 - 25 15 12 17 15 NP imm16, imm8 4 - 22+16n 12+4n 15+4n 17+3i 15+2i NP n = imm8-1; i = imm8

Example: enter 1, 0

ESC Escape escape opcodes D8 - DF are used by floating point instructions

HLT Halt

bytes 8088 186 286 386 486 Pentium 1 2 2 2 5 4 4 NP

Example: hlt

IDIV Signed divide

operand bytes 8088 186 286 386 486 Pentium r8 2 101-112 44-52 17 19 19 22 NP r16 2 165-184 53-61 25 27 27 30 NP r32 2 - - - 43 43 46 NP mem8 2+d(0-2) 107-118+EA 50-58 20 22 20 22 NP mem16 2+d(0-2) 171-190+EA 59-67 28 30 28 30 NP mem32 2+d(0-2) - - - 46 44 46 NP

implied operand quotient remainder dividend AX / byte = AL AH DX:AX / word = AX DX EDX:EAX / dword = EAX EDX

Example: idiv ebx

IMUL Signed multiply

Accumulator Multiplies

operand bytes 8088 186 286 386 486 Pentium r8 2 80-98 25-28 13 9-14 13-18 11 NP r16 2 128-154 34-37 21 9-22 13-26 11 NP r32 2 - - - 9-38 13-42 10 NP mem8 2+d(0-2) 86-104+EA 32-34 16 12-17 13-18 11 NP mem16 2+d(0-2) 134-160+EA 40-43 24 12-25 13-26 11 NP mem32 2+d(0-2) - - - 12-41 13-42 10 NP

implied operand result multiplicand (multiplier)

AL * byte = AX AX * word = DX:AX EAX * dword = EDX:EAX

Example: imul ebx

2 and 3 operand Multiplies

operands bytes 186 286 386 486 Pentium r16, imm 2+i(1,2) - 21 9-14/9-22 13-18/13-26 10 NP r32, imm 2+i(1,2) - - 9-38 13-42 10 NP r16,r16,imm 2+i(1,2) 22/29 21 9-14/9-22 13-18/13-26 10 NP r32,r32,imm 2+i(1,2) - - 9-38 13-42 10 NP r16,m16,imm 2+d(0-2) 25/32 24 12-17/12-25 13-18/13-26 10 NP +i(1,2) r32,m32,imm 2+d(0-2)+i(1,2) - 12-41 13-42 10 NP r16, r16 2+i(1,2) - - 9-22 13-18/13-26 10 NP r32, r32 2+i(1,2) - - 9-38 13-42 10 NP r16, m16 2+d(0-2)+i(1,2) - 12-25 13-18/13-26 10 NP r32, m32 2+d(0-2)+i(1,2) - 12-41 13-42 10 NP all forms: dest, src cycles for: byte/word or dword dest, src1, src2

Example: imul eax, ebx, 10

IN Input from port

operands bytes 8088 186 286 386 486 Pentium al, imm8 2 14 10 5 12 14 7 NP ax, imm8 2 14 10 5 12 14 7 NP eax, imm8 2 - - - 12 14 7 NP al, dx 1 12 8 5 13 14 7 NP ax, dx 1 12 8 5 13 14 7 NP eax, dx 1 - - - 13 14 7 NP

Protected mode

operands bytes 386 486 Pentium acc, imm 2 6/26/26 9/29/27 4/21/19 NP acc, dx 1 7/27/27 8/28/27 4/21/19 NP

cycles for: CPL <= IOPL / CPL > IOPL / V86

Example: in al, dx

INC Increment

operand bytes 8088 186 286 386 486 Pentium r8 2 3 3 2 2 1 1 UV r16 1 3 3 2 2 1 1 UV r32 1 3 3 2 2 1 1 UV mem 2+d(0,2) 23+EA 15 7 6 3 3 UV

Example: inc ebx

INS/INSB/INSW/INSD Input from port to string

variations bytes 8088 186 286 386 486 Pentium insb 1 - 14 5 15 17 9 NP insw 1 - 14 5 15 17 9 NP insd 1 - - - 15 17 9 NP

Protected Mode

bytes 386 486 Pentium 1 9/29/29 10/32/30 6/24/22 NP

cycles for: CPL <= IOPL / CPL > IOPL / V86

Example: rep insb

INT Call interrupt procedure

operands bytes 8088 186 286 386 486 Pentium 3 1 72 45 23+m 33 26 13 NP imm8 2 71 47 23+m 37 30 16 NP

Protected mode

bytes 8088 186 286 386 486 Pentium 1 - - (40-78)+m 59-99 44-71 27-82 NP

Example: int 21h

INTO Call interrupt procedure if overflow bytes 8088 186 286 386 486 Pentium 1 4/73 4/48 3/24+m 3/35 3/28 4/13 NP

Protected mode

bytes 286 386 486 Pentium 1 (40-78)+m 59-99 44-71 27-56 NP

Task switch clocks not shown

Example: into

INVD Invalidate data cache (486+)

bytes 8088 186 286 386 486 Pentium 2 - - - - 4 15 NP

Example: invd

INVLPG Invalidate TLB entry (486+)

operands bytes 486 Pentium mem32 5 12 25 NP

Example: invlpg [eax]

IRET Return from interrupt

bytes 8088 186 286 386 486 Pentium 1 44 28 17+m 22 15 8-27 NP

Task switch clocks not shown

Example: iret

IRETD 32-bit return from interrupt (386+)

bytes 386 486 Pentium 1 22 15 10-27 NP

Task switch clocks not shown

Example: iretd

Jcc Jump on condition code

operand bytes 8088 186 286 386 486 Pentium near8 2 4/16 4/13 3/7+m 3/7+m 1/3 1 PV near16 3 - - - 3/7+m 1/3 1 PV

cycles for: no jump/jump

conditional jump instructions:

ja jump if above jnbe jump if not below or equal jae jump if above or equal jnb jump if not below jb jump if below jnae jump if not above or equal jbe jump if below or equal jna jump if not above jg jump if greater jnle jump if not less or equal jge jump if greater or equal jnl jump if not less jl jump if less jnge jump if not greater or equal jle jump if less or equal jng jump if not greater

je jump if equal jz jump if zero jne jump if not equal jnz jump if not zero

jc jump if carry jnc jump if not carry js jump if sign jns jump if not sign jnp jump if no parity (odd) jpo jump if parity odd jo jump if overflow jno jump if not overflow jp jump if parity (even) jpe jump if parity even

Example: jne not_equal

JCXZ/JECXZ Jump if CX/ECX = 0

operand bytes 8088 186 286 386 486 Pentium dest 2 6/18 5/16 4/8+m 5/9+m 5/8 5/6 NP dest 2 - - - 5/9+m 5/8 5/6 NP

cycles for: no jump/jump

Example: jcxz cx_is_zero

JMP Unconditional jump operand bytes 8088 186 286 386 486 Pentium short 2 15 13 7+m 7+m 3 1 PV near 3 15 13 7+m 7+m 3 1 PV far 5 15 13 11+m 12+m 17 3 NP r16 2 11 11 7+m 7+m 5 2 NP mem16 2+d(0,2) 18+EA 17 11+m 10+m 5 2 NP mem32 2+d(4) 24+EA 26 15+m 12+m 13 4 NP

r32 2 - - - 7+m 5 2 NP mem32 2+d(0,2) - - - 10+m 5 2 NP mem48 2+d(6) - - - 12+m 13 4 NP

cycles for jumps through call gates not shown

Example: jmp target_address

LAHF Load flags into AH

bytes 8088 186 286 386 486 Pentium 1 4 2 2 2 3 2 NP

Example: lahf

LAR Load access rights byte (286+)

operands bytes 286 386 486 Pentium r16, r16 3 14 15 11 8 NP r32, r32 3 - 15 11 8 NP r16, m16 3 16 16 11 8 NP r32, m32 3 - 16 11 8 NP

Example: lar eax, ebx

LDS Load far pointer

operands bytes 8088 186 286 386 486 Pentium reg, mem 2+d(2) 24+EA 18 7 7 6 4 NP

Example: lds si, ptr_1

LES Load far pointer

operands bytes 8088 186 286 386 486 Pentium reg, mem 2+d(2) 24+EA 18 7 7 6 4 NP

Example: les di, ptr_2

LFS Load far pointer (386+)

operands bytes 386 486 Pentium reg, mem 3+d(2,4) 7 6 4 NP

Example: lfs si, ptr_3

LGS Load far pointer (386+)

operands bytes 386 486 Pentium reg, mem 3+d(2,4) 7 6 4 NP

Example: lgs si, ptr_4

LSS Load stack segment and offset

operands bytes 386 486 Pentium reg, mem 3+d(2,4) 7 6 4 NP

Example: lss bp, ptr_5

LEA Load effective address

operands bytes 8088 186 286 386 486 Pentium r16, mem 2+d(2) 2+EA 6 3 2 1-2 1 UV r32, mem 2+d(2) - - - 2 1-2 1 UV

Example: lea eax, [eax+ebx*2+3]

LEAVE High level procedure exit (186+)

bytes 186 286 386 486 Pentium 1 8 5 4 5 3 NP

Example: leave

LGDT Load global descriptor table register (286+) operand bytes 286 386 486 Pentium mem48 5 11 11 11 6 NP

Example: lgdt descriptor[ebx]

LIDT Load interrupt descriptor table register (286+)

operand bytes 286 386 486 Pentium mem48 5 12 11 11 6 NP

Example: lidt descriptor[ebx]

LLDT Load local descriptor table register (286+)

operand bytes 286 386 486 Pentium r16 3 17 20 11 9 NP mem16 3+d(0-2) 19 24 11 9 NP

Example: lldt ax

LMSW Load machine status word (286+)

operand bytes 286 386 486 Pentium r16 3 3 10 13 8 NP mem16 3+d(0-2) 6 13 13 8 NP

Example: lmsw ax

LOCK Lock bus on next instruction (prefix)

bytes 8088 186 286 386 486 Pentium 1 2 2 0 0 1 1 NP

(Note: xchg always is locked whether it is specified or not)

Example: lock mov mem, 1

LODS/LODSB/LODSW/LODSD Load string operand

variations bytes 8088 186 286 386 486 Pentium lodsb 1 16 10 5 5 5 2 NP lodsw 1 16 10 5 5 5 2 NP lodsd 1 - - - 5 5 2 NP

Example: lodsb

LOOP Loop control with CX counter

operand bytes 8088 186 286 386 486 Pentium short 2 5/17 5/15 4/8+m 11+m 6/7 5/6 NP loopw short (uses CX in 32-bit mode) loopd short (uses ECX in 16-bit mode)

Example: loop loop_start

LOOPE/LOOPZ Loop while equal (or zero)

operand bytes 8088 186 286 386 486 Pentium short 2 6/18 5/16 4/8 11+m 6/9 7/8 NP loopew short (uses CX in 32-bit mode) loopzw short (uses CX in 32-bit mode) looped short (uses ECX in 16-bit mode) loopzd short (uses ECX in 16-bit mode)

Example: loope loop_start

LOOPNE/LOOPNZ Loop while not equal (or not zero)

operand bytes 8088 186 286 386 486 Pentium short 2 5/19 5/16 4/8 11+m 6/9 7/8 NP loopnew short (uses CX in 32-bit mode) loopnzw short (uses CX in 32-bit mode) loopned short (uses ECX in 16-bit mode) loopnzd short (uses ECX in 16-bit mode)

Example: loopne loop_start

LSL Load segment limit (286+)

operands bytes 286 386 486 Pentium r16, r16 3 14 20/25 10 8 NP r32, r32 3 - 20/25 10 8 r16, m16 3+d(0,2) 16 21/26 10 8 r32, m32 3+d(0,2) - 21/26 10 8

Example: lsl eax, ebx

LTR Load task register (286+)

operand bytes 286 386 486 Pentium r16 3 17 23 20 10 NP mem16 3+d(0,2) 19 27 20 10

Example: ltr ax

MOV Move data

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 2 2 2 2 1 1 UV mem, reg 2+d(0-2) 13+EA 9 3 2 1 1 UV reg, mem 2+d(0-2) 12+EA 12 5 4 1 1 UV mem, imm 2+d(0-2) 14+EA 12-13 3 2 1 1 UV* +i(1,2) reg, imm 2+i(1,2) 4 3-4 2 2 1 1 UV

acc, mem 3 14 8 5 4 1 1 UV mem, acc 3 14 9 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: mov eax, ebx

Segment Register Moves

Real Mode operands bytes 8088 186 286 386 486 Pentium seg, r16 2 2 2 2 2 3 2-11 NP seg, m16 2+d(0,2) 12+EA 9 5 5 3 3-12 NP r16, seg 2 2 2 2 2 3 1 NP m16, seg 2+d(0,2) 13+EA 11 3 2 3 1 NP

Example: mov ds, ax

Protected Mode Differences operands bytes 286 386 486 Pentium seg, r16 2 17 18 9 2-11* NP seg, m16 2+d(0,2) 19 19 9 3-12* NP * = add 8 if new descriptor; add 6 if SS

MOVE to/from special registers (386+)

operands bytes 386 486 Pentium r32, cr32 3 6 4 4 NP cr32, r32 3 4/10* 4/16* 12/22* NP

r32, dr32 3 14/22* 10 2/12* NP dr32, r32 3 16/22* 11 11/12* NP

r32, tr32 3 12 3/4* - NP tr32, r32 3 12 4/6* - NP

* = cycles depend on which special register

Example: mov cr0, eax

MOVS/MOVSB/MOVSW/MOVSD Move data from string to string

variations bytes 8088 186 286 386 486 Pentium movsb 1 18 9 5 7 7 4 NP movsw 1 26 9 5 7 7 4 NP movsd 1 - - - 7 7 4 NP rep movsb 2 9+17n 8+8n 5+4n 7+4n 12+3n* 3+n NP rep movsw 2 9+25n 8+8n 5+4n 7+4n 12+3n* 3+n NP rep movsd 2 - - - 7+4n 12+3n* 3+n NP

* = 5 if n=0, 13 if n=1 (n = count of bytes, words or dwords)

Example: rep movsb

MOVSX Move with sign-extend (386+)

operands bytes 386 486 Pentium reg, reg 3 3 3 3 NP reg, mem 3+d(0,1,2,4) 6 3 3 NP (Note: destination reg is 16 or 32-bits; source is 8 or 16 bits)

Example: movsx ebx, ax

MOVZX Move with zero-extend (386+)

operands bytes 386 486 Pentium reg, reg 3 3 3 3 NP reg, mem 3+d(0,1,2,4) 6 3 3 NP

(Note: destination reg is 16 or 32-bits; source is 8 or 16 bits)

Example: movzx ebx, ax

MUL Unsigned multiply

operand bytes 8088 186 286 386 486 Pentium r8 2 70-77 26-28 13 9-14 13-18 11 NP r16 2 118-133 35-37 21 9-22 13-26 11 NP r32 2 - - - 9-38 13-42 10 NP mem8 2+d(0-2) 76-83+EA 32-34 16 12-17 13-18 11 NP mem16 2+d(0-2) 124-139+EA 41-43 24 12-25 13-26 11 NP mem32 2+d(0-2) - - - 12-41 13-42 10 NP

implied operand result multiplicand (multiplier) AL * byte = AX AX * word = DX:AX EAX * dword = EDX:EAX

Example: mul ebx

NEG Two's complement negation

operand bytes 8088 186 286 386 486 Pentium reg 2 3 3 2 2 1 1 NP mem 2+d(0-2) 24+EA 13 7 6 3 3 NP

Example: neg eax

NOP No operation

bytes 8088 186 286 386 486 Pentium 1 3 3 3 3 1 1 UV

Example: nop

NOT One's complement negation

operands bytes 8088 186 286 386 486 Pentium reg 2 3 3 2 2 1 1 NP mem 2+d(0-2) 24+EA 13 7 6 3 3 NP

Example: not eax

OR Logical inclusive or

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 UV reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: or eax, ebx

OUT Output to port

operands bytes 8088 186 286 386 486 Pentium imm8, al 2 14 9 3 10 16 12 NP imm8, ax 2 14 9 3 10 16 12 NP imm8, eax 2 - - - 10 16 12 NP dx, al 1 12 7 3 11 16 12 NP dx, ax 1 12 7 3 11 16 12 NP dx, eax 1 - - - 11 16 12 NP

Protected Mode

operands bytes 386 486 Pentium imm8, acc 2 4/24/24 11/31/29 9/26/24 NP dx, acc 1 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 Output string to port

variations bytes 186 286 386 486 Pentium outsb 1 14 5 14 17 13 NP outsw 1 14 5 14 17 13 NP outsd 1 - - 14 17 13 NP

Protected Mode

bytes 386 486 Pentium 1 8/28/28 10/32/30 10/27/25 NP

cycles for: CPL <= IOPL / CPL > IOPL / V86

Example: rep outsw

POP Pop a word/dword from the stack

operand bytes 8088 186 286 386 486 Pentium reg 1 12 10 5 4 1 1 UV mem 2+d(0-2) 25+EA 20 5 5 6 3 NP seg 1 12 8 5 7 3 3 NP FS/GS 2 - - - 7 3 3 NP

Protected Mode

operand bytes 286 386 486 Pentium CS/DS/ES 1 20 21 9 3-12 NP SS 1 20 21 9 8-17 NP FS/GS 2 - 21 9 3-12 NP

Example: pop eax

POPA/POPAD Pop all (186+)/Pop all double (386+)

variations bytes 186 286 386 486 Pentium popa 1 51 19 24 9 5 NP popad 1 - - 24 9 5 NP

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: popa

POPF/POPFD Pop flags/Pop flags double (386+)

variations bytes 8088 186 286 386 486 Pentium popf 1 12 8 5 5 9 6 NP popfd 1 - - - 5 9 6 NP

Protected Mode

bytes 286 386 486 Pentium popf 1 5 5 6 4 NP popfd 1 - 5 6 4 NP

Example: popf

PUSH push a word/dword to the stack

operand bytes 8088 186 286 386 486 Pentium reg 1 15 10 3 2 1 1 UV mem 2+d(0-2) 24+EA 16 5 5 4 2 NP seg 1 14 9 3 2 3 1 NP imm 1+i(1,2) - - 3 2 1 1 NP FS/GS 2 - - - 2 3 1 NP

Example: push eax

PUSHA/PUSHAD Push all (186+)/Push all double (386+) variations bytes 186 286 386 486 Pentium pusha 1 36 17 18 11 5 NP pushad 1 - - 18 11 5 NP

pusha = push ax, cx, dx, bx, sp, bp, si, di, pushad = push eax, ecx, edx, ebx, esp, ebp, esi, edi

Example: pusha

PUSHF/PUSHFD Push flags/Push flags double (386+)

variations bytes 8088 186 286 386 486 Pentium pushf 1 14 9 3 4 4 9 NP pushfd 1 - - - 4 4 9 NP

Protected Mode

bytes 286 386 486 Pentium pushf 1 3 4 3 3 NP pushfd 1 - 4 3 3 NP

Example: pushf

RCL Rotate bits left with CF

operands bytes 8088 186 286 386 486 Pentium reg, 1 2 2 2 2 9 3 1 PU mem, 1 2+d(0,2) 23+EA 15 7 10 4 3 PU reg, cl 2 8+4n 5+n 5+n 9 8-30 7-24 NP mem, cl 2+d(0,2) 28+EA+4n 17+n 8+n 10 9-31 9-26 NP reg, imm 3 - 5+n 5+n 9 8-30 8-25 NP mem, imm 3+d(0,2) - 17+n 8+n 10 9-31 10-27 NP

Example: rcl eax, 16

RCR Rotate bits right with CF

operands bytes 8088 186 286 386 486 Pentium reg, 1 2 2 2 2 9 3 1 PU mem, 1 2+d(0,2) 23+EA 15 7 10 4 3 PU reg, cl 2 8+4n 5+n 5+n 9 8-30 7-24 NP mem, cl 2+d(0,2) 28+EA+4n 17+n 8+n 10 9-31 9-26 NP reg, imm 3 - 5+n 5+n 9 8-30 8-25 NP mem, imm 3+d(0,2) - 17+n 8+n 10 9-31 10-27 NP

Example: rcr eax, 16

ROL Rotate bits left

operands bytes 8088 186 286 386 486 Pentium reg, 1 2 2 2 2 3 3 1 PU mem, 1 2+d(0,2) 23+EA 15 7 7 4 3 PU reg, cl 2 8+4n 5+n 5+n 3 3 4 NP mem, cl 2+d(0,2) 28+EA+4n 17+n 8+n 7 4 4 NP reg, imm 3 - 5+n 5+n 3 2 1 PU mem, imm 3+d(0,2) - 17+n 8+n 7 4 3 PU*

* = not pairable if there is a displacement and immediate

Example: rol eax, 16

ROR Rotate bits right

operands bytes 8088 186 286 386 486 Pentium reg, 1 2 2 2 2 3 3 1 PU mem, 1 2+d(0,2) 23+EA 15 7 7 4 3 PU reg, cl 2 8+4n 5+n 5+n 3 3 4 NP mem, cl 2+d(0,2) 28+EA+4n 17+n 8+n 7 4 4 NP reg, imm 3 - 5+n 5+n 3 2 1 PU mem, imm 3+d(0,2) - 17+n 8+n 7 4 3 PU*

* = not pairable if there is a displacement and immediate

Example: ror eax, 16

RDMSR Read from model specific register (Pentium+)

bytes Pentium 2 20-24 NP

Example: rdmsr

REP Repeat string operation

See: MOVS (rep movs) move block See: STOS (rep stos) fill block

REPE Repeat while equal (or zero) string operation

See: CMPS (repe cmps) find non-matching memory items See: CMPS (repe scas) find non-acc matching byte in memory

REPNE Repeat while not equal (or not zero) string operation

See: CMPS (repne cmps) find first matching memory items See: SCAS (repne scas) find first matching memory item to acc

RET/RETN/RETF Return from procedure variations/ operands bytes 8088 186 286 386 486 Pentium retn 1 20 16 11+m 10+m 5 2 NP retn imm16 1+d(2) 24 18 11+m 10+m 5 3 NP retf 1 34 22 15+m 18+m 13 4 NP retf imm16 1+d(2) 33 25 15+m 18+m 14 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 286 386 486 Pentium retf 1 25+m/55 32+m/62 18/33 4-13/23 NP retf imm16 1+d(2) 25+m/55 32+m/68 17/33 4-13/23 NP

cycles for: same privilege level/lower privilege level

RSM Resume from system management mode (Pentium+)

bytes Pentium 2 83 NP

Example: rsm

SAL/SHL/SAR/SHR Shift bits

operands bytes 8088 186 286 386 486 Pentium reg, 1 2 2 2 2 3 3 1 PU mem, 1 2+d(0,2) 23+EA 15 7 7 4 3 PU reg, cl 2 8+4n 5+n 5+n 3 3 4 NP mem, cl 2+d(0,2) 28+EA+4n 17+n 8+n 7 4 4 NP reg, imm 3 - 5+n 5+n 3 2 1 PU mem, imm 3+d(0,2) - 17+n 8+n 7 4 3 PU*

* = not pairable if there is a displacement and immediate

sal = shift arithmetic left sar = shift arithmetic right shl = shift left (same as sal) shr = shift right

Example: shl eax, 1

SAHF Store AH into flags

bytes 8088 186 286 386 486 Pentium 1 4 3 2 3 2 2 NP

Example: sahf

SBB Integer subtraction with borrow

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 PU mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 PU reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 PU reg, imm 2+i(1,2) 4 4 3 2 1 1 PU mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 PU* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 PU

* = not pairable if there is a displacement and immediate

Example: sbb eax, ebx

SCAS/SCASB/SCASW/SCASD Scan string data

variations bytes 8088 186 286 386 486 Pentium scasb 1 19 15 7 7 6 4 NP scasw 1 19 15 7 7 6 4 NP scasd 1 - - - 7 6 4 NP repX scasb 2 9+15n 5+15n 5+8n 5+8n 7+5n* 8+4n NP repX scasw 2 9+19n 5+15n 5+8n 5+8n 7+5n* 8+4n NP repX scasd 2 - - - 5+8n 7+5n* 8+4n NP

repX = repe or repz or repne or repnz

* = 5 if n=0 (n = count of bytes, words or dwords)

Example: repne scasb SET Set byte to 1 on condition else set to 0 (386+)

operand bytes 386 486 Pentium r8 3 4 4/3 1/2 NP mem8 3+d(0-2) 5 3/4 1/2 NP

Cycles are for: true/false

setCC = one of:

seta setae setb setbe setc sete setg setge setl setle setna setnae setnb setnbe setnc setne setng setnge setnl setnle setno setnp setns setnz seto setp setpe setpo sets setz

Example: setne al

SGDT Store global descriptor table register (286+)

operand bytes 286 386 486 Pentium mem48 5 11 9 10 4 NP

Example: sgdt descriptor[ebx]

SIDT Store interrupt descriptor table register (286+)

operand bytes 286 386 486 Pentium mem48 5 12 9 10 4 NP

Example: sidt descriptor[ebx]

SHLD Double precision shift left (386+)

operands bytes 386 486 Pentium reg, reg, imm 4 3 2 4 NP mem, reg, imm 4+d(0-2) 7 3 4 NP reg, reg, cl 4 3 3 4 NP mem, reg, cl 4+d(0-2) 7 4 5 NP

Example: shld eax, ebx, 16

SHRD Double precision shift right (386+)

operands bytes 386 486 Pentium reg, reg, imm 4 3 2 4 NP mem, reg, imm 4+d(0-2) 7 3 4 NP reg, reg, cl 4 3 3 4 NP mem, reg, cl 4+d(0-2) 7 4 5 NP

Example: shrd eax, ebx, 16

SLDT Store local descriptor table register (286+)

operands bytes 286 386 486 Pentium r16 3 2 2 2 2 NP mem16 3+d(0-2) 3 2 3 2 NP

Example: sldt ax

SMSW Store machine status word (286+)

operands bytes 286 386 486 Pentium r16 3 2 2 2 4 NP mem16 3+d(0-2) 3 3 3 4 NP

Example: smsw ax

STC Set the carry flag

bytes 8088 186 286 386 486 Pentium 1 2 2 2 2 2 2 NP

Example: stc

STD Set direction flag (set to reverse string direction)

bytes 8088 186 286 386 486 Pentium 1 2 2 2 2 2 2 NP

Example: std

STI Set interrupt flag (enable)

bytes 8088 186 286 386 486 Pentium 1 2 2 2 3 5 7 NP

Example: sti

STOS/STOSB/STOSW/STOSD Store string data

variations bytes 8088 186 286 386 486 Pentium stosb 1 11 10 3 4 5 3 NP stosw 1 15 10 3 4 5 3 NP stosd 1 - - - 4 5 3 NP rep stosb 2 9+10n 6+9n 4+3n 5+5n 7+4n* 3+n NP rep stosw 2 9+14n 6+9n 4+3n 5+5n 7+4n* 3+n NP rep stosd 2 - - - 5+5n 7+4n* 3+n NP

* = 5 if n=0, 13 if n=1 (n = count of bytes, words or dwords)

Example: rep stosd

STR Store task register (286+)

operand bytes 286 386 486 Pentium r16 3 2 2 2 2 NP mem16 3+d(0-2) 3 2 3 2 NP

Example: str bx

SUB Integer subtraction

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 UV reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: sub eax, ebx

TEST Logical compare

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 13+EA 10 6 5 2 2 UV reg, mem 2+d(0,2) 13+EA 10 6 5 2 2 UV reg, imm 2+i(1,2) 5 4 3 2 1 1 UV mem, imm 2+d(0,2) 11+EA 10 6 5 2 2 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 1 UV

* = not pairable if there is a displacement and immediate

Example: sub eax, ebx

VERR Verify a segment for reading (286+)

operand bytes 286 386 486 Pentium r16 3 14 10 11 7 NP mem16 3+d(0,2) 16 11 11 7 NP

Example: verr ax

VERW Verify a segment for writing (286+)

operand bytes 286 386 486 Pentium r16 3 14 15 11 7 NP mem16 3+d(0,2) 16 16 11 7 NP

Example: verr ax

WAIT Wait for co-processor

bytes 8088 186 286 386 486 Pentium 1 4 6 3 6 1-3 1 NP

Example: wait

WBINVD Write-back and invalidate data cache (486+)

bytes 486 Pentium 2 5 2000+ NP

Example: wbinvd WRMSR Write to model specific register (PENTIUM+)

bytes Pentium 2 30-45 NP

Example: wrmsr

XADD Exchange and add (486+)

operands bytes 486 Pentium reg, reg 3 3 3 NP mem, reg 3+d(0-2) 4 4 NP

Example: xadd eax, ebx

XCHG Exchange register/memory with register

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 4 4 3 3 3 3 NP reg, mem 2+d(0-2) 25+EA 17 5 5 5 3 NP mem, reg 2+d(0-2) 25+EA 17 5 5 5 3 NP

acc, reg 1 3 3 3 3 3 2 NP reg, acc 1 3 3 3 3 3 2 NP

in above: acc = AX or EAX only

Example: xchg ax, dx

XLAT/XLATB Table look-up translation

bytes 8088 186 286 386 486 Pentium 1 11 11 5 5 4 4 NP

Example: xlat

XOR Logical exclusive or

operands bytes 8088 186 286 386 486 Pentium reg, reg 2 3 3 2 2 1 1 UV mem, reg 2+d(0,2) 24+EA 10 7 7 3 3 UV reg, mem 2+d(0,2) 13+EA 10 7 6 2 2 UV reg, imm 2+i(1,2) 4 4 3 2 1 1 UV mem, imm 2+d(0,2) 23+EA 16 7 7 3 3 UV* +i(1,2) acc, imm 1+i(1,2) 4 4 3 2 1 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. Address Generation Interlock. On the 486 and Pentium processors the pipeline is stalled for AGI: one cycle if a component of an address is loaded or calculated in the previous machine cycle. The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR Arithmetic Logic Unit: and CMP. The placement of data or code on a specific address boundary (i.e. a 2, 4, or 8 byte evenly Alignment: divisible address). ALU: See Arithmetic Logic Unit. The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR Arithmetic Logic Unit: and CMP. American Standard Code for Information Interchange. A standard code for representing ASCII: English characters and symbols with various extensions for foreign characters. A program that translates an assembly language program to machine language (or object Assembler: code). A programming language, based on the architecture of a particular machine, where most Assembly Language: statements translate into one machine instruction. Base address: The address at the start of a structure or of data array. A register that contains a base address. Usually BX (EBX) or BP (EBP) is a base register. For Base register: 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. Also See base address. In number systems, used to specify the number of digits in a system, Base: i.e. base 10 has ten digits, base 2 has two, etc. Binary Coded Decimal. See also Packed BCD. This is a format for encoding base 10 numbers BCD: where the low order 4 bits are used to store the numercial value. A method of storing multi-byte data types where the low-order byte is stored at the highest Big-endian: address and the high-order byte is stored at the lower address. Basic Input/Output System. Built-in software (usually stored in ROM) that is used to start up BIOS: 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. A small fast memory buffer that holds a copy of the most recently used or most active portions Cache: of the larger slower memory. Also see Disk Cache. The main processing unit in a computer. Sometimes referred to as the processor, the chip or Central Processor Unit: the computer. A data type that is an array of characters. Usually followed by a byte of 0 in assembly Character String: language or C. Character: A data type that is the same as a byte. A simple error detection scheme where values are added (summed) into a variable to be Checksum: compared with a similar previously calculated value. A small piece of semiconducting material on which an electronic circuit is placed. A CPU Chip: 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. A program that translates a high level language (such as C, Pascal or Fortran) into machine Compiler: 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. Control Program for Microcomputers. An operating system originally designed for 8080 and CP/M: Z-80 based computers. CPU: See Central Processor Unit. Cyclic redundancy check. A complex error detection scheme, similar to a checksum, but each CRC: 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. A program that allows executing, monitoring and modifying a program's code and data to Debugger: enable a programmer to locate program errors (or bugs). An assembler statement that contains information for the use of the assembler rather than an Directive: instruction to be assembled and executed as part of the program. A program that attempts the difficult task of reconstructing an assembly language source file Disassembler: from machine language. A program and/or areas of memory set aside keep frequently used or most recently used data Disk Cache: 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. Dynamic RAM. The type of memory chip used in most computers. It is called dynamic DRAM: 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. The combination of any or all of a base register, index register and displacement used to Effective Address: 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. A reference to memory consisting of a segment and an offset. In real mode the segment is the Far Pointer: upper 16 bits of a 20-bit segment starting address. In protected mode the segment is a selector. An exception that is called with the return address on the stack of the instruction that caused Fault: the fault. An organized collection of data or information, usually stored on a disk with a specific name File: or filename. A program model where all segment registers are the same and are usually set to be larger Flat Model: than 64K segments. The portion of the 80486 or Pentium that performs the floating point operations like the Floating Point Unit: floating point processor. FPP: See Floating Point Processor. A floating point math processor. The processing unit that performs IEEE 754 floating point Floating Point Processor: 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. Institute of Electrical and Electronic Engineers. An organization best known for developing IEEE: electrical and electronic standards for the computer industry. A register that contains an index value. Usually SI (ESI) or DI (EDI) is an index register. For Index register: 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. A positive whole number, negative whole number or zero. On computers integers have a Integer: limited range, for example byte integers have a range of -128 to +127. A program that executes another program by reading each program statement and interpreting Interpreter: 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 An identifier used in assembly language programs to specify a memory address by name Label: 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. A 20-, 24-, or 32-bit address into a large unsegmented memory space. With paging (virtual Linear Address: memory) disabled the linear address is the physical address. With paging enabled the paging mechanism translates the linear address to a physical address. The complex process of combining object files and hooking, or linking together, subroutines Link: or data in one file that are referenced in another file. A program that links one or more object files into an executable program file, usually a .EXE Linker: file. A method of storing multi-byte data types where the low-order byte is stored at the lowest Little-endian: address and the high-order byte is stored at the highest address. The Intel 80x86 processor use this format. A segment and offset combine to generate a logical address. The segmentation unit translates Logical Address: 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. A bit pattern constructed to be logically combined with a data value to allow only some bits of Mask: the original data value to show through (i.e. the others are masked out). A floating point math processor. Termed a "co-processor" when added as an optional separate Math Coprocessor: chip. MegaHertz: A million hertz; A million cycles per second. Mhz: MegaHertz. Microprocessor: A computer processor fully contained on one integrated circuit (or chip). Part of a program, usually one file, containing one or more procedures or subroutines and/or Module: data values. MS-DOS: Microsoft DOS (Disk Operating System). A reference to memory containing only the offset portion of the address. The offset must be Near Pointer: 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. An intermediate form of machine language produced by assemblers and compilers that is Object code: structured so that it can be linked together. A 16-bit number that specifies the byte number beyond the start of a segment. On the 80386 Offset: and above segments may have 32-bit offsets. Data provided in a register, in memory or immediately with an instruction to be used in the Operand: processing of the instruction. The program(s) that load applications and control access to memory, disk files, I/O ports, etc., Operating System: such as DOS, Windows, OS/2 and UNIX. OS: See Operating System. Packed Binary Coded Decimal. A data format that stores one decimal digit in each nibble of a Packed BCD: byte. Page: A 4K-byte block of memory. This is the size of memory block used for paging. A method of managing memory, by an operating system, to implement a virtual memory Paging: system. Pages of memory are stored on a disk when not in use and recalled later when needed. The process of issuing two instructions at the same time to each of the U and V pipelines of Pairing: the Pentium. Paragraph: 16 bytes of memory. An error detection system commonly used in data communications where the sum of the set Parity: bits in a data packet is odd or even. PC-DOS: Personal Computer DOS. IBM's version of MS-DOS. The actual hardware address of memory issued by the processor. The maximum physical Physical Address: 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. One of several machine language codes that can be placed in front of other instructions to Prefix: modify their actions or default conditions. Short for microprocessor. The part of the computer that actually performs the arithmetic, Processor: logical and control functions of a computer. A CPU mode where memory address ranges are protected from being read and/or written to Protected Mode: by unauthorized segments of code. Pseudo-op: Another term for assembler directives. Quadword: A data type consisting of 8 bytes or 64-bits. Random Access Memory. The read/write memory used by the computer, usually consisting of RAM: DRAM chips. A quality of a procedure or program that allows it to be interrupted and called or run again and Re-entrant: both logical instances remain intact and properly execute independently of each other. The only CPU mode of the 8088 and 8086 and the startup mode for the 80286 and above. Real Mode: There is no memory protection as in the protected mode. A storage area in a CPU. Each register usually has a number of operations that can be directly Register: performed on it by the CPU, unlike a memory storage location. Processors designed with the general concepts of a load/store architecture, few addressing Reduced Instruction Set Computer: modes, many registers, fixed length instructions and the "simple is faster" design criteria. A prefix for an instruction that causes a segment register, other than the normal default Segment Override: segment register to be used during the execution of the following instruction. Real mode: A portion of memory specified by a 20-bit starting address of which the low 4 bits Segment: are always zero and whose length can be up to 64K. Protected mode: A portion of memory described by a descriptor table entry. In protected mode, a pointer to a segment descriptor. A selector is a 16-bit value and is used in Selector: protected mode instead of a paragraph address in a segment register. Static RAM. Faster and more stable than DRAM, but requires more power and is more SRAM: 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. A last-in first-out data data structure in memory used for saving return addresses, temporary Stack: variables and system status information. A system can have any number of stacks, but only one may be in use at any time Any consectutive bytes of memory can be a string. HLL's specify rules for defining strings. In String: 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. A mathematical operation where a binary value is multiplied by -1. Each bit is changed to the Two's Complement: opposite value and then one is added to the entire value. A positive whole number or zero. On computers unsigned integers have a limited ranged, for Unsigned Integer: example an 8-bit unsigned integer has a range of 0 to 255. V86 Mode: See Virtual-8086 Mode. A scheme used that allows programs to logically allocate and use more memory than is Virtual Memory: physically available by moving and swapping portions that are not currently needed or infrequently used to a hard disk. A mode on 386 and above processors that provides for the emulation of the 8086 architecture. Virtual-8086 Mode: An operating system may run a mix of protected mode tasks amd virtual-8086 mode tasks. A data type consisting of two bytes or 16 bits. (On non-x86 architectures a word usually refers Word: 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 CreateConsoleScreenBuffer FillConsoleOutputAttribute FillConsoleOutputCharacter FlushConsoleInputBuffer FreeConsole GenerateConsoleCtrlEvent GetConsoleCP GetConsoleCursorInfo GetConsoleMode GetConsoleOutputCP GetConsoleScreenBufferInfo GetConsoleTitle GetLargestConsoleWindowSize GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons GetStdHandle HandlerRoutine PeekConsoleInput ReadConsole ReadConsoleInput ReadConsoleOutput ReadConsoleOutputAttribute ReadConsoleOutputCharacter ScrollConsoleScreenBuffer SetConsoleActiveScreenBuffer SetConsoleCP SetConsoleCtrlHandler SetConsoleCursorInfo SetConsoleCursorPosition SetConsoleMode See SetConsoleWindowInfo SetStdHandle WriteConsole WriteConsoleInput WriteConsoleOutput WriteConsoleOutputAttribute WriteConsoleOutputCharacter

Console-Strukturen

CHAR_INFO CONSOLE_CURSOR_INFO CONSOLE_SCREEN_BUFFER_INFO COORD FOCUS_EVENT_RECORD INPUT_RECORD KEY_EVENT_RECORD MENU_EVENT_RECORD MOUSE_EVENT_RECORD SMALL_RECT WINDOW_BUFFER_SIZE_RECORD

WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben

#define FOREGROUND_BLUE 0x0001 // text color contains blue #define FOREGROUND_GREEN 0x0002 // text color contains green #define FOREGROUND_RED 0x0004 // text color contains read #define FOREGROUND_INTENSITY 0x0008 // text color is intensified #define BACKGROUND_BLUE 0x0010 // background color contains blue #define BACKGROUND_GREEN 0x0020 // background color contains green #define BACKGROUND_RED 0x0040 // background color contains red #define BACKGROUND_INTENSITY 0x0080 // background 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 #include #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 CreateConsoleScreenBuffer FillConsoleOutputAttribute FillConsoleOutputCharacter FlushConsoleInputBuffer FreeConsole GenerateConsoleCtrlEvent GetConsoleCP GetConsoleCursorInfo GetConsoleMode GetConsoleOutputCP GetConsoleScreenBufferInfo GetConsoleTitle GetLargestConsoleWindowSize GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons GetStdHandle HandlerRoutine PeekConsoleInput ReadConsole ReadConsoleInput ReadConsoleOutput ReadConsoleOutputAttribute ReadConsoleOutputCharacter ScrollConsoleScreenBuffer SetConsoleActiveScreenBuffer SetConsoleCP SetConsoleCtrlHandler SetConsoleCursorInfo SetConsoleCursorPosition SetConsoleMode See SetConsoleWindowInfo SetStdHandle WriteConsole WriteConsoleInput WriteConsoleOutput WriteConsoleOutputAttribute WriteConsoleOutputCharacter

Diese Funktionen verwenden die Console - Strukturen:

CHAR_INFO CONSOLE_CURSOR_INFO CONSOLE_SCREEN_BUFFER_INFO COORD FOCUS_EVENT_RECORD INPUT_RECORD KEY_EVENT_RECORD MENU_EVENT_RECORD MOUSE_EVENT_RECORD SMALL_RECT WINDOW_BUFFER_SIZE_RECORD

Für den Text - Bildschirm sind in WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben definiert:

#define FOREGROUND_BLUE 0x0001 // text color contains blue #define FOREGROUND_GREEN 0x0002 // text color contains green #define FOREGROUND_RED 0x0004 // text color contains read #define FOREGROUND_INTENSITY 0x0008 // text color is intensified #define BACKGROUND_BLUE 0x0010 // background color contains blue #define BACKGROUND_GREEN 0x0020 // background color contains green #define BACKGROUND_RED 0x0040 // background 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 _INPUT_RECORD { WORD EventType; union { typedef struct _CHAR_INFO { KEY_EVENT_RECORD KeyEvent; union { MOUSE_EVENT_RECORD MouseEvent; WCHAR UnicodeChar; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; CHAR AsciiChar; MENU_EVENT_RECORD MenuEvent; } Char; FOCUS_EVENT_RECORD FocusEvent; WORD Attributes; } Event; } CHAR_INFO; } INPUT_RECORD; typedef struct _COORD { typedef struct _SMALL_RECT { SHORT X; SHORT Left; SHORT Y; SHORT Top; } COORD; SHORT Right; typedef struct _CONSOLE_SCREEN_BUFFER_INFO { SHORT Bottom; COORD dwSize; } SMALL_RECT; COORD dwCursorPosition; typedef struct _KEY_EVENT_RECORD { WORD wAttributes; BOOL bKeyDown; SMALL_RECT srWindow; WORD wRepeatCount; COORD dwMaximumWindowSize; WORD wVirtualKeyCode; } CONSOLE_SCREEN_BUFFER_INFO; WORD wVirtualScanCode; typedef struct _CONSOLE_CURSOR_INFO { union { DWORD dwSize; WCHAR UnicodeChar; BOOL bVisible; CHAR AsciiChar; } CONSOLE_CURSOR_INFO; } 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 #include #include //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" )); Key_Hit(&ms) ; for ( i = 0 ; i < 512 ; i ++ ) { iChar[0] = (TCHAR)i; 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 = GET_WM_COMMAND_CMD (wParam,lParam); int wmCMD = HIWORD( wParam ) ; int wmID = GET_WM_COMMAND_ID (wParam,lParam); #endif HWND wmHWND= GET_WM_COMMAND_HWND(wParam,lParam); int wmID = LOWORD( wParam ); HWND wmHWND= (HWND)(UINT)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 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’ : Rücktaste; break; case ‘\t’ : Tabulatortaste; break; case ‘\n’ : LF-Taste; break; default : //normales Zeichen bearbeiten } } ... } return DefWindowProc( hWnd, iMsg, wParam, lParam ) ; }

In dem obigen Beispiel werden nur einige WM_CHAR - Nachrichten behandelt.

Tabelle der WM - Tastatur - Nachrichten

Es gibt die folgenden Keyboard - Nachrichten:

Tasten- wParam, lParam enthalten ... Nachricht

fActive = LOWORD(wParam); // activation flag WM_ACTIVATE fMinimized = (BOOL) HIWORD(wParam); // minimized flag hwndPrevious = (HWND) lParam; // window handle

// handle of window losing focus WM_SETFOCUS hwndLoseFocus = (HWND) wParam;

// handle of window receiving focus WM_KILLFOCUS hwndGetFocus = (HWND) wParam;

WM_KEYDOWN nVirtKey = (int) wParam; // virtual-key code WM_KEYUP lKeyData = lParam; // key data

WM_CHAR chCharCode = (TCHAR) wParam; // character code WM_SYSCHAR lKeyData = lParam; // key data

idHotKey = (int) wParam; // identifier of hot key WM_HOTKEY fuModifiers = (UINT) LOWORD(lParam); // key-modifier flags uVirtKey = (UINT) HIWORD(lParam); // virtual-key code

wParam = 0; // not used; must be zero WM_GETHOTKEY lParam = 0; // not used; must be zero

// virtual-key code and modifiers of hot key WM_SETHOTKEY wParam = (WPARAM) MAKEWORD(vkey, modifiers) lParam = 0; // not used; must be zero

chCharCode = (TCHAR) wParam; // character code WM_DEADCHAR lKeyData = lParam; // key data

chCharCode = (TCHAR) wParam; // character code WM_SYSDEADCHAR lKeyData = lParam; // key data

WM_SYSKEYDOWN nVirtKey = (int) wParam; // virtual-key code WM_SYSKEYUP 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 = 0x30 VK_A = 0x41 VK_LWIN = 0x5B VK_RWIN = 0x5C VK_APPS = 0x5D VK_NUMPAD0 = 0x60 ..VK_9 ...0x39 ..VK_Z ..0x5A 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_PROCESSKEY VK_RSHIFT VK_LCONTROL VK_RCONTROL VK_LMENU VK_RMENU = 0xA1 = 0xA2 = 0xA3 = 0xA4 = 0xA5 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 ( VK_LBUTTON ) < 0 ) // linke Maus - Taste down || ( GetAsyncKeyState ( VK_ESCAPE ) < 0 ) // Escape Taste ) { // ... z.B. exit ( -1 ); oder // ... SendMessage ( hWnd, WM_CLOSE, 0, 0 ) }

erfolgen. Um den Zustand von mehreren Tasten zu untersuchen, wie z.B. die

● Shift - Taste ( VK_SHIFT, VK_LSHIFT, VK_RSHIFT ), ● Ctrl - Taste ( VK_CONTROL, VK_LCONTROL, VK_RCONTROL ), ● Alt - Taste ( VK_MENU, VK_LMENU, VK_RMENU ) können alle 256 Virtual Keys in einen Buffer buf kopiert werden. Die Funktionen GetKeyboardState(), SetKeyboardState(), GetAsyncKeyState(), GetKeyState(), MapVirtualKey() werden benutzt. Es kann dann z.B. zwischen linken und rechten SHIFT - Tasten unterschieden werden. Die GetKeyboardState( buf ) - Funktion kopiert alle 256 Virtual Keys in einen Buffer buf. Eine Taste ist gerade gedrückt, wenn das 7. Bit gesetzt ist ( sonst 0 ). Der Gedrückt/Losgelassen - Zustand hat 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 was previously 1 if the key is up; up; 1 if Windows displays a 15 14 13 1 if the ALT key is down. 12 0 if the key is down. 0 if the key was previously menu. down. 1 if Windows displays a 1 if the key is extended; 11 10 Not used. 9 Not used. 8 dialog box. 0 if it is not. hardware-scan code 7 generally 0. 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 wParam, lParam enthalten ... WM_CAPTURECHANGED hwndNewCapture = (HWND) lParam; // handle of window to gain mouse capture WM_MOUSEMOVE fwKeys = wParam; // key flags WM_LBUTTONDOWN xPos = LOWORD(lParam); // horizontal position of cursor WM_LBUTTONUP yPos = HIWORD(lParam); // vertical position of cursor WM_RBUTTONDOWN fwKeys: WM_RBUTTONUP MK_CONTROL Set if the CTRL key is down. WM_MBUTTONDOWN MK_LBUTTON Set if the left mouse button is down. WM_MBUTTONUP MK_MBUTTON Set if the middle mouse button is down. WM_LBUTTONDBLCLK MK_RBUTTON Set if the right mouse button is down. WM_MBUTTONDBLCLK MK_SHIFT Set if the SHIFT key is down. WM_RBUTTONDBLCLK 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 0x0000 #define WM_CREATE 0x0001 #define WM_DESTROY 0x0002 #define WM_MOVE 0x0003 #define WM_SIZE 0x0005

#define WM_ACTIVATE 0x0006

// WM_ACTIVATE state values #define WA_INACTIVE 0 #define WA_ACTIVE 1 #define WA_CLICKACTIVE 2

#define WM_SETFOCUS 0x0007 #define WM_KILLFOCUS 0x0008 #define WM_ENABLE 0x000A #define WM_SETREDRAW 0x000B #define WM_SETTEXT 0x000C #define WM_GETTEXT 0x000D #define WM_GETTEXTLENGTH 0x000E #define WM_PAINT 0x000F #define WM_CLOSE 0x0010 #define WM_QUERYENDSESSION 0x0011 #define WM_QUIT 0x0012 #define WM_QUERYOPEN 0x0013 #define WM_ERASEBKGND 0x0014 #define WM_SYSCOLORCHANGE 0x0015 #define WM_ENDSESSION 0x0016 #define WM_SHOWWINDOW 0x0018 #define WM_WININICHANGE 0x001A #if(WINVER >= 0x0400) #define WM_SETTINGCHANGE WM_WININICHANGE #endif /* WINVER >= 0x0400 */

#define WM_DEVMODECHANGE 0x001B #define WM_ACTIVATEAPP 0x001C #define WM_FONTCHANGE 0x001D #define WM_TIMECHANGE 0x001E #define WM_CANCELMODE 0x001F #define WM_SETCURSOR 0x0020 #define WM_MOUSEACTIVATE 0x0021 #define WM_CHILDACTIVATE 0x0022 #define WM_QUEUESYNC 0x0023

#define WM_GETMINMAXINFO 0x0024 #define WM_PAINTICON 0x0026 #define WM_ICONERASEBKGND 0x0027 #define WM_NEXTDLGCTL 0x0028 #define WM_SPOOLERSTATUS 0x002A #define WM_DRAWITEM 0x002B #define WM_MEASUREITEM 0x002C #define WM_DELETEITEM 0x002D #define WM_VKEYTOITEM 0x002E #define WM_CHARTOITEM 0x002F #define WM_SETFONT 0x0030 #define WM_GETFONT 0x0031 #define WM_SETHOTKEY 0x0032 #define WM_GETHOTKEY 0x0033 #define WM_QUERYDRAGICON 0x0037 #define WM_COMPAREITEM 0x0039

#define WM_COMPACTING 0x0041 #define WM_COMMNOTIFY 0x0044 /* no longer suported */ #define WM_WINDOWPOSCHANGING 0x0046 #define WM_WINDOWPOSCHANGED 0x0047

#define WM_POWER 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 0x004A #define WM_CANCELJOURNAL 0x004B

#if(WINVER >= 0x0400) #define WM_NOTIFY 0x004E #define WM_INPUTLANGCHANGEREQUEST 0x0050 #define WM_INPUTLANGCHANGE 0x0051 #define WM_TCARD 0x0052 #define WM_HELP 0x0053 #define WM_USERCHANGED 0x0054 #define WM_NOTIFYFORMAT 0x0055

#define NFR_ANSI 1 #define NFR_UNICODE 2 #define NF_QUERY 3 #define NF_REQUERY 4

#define WM_CONTEXTMENU 0x007B #define WM_STYLECHANGING 0x007C #define WM_STYLECHANGED 0x007D #define WM_DISPLAYCHANGE 0x007E #define WM_GETICON 0x007F #define WM_SETICON 0x0080 #endif /* WINVER >= 0x0400 */

#define WM_NCCREATE 0x0081 #define WM_NCDESTROY 0x0082 #define WM_NCCALCSIZE 0x0083 #define WM_NCHITTEST 0x0084 #define WM_NCPAINT 0x0085 #define WM_NCACTIVATE 0x0086 #define WM_GETDLGCODE 0x0087

#define WM_NCMOUSEMOVE 0x00A0 #define WM_NCLBUTTONDOWN 0x00A1 #define WM_NCLBUTTONUP 0x00A2 #define WM_NCLBUTTONDBLCLK 0x00A3 #define WM_NCRBUTTONDOWN 0x00A4 #define WM_NCRBUTTONUP 0x00A5 #define WM_NCRBUTTONDBLCLK 0x00A6 #define WM_NCMBUTTONDOWN 0x00A7 #define WM_NCMBUTTONUP 0x00A8 #define WM_NCMBUTTONDBLCLK 0x00A9

#define WM_KEYFIRST 0x0100 #define WM_KEYDOWN 0x0100 #define WM_KEYUP 0x0101 #define WM_CHAR 0x0102 #define WM_DEADCHAR 0x0103 #define WM_SYSKEYDOWN 0x0104 #define WM_SYSKEYUP 0x0105 #define WM_SYSCHAR 0x0106 #define WM_SYSDEADCHAR 0x0107 #define WM_KEYLAST 0x0108

#if(WINVER >= 0x0400) #define WM_IME_STARTCOMPOSITION 0x010D #define WM_IME_ENDCOMPOSITION 0x010E #define WM_IME_COMPOSITION 0x010F #define WM_IME_KEYLAST 0x010F #endif /* WINVER >= 0x0400 */

#define WM_INITDIALOG 0x0110 #define WM_COMMAND 0x0111 #define WM_SYSCOMMAND 0x0112 #define WM_TIMER 0x0113 #define WM_HSCROLL 0x0114 #define WM_VSCROLL 0x0115 #define WM_INITMENU 0x0116 #define WM_INITMENUPOPUP 0x0117 #define WM_MENUSELECT 0x011F #define WM_MENUCHAR 0x0120 #define WM_ENTERIDLE 0x0121

#define WM_CTLCOLORMSGBOX 0x0132 #define WM_CTLCOLOREDIT 0x0133 #define WM_CTLCOLORLISTBOX 0x0134 #define WM_CTLCOLORBTN 0x0135 #define WM_CTLCOLORDLG 0x0136 #define WM_CTLCOLORSCROLLBAR 0x0137 #define WM_CTLCOLORSTATIC 0x0138

#define WM_MOUSEFIRST 0x0200 #define WM_MOUSEMOVE 0x0200 #define WM_LBUTTONDOWN 0x0201 #define WM_LBUTTONUP 0x0202 #define WM_LBUTTONDBLCLK 0x0203 #define WM_RBUTTONDOWN 0x0204 #define WM_RBUTTONUP 0x0205 #define WM_RBUTTONDBLCLK 0x0206 #define WM_MBUTTONDOWN 0x0207 #define WM_MBUTTONUP 0x0208 #define WM_MBUTTONDBLCLK 0x0209 #if(_WIN32_WINNT >= 0x0400) #define WM_MOUSEWHEEL 0x020A #endif /* _WIN32_WINNT >= 0x0400 */ #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 120 /* Value for rolling one detent */ #endif /* _WIN32_WINNT >= 0x0400 */ #if(_WIN32_WINNT >= 0x0400) #define WHEEL_PAGESCROLL (UINT_MAX) /* Scroll one page */ #endif /* _WIN32_WINNT >= 0x0400 */

#define WM_PARENTNOTIFY 0x0210 #define MENULOOP_WINDOW 0 #define MENULOOP_POPUP 1 #define WM_ENTERMENULOOP 0x0211 #define WM_EXITMENULOOP 0x0212

#if(WINVER >= 0x0400) #define WM_NEXTMENU 0x0213 #define WM_SIZING 0x0214 #define WM_CAPTURECHANGED 0x0215 #define WM_MOVING 0x0216 #define WM_POWERBROADCAST 0x0218 #define WM_DEVICECHANGE 0x0219

#define WM_IME_SETCONTEXT 0x0281 #define WM_IME_NOTIFY 0x0282 #define WM_IME_CONTROL 0x0283 #define WM_IME_COMPOSITIONFULL 0x0284 #define WM_IME_SELECT 0x0285 #define WM_IME_CHAR 0x0286 #define WM_IME_KEYDOWN 0x0290 #define WM_IME_KEYUP 0x0291 #endif /* WINVER >= 0x0400 */

#define WM_MDICREATE 0x0220 #define WM_MDIDESTROY 0x0221 #define WM_MDIACTIVATE 0x0222 #define WM_MDIRESTORE 0x0223 #define WM_MDINEXT 0x0224 #define WM_MDIMAXIMIZE 0x0225 #define WM_MDITILE 0x0226 #define WM_MDICASCADE 0x0227 #define WM_MDIICONARRANGE 0x0228 #define WM_MDIGETACTIVE 0x0229

#define WM_MDISETMENU 0x0230 #define WM_ENTERSIZEMOVE 0x0231 #define WM_EXITSIZEMOVE 0x0232 #define WM_DROPFILES 0x0233 #define WM_MDIREFRESHMENU 0x0234

#if(_WIN32_WINNT >= 0x0400) #define WM_MOUSEHOVER 0x02A1 #define WM_MOUSELEAVE 0x02A3 #endif /* _WIN32_WINNT >= 0x0400 */

#define WM_CUT 0x0300 #define WM_COPY 0x0301 #define WM_PASTE 0x0302 #define WM_CLEAR 0x0303 #define WM_UNDO 0x0304 #define WM_RENDERFORMAT 0x0305 #define WM_RENDERALLFORMATS 0x0306 #define WM_DESTROYCLIPBOARD 0x0307 #define WM_DRAWCLIPBOARD 0x0308 #define WM_PAINTCLIPBOARD 0x0309 #define WM_VSCROLLCLIPBOARD 0x030A #define WM_SIZECLIPBOARD 0x030B #define WM_ASKCBFORMATNAME 0x030C #define WM_CHANGECBCHAIN 0x030D #define WM_HSCROLLCLIPBOARD 0x030E #define WM_QUERYNEWPALETTE 0x030F #define WM_PALETTEISCHANGING 0x0310 #define WM_PALETTECHANGED 0x0311 #define WM_HOTKEY 0x0312

#if(WINVER >= 0x0400) #define WM_PRINT 0x0317 #define WM_PRINTCLIENT 0x0318

#define WM_HANDHELDFIRST 0x0358 #define WM_HANDHELDLAST 0x035F

#define WM_AFXFIRST 0x0360 #define WM_AFXLAST 0x037F #endif /* WINVER >= 0x0400 */

#define WM_PENWINFIRST 0x0380 #define WM_PENWINLAST 0x038F

#if(WINVER >= 0x0400) #define WM_APP 0x8000 #endif /* WINVER >= 0x0400 */

/* NOTE: All Message Numbers below 0x0400 are RESERVED. * Private Window Messages Start Here: */

#define WM_USER 0x0400

#define WM_DDE_FIRST 0x03E0 #define WM_DDE_INITIATE (WM_DDE_FIRST) #define WM_DDE_TERMINATE (WM_DDE_FIRST+1) #define WM_DDE_ADVISE (WM_DDE_FIRST+2) #define WM_DDE_UNADVISE (WM_DDE_FIRST+3) #define WM_DDE_ACK (WM_DDE_FIRST+4) #define WM_DDE_DATA (WM_DDE_FIRST+5) #define WM_DDE_REQUEST (WM_DDE_FIRST+6) #define WM_DDE_POKE (WM_DDE_FIRST+7) #define WM_DDE_EXECUTE (WM_DDE_FIRST+8) #define WM_DDE_LAST (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 WM_NCLBUTTONDOWN: case WM_NCLBUTTONUP: case WM_NCLBUTTONDBLCLK: case 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 Creator function Destroyer function User Objects Creator function Destroyer function Objects Accelerator CreateAcceleratorTable DestroyAcceleratorTable Cursor LoadCursor, GetCursor, DestroyCursor table CreateCursor SetCursor DDE DdeConnect, DdeConnectList, DdeDisconnect, Desktop GetThreadDesktop Applications cannot conver- DdeQueryNextServer, DdeDisconnectList delete this object. sation DdeReconnect Hook SetWindowsHook, UnhookWindowsHook, Menu CreateMenu, DestroyMenu SetWindowsHookEx UnhookWindowsHookEx CreatePopupMenu, GetMenu, GetSubMenu, GetSystemMenu,LoadMenu, LoadMenuIndirect Window CreateWindow, DestroyWindow Window BeginDeferWindowPos EndDeferWindowPos CreateWindowEx, position CreateDialogParam, CreateDialogIndirectParam, CreateMDIWindow, FindWindow, GetWindow, GetClipboardOwner, GetDesktopWindow, GetDlgItem, GetForegroundWindow, GetLastActivePopup, GetOpenClipboardWindow, GetTopWindow, WindowFromDC, WindowFromPoint, and others Window GetProcessWindowStation Applications cannot station delete this object.

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 Programm, Block Programm 0 (Allignment) ( Lader )

Heap System Programm, Block Programm, Block 32 Byte allokiert ( System bei shared ) bis zur Freigabe ( System bei shared ) Resourcen RC-Compiler Programm, Block Programm ca. 32 Byte ( Linker, Lader ) (System bei stock) (System bei stock)

GDI Objekte USER-Funktionen System Programm, Block ca. 30-50 Byte ( Linker mit *.lib, Lader ) ( Programm ) bis zur Freigabe ( System bei stock )

User Objekte Linker Programm, Block Programm, Block ca. 30-50 Byte bis zur Freigabe

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 16- bit 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 strcat, wcscat lstrcat strchr, wcschr none strcmp, wcscmp lstrcmp strcpy, wcscpy lstrcpy strcspn, wcscspn none _strdup, _wcsdup none strerror FormatMessage _strerror FormatMessage _stricmp, _wcsicmp lstrcmpi CharLower, strlen, wcslen lstrlen _strlwr, _wcslwr strncat, wcsncat none CharLowerBuffer strncmp, wcsncmp none strncpy, wcsncpy none _strnicmp, _wcsnicmp none FillMemory, _strnset, _wcsnset strpbrk, wcspbrk none strrchr, wcsrchr none ZeroMemory FillMemory, _strrev, _wcsrev none _strset, _wcsset strspn, wcsspn none ZeroMemory CharUpper, strstr, wcsstr none strtok, wcstok none _strupr, _wcsupr CharUpperBuffer

Buffer Manipulation C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _memccpy none memchr none memcmp none memcpy CopyMemory FillMemory, _memicmp none memmove MoveMemory memset _swab none ZeroMemory

Character Classification C-Run- C-Run- C-Run- Win32 C-Run-time Win32 Win32 Win32 time time time IsCharAlpha, none, isalnum IsCharAlphaNumeric isalpha GetStringTypeW __isascii none iscntrl GetStringTypeW (Unicode) (Unicode) none, __iscsym none __iscsymf none isdigit GetStringTypeW isgraph none (Unicode) IsCharLower, none, none, islower GetStringTypeW isprint none ispunct GetStringTypeW isspace GetStringTypeW (Unicode) (Unicode) (Unicode) IsCharUpper, none, isupper GetStringTypeW isxdigit GetStringTypeW __toascii none tolower CharLower (Unicode) (Unicode) _tolower none toupper CharUpper _toupper none Directory Control C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _chdir SetCurrentDirectory _chdrive SetCurrentDirectory _getcwd GetCurrentDirectory _getdrive GetCurrentDirectory _mkdir CreateDirectory _rmdir RemoveDirectory _searchenv SearchPath

File Handling C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _access none _chmod SetFileAttributes _chsize SetEndOfFile _filelength GetFileSize _fstat See Note 5 _fullpath GetFullPathName _get_osfhandle none _isatty GetFileType _locking LockFileEx _makepath none _mktemp GetTempFileName _open_osfhandle none remove DeleteFile rename MoveFile _setmode none _splitpath none _stat none _umask none _unlink DeleteFile

Creating Text Output Routines C-Run-time Win32 C-Run-time Win32 _displaycursor* SetConsoleCursorInfo _gettextcolor* GetConsoleScreenBufferInfo _gettextcursor* GetConsoleCursorInfo _gettextposition* GetConsoleScreenBufferInfo _gettextwindow* GetConsoleWindowInfo _outtext* WriteConsole _scrolltextwindow* ScrollConsoleScreenBuffer _settextcolor* SetConsoleTextAttribute _settextcursor* SetConsoleCursorInfo _settextposition* SetConsoleCursorPosition _settextwindow* SetConsoleWindowInfo _wrapon* SetConsoleMode

Stream Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 clearerr none fclose CloseHandle _fcloseall none _fdopen none feof none ferror none fflush FlushFileBuffers fgetc none _fgetchar none fgetpos none fgets none _fileno none _flushall none fopen CreateFile fprintf none fputc none freopen _fputchar none fputs none fread ReadFile SetStdHandle (std handles) fscanf none fseek SetFilePointer fsetpos SetFilePointer _fsopen CreateFile SetFilePointer ftell fwrite WriteFile getc none getchar none (check return value) gets none _getw none printf none putc none putchar none puts none _putw none rewind SetFilePointer _rmtmp none scanf none setbuf none setvbuf none _snprintf none sprintf wsprintf sscanf none _tempnam GetTempFileName tmpfile none tmpnam GetTempFileName ungetc none vfprintf none vprintf none _vsnprintf none vsprintf wvsprintf

Low-Level I/O C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _close _lclose, CloseHandle _commit FlushFileBuffers _creat _lcreat, CreateFile _dup DuplicateHandle _dup2 none _eof none _lseek _llseek, SetFilePointer _open _lopen, CreateFile SetFilePointer _read _lread, ReadFile _sopen CreateFile _tell _write _lread (check return value)

Console and Port I/O Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 _cgets none _cprintf none _cputs none _cscanf none _getch ReadConsoleInput _getche ReadConsoleInput _inp none _inpw none _kbhit PeekConsoleInput _outp none _outpw none _putch WriteConsoleInput _ungetch none

Memory Allocation C-Run- C-Run-time Win32 C-Run-time Win32 Win32 C-Run-time Win32 time _alloca none _bfreeseg* none _bheapseg* none calloc GlobalAlloc _expand none free GlobalFree _freect* GlobalMemoryStatus _halloc* GlobalAlloc _heapadd none _heapchk none _heapmin none _heapset none _heapwalk none _hfree* GlobalFree malloc GlobalAlloc _memavl GlobalMemoryStatus _memmax GlobalMemoryStatus _msize* GlobalSize realloc GlobalReAlloc _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 abort none assert none atexit none _cexit none _c_exit none _exec functions none exit ExitProcess _exit ExitProcess getenv GetEnvironmentVariable _getpid GetCurrentProcessId longjmp none _onexit none perror FormatMessage _putenv SetEnvironmentVariable raise RaiseException setjmp none signal SetConsoleCtrlHandler _spawn functions CreateProcess system CreateProcess (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 hWnd- Fenster 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, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; EndPaint ( hWnd, & ps ) ; break ; //return 0; 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 #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, // handle to device context LPCTSTR lpString, // pointer to string to draw int nCount, // string length, in characters LPRECT lpRect, // pointer to struct with formatting dimensions UINT uFormat // text-drawing flags );

Für uFormat können die Konstanten

DT_BOTTOM, DT_CALCRECT, DT_CENTER, DT_EDITCONTROL, DT_END_ELLIPSIS oder DT_PATH_ELLIPSIS, DT_EXPANDTABS, DT_EXTERNALLEADING, DT_INTERNAL, DT_LEFT, DT_MODIFYSTRING, DT_NOCLIP, DT_NOPREFIX, DT_RIGHT, DT_RTLREADING, DT_SINGLELINE, DT_TABSTOP, DT_TOP, DT_VCENTER, DT_WORDBREAK, DT_WORD_ELLIPSIS

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 ===> Compiler ===> *.OBJ *.H, *.RC ===> Resourcen-Compiler ===> *.RES *.OBJ, *.DEF ===> Linker ===> (*.EXE) (*.EXE), *.RES ===> Resourcen-Compiler ===> *.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 BUTTON 0x80 WNDCLASSEX wcx = {0}; #define EDIT 0x81 GetClassInfoEx(GetModuleHandle(0),"EDIT", &wcx); #define STATIC 0x82 GetClassInfoEx(GetModuleHandle(0),"BUTTON", &wcx); #define LISTBOX 0x83 GetClassInfoEx(GetModuleHandle(0),"COMBOBOX",&wcx); #define SCROLLBAR 0x84 GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx); #define COMBOBOX 0x85

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 CONTROL text, id, "Button", BS_PUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy text, id, x, y, cx, cx, style #define DEFPUSHBUTTON CONTROL text, id, "Button", BS_DEFPUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy text, id, x, y, cx, cx, style #define RADIOBUTTON CONTROL text, id, "Button", BS_RADIOBUTTON | WS_TABSTOP | style, x, y, cx, cy text, id, x, y, cx, cx, style #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 RT_CURSOR MAKEINTRESOURCE(1) //für Mauszeiger #define RT_BITMAP MAKEINTRESOURCE(2) //für Rasterbilder #define RT_ICON MAKEINTRESOURCE(3) //Symbol - Rasterbilder #define RT_MENU MAKEINTRESOURCE(4) //für Menuleisten #define RT_DIALOG MAKEINTRESOURCE(5) //für Dialogfelder #define RT_STRING MAKEINTRESOURCE(6) //für Stringtabellen #define RT_FONTDIR MAKEINTRESOURCE(7) //Verzeichnisse der Schriftarten #define RT_FONT MAKEINTRESOURCE(8) //für Schriftarten #define RT_ACCELERATOR MAKEINTRESOURCE(9) //für Tastaturkürzel #define RT_RCDATA MAKEINTRESOURCE(10) //für Daten ohne feste Bindung #define RT_MESSAGETABLE MAKEINTRESOURCE(11) //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

Identification shared by multiple IDR_ IDR_MAINFRAME 1 to 0x6FFF resources of different types

IDD_ Dialog resource IDD_SPELL_CHECK 1 to 0x6FFF

HIDD_ Dialog-resource Help context HIDD_SPELL_CHECK 0x20001 to 0x26FF

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

HIDP_ 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

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 is_VSCROLL "Scrollbar", SBS_VERT|WS_TABSTOP #define STR_BEGIN STRINGTABLE DISCARDABLE BEGIN #define is_HSCROLL "Scrollbar", SBS_HORZ|WS_TABSTOP #define STR_END END #define is_EDIT "Edit",ES_AUTOHSCROLL|ES_LEFT|WS_BORDER\ #define MENU_BEGIN(idRes) idRes MENU DISCARDABLE BEGIN |ES_OEMCONVERT|WS_CHILD|WS_TABSTOP|WS_GROUP//|ES_WANTRETURN #define MENU_END END #define is_EDIT_X "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ #define MENU_ITEM_BEGIN(text) POPUP text BEGIN |ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\ #define MENU_ITEM_END END |WS_VISIBLE|WS_HSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP #define MENU_ITEM(idRes, text, style) MENUITEM text, idRes, style #define is_EDIT_Y "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ #define MENU_SEPARATOR MENUITEM SEPARATOR |ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\ #define ACCEL_BEGIN(idRes) \ |WS_VISIBLE|WS_VSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP idRes ACCELERATORS MOVEABLE PURE BEGIN #define is_EDIT_XY "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\ #define ACCEL_END END |ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL\ #define DLG_BEGIN_MODAL( idRes, txt, x,y,dx,dy ) \ |ES_WANTRETURN|WS_CHILD\ idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\ |WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|WS_BORDER\ STYLE DLG_MODAL_STYLE \ |WS_TABSTOP|WS_GROUP FONT DLG_FONT \ #define DLG_MODELES_STYLE DS_SETFONT|WS_THICKFRAME|WS_MINIMIZEBOX\ CAPTION txt \ |WS_MAXIMIZEBOX|WS_VISIBLE|WS_CAPTION\ BEGIN |WS_POPUPWINDOW //WS_BORDER|WS_POPUP|WS_SYSMENU #define DLG_BEGIN( idRes, txt, x,y,dx,dy ) \ #define DLG_MODAL_STYLE DS_MODALFRAME|DS_SETFONT|WS_POPUP|WS_CAPTION\ idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\ |WS_SYSMENU|WS_VISIBLE STYLE DLG_MODELES_STYLE \ #define DLG_FONT 7, "MS Sans Serif" //"Helv" FONT DLG_FONT \ #define DLG_ITEM(idRes,text,style,x,y,width,height) \ CAPTION txt \ CONTROL text, idRes,style,x,y,width,height BEGIN #define DLG_ICON(idRes,text,style,x,y,width,height) \ #define DLG_END END ICON idRes,-1,x,y,width,height,style #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

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 String- Ressource 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 Jedes Popup/Item MENUITEMTEMPLATEHEADER MENUITEMTEMPLATE typedef struct { typedef struct { WORD versionNumber; // 0 WORD mtOption; // Item-Flag z.B. 0/MF_POPUP/MF_END WORD offset; // 0 WORD mtID; // ID, fehlt bei Popup-Eintrag } MENUITEMTEMPLATEHEADER; 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 Alternative mit LoadMenuIndirect() typedef struct _MENU_STRUCT { int WORD _id; // Menu-Id's, etwa ab 100 nCopyAnsiToWideChar(LPWORD p,LPSTR pAnsiIn) LPSTR _txt; // Menu-Popup/Item-Text { int nChar = 0; MENUFUNC _fn; // auzurufende Funktion do { *p++ = (WORD)*pAnsiIn; nChar++; } } MENU_STRUCT; while (*pAnsiIn++); return nChar; MENU_STRUCT menu_struct[] = } { { 0, "Pop1", 0 }, HMENU { 100, "Item 100", ... }, _set_menu(HWND hwnd,menu_struct * pMenu) { 110, "Item 110", ... }, { int k; if((!hwnd)||(!pMenu))return NULL; { 120, "Item 120", ... }, WORD buf[4000]={0};//memset(...) { 0, "Pop2", 0 }, WORD * p = buf; { 200, "Item 200", ... }, *p++ = 0; //(MENUITEMTEMPLATEHEADER); { 210, "Item 210", ... }, *p++ = 0; //(MENUITEMTEMPLATEHEADER); {0,NULL, ... } WORD *p1=NULL, *p2=NULL; }; // <== Endekriterium ist Pflicht! 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; Alternative mit AppendMenu() HMENU hMenu = LoadMenuIndirect(buf); 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: /////////////////////////////////////////// // so sieht es aus ///////////////////////////////////////////// // Beispiel für Aufruf: ////////////////// /////////////////////////////////////////// typedef struct _DLG_STRUCT { static HWND hwnd; // wird später eingesetzt DLG_STRUCT dlg1[] = { // x, y, cx, cy LPSTR pKlasse; // z.B. "BUTTON" {0,"DIALOG", "dlg-Titel", 50, 50,100,145},//[0] LPSTR pText; // wird in das Ctrl geschrieben {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] WORD x,y,cx,cy; // Position {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] } DLG_STRUCT; {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,"", 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)) 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 DLG_STRUCT WORD _id; // Menu-Id's,etwa ab 100 HWND hwnd; //des Ctrl's LPSTR _txt;// Menu-Item-Text LPSTR pKlasse;//z.B."EDIT" MENUFUNC _fn; // auzurufende Funktion LPSTR pText; //Initialisierung WORD x,y,cx,cy;//Ctrl-Position mit typedef BOOL (* MENUFUNC)(HWND hwnd); kann WM_COMMAND-Aufruf 'automatisiert' werden

//Beispiel: //Beispiel:

BOOL menu_fn100(HWND hwnd) static // static ist Pflicht! { if(hwnd != _hModeless) DLG_STRUCT DLG_STRUCT[] = { // x, y, cx, cy MessageBox(hwnd, {0,"DIALOG", "dlg1-Titel", 40, 20,100,160},//[0] "kein _hModeless","info",MB_OK); {0,"STATIC", "Static-Text",10, 5, 80, 12},//[1] char buf[256]; {0,"LISTBOX", "dlg-List", 10, 20, 80, 40},//[2] wsprintf(buf, {0,"EDIT", "dlg-Edit", 10, 85, 80, 40},//[3] "global _hModeless=%08x",_hModeless); {0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4] MessageBox(hwnd,buf,"info",MB_OK); {0,"BUTTON", "OK", 10,130, 80, 12},//[5] return TRUE; {0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht } //Aufruf mit CALLBAC dlg1_proc: static // static ist Pflicht! static DLG_INDIRECT * MENU_STRUCT menu_struct[] = { pDlg = new DLG_INDIRECT(hwnd); { 0, "Test1", 0 }, pDlg -> create_dlg_indirect(DLG_STRUCT, dlg1_proc); { 100, "100", menu_fn100 }, if(!pDlg) error ... //{ 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); 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 Windows- Klassen, 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", 0x0082 "Static", 0x0083 "ListBox", 0x0084 "ScrollBar", 0x0085 "ComboBox" und die Dialog Box Klasse "#32770".

Hier eine aktuelle Übersicht (User Interface Element Reference): (ANIMATE_CLASS, "SysAnimate32" in Animation control Pop-up menu ("#32768") Commctrl.h) (MONTHCAL_CLASS, "SysMonthCal32" in (PROGRESS_CLASS, "msctls_progress" in Calendar control Progress bar control Commctrl.h) Commctrl.h) Caret Push button ("BUTTON") Check box ("BUTTON") Radio button ("BUTTON") Client object (text, graphics) Scroll bar ("SCROLLBAR") Combo box ("COMBOBOX") Size grip (special mouse pointer) Cursor IDC_ARROW "Normal", IDC_IBEAM "Edit", IDC_WAIT "Wait", 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"

(TRACKBAR_CLASS, "msctls_trackbar" in Slider control Desktop window ("#32769") Commctrl.h) Static text ("STATIC") Dialog box ("#32770") (STATUSCLASSNAME, Status bar control Edit control "EDIT", "RichEdit", "RichEdit20A" "msctls_statusbar32" in Commctrl.h) (WC_HEADER, "SysHeader32" in Switch window ("#32771") Header control Commctrl.h) (WC_TABCONTROL, "SysTabControl" in (HOTKEY_CLASS, "msctls_hotkey32" in Tab control Hot key control Commctrl.h) Commctrl.h) (TOOLBARCLASSNAME, Toolbar control List box ("LISTBOX") "ToolbarWindow32" in Commctrl.h) (TOOLTIPS_CLASS, "tooltips_class" in (WC_LISTVIEW, "SysListView" in ToolTip control List view control Commctrl.h) Commctrl.h) Title bar MDI client window ("MDIClient") (WC_TREEVIEW, "SysTreeView" in Tree view control Menu bar Commctrl.h) (UPDOWN_CLASS, "msctls_updown32" in Up-down control Menu item ( "#32768") Commctrl.h)

Es gibt zahlreiche Funktionen, die zum Erzeugen und Manipulieren von modalen/modeless Dialogen und deren Unterfenster ( Controls ) dienen:

CreateDialog CreateDialogIndirect CreateDialogIndirectParam CreateDialogParam DefDlgProc DialogBox DialogBoxIndirect DialogBoxIndirectParam DialogBoxParam DialogProc EndDialog GetDialogBaseUnits GetDlgCtrlID GetDlgItem GetDlgItemInt GetDlgItemText GetNextDlgGroupItem GetNextDlgTabItem IsDialogMessage MapDialogRect MessageBox MessageBoxEx SendDlgItemMessage SetDlgItemInt SetDlgItemText MessageBoxIndirect

Modale Dialoge

Ein modaler Dialog enthält eine eigene Nachrichten-Schleife. Erscheint ein ( Applikations-)modale Dialog - Box auf dem Bildschirm so wird in dieser Nachrichten-Schleife "gewartet", bis der Benutzer reagieren und den Dialog beendet.

MessageBox()

Eine MessageBox() entspricht einem modalen Dialog. Z.B. wird die Applikation blockiert, bis der Benutzer den "OK" - Button gedrückt hat. Eine MessageBox() erzeugt die Anzeige - Box für Ausgabe-Text ohne externe Resourcen. Eine eingebaute ( intern verfügbare ) CALLBACK - Funktion behandelt die Nachrichten. Es gibt eine Anzahl von verwendbaren Icons und Push- Buttons.

int MessageBoxEx( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType, // style of message box WORD wLanguageId // language identifier );

MessageBoxEx() hat gegenüber MessageBox() einen zusätlichen WORD wLanguageId - Parameter. Falls hWnd = NULL verwendet wird, so gehört die Message - Box zu keinem speziellen Fenster. lpCaption zeigt auf den auszugebenden Text. Für lpszTitle = NULL ist, wird in der Titel - Zeile "Error" angezeigt. Im Fehlerfall gibt die MessageBoxEx() den Wert 0 zurück. Im Erfolgsfall gibt die MessageBoxEx() eine positiven Wert zurück. Der Rückgabe - Wert entspricht dem gedrückten Button.

IDABORT Abort button was selected. IDCANCEL Cancel button or ESC key was selected. IDIGNORE Ignore button was selected. IDNO No button was selected. IDOK OK button was selected. IDRETRY Retry button was selected. IDYES Yes button was selected.

Für uType kann verwendet werden:

MB_ABORTRETRYIGNORE three push buttons: Abort, Retry, and Ignore. MB_OK one push button: OK. This is the default. MB_OKCANCEL two push buttons: OK and Cancel. MB_RETRYCANCEL two push buttons: Retry and Cancel. MB_YESNO two push buttons: Yes and No. MB_YESNOCANCEL three push buttons: Yes, No, and Cancel. ------MB_ICONEXCLAMATION, MB_ICONWARNING icon ( 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( hwnd, MessageBox( 0, "Client-Bereich", "Client-Bereich", "Titel", 0, MB_OK ); MB_OK );

MessageBox( hwnd, MessageBox(hwnd, "MB_ICONSTOP", "MB_ICONINFORMATION",

"Titel", "Titel", MB_OK|MB_ICONSTOP); MB_OK|MB_ICONINFORMATION);

MessageBox(hwnd, int mb_val = MessageBox(hwnd, "MB_ICONQUESTION", "Rückgabewert", Titel",

"Titel", MB_OKCANCEL|MB_DEFBUTTON2); MB_OK|MB_ICONQUESTION); 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, // handle to application instance LPCTSTR lpTemplate, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc // pointer to dialog box procedure );

DialogBox() erzeugt mit lpTemplate = MAKEINTRESOURCE( idRes ) aus der *.RC - Template Resource idRes die DialogBox, indem automatisch die Resourcen - Daten in den Speicher geladen werden und die DialogBox angezeigt wird. Durch eine System - Klassen - CALLBACK - Funktion werden bestimmte Ereignisse ( Tab, ... ) ( vor - ) behandelt. Ein typischer Aufruf hat die Form:

int rval = DialogBox ( hInstance, MAKEINTRESOURCE( idRes ), hWnd, ( DLGPROC )dlgProc ) ;

Zur Behandlung der Ereignisse muß eine DIALOG - CALLBACK - Funktion geschrieben werden. Diese Funktion wird mit DLGPROC lpDialogFunc an DialogBox() übergeben. Der modale Dialog wird erst beendet, wenn in der eigenen CALLBACK - Funktion EndDialog() ausgeführt wird. Der Dialog wird meisten unter WM_CLOSE durch EndDialog ( hWnd, rval ) beendet. Der Rückgabe - Wert von int DialogBox() ist hier rval. Bei einem Fehler wird -1 zurück gegeben.

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 User- Daten. 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 DM_REPOSITION DM_SETDEFID WM_CTLCOLORDLG WM_CTLCOLORMSGBOX WM_ENTERIDLE WM_GETDLGCODE WM_INITDIALOG 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_DELETESTRING CB_DIR CB_FINDSTRING CB_FINDSTRINGEXACT CB_GETCOUNT CB_GETCURSEL CB_GETDROPPEDCONTROLRECT CB_GETDROPPEDSTATE CB_GETDROPPEDWIDTH CB_GETEDITSEL CB_GETEXTENDEDUI CB_GETHORIZONTALEXTENT CB_GETITEMDATA CB_GETITEMHEIGHT CB_GETLBTEXT CB_GETLBTEXTLEN CB_GETLOCALE CB_GETTOPINDEX CB_INITSTORAGE CB_INSERTSTRING CB_LIMITTEXT CB_RESETCONTENT CB_SELECTSTRING CB_SETCURSEL CB_SETDROPPEDWIDTH CB_SETEDITSEL CB_SETEXTENDEDUI CB_SETHORIZONTALEXTENT CB_SETITEMDATA CB_SETITEMHEIGHT CB_SETLOCALE CB_SETTOPINDEX CB_SHOWDROPDOWN CBN_CLOSEUP CBN_DBLCLK CBN_DROPDOWN CBN_EDITCHANGE CBN_EDITUPDATE CBN_ERRSPACE CBN_KILLFOCUS CBN_SELCHANGE CBN_SELENDCANCEL CBN_SELENDOK CBN_SETFOCUS WM_COMPAREITEM WM_DRAWITEM WM_MEASUREITEM

Um einem Control eine Nachricht zu schicken wird anstelle von HWND hCtl = GetDlgItem ( HWND hDlg, int idRes ); LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam); oft LONG SendDlgItemMessage ( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam, LPARAM lParam);

benutzt.

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_Enable (hCtl, fEnable) Static_GetIcon (hCtl, hIcon) Static Static_GetText (hCtl, lpch, cchMax) Text Static_GetTextLength(hCtl) Controls Static_SetIcon (hCtl, hIcon) Static_SetText (hCtl, lpsz)

Button Control

In windowX.h sind die folgenden Button - Macros definiert:

Button Controls

Button_Enable (hCtl, fEnable) Button_GetCheck (hCtl) Button_GetState (hCtl) Button_GetText (hCtl, lpch, cchMax) Button Button_GetTextLength(hCtl) Controls Button_SetCheck (hCtl, check) Button_SetState (hCtl, state) Button_SetStyle (hCtl, style, fRedraw) Button_SetText (hCtl, 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 = GET_WM_COMMAND_CMD ( wParam, lParam ) ; int wmCMD = HIWORD( wParam ) ; int wmID = GET_WM_COMMAND_ID ( wParam, lParam ) ; #endif HWND wmHWND= GET_WM_COMMAND_HWND( wParam, lParam ) ; int wmID = LOWORD( wParam ); HWND wmHWND=(HWND)(UINT)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

Button- Notification- Erklärung Messages

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_CanUndo (hCtl) Edit_EmptyUndoBuffer(hCtl) Edit_Enable (hCtl, fEnable) Edit_FmtLines (hCtl, fAddEOL) Edit_GetFirstVisible(hCtl) Edit_GetHandle (hCtl) Edit_GetLine (hCtl, line, lpch, cchMax) Edit_GetLineCount (hCtl) Edit_GetModify (hCtl) Edit_GetRect (hCtl, lprc) Edit_GetSel (hCtl) Edit_GetText (hCtl, lpch, cchMax) Edit_GetTextLength (hCtl) Edit_LimitText (hCtl, cchMax) Edit Edit_LineFromChar (hCtl, ich) Controls Edit_LineIndex (hCtl, line) Edit_LineLength (hCtl, line) Edit_ReplaceSel (hCtl, lpszReplace) Edit_Scroll (hCtl, dv, dh) Edit_SetHandle (hCtl, h) Edit_SetModify (hCtl, fModified) Edit_SetPasswordChar(hCtl, ch) Edit_SetRect (hCtl, lprc) Edit_SetRectNoPaint (hCtl, lprc) Edit_SetSel (hCtl, ichStart, ichEnd) Edit_SetTabStops (hCtl, cTabs, lpTabs) Edit_SetText (hCtl, lpsz) Edit_SetWordBreak (hCtl, lpfnWordBreak) Edit_Undo(hCtl)

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

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) List ListBox_GetText (hCtl, index, lpszBuffer) Box ListBox_GetSelItems (hCtl, cItems, lpIndices) Controls 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

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) Combo ComboBox_GetLBText (hCtl, index, lpszBuffer) Box ComboBox_GetLBTextLen (hCtl, index) Controls 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 (hCtl, ichStart, ichEnd) ComboBox_SetItemHeight (hCtl, cyItem)Win32 ComboBox_SetItemData (hCtl, index, data) ComboBox_SetText (hCtl, lpsz) ComboBox_ShowDropdown (hCtl, 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 "/",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 DEFPUSHBUTTON "Schliessen",IDOK,135,117,50,14,NOT WS_TABSTOP CONTROL "",IDC_STATIC,"Static", SS_BLACKRECT,126,5,6,125 CONTROL "",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 #include #include ///////////////////////////////////////////////// //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) x6=168, y6=40; //6.Button-Spalte { HWND x=x0; y=y0; hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN, WORD IDC_COMBO = 1000; x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0); hCombo = //RECT rc; my_combo(hwnd,x,y,188,180,"COMBO",IDC_COMBO); //SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc); ComboBox_LimitText(hCombo, MAX_COMBO_CHAR); return hCombo; ComboBox_SetText (hCombo, "0"); } // keine Hand-Eingabe, falls ///////////////////////////////////////////////// // ComboBox_Enable(hCombo, FALSE); HWND my_edit (HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes) x=x1; y=y1; { HWND my_button(hwnd,x,y,dx,cy,"F",0);y+=dy; hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt, my_button(hwnd,x,y,dx,cy,"C",0);y+=dy; WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT my_button(hwnd,x,y,dx,cy,"7",0);y+=dy; |ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, my_button(hwnd,x,y,dx,cy,"4",0);y+=dy; x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0); my_button(hwnd,x,y,dx,cy,"1",0);y+=dy; return hEdit; my_button(hwnd,x,y,dx,cy,"0",0); } x=x2; y=y2; ///////////////////////////////////////////////// my_button(hwnd,x,y,dx,cy,"E",0);y+=dy; // print_append() kann aus den hSrc-Fenster Text holen my_button(hwnd,x,y,dx,cy,"B",0);y+=dy; // und gemäss "printf-ähnlichem" Formats Text "anhängen" my_button(hwnd,x,y,dx,cy,"8",0);y+=dy; // und den gesamten Text in das hDst-Fenster schreiben. my_button(hwnd,x,y,dx,cy,"5",0);y+=dy; // Dadurch entsteht ein "append" von Text my_button(hwnd,x,y,dx,cy,"2",0);y+=dy; // my_button(hwnd,x,y,2*dx+4,cy,"=",0); // Anstelle der Aufruffolge: x=x3; y=y3; // print_append(hEdit,hEdit, "\r\n"); my_button(hwnd,x,y,dx,cy,"D",0);y+=dy; // print_append(hEdit,hEdit, "%u ", u1); my_button(hwnd,x,y,dx,cy,"A",0);y+=dy; // print_append(hEdit,hEdit, "%u ", u2); my_button(hwnd,x,y,dx,cy,"9",0);y+=dy; // my_button(hwnd,x,y,dx,cy,"6",0);y+=dy; // ist günstiger: my_button(hwnd,x,y,dx,cy,"3",0); // print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2); x=x4; y=y4; ///////////////////////////////////////////////// my_button(hwnd,x,y,dx,cy,"%",0);y+=dy; int CDECL print_append my_button(hwnd,x,y,dx,cy,"^",0);y+=dy; ( HWND hDst, HWND hSrc, LPTSTR pFormat, ...) my_button(hwnd,x,y,dx,cy,"|",0);y+=dy; { static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048 my_button(hwnd,x,y,dx,cy,"+",0);y+=dy; err_if(!hDst,"print_append(): hDst?"); my_button(hwnd,x,y,dx,cy,"-",0);y+=dy; memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf; my_button(hwnd,x,y,2*dx+4,dy,"BS",1000); va_list argList; x=x5; y=y5; va_start( argList, pFormat ) ; my_button(hwnd,x,y,dx,cy,"<",0);y+=dy; if(hSrc) // hole Text aus hSrc my_button(hwnd,x,y,dx,cy,">",0);y+=dy; pBuf += GetWindowText(hSrc,Buf,sizeof(Buf)); my_button(hwnd,x,y,dx,cy,"&&",0);y+=dy; // bei Speichermangel pBuf auf Buf[0] my_button(hwnd,x,y,dx,cy,"*",0);y+=dy; if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf; my_button(hwnd,x,y,dx,cy,"/",0); pBuf += wvsprintf( pBuf, pFormat, argList ) ; x=x6; y=y6; va_end( argList ) ; my_button(hwnd,x,y,dx,cy,"M+",1001);y+=dy; // schreibe erweiterten Text in hDest my_button(hwnd,x,y,dx,cy,"M-",1002);y+=dy; SetWindowText( hDst, Buf ); my_button(hwnd,x,y,dx,cy,"MR",1003);y+=dy; return (pBuf-Buf); 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; // show_hex() schreibt uNum in das ziel. // Beispiel: show_hex(10,USE_CE); char * pInfo = // Ziel kann sein (USE_CE|USE_CL|USE_EM) "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" void show_hex(UINT uNum, int ziel ) "M+ addiert zu M \r\nM- subtr. von M\r\n"; { char buf[256]; int radix = 16; //global sind hCombo, hEdit WORD IDC_EDIT = 2000; //schreibe uNum als hex-String (basis 16) in buf hEdit = strupr( ltoa(uNum, buf, radix) ); my_edit(hwnd,x0,y+4,188,140,pInfo,IDC_EDIT); //Ausgabe von buf in ziel Edit_LimitText(hEdit, MAX_EDIT_CHAR); if (USE_CE & ziel) {//in Combo-Liste eintragen: // Hauptnachrichtenschleife ComboBox_SetText(hCombo, buf ) ; BOOL bRet; MSG msg; } while (bRet=GetMessage(&msg, NULL,0,0)){ if (USE_CL & ziel) { //in Combo-Liste eintragen: err_if(-1==bRet,"GetMessage()"); if ( ComboBox_GetCount(hCombo) >= 30) TranslateMessage(&msg); ComboBox_DeleteString(hCombo,30); DispatchMessage (&msg); ComboBox_InsertString(hCombo, 0, buf ); } return 0; } } 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; 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

ScrollBar_Enable (hCtl, flags) ScrollBar_GetPos (hCtl) Scroll ScrollBar_GetRange(hCtl, lpposMin, lpposMax) Bar ScrollBar_SetPos (hCtl, pos, fRedraw) Controls ScrollBar_SetRange(hCtl, posMin, posMax, fRedraw) ScrollBar_Show (hCtl, 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.

sendet und soll die Taste virtueller Maus-Notification-Nachricht Key-Code 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/Entlade- Mechanismus kann explizit durch die Applikation oder implizit Operating-System ausgelöst werden.

Unterschiede zwischen Static-Dynamic- Linking 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 Description DLLSKEL.TXT Short sample description. MAKEFILE The generic makefile for building the DLLSKEL.DLL code sample of this tutorial lesson. DLLSKEL.H 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. DLLSKEL.CPP The main implementation file for DLLSKEL.DLL. Has DllMain and the two exported service functions. DLLSKELI.H The include file for the internal class declarations and the identifier definitions for resources stored inside the DLLSKEL.DLL. DLLSKEL.RC The DLL resource definition file. DLLSKEL.ICO The icon resource. DLLSKEL.DSP 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 non- shared 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; /* Application instance handle. */ HMENU ghMenuMain; /* Main menu handle. */ PRESLINK gprlHead = NULL; /* Head of the linked list of resources.*/ CURRENTDLG gcd; /* Describes the current dialog. */ HPEN hpenDarkGray; /* A dark gray pen. */ HANDLE ghAccTable; /* The accelerator table handle. */ INT gMenuSelected = 0; /* Currently selected menu item. */ HBITMAP ghbmDragHandle = NULL; /* Handle for the drag handle bitmap. */ HBITMAP ghbmDragHandle2 = NULL; /* Handle for hollow drag handle bitmap.*/ HDC ghDCMem = NULL; /* Memory DC for drawing bitmaps. */ INT gCurTool = W_NOTHING; /* Currently selected tool. */ PWINDOWCLASSDESC gpwcdCurTool = NULL; /* Describes current tool. */ BOOL gfToolLocked = FALSE; /* TRUE if a tool is locked down. */ PCUSTLINK gpclHead = NULL; /* 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. It will be * initialized to one of the editor's own icons. */ ORDINAL gordIcon;

/* * 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; /* TRUE if in "hex" mode. */ BOOL gfTranslateMode; /* TRUE if in "translate" mode. */ BOOL gfShowToolbox; /* TRUE if Toolbox is to be shown. */ BOOL gfUseNewKeywords; /* FALSE to only use "CONTROL" keyword. */ INT gcxGrid; /* Current X grid. */ INT gcyGrid; /* Current Y grid. */ INT gxMargin; /* Top/bottom margin. */ INT gyMargin; /* Left/right margin. */ INT gxSpace; /* Horizontal control spacing. */ INT gySpace; /* Vertical control spacing. */ INT gxMinPushSpace; /* Minimum horizontal button spacing. */ INT gxMaxPushSpace; /* Maximum horizontal button spacing. */ INT gyPushSpace; /* 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. */

/*-- Sundry Handles.------*/ HWND hwndStatus = NULL; /* Status ribbon window handle. */ HWND ghwndToolbox = NULL; /* Toolbox window handle. */ HWND ghwndTestDlg = NULL; /* Handle of the Test Mode dialog. */ HWND ghwndMain = NULL; /* Main application window. */ HWND ghwndSubClient = NULL; /* The "fake" client area. */ HWND 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). This * rectangle is only valid if there are selected controls. */ RECT grcSelected;

/* * 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. This will * be one of the DRAG_* constants. */ INT gHandleHit = DRAG_CENTER;

/* * 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_ALL, DID_BS_PUSHBUTTON }, {BS_DEFPUSHBUTTON, BS_ALL, DID_BS_DEFPUSHBUTTON }, {BS_CHECKBOX, BS_ALL, 0 }, {BS_AUTOCHECKBOX, BS_ALL, 0 }, {BS_RADIOBUTTON, BS_ALL, 0 }, {BS_3STATE, BS_ALL, 0 }, {BS_AUTO3STATE, BS_ALL, 0 }, {BS_GROUPBOX, BS_ALL, 0 }, {BS_USERBUTTON, BS_ALL, 0 }, {BS_AUTORADIOBUTTON, BS_ALL, 0 }, {BS_PUSHBOX, BS_ALL, 0 }, {BS_OWNERDRAW, BS_ALL, DID_BS_OWNERDRAW }, {BS_LEFTTEXT, 0, DID_BS_LEFTTEXT } };

/* * Scroll bar styles. */ static CLASSSTYLE acsSB[] = { {SBS_HORZ, SBS_ALL, 0 }, {SBS_VERT, SBS_ALL, 0 }, {SBS_TOPALIGN, 0, 0 }, {SBS_LEFTALIGN, 0, 0 }, {SBS_BOTTOMALIGN, 0, 0 }, {SBS_RIGHTALIGN, 0, 0 }, {SBS_SIZEBOXTOPLEFTALIGN, 0, 0 }, {SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, 0 }, {SBS_SIZEBOX, 0, 0 } };

/* * Entry field styles. */ static CLASSSTYLE acsEdit[] = { {ES_LEFT, ES_ALIGN, DID_ES_LEFT }, {ES_CENTER, ES_ALIGN, DID_ES_CENTER }, {ES_RIGHT, ES_ALIGN, DID_ES_RIGHT }, {ES_MULTILINE, 0, DID_ES_MULTILINE }, {ES_UPPERCASE, 0, DID_ES_UPPERCASE }, {ES_LOWERCASE, 0, DID_ES_LOWERCASE }, {ES_PASSWORD, 0, DID_ES_PASSWORD }, {ES_AUTOVSCROLL, 0, DID_ES_AUTOVSCROLL }, {ES_AUTOHSCROLL, 0, DID_ES_AUTOHSCROLL }, {ES_NOHIDESEL, 0, DID_ES_NOHIDESEL }, {ES_OEMCONVERT, 0, DID_ES_OEMCONVERT }, {ES_READONLY, 0, DID_ES_READONLY } };

/* * Static styles. */ static CLASSSTYLE acsStatic[] = { {SS_LEFT, SS_ALL, DID_SS_LEFT }, {SS_CENTER, SS_ALL, DID_SS_CENTER }, {SS_RIGHT, SS_ALL, DID_SS_RIGHT }, {SS_ICON, SS_ALL, 0 }, {SS_BLACKRECT, SS_ALL, DID_SS_BLACKRECT }, {SS_GRAYRECT, SS_ALL, DID_SS_GRAYRECT }, {SS_WHITERECT, SS_ALL, DID_SS_WHITERECT }, {SS_BLACKFRAME, SS_ALL, DID_SS_BLACKFRAME }, {SS_GRAYFRAME, SS_ALL, DID_SS_GRAYFRAME }, {SS_WHITEFRAME, SS_ALL, DID_SS_WHITEFRAME }, {SS_USERITEM, SS_ALL, DID_SS_USERITEM }, {SS_SIMPLE, SS_ALL, DID_SS_SIMPLE }, {SS_LEFTNOWORDWRAP, SS_ALL, DID_SS_LEFTNOWORDWRAP }, {SS_NOPREFIX, 0, DID_SS_NOPREFIX } };

/* * List box styles. */ static CLASSSTYLE acsLB[] = { {LBS_NOTIFY, 0, DID_LBS_NOTIFY }, {LBS_SORT, 0, DID_LBS_SORT }, {LBS_NOREDRAW, 0, DID_LBS_NOREDRAW }, {LBS_MULTIPLESEL, 0, DID_LBS_MULTIPLESEL }, {LBS_OWNERDRAWFIXED, 0, DID_LBS_OWNERDRAWFIXED }, {LBS_OWNERDRAWVARIABLE, 0, DID_LBS_OWNERDRAWVARIABLE }, {LBS_HASSTRINGS, 0, DID_LBS_HASSTRINGS }, {LBS_USETABSTOPS, 0, DID_LBS_USETABSTOPS }, {LBS_NOINTEGRALHEIGHT, 0, DID_LBS_NOINTEGRALHEIGHT }, {LBS_MULTICOLUMN, 0, DID_LBS_MULTICOLUMN }, {LBS_WANTKEYBOARDINPUT, 0, DID_LBS_WANTKEYBOARDINPUT }, {LBS_EXTENDEDSEL, 0, DID_LBS_EXTENDEDSEL }, {LBS_DISABLENOSCROLL, 0, DID_LBS_DISABLENOSCROLL }, {LBS_NODATA, 0, DID_LBS_NODATA } };

/* * Combo Box styles. */ static CLASSSTYLE acsComboBox[] = { {CBS_SIMPLE, CBS_ALL, DID_CBS_SIMPLE }, {CBS_DROPDOWN, CBS_ALL, DID_CBS_DROPDOWN }, {CBS_DROPDOWNLIST, CBS_ALL, DID_CBS_DROPDOWNLIST }, {CBS_OWNERDRAWFIXED, 0, DID_CBS_OWNERDRAWFIXED }, {CBS_OWNERDRAWVARIABLE, 0, DID_CBS_OWNERDRAWVARIABLE }, {CBS_AUTOHSCROLL, 0, DID_CBS_AUTOHSCROLL }, {CBS_OEMCONVERT, 0, DID_CBS_OEMCONVERT }, {CBS_SORT, 0, DID_CBS_SORT }, {CBS_HASSTRINGS, 0, DID_CBS_HASSTRINGS }, {CBS_NOINTEGRALHEIGHT, 0, DID_CBS_NOINTEGRALHEIGHT }, {CBS_DISABLENOSCROLL, 0, 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 * out when writing dialog styles. */ {WS_MINIMIZEBOX, 0, DID_WS_MINIMIZEBOX }, {WS_MAXIMIZEBOX, 0, 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, DID_MMF_MOVEABLE }, {MMF_PURE, 0, DID_MMF_PURE }, {MMF_PRELOAD, 0, DID_MMF_PRELOAD }, {MMF_DISCARDABLE, 0, DID_MMF_DISCARDABLE } };

/* * Extended Styles. */ static CLASSSTYLE acsExStyle[] = { {WS_EX_DLGMODALFRAME, 0, 0 }, {0x0002 /*WS_EX_DRAGOBJECT*/, 0, 0 }, {WS_EX_NOPARENTNOTIFY, 0, 0 }, {WS_EX_TOPMOST, 0, 0 }, {WS_EX_ACCEPTFILES, 0, 0 }, {WS_EX_TRANSPARENT, 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, HELPID_EDIT_RESTOREDIALOG }, {MENU_CUT, HELPID_EDIT_CUT }, {MENU_COPY, HELPID_EDIT_COPY }, {MENU_PASTE, HELPID_EDIT_PASTE }, {MENU_DELETE, HELPID_EDIT_DELETE }, {MENU_DUPLICATE, HELPID_EDIT_DUPLICATE }, {MENU_SYMBOLS, HELPID_EDIT_SYMBOLS }, {MENU_STYLES, HELPID_EDIT_STYLES }, {MENU_SIZETOTEXT, HELPID_EDIT_SIZETOTEXT }, {MENU_NEWDIALOG, HELPID_EDIT_NEWDIALOG }, {MENU_SELECTDIALOG, HELPID_EDIT_SELECTDIALOG },

{MENU_ALIGNLEFT, HELPID_ARRANGE_ALIGNLEFT }, {MENU_ALIGNVERT, HELPID_ARRANGE_ALIGNVERT }, {MENU_ALIGNRIGHT, HELPID_ARRANGE_ALIGNRIGHT }, {MENU_ALIGNTOP, HELPID_ARRANGE_ALIGNTOP }, {MENU_ALIGNHORZ, HELPID_ARRANGE_ALIGNHORZ }, {MENU_ALIGNBOTTOM, HELPID_ARRANGE_ALIGNBOTTOM }, {MENU_SPACEHORZ, HELPID_ARRANGE_SPACEHORZ }, {MENU_SPACEVERT, HELPID_ARRANGE_SPACEVERT }, {MENU_ARRSIZEWIDTH, HELPID_ARRANGE_ARRSIZEWIDTH }, {MENU_ARRSIZEHEIGHT, HELPID_ARRANGE_ARRSIZEHEIGHT }, {MENU_ARRPUSHBOTTOM, HELPID_ARRANGE_ARRPUSHBOTTOM }, {MENU_ARRPUSHRIGHT, HELPID_ARRANGE_ARRPUSHRIGHT }, {MENU_ORDERGROUP, HELPID_ARRANGE_ORDERGROUP }, {MENU_ARRSETTINGS, HELPID_ARRANGE_ARRSETTINGS },

{MENU_TESTMODE, HELPID_OPTIONS_TESTMODE }, {MENU_HEXMODE, HELPID_OPTIONS_HEXMODE }, {MENU_TRANSLATE, HELPID_OPTIONS_TRANSLATE }, {MENU_USENEWKEYWORDS, HELPID_OPTIONS_USENEWKEYWORDS }, {MENU_SHOWTOOLBOX, 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, HELPID_COMMONFILEOPENINCLUDE }, {DID_COMMONFILEOPENRES, HELPID_COMMONFILEOPENRES }, {DID_COMMONFILESAVEINCLUDE, HELPID_COMMONFILESAVEINCLUDE }, {DID_COMMONFILESAVERES, HELPID_COMMONFILESAVERES }, {DID_COMMONFILEOPENDLL, HELPID_COMMONFILEOPENDLL },

{DID_TOOLBOX, HELPID_TOOLBOX }, {DID_STATUS, HELPID_PROPERTIESBAR },

{0, 0 } };

/* * Language and Sub Language tables. */ static SUBLANGTABLE aslNeutral[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, { SUBLANG_DEFAULT, IDS_SUBLANG_DEFAULT, 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, IDS_SL_NEUTRAL }, { SUBLANG_DUTCH, IDS_SUBLANG_DUTCH, IDS_SL_DUTCH }, { SUBLANG_DUTCH_BELGIAN,IDS_SUBLANG_DUTCH_BELGIAN, IDS_SL_DUTCH_BELGIAN} }; static SUBLANGTABLE aslEnglish[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, IDS_SL_NEUTRAL }, { SUBLANG_ENGLISH_US, IDS_SUBLANG_ENGLISH_US, IDS_SL_ENGLISH_US }, { SUBLANG_ENGLISH_UK, IDS_SUBLANG_ENGLISH_UK, IDS_SL_ENGLISH_UK }, { SUBLANG_ENGLISH_AUS, IDS_SUBLANG_ENGLISH_AUS, IDS_SL_ENGLISH_AUS }, { SUBLANG_ENGLISH_CAN, IDS_SUBLANG_ENGLISH_CAN, 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, IDS_SL_NEUTRAL }, { SUBLANG_GERMAN, IDS_SUBLANG_GERMAN, IDS_SL_GERMAN }, { SUBLANG_GERMAN_SWISS, IDS_SUBLANG_GERMAN_SWISS, IDS_SL_GERMAN_SWISS } }; static SUBLANGTABLE aslItalian[] = { { SUBLANG_NEUTRAL, IDS_SUBLANG_NEUTRAL, 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 *prev; struct _tcpinfo *next; UINT state; UINT localip; UINT localport; UINT remoteip; UINT remoteport; } TCPINFO, *PTCPINFO;

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 that the object manipulate the correct reference count when adding or releasing artificial reference counts. To ensure this is the case, always call ExternalAddRef and ExternalRelease instead of InternalRelease and InternalAddRef. It is rare to call InternalRelease 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 the name of the local class that will be defined. An 'X' will automatically be prepended to the name. This naming convention is used to avoid collisions with global classes of the same name. In addition, the name of the embedded member, the same as the localClass 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 Nein Ja virtual Funktion? 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 Framework-Objekte Value-Übergabe Referenz-Übergabe void Do(CMyValue val); void Do( const CMyValue& val ); ( wenige Bytes ) ( 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 return-Werte eines CMyValue GetCurrentValue(); CMyView* GetCurrentView(); Value-Objektes Framework-Objektes

Hinweise zur Programmierung

Overloading-Operatoren und Copy-Konstructoren sollten vermieden werden ( insbesondere bei Framework-Klassen ). Falls dennoch erforderlich, so sollte der Copy- Konstructor 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 Example Example MFC Class Type Variable Object HWND hWnd; CWnd* pWnd; HDLG hDlg; CDialog* pDlg; HDC hDC; CDC* pDC; HGDIOBJ hGdiObj; CGdiObject* pGdiObj; HPEN hPen; CPen* pPen;1 HBRUSH hBrush; CBrush* pBrush;1 HFONT hFont; CFont* pFont;1 HBITMAP hBitmap; CBitmap* pBitmap;1 HPALETTE hPalette; CPalette* pPalette;1 HRGN hRgn; 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 HSZ hszStr; CString pStr;2 POINT pt; CPoint 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; // CDC drawing tool class CPen; // a pen / HPEN wrapper class CBrush; // a brush / HBRUSH wrapper class CFont; // a font / HFONT wrapper class CBitmap; // a bitmap / HBITMAP wrapper class CPalette; // a palette / HPALLETE wrapper class CRgn; // a region / HRGN wrapper

class CDC; // a Display Context / HDC wrapper class CClientDC; // CDC for client of window class CWindowDC; // CDC for entire window class CPaintDC; // embeddable BeginPaint struct helper

class CMenu; // a menu / HMENU wrapper

class CCmdTarget; // a target for user commands class CWnd; // a window / HWND wrapper class CDialog; // 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; // standard SDI frame class CMDIFrameWnd; // standard MDI frame class CMDIChildWnd; // standard MDI child class CMiniFrameWnd; // half-height caption frame wnd

// views on a document class CView; // a view on a document class CScrollView; // a scrolling view

class CWinThread; // thread base class class CWinApp; // 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 ) Macro-Name Macro-Typ _AFXDLL Stand-alone dynamic-link library (DLL) version _DEBUG Debug version including diagnostics _MBCS Compilation for multi-byte character sets _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, "nafxcwd.lib") #else #pragma comment(lib, "nafxcw.lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "uafxcwd.lib") #else #pragma comment(lib, "uafxcw.lib") #endif #endif 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 char *LPSTR; typedef unsigned int *PUINT; typedef long BOOL; typedef unsigned char BYTE; typedef unsigned long DWORD; typedef unsigned short WORD; typedef 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: Mit der Datei Neu Projekt Win32ConsoleAnwendung rechten Maustaste auf dem Projetname: myauf01 grauen Fenster-Rand Pfad : d:\temp\my... können die benötigten Hilfsfenster (x) Neuen Arbeitsbereich erstellen aktiviert werden:

2. Studie-Menu: Ausgabe-Fenster Datei Neu Dateien C++-Quellcodedatei ( für die Übersetzungsfehler ) [x] dem Projekt hinzufügen Minileiste-Erstellen Dateiname: myauf01 ( zum Compilieren, Linken, Starten ) Pfad : d:\temp\my... Arbeitsbereich ( für Klassen und Dateien )

Console-Applikation

Zum Ausführen von Tests ist eine Console-Applikation zu erstellen. #include #include 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 hat den Wert ... TRUE hat den Wert ... ( a < *p ) hat den Wert ... ( (BYTE) a < (BYTE) *p ) hat den Wert ... *(p+3) hat den Wert ... Welche Änderungen ergeben sich, wenn

#define UNICODE #include 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] ergibt ..... 10 x[k**z+3]**z+3 ergibt .....

11 x[x[k]] 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 #include

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 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 7 6..0 byte S integer

signed 15 14..0 word S integer

signed 31 30..0 dword S integer unsigned 7..0 byte integer unsigned 15..0 word integer unsigned 31..0 dword integer unsigned 63..0 qword integer

7..4 3..0 BCD res. BCD

packed 7..4 3..0 BCD BCD BCD

pointer datatype formats

near 31..0 pointer offset or virtual address

far 47..32 31..0 pointer segment or selector offset

FP datatype formats

single 31 30..23 22..0 real S exp. fraction

double 63 62..52 51..0 real S exp. fraction extended 79 78..64 63 62..0 real S exp. I fraction

word 15 14..0 integer S integer

short 31 30..0 integer S integer

long 63 62..0 integer S integer packed 79 78..72 71..0 BCD S res. D17 D16 D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0

MMX datatype formats packed 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 packed 63..48 47..32 31..16 15..0 word word word word word packed 63..32 31..0 dword 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 127..112 111..96 95..80 79..64 63..48 47..32 31..16 15..0 word word word word word word word word word packed 127..96 95..64 63..32 31..0 dword dword dword dword dword packed 127..64 63..0 qword qword qword

SSE datatype format

scalar 127..96 95..64 63..32 31..0 single FP reserved reserved reserved single FP packed 127..96 95..64 63..32 31..0 single FP single FP single FP single FP single FP

SSE2 datatype format

scalar 127..64 63..0 double FP reserved double FP packed 127..64 63..0 double FP 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 ( Maus- Nachrichten, 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 //======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 = sizeof( WNDCLASSEX ) ; wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wndclass.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wndclass.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = "my_class" ; wndclass.hIconSm = 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 WM_LBUTTONUP: break; case WM_RBUTTONUP: break; case WM_MBUTTONUP: break; case WM_LBUTTONDOWN: break; case WM_RBUTTONDOWN: break; case WM_MBUTTONDOWN: break; case WM_LBUTTONDBLCLK: break; case WM_MBUTTONDBLCLK: break; case WM_RBUTTONDBLCLK: break; case WM_MOUSEMOVE: 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_ABORTRETRYIGNORE MB_OKCANCEL MB_RETRYCANCEL MB_YESNO MB_YESNOCANCEL MB_DEFBUTTON2 MB_DEFBUTTON3 MB_ICONHAND MB_ICONSTOP MB_ICONERROR MB_ICONQUESTION MB_ICONASTERISK MB_ICONEXCLAMATION MB_ICONWARNING 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_ICONSTOP MB_ICONERROR MB_ICONQUESTION MB_ICONASTERISK MB_ICONEXCLAMATION MB_ICONWARNING 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 //======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 Kontext- Menü ( 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 //======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 = sizeof( WNDCLASSEX ) ; wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon ( NULL, IDI_APPLICATION ) ; wndclass.hCursor = LoadCursor ( NULL, IDC_ARROW ) ; wndclass.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = "my_class" ; wndclass.hIconSm = 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. Wozu dient der Rückgabewert von MessageBox()? 2. Enthält eine MessageBox() eine eigene Hauptnachrichtenschleife? 3. Was bedeutet modal? 4. Was enthält wParam bei einem Aufruf der CALLBACK-Funktion infolge eines Menu-Item-Klick? 5. 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 //======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

#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;kmtOption = 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;k0)LastItem[k-1]=TRUE; } } LastItem[j]=TRUE; LastItem[m-1]=TRUE;

for(k=0;k

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 Fenster- Titelzeile.

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 Ressourcen- IDentifizierer einzufügen:

#define IDM_MAIN_MENU 101 #define IDM_MAIN_EXIT 4001 #define IDM_MAIN_NEW 4002 #define IDM_MAIN_EXAMPLE_1 4003 #define IDM_MAIN_EXAMPLE_2 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 rc- Quelltext 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.Menu- Eintrages 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

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, "" "\r\n\r\n ...\r\n\r\n" "\r\n

...

\r\n

\r\n...\r\n

\r\n\r\n"); 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-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.

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. Wann wird in der CALLBACK-Funktion return 0; verwendet? 2. Warum wird ein DestroyWindow(ghwnd[0]) aber kein DestroyWindow(ghwnd[1]) benötigt? 3. Welche Prä-Zeichen (??_...) verwendet die "EDIT"-Klasse für Edit-Nachrichten? 4. 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()? 5. Welche alternativen Möglichkeiten gibt es anstelle der Verwendung von Virtual-Mem-Speicher? 6. Wozu dient LoadAccelerators()? 7. Wodurch wird ein WS_CHILD-Fenster zerstört? 8. Wie kann CreateWindowEx() eine vorhandene Klasse von MS verwenden? 9. Was bedeutet Window Sub-Classing? #include

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 // wird immer gebraucht #include // 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

/////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////// // File: main.cpp // Hauptprogramm für GDI-Tests //////////////////////////////////////////////////// #include ??? // #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", 0 }, { 100, L"loesche", loesche }, { 120, L"MessageBox()", 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_DIALOG- Dialog-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_DIALOG- Dialog 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 #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 rc- Quelltext 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 Konstanten- Bezeichner 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 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 '^' : 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 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://M- case 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. Enthält die Funktion DialogBox() eine Hauptnachrichtenschleife? 2. Nennen Sie unterschiedliche Möglichkeiten, wie DialogBox() mit einem Menu versehen werden kann. 3. Wozu dient der ret-Parameter bei EndDialog(hwnd,ret)? 4. Welche Nachricht wird durch einen Button-Klick ausgelöst? 5. Wie heißt die Klasse, die Button's erstellt und die MS-CALLBACK-Funktion enthält? 6. 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 Notify- Nachrichten 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 #include #include #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 #include #include

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 #include /////////////////////////////////////////////////////////// // 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

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.

Standard- File-Open-Dialog

Es ist ein File-Open-Dialog gemaess dem angefuegten Muster eines Standard-Dialoges zu verwenden.

#include // 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 idDlg, DLGPROC dlgProc); bDLG (HWND hwnd, int idDlg, DLGPROC dlgProc, void * buf, int sizebuf); HWND _hwnd; CREATESTRUCT _cs; void * _buf; void * _bufOld; int _bufSize; int _idDlg, _ret; } ;

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 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 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 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_COMBO_REPL IDC_BUTTON_FIND 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 #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 // wird immer gebraucht #include #include // 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 #include #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; iget_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 HWND hFind, hRepl, hEdit; static int idxSelStart, idxSelEnd, nChar; static char buf[256], *pBuf,*pFind; static 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, "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 },

{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 File: myDll.cpp #ifndef MYDLL_H #define _DLLBUILD_ #define MYDLL_H #include "myDll.h" /////////////////// #include /////////////////////////////////// // 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 Mapping- Makros ( 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;