SP2-SCRIPT Info Einleitung System Schnittstellen Kybernetik

Transcription

SP2-SCRIPT Info Einleitung System Schnittstellen Kybernetik
SP2-SCRIPT
Info
Einleitung
System
Schnittstellen
Kybernetik
Normen
Betriebssysteme
Datentypen
windowsx.h
Entwicklungsumg.
Assembler
main()
Console-App
Nachrichten
WM-Konstanten
def_wnd.c
def_dlg.c
Win-Objekte
Ressourcen
Dialoge
Dll's
MFC
SP01
SP01
SP02
SP02
Q02
SP03
SP03
Q03
menu.cpp
SP04
SP04
Q04
Menu
SP05
SP05
hex1.exe
hex1.txt
hex2.exe
hex2.txt
But
SP06
SP06
tray
butt
SP07
SP07
quell
test
SP08
SP08
SP09
SP09
Info: Systemprogrammierung
Hier finden sie Unterlagen zu den Veranstaltungen:
( Grafische Darstellungen
und Erkennen nach )
Antoine de Saint-Exupéry:
Man sieht nur mit dem Herzen gut.
Das Wesentliche ist für die Augen unsichtbar.
Einleitung
Diese Veranstaltung hat das Ziel, in die Programmierung mit dem aktuellen ( Windows-) Betriebssystem einzuführen. Die
unfangreiche Funktionalität eines Betriessystem ( als Virtuelle Maschine und Resourcen-Verwalter ) wird auf den "unteren
Ebenen" für die Programmierung genutzt. Wegen der Komplexität und des Umfanges wird diese Einführung nicht
vollständig sein. Das Skript kann der Vor- und Nachbereitung der Veranstaltung dienen.
Ziel der Veranstaltung
In der Veranstaltung werden grundlegende Begriffe erklärt, und in die Programmierung der Betriebssystem-Funktionalität
eingeführt. Der Schwerpunkt liegt auf praktischen Anwendungsaspekten. Wegen des Stoff-Umfanges kann nur eine spezielle
Auswahl behandelt werden.
Kognitive Ziele
Verstehen von Sachverhalten bedeutet, dass wir ( innerhalb eines stillschweigend vorausgesetzten Kontext ) in Begriffen,
Schlüssen, Urteilen denken und Erkenntnisse in Zusammenhänge einordnen können.
●
●
Beschreibungen antworten auf Wie - Fragen,
Erklärungen antworten auf Warum - Fragen.
Praktische Ziele
Im engeren Sinne wird als Grunglage ein aktuelles Betriebssystem ( Windows ) und aktuelle Programmierwerkzeuge
verwendet ( Entwicklungsumgebung, Debbuger, Ressourcen-Erstellung, Nachrichtenverfolgung, usw. ).
Danke
Ich möchte mich
●
●
●
●
●
bei meiner Frau für das Verständnis,
bei den Kollegen für interessante Diskussionen,
bei meinen Diplomanden für die geleistete Arbeit,
bei den Tutoren für den aufopfernden Einsatz und
bei den Studenten für zahlreiche Fragen
bedanken.
Ron Kritzfeld:
Der Pragmatiker entscheidet Fälle
nicht nach Grundsätzen,
sondern fallweise.
In dem Wort "Systemprogrammierung" steckt "System" und "Programmierung". Diese Begriffe werden unten behandelt.
Was ist ein Programm?
Das Wort Programm kommt aus dem griechischen und bedeutet "schriftliche Bekanntmachung, Tagesordnung". Das
Programmieren möchte ein bestimmtes Verhalten entwickeln, aufschreiben und festlegen um damit Abläufe zu unterstützen,
steuern, regeln. Ein Programm kann bedeuten:
●
●
●
●
●
●
●
●
●
●
Vorhaben
ökonomisches Sortiment, Warenangebot
Vorstellungs-, Aufführungs-, Vortrags-, Konzertfolge oder Spielfolge ( Theater, Fernsehen )
Angebot an Sendungen ( Gesamtheit der Sendungen des Tages, Rundfunk, Fernsehen )
Darlegung von Zielen und Grundsätzen ( politische Partei, Staatsführung )
Vorgesehenen Ablauf für eine Reihe von Darbietungen
Folge von Tätigkeiten; Arbeitsplan für ein Vorhaben
Zeit- od. Terminplan, festlegen der Abfolge von Vorgängen
Detailplanung der einzelnen technischen Arbeitsschritte für die Ausführung ( durch ausführende Einheiten
)
Folge von Anweisungen an den Computer, mit denen bestimmte Aufgaben von physikalisch-technischen
Einheiten ausgeführt werden ( Realisierung mit Algorithmen, Programmiersprache, Hardware, Sensoren,
Aktoren )
Beispiel: Im Raum von Ressourcen und Wissen entwickelt der Programmatiker ( z.B. Prof. ) ein Vorlesungsprogramm
für eine Veranstaltung. Art und Umfang der Durchführung hängen auch von der Programmatik ( Zielsetzung,
Zielvorstellung ) und der programmatischen ( zielsetzend, richtungsweisend, auf dem Programm beruhenden ) Mitarbeit
der Studierenden ab, die zum programmgemäßen ( planmäßig, so wie es geplant ist ) Gelingen beitragen.
allg. Programmiermodell
Das Erstellen einer Schrittfolge ( programmieren ) erfolgt auf einer abstrakten, formalen Ebene ( Projektabwicklungen,
militärische Planungen, Arbeitsvorbereitungen, volkswirtschaftliche Verflechtungs- und Vorgehensmodelle,
Software/Hardware-Entwicklungszyklen, Entwicklungsmodelle, usw. ).
Das erstellte Programm garantiert noch nicht die Fehlerfreiheit ( Verwendbarkeit, Ausführung ). In komplexen
Ausführungssystemen ( Organisationen, Computersysteme, Netze, usw. ) können vorausschauenden Beurteilungen schwierig
sein ( Funktionstests, Laufzeitverhalten, Skalierung, Fehlerfreiheit, zusichernde Garantien, Verfeinerungen, usw. ). Für ein
allgemeines, abstraktes Programmier-Modell gibt es unterschiedliche Ansätze. Ein universelles Modell soll auch für nicht
technische Systeme brauchbar sein. Das folgende Modell kann komplexe Prozesse beschreiben und ist einem ComputerSystem nachgebildet. Es besteht aus den Komponenten: Memory, Prozessor, Receptor, Effektor, Enviroment.
Memory
Prozessor
enthält:
1. Nutzdaten,
2. Daten für den Prozessor:
Programm - Code,
Umschaltungen und
Steuerungen
führt aus:
elementare Verarbeitungsschritte,
Verzweigungen,
kurzzeitige Speicherung von
Zwischenwerten,
Prozess - Umschaltung
Memory
Prozessor
Wandler
wandelt um:
<==
Rececptor(
Sensor )
Enviroment
Übertragungsmedium:
Weiterleitung
von Signalfolgen
==>
Effektor( Aktor )
Wandler
Enviroment
Bei einem ( biologischen ) lernenden System ist die Trennung von Speichern und Ausführen oft schwierig.
Ein technischer Prozessor kann Daten im Speicher ablegen, finden, holen, ändern, überschreibend-speichern. Es gibt
●
Daten, die der Prozessor als von aussen kommende Befehle ( OpCode ) erkennt und interpretiert ( fester
Befehlssatz ). Solche Befehle sind z.B.
❍ ausführen von elementaren Operationen
❍ internes ( zwischen- ) speichern von aktuellen Ausdrücken
❍ interne Ausführungsverzweigungen durchführen ( Sprung, "bedingter Adressversatz" )
Speichern aller internen Prozessordaten und umschalten auf einen neuen Prozess oder in einen neuen
Ausführungsmodus
Nutz-Daten, die der Prozessor
holt, ändert, geändert speichert
Daten, die dem Prozessor
äussere Zustände signalisieren ( Steuerbus-Signale ) und sein
gesamtes Verhalten beeinflussen. Solche Hardware/Software-Steuerdaten können den Prozessor in einen
anderen Zustand ( z.B. wach, schlafend ) umschalten. Im schlafenden Zustand können unbewusste
Aufräumungsarbeiten durchgeführt werden.
❍
●
●
Die Folge von Prozessor-Befehlen bilden ein Programm. Ein Programm braucht zur Ausführung eine interpretierende
Apparatur. Jeder interpretierende Apparatur kann nur die eigenen Befehle interpretieren ( braucht speziell auf die Apparatur
abgestimmte Programm-Sequenzen ). Der Prozessor arbeitet mit dem Effektor und dem Receptor zusammen, die
Signalumwandlungen durchführen. Kommunikation ist ein wechselseitiger Prozess von Sender und Empfänger ( feed back,
Rückkoppelung zwischen Empfänger und Sender ).
Was ist ein System?
In der Philosophie ist ein System [ griechisch: "gegliedertes Ganzes"; von griechisch systema: das Zusammengesetzte ], eine
Bezeichnung für das geordnete Zusammenstellen von grundlegenden Erkenntnissen zu einem Ganzen, d.h. zu einer Lehre,
einer Doktrin oder einem Lehrgebäude. In der Wissenschaftstheorie ist ein System die Gesamtheit der Prinzipien, die einer
Theorie zugrunde liegen. Nach Immanuel Kant ( Kritik der reinen Vernunft, 1781 ) ist das System "die Einheit der
mannigfaltigen Erkenntnisse unter eine Idee".
Beispiel: Fachwerksystem
Ein Fachwerk besteht aus einem System
von Stäben, die miteinander verbunden
sind. Die Stäbe erfüllen erst dann die
Funktionen des Fachwerksystems, wenn
die Stäbe zu einem "neuen Ganzen"
montiert sind. Das Fachwerksystem
kann Lasten tragen und damit seine
Aufgabe erfüllen, wenn die Lasten über
Stäbe und Stabverbindungen ( an die
Erde ) abgeleitet werden.
"Schnittstellen" sind gedachte
Trennstellen, um rechnerisch die innen
wirkenden Schnittgrössen ( Kräfte,
Momente ) zu ermitteln.
Zu einem konkreten Systemen gehören (
meist ) unterteilende Fachbegriffe, die
die Vielfalt spezifizieren und das
wissenschaftlichen Modell beschreiben.
Als strukturbildende Einteilung wird der
System-Begriff in allen Wissenschaften
verwenden.
Hier einige Beispiele: In der
Psychologie formulierte Gregory
Bateson ( 9.5.1904-11.6.1980 ) die
Double-Bind-Theorie zur Rolle der
Familie bei der Entstehung von
Schizophrenie.
Die zunehmende Bevölkerung führte zu
Umweltschutz, Grenzen des
Wachstums, Populationen, Ökologie,
Biozönosen, Nahrungsbeziehungen
zwischen den Arten, usw. Die Biologie
und Evolutionstheorie führten zu
verwobenen ( grossen ) Systemen. Die
Ökologie ( zu griechisch oikos: Haus
und lógos: Lehre ) beschreibt Systeme
undderen Wechselbeziehungen
zwischen den Organismen der
unbelebten/belebten Umwelt und dem
Stoff- und Energiehaushalt Es wird
zwischen der unbelebten Umwelt (
abiotische Faktoren wie Klima, Boden )
und der belebte Umwelt ( biotische
Faktoren ) unterschieden.
●
●
●
●
Die Aut-Ökologie behandelt
Beziehungen zwischen
Individuum und Umwelt Die
Dem-Ökologie (
Populationsökologie ) behandelt
Beziehungen zwischen
Wechselbeziehungen artgleicher
Individuen
Die Syn-Ökologie behandelt
Wechselbeziehungen
verschiedener Populationen
Biozönosen kennzeichnet die
Gesamtheit aller Lebewesen
eines bestimmten Lebensraums.
Die System-Ökologie behandelt
Ökosysteme untereinander
Die Human-Ökologie behandelt
Wechselwirkungen zwischen
dem Menschen und seiner
natürlichen und technischen
Umwelt
Syllogistik [griechisch] die, Logik: von
Aristoteles begründete Lehre vom
Schluss als Kernstück der traditionellen
Logik. Aus der Verbindung von zwei
Vordersätzen (Prämissen) geht dabei der
Schlusssatz (Konklusion) als logische
Folgerung hervor. Die Syllogistik stellt in
der modernen Logik einen Teil der
prädikatenlogischen Schlüsse dar (
Prädikat lateinisch: auszeichnende
Bewertung ).
In der Mathematik ist der von D.Hilbert
begründete ( nur aus Axiomen gewonne
) Formalismus als mathematisch
erweisbare Widerspruchsfreiheit
gescheitert ( Gegenposition zum
Intuitionismus ). K.Gödel hat 1931 den
Unvollständigkeitssatz bewiesen:
Eine mathematische
Theorie,
die die Arithmetik
umfasst,
und die
widerspruchsfrei ist,
kann nicht alle in ihr
wahren Aussagen
beweisen.
Intuitionismus [lateinisch] der, als
mathematische Grundlagenforschung die
von L.Kronecker, H.Poincaré, H.L.
Lebesgue u.a. vertretene Lehre, dass die
Gesamtheit der natürlichen Zahlen
intuitiv und unableitbar gegeben sei und
dass sich die Gesamtheit der reellen
Zahlen (Kontinuum) arithmetisch nicht
bilden lasse. Einen intuitionistischen
Neuaufbau der Mathematik versuchten
seit 1907 L.E.J. Brouwer, H.Weyl,
A.Heyting u.a. mit der Forderung der
effektiven Konstruktion zur Definition
mathematischer Objekte und unter
Einschränkung des Tertium non datur (
lateinisch: ein Drittes gibt es nicht; Satzes
vom ausgeschlossenen Dritten; ein
Axiom, das besagt, dass eine Aussage gilt
oder nicht gilt; eine dritte Möglichkeit
besteht nicht ) auf endliche Mengen.
In der Informatik werden in der
Systemanalyse Methoden zur Einteilung
und Untersuchung von Arbeitsgebieten
und Arbeitsabläufe entwickelt (
Automatisierung, Phase der
Softwaretechnik, usw. ).
Aristoteles:
Das Ganze ist mehr als
die Summe der Teile.
Im allgemeinen Sinne ist ein System eine Sammlung von Komponenten, die zusammenwirken. Das System enthält den
ganzheitlichen Zusammenhang von Dingen, Vorgängen, Teilen, ( z.B. ökologische Wechselwirkungen in der Natur; vom
Menschen hergestelltes soziologisch-politisches System ) und entspricht einem geordneten, zusammenwirkendem Ganzen.
Ein System besteht aus wechselwirkenden Komponenten.
Die Wechselwirkungen werden durch Relationen ( Funktionen, Methoden ) ausgedrückt. Die Komponenten ( Elemente,
Bausteine, Teile ) haben Eigenschaften, die als Merkmale und Methoden gekennzeichnet werden können. Ein System besteht
aus einer Menge von Elementen, welche Eigenschaften besitzen und durch Relationen miteinander verknüpft sind.
Ein System ist ein Gebilde ( Gefüge, Komplex, Zusammenstellung ) von bestimmten Objekten ( Komponenten, Bestandteile,
Gegenstände ) zwischen denen Beziehungen ( Verbindungen, Kopplungen ) mit bestimmten Eigenschaften bestehen. Ein
System ist ein Gefüge von Objekten und Beziehungen mit bestimmten Eigenschaften.
Der System - Begriff wird in vielfältiger Weise verwendet. Z.B. sind Programmen, Verfahren, Daten und Methoden zur
Informationsverarbeitung in einem.
In der Informatik wird der System - Begriff in vielfältiger Weise benutzt.
●
●
●
●
●
●
●
Ein Hardware-System besteht z.B. Mikroprozessoren, elektronischen Bausteinen, elektronischen Geräten,
weiteren Schaltungen, physikalischen Sensoren und Aktoren
Ein Computer besteht aus System-Software, Betriebssystem, Firmware, Middleware, Software-Komponenten,
Anwendungssoftware, Hardware-System, Speicher-System, Ein- und Ausgabegeräten, Peripherie, usw.
Eingabegeräten ( Tastatur, Maus, Laufwerk ),
Ausgabegeräten ( Bildschirm, Laufwerk ) und
Peripheriegeräten ( Drucker, Modem )
Datenbanksystem ( Anwendungsprogramm zum Erfassen, Suchen, Sortieren und Verwalten größerer
Datenmengen, Daten-, Adressen- und Artikelverwaltung, Buchhaltungssysteme, Rechnungssystem, SQLAbfragen, Recherchen, Suchmaschinen )
CIM ( englisch computer integrated manufacturing, rechnerintegrierte Fertigung ) enthält für die Konstruktion
und Fertigung mit Hilfe eines Rechners CAD ( Computer-Aided-Design ) und CAM ( Computer-AidedManufacturing )
Nach DIN 19226 gilt:
Ein System ist eine abgegrenzte Anordnung von aufeinander einwirkenden Gebilden. Solche Gebilde
können sowohl Gegenstände als auch Denkmethoden und deren Ergebnisse ( z.B.
Organisationsformen, mathematische Methoden, Programmiersprachen) sein. Diese Anordnung wird
durch eine Hüllfläche von ihrer Umgebung abgegrenzt oder abgegrenzt gedacht. Durch die Hüllfläche
werden Verbindungen des Systems mit seiner Umgebung geschnitten. Die mit diesen Verbindungen
übertragenen Eigenschaften und Zustände sind die Größen, deren Beziehungen untereinander das
dem System eigentümliche Verhalten beschreibt. Durch zweckmäßiges Zusammenfügen und
Unterteilen von solchen Systemen können größere und kleinere Systeme entstehen.
Objektbezogene Systembezeichnungen:
abstrakt:
lat. abstrahere: wegziehen, wegschleppen, von den individuellen Merkmalen losgelöst, nicht
konkret, sinnlich nicht wahrnehmbar, rein begrifflich, unanschaulich, von der Wirklichkeit
abgetrennt; Gegensatz: konkret. Abstrakt wird auch als Bezeichnung für die Erfassung des
Wesentlichen verwendet ( z.B. Person – Mensch – Säugetier – Lebewesen – Seiendes etc. ).
Aristoteles nannte es aphairesis ( griechisch: Wegnahme ) das methodische Erfassen des
Wesentlichen ( Abstraktionsmethode, induktiven Logik, Phänomenologie ).
formal Formal meint die äußere Form ( nicht den Inhalt ) und kann ohne Entsprechung in der
Wirklichkeit sein, der Form genügend, nur äußerlich, nicht in Wirklichkeit, Axiome werden in
Zeichen des Operationssystems ausgedrückt
verbal mündlich, mit Worten, mit Hilfe der Sprache
konkret:
gegenständlich, dinglich, fassbar, wirklich, tatsächlich, anschaulich, sinnlich wahrnehmbar;
Gegensatz: abstrakt.
konzipiert lat. concipere: zusammenfassen, begreifen, sich vorstellen; von einer bestimmten Vorstellung,
Idee ausgehend etwas planen, entwerfen, entwickeln; einen Plan oder ein schriftliches Konzept
für etwas machen;
real lat., zu res "Sache", wirklich, tatsächlich, nicht nur in der Einbildung, in der Wirklichkeit
vorhanden, der Realität entsprechend;
Gegensatz: irreal.
künstlich:
Wer sich künstlich aufregt, regt sich über etwas mehr als nötig auf
natürlich:
Die lateinische Fügung ( in natura ) entspricht der Bedeutung "in Wirklichkeit; in seiner
wirklichen, natürlichen Gestalt". Das Haus sieht in natura ganz anders aus als auf dem Foto.
Ein System S besteht aus einer Menge M von Komponenten und damit definierten Relation R, d.h. aus dem Begriffspaar S =
( M, R ).
Wird
M = { i, s, o } : Eingabe-, System-,
Ausgabe - Zustände
R = { I, S, O } : Eingabe-, Übergangs-, Ausgabe - Funktionen
in
S = ( M, R )
: Menge von Komponenten, Relationen
eingesetzt, so ergibt sich mit der Zeit t die Darstellung
eines Sytems S zu
S
= ( { i, s, o, t }, { I, S, O } )
Gödel:
Jedes formale System ist unvollständig. Die wahre Welt umfasst mehr als das Denken. Das Denken
umfasst mehr als die Sprache.
Ein diskretes System wird in der Graphentheorie ( Topologie ) dargestellt durch eine Menge von Punkten ( Ecken oder
Knoten ), die durch Kanten ( Linien; gerichtete oder ungerichtete ) verbunden sind.
Ein statisches System ist unabhängig von der Zeit.
Bei einem dynamischen System können sich im Laufe der Zeit die Komponenten und Beziehungen ändern.
Ein offenes System ist sind durch den Austausch von Materie, Energie, Information mit der System - Umgebung
gekennzeichnet.
Bei einem geschlossenes System ist kein Austausch mit der System - Umgebung möglich. Ein geschlossenes System geht
langfristig in den Zustand maximaler Entropie über.
Bei einem Aufbausystem steht die statische Darstellung der Systemstruktur, d.h. die Verknüpfung der in einem System
enthaltenen Komponenten im Vordergrund ( Strukturbäume, Hirarchiestrukturen, Strukturmatrizen, ). Charakteristisch sind
die Bezeichnungen für die Verknüpfungen: Relation, Beziehung, Kopplung.
Bei einem Ablaufsystem steht die Darstellung der Systemfunktionen als Folgeverknüpfung ( Vorgänger, Nachfolger,
Sequenz ) im Vordergrund. Ein modulares System [ engl. modular systems ] nutzen eine funktionale Zerlegung ind kleinere
Teilaufgaben.
Praktische Anwendungen sind: Netzpläne, Programmablaufpläne, Flußdiagramme. Die Netzplantechnik ( Teilgebiet des
Operations-Research ) ist ein Verfahren zur Analyse, Planung und Kontrolle von Großprojekten und zur Gewährleistung
eines optimalen Einsatzes von Personal, Betriebs- und Finanzmitteln. Die Projekte werden zunächst gedanklich in
Einzeltätigkeiten ( Aktivitäten, Vorgänge ) zerlegt und diese dann gemäß ihren technologisch bedingten Verknüpfungen mit
Mitteln der Graphentheorie ( Graph ) dargestellt, im einfachsten Fall mit Pfeilen als Tätigkeiten und Knoten als Ereignissen.
Der sich daraus ergebende Netzplan bildet die Grundlage für die Zeitplanung. Dabei werden die frühestmöglichen Zeitpunkte
für den Abschluss der Einzeltätigkeiten und damit auch das frühestmögliche Projektende errechnet ( kritischer Pfad ). Aus
der Bestimmung der spätestzulässigen, das frühestmögliche Projektende nicht gefährdenden Eintrittszeitpunkten der
Einzeltätigkeiten ergeben sich gewisse zeitliche Spielräume ( Pufferzeiten ). Die bekanntesten Methoden der Netzplantechnik
sind CPM ( englisch critical path method ) und MPM ( Metra Potenzial-Methode ) für deterministische sowie PERT (
englisch program evaluation and review technique ) für stochastische Vorgänge.
Damit grundlegende Wechselwirkungen zwischen diese Komponenten möglich sind, läuft auf diesem Hardwaresystem ein
Betriebssystem. Das Betriebssystem ist ein wesentlicher Bestandteil der Systemsoftware. Die Systemsoftware besteht aus
einzelnen Teilen und Gruppe von Basisprogrammen, die die Hardware unmittelbar ansprechen und Dateien verwalten. Die
Anwendungssysteme ( Applikationen, Programme ) nutzen diese grundlegenden Basisprogramme.
Der Begriff Systemtechnik ( System Engineering, auch System Analysis ) entstammt etymologisch dem Griechischen und
bedeutet soviel wie "zusammen, stellen, Handwerk". Der Begriff Systemtechnik wird als Verallgemeinerung und
Erweiterung der ingenieurwissenschaftlichen Methodik betrachtet. Die Systemtechnik ist auf die Untersuchung und
Entwicklung von Systemen als sinnvoll gegliedertes Gebilde ausgerichtet. Strukturiert werden Objekte und Prozesse.
Wissenschaftliche Fragen werden in der Systemtheorie behandelt.
Beispiele
Transport von Informationen: Telefon TAPI
Transportsystem PKW:
Rolls-Royce ( Typ: Silver Ghost,
6-Zyl.-Luxusauto von 1909,
Aluminiumkarosserie,
faltbaren Verdeck,
Innenausstattung aus Leder
Transportsystem Bahn:
ICE T der Baureihe 415
mit Neigetechnik, 1999
System Flugzeug: Airbus A 319
Bauelemente-Bauplan; Gesamtlänge/Spannweite/Höhe=33,84/34,10/11,76 m
Was sind Schnittstellen?
Ein Fachwerksystem besteht aus Stäben, die miteinander verbunden sind. Die "Schnittstellen" sind gedachte Trennstellen, für
die innen wirkenden Schnittgrössen ( Kräfte, Momente ).
Bei verteilten Aufgaben erfolgt der Informationsaustausch an Übergangspunkten ( Schnittstellen ). Die Kommunikation
findet über die Schnittstellen statt. Engpässe an diesen Informations-Schnittstellen ( Mitarbeiter-Abteilungsleiter,
Abteilungsleiter-Führungsebene, Schnittstellen zwischen Software-Modulen, Schnittstellen zwischen Hardware-Modulen,
Schnittstellen zwischen Software-Hardware, usw. ) können zu Frust führen.
Hardware-Schnittstellen haben i.a. eine physische Übertragungsstrecke ( Sender, Kanal, Empfänger ). SoftwareSchnittstellen nutzen für die asynchrone Kommunikation i.a. adressierbare Speicher ( Buffer, LIFO, FIFO, usw. ). Besonders
leistungsfähige Computer ( hohe Taktraten, großes Speichervolumen ) können helfen, die Informationen am rechten Ort, zur
rechten Zeit, in der rechten Form bereit zu stellen. Software-Schnittstellen regeln semantisch die Nachrichten-Verteilung (
z.B. auf Quelltext-Modul-Ebene, auf Maschinen-Ebene bei DLL's ).
Albert Einstein:
Fortschritt lebt vom Austausch des Wissen.
Software-Ergonomie
Die Schnittstelle zwischen dem Menschen und dem Computer ( Mensch-Maschine-Schnittstelle, Man-Machine-Interface
MMI, auch Human-Machine-Interface HMI ) ist meistens eine Benutzer-Oberflächen ( Bedienung, Schnittstellen, HMI,
MMI ), die visuelle Bildschirm-Fenster-Techniken nutzt SAA ( Mitte der 80er Jahre von IBM entwickelt ) ist eine
Abkürzung für System Application Architecture, die einen vereinheitlichter Aufbau der Mensch-Computer-Schnittstelle
definiert. Art der Gestaltung von Software, die die Arbeit erleichtert und bereichert sowie den Gesundheitsschutz
angemessen berücksichtigt. Zur Software-Ergonomie gehören vor allem Benutzerfreundlichkeit sowie Möglichkeiten der
individuellen Einstellung und Anpassung, z.B.: Auswahl, Anordnung und Größe der Bedienungselemente, Farbwahl,
Zoomen der Darstellung, Vorgaben für Tastatur und Maus ( etwa Wiederhol- und Klicktempo ), Lautstärke- und
Klangregelungen.
Zur Software-Ergonomie zählen außerdem Arbeitserleichterungen, die die Bedienung vereinfachen und dem Benutzer
Routinetätigkeiten abnehmen, z.B.
●
●
●
●
Grafische Benutzeroberflächen
Vereinfachte Verfahren wie Drag and Drop
Zusammenfassen von Befehls- und Aktionsfolgen in Makros
Automatisierte Funktionen ( z.B. kontexsensible Hilfen, intelligente Aktionsunterstützung,
Rechtschreibprüfung, Korrektur von "Drehern", usw.)
Die Software soll der Aufgabe angemessen, fehlertolerant, lernfördernd sein, und echte Dialoge bieten. Software-Ergonomie
ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG von 1990 ( DIN 66234, Teil 8 ) legt die
Anforderungen fest, die ein ergonomisch gestalteter Dialog zwischen Mensch und Computer erfüllen soll. Arbeitgeber sollen
benutzerfreundliche Software einsetzen, die der ausführenden Tätigkeit angepasst ist ( verständliche Format, angemessenes
Bearbeitungtempo, Rückmeldungen über Ergebnisse der Abläufe ).
Kybernetik
Der Name Kybernetik stammt von N.Wiener ( 1948, Cybernetics ), der neben C.E.Shannon, A.N.Kolmogorow, J.von
Neumann grundlegende Arbeiten zur Kybernetik lieferte. Kybernetik ist eine interdisziplinäre Wissenschaft, die sich mit
Kommunikations- und Steuerungssystemen in lebenden Organismen, Maschinen und Organisationen beschäftigt.
Kommunikations- und Steuerungssysteme bei lebenden Organismen und bei Maschinen werden analog betrachtet. Die
Kybernetik [von griechisch kybernetike, kybernetes (téchne): Steuermannskunst, Rudergänger, Kommandant ] ist eine
fachübergreifende Wissenschaft, die nach Erklärung von dynamischen, komplexen Systemen und formalen Modellen sucht.
Die Beschreibung der Modelle nutzt die mathematische Schreibweisen. Oft wird versucht, die funktionalen Zusammenhänge
mit Computerprogrammen nachzubilden.
Kybernetisches Modell als Regelkreises
Die externe
Führungsgrösse
übermittelt einen
gewünschten SollWert xk. Der
Regler vergleicht
Soll- und Ist-Wert,
ermittelt die
Abweichung, sucht
eine optimale
Handlungsstrategie
und legt die
Stellgrösse y fest,
die über das
Stellorgan wirkt
und zum
gewünschten
Ergebnis führen
soll. Der Fühler
misst den ist-Wert
x und meldet
diesen an den
Regler.
Eine Blackbox [ englisch schwarzer Kasten ] ist ein grafisches Box-Symbol für Systemkomponenten, wobei der innere
Aufbau des Kasten nicht bekannt, aber die äusseren Reaktionen aus Eingangssignale gemessen, untersucht und beschrieben
werden können. Wird eine Blackbox unterteilt, so ergeben sich für die inneren Komponenten äussere Reaktionen ( innere
Untersuchungen ). Jede Verfeinerung erhöht die Gesamtkomplexität aller möglichen Wechselwirkungen.
Kybernetik bezeichnet heute oft interdisziplinäre Foschungsaktivitäten ( z.B. Aufbau von neuralen Netze in Medizin
Psychologie, Informatik ) und weniger ein abgetrenntes, eigenständiges Forschungsgebiet.
Beispiel:
Im menschlichen Körper koordiniert z.B. das Nervensystem ( Gehirn ) die Verarbeitung der
Informationen. Natürliche Prozesse ( 2.Hauptsatz der Thermodynamik ) streben einen Zustand der
Unordnung oder des Chaos an. Die Auswahl einer bestimmten Botschaft hängt von der Vielfalt der
Wahlfreiheit einer Aktion ab ( Entropie ist das Maß der Wahrscheinlichkeit, mehr Chaos führt zur
Erhöhung der Entropie ). In diesem Bild kann Leben nur materiell und als Maschine beschrieben
werden. Es gibt keine Gefühle, Willen, Geist. Ein zielgerichtetes Verhalten von Menschen bedingt zur
Aufrechterhaltung von der Ordnung impizite Steuerungsmechanismen.
Vielfach können Eigenschaften und Verhaltensweisen von realer Systeme aus unterschiedlichen Wissenschaftbereichen
fachübergreifend aus einer zusammenfassenden Modellvorstellung behandelt und verstanden werden. Bescheibende ModellIdentität entstehen durch Reduktion von Komplexität ( Selektion von Komponenten ) und der Erfassung und Behandlung von
Wechselwirkungen zwischen den Komponenten.
Wissenschaftliche Untersuchung ( Kybernetik ) umfassen Psychologie, künstlicher Intelligenz, Servomechanismen,
Wirtschaft, Neurophysiologie, Systemsteuerung und sozialen Systemen
Um die Gleichartigkeit von ähnlichen Erscheinungen in ganz unterschiedlichen Bereichen eines abstrakten kybernetischen
Systems zu finden, werden vorrangig die Aufnahme, Übertragung, Rückkopplung von Informationen betrachtet. Zu ihren
Hauptmethoden zählen Analogie- und Modellverfahren ( z.B. Blackboxmethode ). Zentrale Begriffe sind System,
Information, Steuerung und Regelung.
Hauptdisziplinen sind:
●
●
●
●
●
●
Steuerungstheorie und Regelungstheorie
Systemtheorie
Informationstheorie und Automatentheorie
Zuverlässigkeitstheorie
Algorithmenheorie und Spieltheorie
künstliche Intelligenz
Beispiele
Die spezielle Kybernetik behandelt die Theorie und Konstruktion von lernenden ( sich selbst organisierenden ) Automaten
und sich selbst reproduzierenden Maschinen ( lernende Automaten ).
Die angewandte Kybernetik versucht empirischer Sachverhalte im kybernetischen Zusammenhang zu erklären ( in Technik,
Ökonomie, Biologie, Bionik, Ökologie, Medizin, Soziologie, Pädagogik, Psychologie, Linguistik ).
Die politische Kybernetik ( Talcott Parsons, David Eastons, Gabriel A.Almonds und Karl W.Deutschs ) als
politikwissenschaftliches Theorie- und Analysekonzept untersucht wechselseitige Rückkopplungen und Steuerungsprozesse (
Umweltproblematik, Globalisierung der Wirtschaft, Bevölkerungswachstum, Migration ) innerhalb eines politischen Systems
( Beziehungsgeflechten ) ( Wie und dem Warum, Theorien des politischen Handelns, politischer Entscheidung und Planung
).
Für Niklas Luhmann (1927-1998) ist ein soziales System ein reales System, das durch beobachtung das soziale System selbst
bestimmt ( selbstreferentielle Systeme ). Der Mensch gehört zu seiner Umwelt und beide sind Teil des sozialen System. In
diesem Sinne sind rigide Ideologien ( als geschlossenes System ohne Austausches mit ihrer Umwelt ) kein Teil eines sozialen
System. Nach Luhmann ( Theorie der Gesellschaft ) besitzt die moderne Gesellschaft kein Zentrum ( weder in Politik, noch
in Moral oder Wirtschaft ), das alle anderen Gesellschaftsbereiche erklären kann. Eine Gesellschaftstheorie kann nicht auf
einige Bereiche eingeschränkt werden ( wie z.B. Religion, Wirtschaft, Recht ). Jedes System arbeitet spezifisch:
●
●
●
●
Das Wirtschaftssystem funktioniert über das Medium Geld ( Gewinnoptimierung )
Das Rechtssystem über erlassene Gesetze ( Machtmonopol des Staates )
Die Menschen als psychische Systeme über Bewusstsein
Die Religionssysteme über einen bekennenden Glauben
Humberto R.Maturana und Francesco J.Varela versuchen die biologische Systemtheorie ( Neurophysiologie ) in den
Sozialwissenschaften anzuwenden.
Normen
Was ist eine normal?
Im Alltag verhalten sich die Menschen i.a. "funktional-normal". Der Einzelne versucht seine Verhaltensweisen ( mit seiner
kognitiven Kompetenzen ) zu bewerten um sich "angepasst und normal" zu verhalten. Normal ist, was häufig vorkommt (
z.B. Alkohol ). Normal ist, was "im gesellschaftlichen Funktionieren" dem eigenen, wünschenswerten Ideal entspricht.
Normal ist, was als gesellschaftliche Idealnormen erkennbar wird ( z.B. Schönheitsideale ). Schulische Leistungskriterien
und Anforderungen zeigen die vielen Unterschiede auf von Erzieher, Eltern, Lehrer, Ausbilder ( individuelle
Normvorstellungen, Bezugsnormen des Lehrenden, Erwartungsnormen der Gesellschaft, Bedürfnissen und Zielsetzungen des
Einzelnen, Idealnormen und das durchschnittliche Verhalten ).
Was ist eine Norm?
Allgemein beruhen die Wechselwirkungen von System-Komponenten auf Vereinbarungen. Damit z.B. im Fertigungsbau (
Maschinenbau ) unterschiedliche Hersteller Schrauben fertigen können, müssen Durchmesser und Gewindeart ( und vieles
mehr ) "genormt" sein. Die Einhaltung der Norm "garantiert" die Verwendbarkeit. Im Informations- und Medienzeitalter
braucht auch die Kommunikation zahlreiche vereinbarungen ( einheitliche Buchstaben, Schrift, Sprache, usw. ). Ein
Austausch von Informationen ist nur auf der Grundlage von Vereinbarungen möglich. Z.B. macht die Unterhaltung von 2
Betrunkenen ( in unterschiedlichen Sprachen ) wenig Sinn.
Genormt wird nur, was in einem Gefüge verwendet und genutzt werden kann. Standards und Normen kennzeichnen einen
gewissen Abschluss von Erfahrungen. Neue Erfindungen und inovative Entwicklungen erweitern den möglichen
Gestaltungsraum, ( Erweitern und Ergänzen von bestehenden Normen ). Normen für technische Komponenten und Geräte
orientieren sich an sachlichen Bezügen. Die meisten nationalen und internationalen Normungsinstitutionen wurden im im
20.Jahrhundert gegründet und dienem dem Zweck die Austauschbarkeit von Komponenten und Erfahrungen zu fördern.
Durch Normen wird der Warenverkehr vereinfacht ( bei "Normenchaos" erschwert ).
Normung ist mit Rationalisierung der industriellen Massenproduktion und Vereinfachung des Warenverkehrs verknüpft und
eine Vorbedingung freie eine frei Wirtschaft ( Globalisierung ). Das Deutsche Institut für Normung ( DIN ) erklärt ( definiert
) den Begriff Normung gemäss:
Nach DIN 820-1 ist Normung die planmäßige, durch interessierte Kreise gemeinschaftlich
durchgeführte Vereinheitlichung von materiellen und immateriellen Gegenständen zum Nutzen der
Allgemeinheit; sie darf nicht zu einem wirtschaftlichen Sondervorteil Einzelner führen.
Normung fördert vor allem die Rationalisierung, Regelung, Kommunikationsverbesserung und
Qualitätssicherung in Wirtschaft, Technik, Wissenschaft und Verwaltung; sie soll überdies der
Sicherheit des Menschen, dem Schutz der Umwelt und der Qualitätsverbesserung in allen
Lebensbereichen dienen.
Zur Effizienzsteigerung und Kostensenkung durch Normung kommt es etwa durch die
Austauschbarkeit oder Vereinbarkeit genormter Produkte, die Verringerung der Typenvielfalt, die
Erleichterung der Lagerhaltung und des Warenverkehrs.
Normen sind darüber hinaus als Beschreibung technischer Sachverhalte für Gesetzgebung und
Rechtsverkehr von Bedeutung.
DIN-Normen enthalten in der Hauptsache Angaben, Anweisungen oder Anforderungen für die Herstellung, Wartung oder
Handhabung von Gegenständen, Geräten oder Anlagen, den Ablauf oder die Ausführung von Vorgängen oder
Dienstleistungen, die Qualität oder Qualitätsprüfung, -sicherung oder -verbesserung technischer Produkte, die Sicherheit
oder Gesundheit des Menschen oder den Schutz der Umwelt.
Einheiten
Für die Objektivierung von vergleichenden Messungen sind Basis-Einheiten definiert. In Industrienationen ist das
Internationale bzw. das SI-Einheitensystem ( Système international ) verbindlich. Durch das "Gesetz über Einheiten im
Meßwesen" vom 2.7.1969 und der Ausführungsverordnung vom 26.6.1970 wurde das SI-Einheitensystem in der BRD
verbindlich eingeführt. Außer seinen 6 Basiseinheiten ( Meter, Kilogramm, Sekunde, Ampere, Kelvin, Mol, candela m, kg, s,
A, K mol, und cd werden auch die abgeleiteten Einheiten N, Pa, J, W und Pa s benutzt.
1 t = 1000 kg
Masse
Volumen 1 l = 103 m3
1 h = 60 min = 3600 s
Zeit
Temperatur1 °C = 1 K
differenz
1 bar = 105 Pa Winkel
Druck
1° = PI rad/180
Für die Einheit 1 rad = 1 m/m darf nach DIN 1301 bei Zahlenrechnungen auch 1 stehen. Nach DIN 1301 können Vorsätze
für dezimale Vielfache und Teile verwendet werden:
Abkürzung: E
P
T
G
M
k
h
da
d
c
m
µ
n
p
f
a
Kurzname: Exa Peta Tera Giga Mega Kilo Hekto Deka Dezi Zenti Milli Mikro Nano Piko Femto Atto
Wert: 1018 1015 1012 109
106
103
102
101 10-1 10-2 10-3
10-6
10-9 10-12 10-15 10-18
Nach DIN 1314 wird der Druck p meist in der Einheit bar angegeben und zählt vom Nullpunkt aus. Druckdifferenzen
werden durch die Formelzeichen, nicht aber durch die Einheit gekennzeichnet. Dies gilt besonders für die
Manometerablesung bzw. atmosphärischen Druckdifferenzen.
Nationale Normungsinstitutionen
1917 wurde in Deutschland der Normalienausschuß für den Allgemeinen Maschinenbau gegründet
1926 in Deutscher Normenausschuß e.V. ( DNA ) umbenannt wurde.
1936 wurden die Normen staatlich verbindlich.
1975 erfolgte eine Umbenennung in DIN = Deutsches Institut für Normung e.V. und die Anerkennung als nationale
Normungsinstitution der Bundesrepublik Deutschland
1990 übernahm das DIN die gesamtdeutsche Normung. DIN hat die Rechtsform eines eingetragenen, gemeinnützigen
Vereins mit Sitz in Berlin. Mitglieder ( etwa 6000 ) können Firmen, Verbände, interessierte Körperschaften, Behörden und
Organisationen aber keine Einzelpersonen sein. Die Normungsarbeit wird in 4600 Arbeitsausschüssen von etwa 28 500
Fachleuten ( ehrenamtliche Mitarbeiter von Herstellern, Handel, Handwerk, Verbraucher, Behörden,
Wissenschaftseinrichtungen ) geleistet und von 1000 hauptamtlichen Mitarbeitern koordiniert. DIN finanziert sich zu etwa
60% aus dem eigenen Beuth-Verlag ( Normen, Normentwürfe und DIN-Taschenbücher ). Die eigene Normungsarbeit ist in
DIN 820-4) festgelegt und ausgerichtet an Freiwilligkeit, Öffentlichkeit, Beteiligung aller interessierten Kreise, Konsens,
Einheitlichkeit und Widerspruchsfreiheit, Ausrichtung am Stand der Technik, an den wirtschaftlichen Gegebenheiten und am
allgemeinen Nutzen sowie Internationalität.
Internationale Normungsinstitutionen
1906 Genf: International Electrotechnical Commission ( IEC )
1926 Genf: International Federation of the National Standardizing Associations ( ISA )
1947 International Organization for Standardization ( ISO, ersetzte die ISA ). Die ISO besteht aus etwa 120 nationalen
Normungsinstitutionen. Die Internationale Fernmelde-Union ( IFU ) ist für Telekommunikation zuständig.
1961 Brüssel: das Europäische Komitee für Normung ( CEN, Comité Européen de Normalisation; nicht staatliche,
gemeinnützige Vereinigung; Deutsches Mitglied ist das DIN )
1961 Brüssel: Europäische Komitee für elektrotechnische Normung ( CENELEC, Comité Européen de Normalisation
Electrotechnique; nicht staatliche, gemeinnützige Vereinigung; Deutsche Mitglieder sind die DKE = Deutsche
Elektrotechnische Kommission und der VDE = Verband Deutscher Elektrotechniker )
1982 Zusammenschluss von CEN und CENELEC zur Gemeinsamen Europäischen Normungsinstitution. CEN/CENELECMitglieder übernehmen ( soweit möglich ) die europäischen Normen ( EN ) als nationale Normen. Im Bereich der
Telekommunikation sorgt das Europäische Institut für Telekommunikationsnormen ( ETSI, Institut Européen des Normes de
Télécommunication, etwa 12000 europäische Normen ) in enger Zusammenarbeit mit CEN/CENELEC für europaweite
Normen.
DFÜ-Normen schafft die CCITT ( ComitConsultatif International Télégraphique et Téléphonique, Genf, nationalen
Behörden, privaten Firmen sowie nationalen und internationalen wissenschaftlichen Organisationen ) ständiges Organ der
internationalen Fernmeldeunion ( Abkürzung ITU ). Das CCITT ist 1993 in der ITU aufgegangen.
Beispiele für Normen
X.400
An international message-handling standard for connecting e-mail networks and for connecting users to email networks. X.400 is published by the International Telegraph and Telephone Consultative Committee (
CCITT standards body, now called the International Telecommunications Union (ITU). The X.400
Application Programming Interface Association XAPIA defines programming interfaces to X.400. MAPI
applications are fully interoperable with X.400 messaging applications.
X.435
Electronic Data Interchange (EDI): A standard for integrating data with various native formats into a, which
has been defined by the International Telegraph and Telephone Consultative Committee standards body,
now called the International Telecommunications Union (ITU), and is implemented in the X.435 messagehandling standard. X.435 is an international message-handling standard that is published by the
International Telegraph and Telephone Consultative Committee CCITT standards body, now called the
International Telecommunications Union (ITU), and that implements the Electronic Data Interchange (EDI)
standard for integrating data with various native formats into a message.
X.400
Schicker, Pietro, "Message Handling Systems, X.400", Message Handling Systems and Distributed
Applications, E. Stefferud, O-j. Jacobsen, and P. Schicker, eds., North-Holland, 1989, pp. 3-41.
X.500
An international message-handling standard for directory services, published by the International Telegraph
and Telephone Consultative Committee CCITT standards body, now called the Internal
Telecommunications Union (ITU).
X.509
An international message-handling standard for message authentication and encryption. X.509 is published
by the International Telegraph and Telephone Consultative Committee CCITT standards body, now called
the Internal Telecommunications Union (ITU).
XAPIA
The X.400 Application Programming Interface Association, the standards-setting body for programming
interfaces to X.400 components. XAPIA also defines the Common Messaging Calls inteface component.
US-ASCII
Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986.
ISO-646
International Standard--Information Processing--ISO 7-bit coded character set for information interchange,
ISO 646:1983.
ISO-2022
International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension
techniques, ISO 2022:1986.
ISO-8859
Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1,
ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3,
1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988.
Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part 8:
Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990. <
ISO 9241-10
Grundsätze der Dialoggestaltung
ISO/DIS 9241Richtlinien zur Gebrauchstauglichkeit
11
ISO/DIS 9241Informationsdarstellung
12
ISO/DIS 9241Benutzerführung
13
ISO 9241-14
Dialogführung über Menüs
ISO/DIS 9241- Dialogführung über Kommandosprachen.
15
(DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO).
ISO/DIS 9241- Dialogführung über direkte Manipulation.
1+
(DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO).
ISO/DIS 9241- Dialogführung über Bildschirmformulare
17
(DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO).
ISO 9241
1998 verabschiedete die ISO die Ergonomie-Normenreihe. "Ergonomische Anforderungen an
Bürotätigkeiten mit Bildschirmgeräten"
ISO/IEC 10646 Unicode
ISO-Norm
13407
Beschreibt einen benutzerorientierten Entwicklungszyklus ( 1998 verabschiedet ). Unter dem Titel
"Benutzer-orientierte Gestaltung interaktiver Systeme" formuliert die Norm für Hard- und Software
Kriterien, die die Anpassung interaktive Systeme an den Benutzer ermöglichen sollen.
RFC 783
Sollins, K., "TFTP Protocol (revision 2)", RFC 783, MIT, June 1981.
RFC-821
Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821, USC/Information Sciences Institute, August
1982.
RFC822
Standard of the Format of Internet Text Messages ,D.Crocker,1982: Legt den Aufbau des Kopfes einer EMail-Nachricht fest,z.b. die Codierung von Sender- und Empfaengeradresse.
RFC1521
MIME(Multipurpose Internet Mail Extensions)Part One: Definiert ein Schema fuer die Unterbringung
verschiedenartigster Daten innerhalb des Hauptteils einer E-Mail-Nachricht. Beispilesweise von Grafiken
oder ausfuehrbaren Dateien. Gilt nicht fuer E-Mail ,sondern natuerlich auch fuer das Web.
RFC1522
MIME(Multipurpose Internet Mail Extensions)Part Two: Der zweite Teil der MIME-Definition. Definiert
den Kodierungsmechanismus fuer Zeichen,die ueber den 7-Bit-Us_ASCII-Zeichensatz hinausgehen,in den
Kopffeldern von E-Mail-Nachrichten.
RFC 2617
Digest Access Authentication
GIF
Graphics Interchange Format (Version 89a), Compuserve, Inc., Columbus, Ohio, 1990.
MPEG
Video Coding Draft Standard ISO 11172 CD, ISO IEC/TJC1/SC2/WG11 (Motion Picture Experts Group),
May, 1991.
PCM
CCITT, Fascicle III.4 - Recommendation G.711, Geneva, 1972, "Pulse Code Modulation (PCM) of Voice
Frequencies".
POSTSCRIPT Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, 1985.
POSTSCRIPT2 Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, Second Edition, 1990.
ATK
Borenstein, Nathaniel S., Multimedia Applications Development with the Andrew Toolkit, Prentice-Hall,
1990.
ECMA-158
December 1997, Standardizing Information and Communication Systems, Portable Common Tool
Environment (PCTE) - C Programming Language Binding
DIN 1304
Formelzeichen
DIN 66234 (
Software-Ergonomie ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG
Teil 8)
von 1990 ( DIN 66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter Dialog
EG ( 90/270/ ) zwischen Mensch und Computer erfüllen soll. Arbeitgeber sollen benutzerfreundliche Software einsetzen,
die der ausführenden Tätigkeit angepasst ist ( verständliche Format, angemessenes Bearbeitungtempo,
Rückmeldungen über Ergebnisse der Abläufe ).
...
Sinnbilder Schaltpläne von Leitungen, Schaltern, Maschinen und Aggregate DIN-Normen oder den
Richtlinien entnommen.
ECMA Standards
ECMA - Standardizing Information and Communication Systems ( ECMA blue cover)
Stichwort
Kommentar
ECMA-6
7-Bit Coded Character Set, 6th edition (December 1991)
ECMA-13
File Structure and Labelling of Magnetic Tapes for Information Interchange, 4th edition (December
1985)
ECMA-35
Character Code Structure and Extension Techniques, 6th edition (December 1994)
ECMA-43
8-Bit Coded Character Set Structure and Rules, 3rd edition(December 1991)
ECMA-48
Control Functions for Coded Character Sets, 5th edition(June 1991)
ECMA-74
Measurement of Airborne Noise Emitted by Information Technology and Telecommunications
Equipment, 6th edition (December 1999)
ECMA-94
8-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabets No. 1 to No. 4, 2nd edition (June
1986)
ECMA-99
Data Interchange on 130 mm Flexible Disk Cartridges Using MFM Recording at 13 262 ftprad on Both
Sides, 3,8 Tracks per mm (September 1985)
ECMA-100
Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 7 958 ftprad on
80 Tracks on Each Side - ISO Type 301, 2nd edition (December 1988)
ECMA-106
Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point - Circuit
Mode Basic Services (SSIG-BC), 3rd edition (December 1993)
ECMA-107
Volume and File Structure of Disk Cartridges for Information Interchange, 2nd edition (June 1995)
ECMA-108
Measurement of High-Frequency Noise emitted by Information Technology and Telecommunications
Equipment, 3rd edition (December 1996)
ECMA-109
Declared Noise Emission Values of Information Technology and Telecommunications Equipment, 4th
edition (December 1996)
ECMA-113
8-Bit Single-Byte Coded Graphic Character Sets - Latin/Cyrillic Alphabet, 3rd edition (December 1999)
ECMA-114
8-Bit Single-Byte Coded Graphic Character Sets - Latin/Arabic Alphabet, 2nd edition (December 2000)
ECMA-118
8-Bit Single-Byte Coded Graphic Character Sets - Latin/Greek Alphabet (December 1986)
ECMA-119
Volume and File Structure of CDROM for Information Interchange, 2nd edition (December 1987)
ECMA-120
Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges, 3rd edition (December 1993)
ECMA-121
8-Bit Single-Byte Coded Graphic Character Sets - Latin/Hebrew Alphabet, 2nd edition (December 2000)
ECMA-125
Data Interchange on 90 mm Flexible Disk Cartridges Using MFM Recording at 15 916 ftprad on
80 Tracks on Each Side - ISO Type 302 (December 1987)
ECMA-128
8-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabet No. 5, 2nd edition (December 1999)
ECMA-130
Data Interchange on Read-only 120 mm Optical Data Disks (CD-ROM), 2nd edition (June 1996)
ECMA-133
Private Integrated Services Network (PISN) - Reference Configurations for PISN Exchanges (PINX),
2nd edition (December 1998)
ECMA-139
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS
Format (June 1990)
ECMA-142
Private Integrated Services Network (PISN) - Circuit Mode 64kbit/s Bearer Services - Service
Description, Functional Capabilities and Information Flows (BCSD), 2nd edition (June 1997)
ECMA-143
Private Integrated Services Network (PISN) - Circuit Mode Bearer Services - Inter-Exchange Signalling
Procedures and Protocol (QSIG-BC), 3rd edition (June 1997)
ECMA-144
8-Bit Single-Byte Coded Character Sets - Latin Alphabet No. 6, 3rd edition (December 2000)
ECMA-145
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording (December
1990)
ECMA-146
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording DATA/DAT Format (December 1990)
ECMA-147
Data Interchange on 90 mm Flexible Disk Cartridges using MFM Recording at 31 831 ftprad on
80 Tracks on Each Side - ISO Type 303 (December 1990)
ECMA-148
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Identification Supplementary Services (ISSD), 3rd edition (June 1997)
ECMA-149
Portable Common Tool Environment (PCTE) - Abstract Specification, 4th edition (December 1997)
ECMA-150
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDSDC Format using 60 m and 90 m Length Tapes, 2nd edition (June 1992)
ECMA-151
Data Compression for Information Interchange - Adaptive Coding with Embedded Dictionary - DCLZ
Algorithm (June 1991)
ECMA-152
Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges - Extended Format, 2nd edition
(December 1993)
ECMA-153
Information Interchange on 130 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM)
Type, using the Magneto-Optical Effect, 2nd edition (June 1994)
ECMA-154
Data Interchange on 90 mm Optical Disk Cartridges, Read only and Rewritable, M.O., 2nd edition (June
1994)
ECMA-155
Private Integrated Services Networks - Addressing, 2nd edition (June 1997)
ECMA-156
Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Keypad
Protocol for the Support of Supplementary Services (SSIG-KP), 2nd edition (June 1993)
ECMA-157
Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point Identification Supplementary Services (SSIG-ID), 2nd edition (June 1993)
ECMA-158
Portable Common Tool Environment (PCTE) - C Programming Language Binding, 4th edition
(December 1997)
ECMA-159
Data Compression for Information Interchange - Binary Arithmetic Coding Algorithm (December 1991)
ECMA-160
Determination of Sound Power Levels of Computer and Business Equipment Using Sound Intensity
Measurements; Scanning Method in Controlled Rooms, 2nd edition (December 1992)
ECMA-161
Private Telecommunication Networks (PTN) - Signalling at the S Reference Point - Generic Feature Key
Management Protocol for the Control of Supplementary Services (SSIG-FK), 2nd edition (June 1993)
ECMA-162
Portable Common Tool Environment (PCTE) - Ada Programming Language Binding, 4th edition
(December 1997)
ECMA-163
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Name Identification Supplementary Services (NISD), 3rd edition (September 1997)
ECMA-164
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Name Identification
Supplementary Services (QSIG-NA), 3rd edition (September 1997)
ECMA-165
Private Integrated Services Network (PISN) - Generic Functional Protocol for the Support of
Supplementary Services - Inter-Exchange Signalling Procedures and Protocol (QSIG-GF),
4th edition(June 2001)
ECMA-167
Volume and File Structure for Write-Once and Rewritable Media using Non-Sequential Recording for
Information Interchange, 3rd edition(June 1997)
ECMA-168
Volume and File Structure of Read-Only and Write-Once Compact Disk Media for Information
Interchange, 2nd edition (December 1994)
ECMA-169
8 mm Wide Magnetic Tape Cartridge Dual Azimuth Format for Information Interchange - Helical Scan
Recording (June 1992)
ECMA-170
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS
Format Using 60 m and 90 m Length Tapes (June 1992)
ECMA-171
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording DATA/DAT-DC Format Using 60 m and 90 m Length Tapes (June 1992)
ECMA-173
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Diversion Supplementary Services (CFSD), 2nd edition (June 1997)
ECMA-174
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Diversion
Supplementary Services (QSIG-CF), 2nd edition (June 1997)
ECMA-175
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Path Replacement Additional Network Feature (ANF-PRSD), 3rd edition (December 1998)
ECMA-176
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Path Replacement
Additional Network Feature (QSIG-PR), 3rd edition (December 1998)
ECMA-177
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Transfer Supplementary Service (CTSD), 2nd edition (September 1997)
ECMA-178
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Transfer
Supplementary Service (QSIG-CT), 2nd edition (September 1997)
ECMA-179
Services for Computer Supported Telecommunications Applications (CSTA) Phase I (June 1992)
ECMA-180
Protocol for Computer Supported Telecommunications Applications (CSTA) Phase I (June 1992)
ECMA-182
Data Interchange on 12,7 mm 48-Track Magnetic Tape Cartridges - DLT1 Format (December 1992)
ECMA-183
Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1 Gigabyte per Cartridge (December
1992)
ECMA-184
Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1,3 Gigabytes per Cartridge (December
1992)
ECMA-185
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Completion Supplementary Services (CCSD), 2nd edition (June 1997)
ECMA-186
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Completion
Supplementary Services (QSIG-CC), 3rd edition (February 2000)
ECMA-189
Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM)
Type using the SSF Method (June 1993)
ECMA-190
Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM)
Type using the CCS Method (June 1993)
ECMA-191
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Offer Supplementary Service (COSD), 2nd edition (June 1997)
ECMA-192
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Offer
Supplementary Service (QSIG-CO), 3rd edition (June 1997)
ECMA-193
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Do Not Disturb and Do Not Disturb Override Supplementary Services (DND(O)SD), 2nd edition (June
1997)
ECMA-194
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Do Not Disturb and
Do Not Disturb Override Supplementary Services (QSIG-DND(O)), 3rd edition (June 1997)
ECMA-195
Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 2 Gigabytes per Cartridge, 2nd edition
(June 1995)
ECMA-196
Data Interchange on 12,7 mm 36-Track Magnetic Tape Cartridges (December 1993)
ECMA-197
Data Interchange on 12,7 mm 112-Track Magnetic Tape Cartridges - DLT2 Format (December 1993)
ECMA-198
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-2
Format using 120 m Length Tapes, 2nd edition (June 1995)
ECMA-201
Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 230 Megabytes per Cartridge, 2nd
edition (December 1994)
ECMA-202
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Intrusion Supplementary Service (CISD), 2nd edition (June 1997)
ECMA-203
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Intrusion
Supplementary Service (QSIG-CI), 3rd edition (June 1997)
ECMA-205
Commercially Oriented Functionality Class for Security Evaluation (COFC) (December 1993)
ECMA-206
Association Context Management including Security Context Management (December 1993)
ECMA-207
Data Interchange on 90 mm Flexible Disk Cartridges - 326 Data Tracks on each Side - Capacity: 21
Mbytes - ISO Type 305 (June 1994)
ECMA-208
System-Independent Data Format - SIDF (December 1994)
ECMA-209
Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT3 Format (December 1994)
ECMA-210
12,65 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DATAD3-1 Format, 2nd edition (December 1995)
ECMA-211
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Advice of Charge Supplementary Services (AOCSD), 2nd edition (June 1997)
ECMA-212
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Advice of Charge
Supplementary Services (QSIG-AOC), 2nd edition (June 1997)
ECMA-213
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Recall Supplementary Service (RESD), 2nd edition (June 1997)
ECMA-214
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Recall Supplementary
Service (QSIG-RE), 2nd edition (June 1997)
ECMA-215
Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange
Signalling Protocol - Cordless Terminal Incoming Call Additional Network Feature (QSIG-CTMI), 2nd
edition (September 1997)
ECMA-216
Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange
Signalling Protocol - Cordless Terminal Location Registration Supplementary Service (QSIG-CTLR),
2nd edition (September 1997)
ECMA-217
Services for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994)
ECMA-218
Protocol for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994)
ECMA-219
Authentication and Priviledge Attribute Security Application with Related Key Distribution Functions Part 1, 2 and 3, 2nd edition (March 1996)
ECMA-220
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Interception Additional Network Feature (ANF-CINTSD), 2nd edition (June 1997)
ECMA-221
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Interception
Additional Network Feature (QSIG-CINT), 2nd edition (June 1997)
ECMA-222
Adaptive Lossless Data Compression Algorithm(June 1995)
ECMA-223
Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 385 Megabytes per Cartridge (June
1995)
ECMA-224
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Transit Counter Additional Network Feature (ANF-TCSD), 2nd edition (June 1997)
ECMA-225
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Transit Counter
Additional Network Feature (QSIG-TC), 2nd edition (June 1997)
ECMA-226
Private Integrated Services Network (PISN) - Mapping Functions for the Employment of Dedicated
Circuit Mode Connections as Inter-PTNX Connections (MAPPING-CM-STATIC) (June 1995)
ECMA-230
Portable Common Tool Environment (PCTE) - IDL Binding (Interface Definition Language), 2nd edition
(December 1997)
ECMA-231
Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 4 Format (December 1995)
ECMA-232
Private Integrated Services Network (PISN) - Profile Standard for the Connection of Radio Paging
Equipment (RPE) to a PISN (December 1995)
ECMA-233
Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange
Signalling Protocol - Cordless Terminal Outgoing Call Additional Network Feature (QSIG-CTMO), 2nd
edition (September 1997)
ECMA-234
Application Programming Interface for Windows (APIW) (December 1995)
ECMA-235
The ECMA GSS-API Mechanism (March 1996)
ECMA-236
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-3
Format using 125 m Length Tapes (June 1996)
ECMA-238
Data Interchange on 130 mm Optical Disk Cartridge of Type WORM (Write Once Read Many) using
Irreversible Effects - Capacity: 2,6 Gbytes per Cartridge (June 1996)
ECMA-239
Data Interchange on 90 mm Optical Disk Cartridges - HS-1 Format - Capacity: 650 Megabytes per
Cartridge (June 1996)
ECMA-240
Data Interchange on 120 mm Optical Disk Cartridges using Phase Change PD Format - Capacity: 650
Mbytes per Cartridge (June 1996)
ECMA-241
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Message Waiting Indication Supplementary Service (MWISD), 4th edition (February 2002)
ECMA-242
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Message Waiting
Indication Supplementary Service (QSIG-MWI), 3rd edition (December 1998)
ECMA-243
Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange
Signalling Protocol - Cordless Terminal Authentication Supplementary Services (QSIG-CTAU), 2nd
edition (September 1997)
ECMA-244
Private Integrated Services Network (PISN) - Mapping Functions for the Employment of a Circuit Mode
Basic Service and the Supplementary Service User-to-User Signalling as a pair of On-demand InterPINX Connections (Mapping-UUS), 2nd edition (September 2000)
ECMA-245
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - PINX Clock
Synchronization (SYNC-SIG), 2nd edition (September 1997)
ECMA-246
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-1
Format, 2nd edition(June 1998)
ECMA-247
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - HH-1
Format, 2nd edition(June 1998)
ECMA-248
12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-1
Format, 2nd edition (June 1998)
ECMA-249
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DA-2
Format, 2nd edition (June 1998)
ECMA-250
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Common Information Additional Network Feature (ANF-CMNSD), 2nd edition (December 1998)
ECMA-251
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Common Information
Additional Network Feature (QSIG-CMN), 2nd edition (December 1998)
ECMA-252
Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Transit
Counter Additional Network Feature (B-QSIG-TC) (December 1996)
ECMA-253
Private Integrated Services Network (PISN) - Mapping Functions for the Employement of 64 kbit/s
Circuit Mode Connection with 16 kbit/s Sub-multiplexing (Mapping/16), 2nd edition (September 2000)
ECMA-254
Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Generic
Functional Protocol (B-QSIG-GF), 2nd edition (December 1999)
ECMA-258
Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 3-XT Format (June 1997)
ECMA-259
Data Interchange on 12,7 mm 208-Track Magnetic Tape Cartridges - DLT 5 Format (June 1997)
ECMA-260
Data Interchange on 356 mm Optical Disk Cartridges - WORM, using Phase Change Technology
Capacity: 14,8 and 25 Gbytes per Cartridge (June 1997)
ECMA-261
Broadband Private Integrated Services Network (B-PISN) - Service Description - Broadband Connection
Oriented Bearer Services (B-BCSD) (June 1997)
ECMA-262
ECMAScript Language Specification, 3rd edition (December 1999)
ECMA-263
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Priority Interruption and Call Priority Interruption Protection Supplementary Services (CPI(P)SD),
2nd edition (December 1998)
ECMA-264
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Priority
Interruption and Call Priority Interruption Protection Supplementary Services (QSIG-CPI(P)), 2nd
edition (December 1998)
ECMA-265
Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol Signalling ATM Adaptation Layer (B-QSIG-SAAL) (September 1997)
ECMA-266
Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Basic
Call/Connection Control (B-QSIG-BC) (September 1997)
ECMA-267
120 mm DVD - Read-Only Disk, 3rd edition (April 2001)
ECMA-268
80 mm DVD - Read-Only Disk, 3rd edition (April 2001)
ECMA-269
Services for Computer Supported Telecommunications Applications (CSTA) Phase III, 4th edition (June
2000)
ECMA-270
Portable Common Tool Environment (PCTE) - Mapping from CASE Data Interchange Format (CDIF) to
PCTE (December 1997)
ECMA-271
Extended Commercially Oriented Functionality Class for Security Evaluation (E - COFC), 2nd edition
(December 1999)
ECMA-272
120 mm DVD Rewritable Disk (DVD-RAM), 2nd edition (June 1999)
ECMA-273
Case for 120 mm DVD-RAM Disks (February 1998)
ECMA-274
Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes,
2nd edition (June 1999)
ECMA-275
Measurement of structure-borne vibration induced by small air moving devices (AMDs) (June 1998)
ECMA-276
Private Integrated Services Network (PISN) - Reference Configuration for PINX Extension Lines (June
1998)
ECMA-277
Private Integrated Services Network (PISN) - Circuit Emulation Specification - Emulation of Basic
Access by ATM Networks (June 1998)
ECMA-278
Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridge - Parallel Serpentine Format, 2nd
edition (June 2000)
ECMA-279
80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R)
(December 1998)
ECMA-280
Data Interchange on 130 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using
Irreversible Effects - Capacity: 5,2 Gbytes per Cartridge (December 1998)
ECMA-281
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Private User Mobility (PUM) - Registration Supplementary Service (PUMRSD), 2nd edition(June 2000)
ECMA-282
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility
(PUM) - Registration Supplementary Service (QSIG-PUMR), 2nd edition (June 2000)
ECMA-283
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Private User Mobility (PUM) - Call Handling Additional Network Features (PUMCHSD), 2nd edition
(June 2000)
ECMA-284
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility
(PUM) - Call Handling Additional Network Features (QSIG-PUMCH), 2nd edition (June 2000)
ECMA-285
Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III, 2nd edition (June
2000)
ECMA-286
Data Interchange on 12,7 mm 208-Track Magnetic Tape Cartridges - DLT 6 Format, 2nd edition (June
2000)
ECMA-287
Safety of electronic equipment (June 1999)
ECMA-288
3,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-4
Format (June 1999)
ECMA-289
Private Integrated Services Network (PISN) - Mapping Functions for the Employment of 64 kbit/s
Circuit Mode Connections with 8 kbit/s Sub-Multiplexing (Mapping/8), 2nd edition (September 2000)
ECMA-290
ECMAScript Components Specification (June 1999)
ECMA-291
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-1 with
MIC Format (December 1999)
ECMA-292
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-2 with
MIC Format (December 1999)
ECMA-293
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording MammothTape-2 Format (December 1999)
ECMA-294
B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange
Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer
Control Environment - Part 1: Protocol Specification (December 1999)
ECMA-295
B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange
Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer
Control Environment - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma
Specification (December 1999)
ECMA-296
B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange
Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 1: Protocol Specification
(December 1999)
ECMA-297
B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange
Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 2: Protocol
Implementation Conformance Statement (PICS) Proforma Specification (December 1999)
ECMA-298
Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol Separated Bearer Control (SBC) (B-QSIG-SBC) (December 1999)
ECMA-299
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Single Step Call Transfer Supplementary Service (SSCT-SD) (February 2000)
ECMA-300
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Single Step Call
Transfer Supplementary Service (QSIG-SSCT) (February 2000)
ECMA-301
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Location Registration Supplementary Service and Wireless Terminal Information
Exchange Additional Network Feature (WTMLR-SD) (June 2000)
ECMA-302
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal
Location Registration Supplementary Service and Wireless Terminal Information Exchange Additional
Network Feature (QSIG-WTMLR) (June 2000)
ECMA-303
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Call Handling Additional Network Features (WTMCH-SD) (June 2000)
ECMA-304
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal
Call Handling Additional Network Features (QSIG-WTMCH) (June 2000)
ECMA-305
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Wireless Terminal Authentication Supplementary Services (WTMAU-SD) (June 2000)
ECMA-306
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal
Authentication Supplementary Services (QSIG-WTMAU) (June 2000)
ECMA-307
Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Generic
Functional Protocol for the Support of Supplementary Services (June 2000)
ECMA-308
Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call
Transfer Supplementary Services, 2nd edition (June 2001)
ECMA-309
Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call
Diversion Supplementary Services, 2nd edition (June 2001)
ECMA-310
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Simple Dialog Supplementary Service (SDSD) (June 2000)
ECMA-311
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Simple Dialog
Supplementary Service (QSIG-SD) (June 2000)
ECMA-312
Private Integrated Services Network (PISN) - Profile Standard for the Use of PSS1 (QSIG) in Air Traffic
Services Networks, 2nd edition (June 2001)
ECMA-313
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Call Identification and Call Linkage Additional Network Feature (CIDLSD) (September 2000)
ECMA-314
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Identification
and Call Linkage Additional Network Feature (QSIG-CIDL) (September 2000)
ECMA-315
12,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-2
(December 2000)
ECMA-316
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - VXA-1
Format (December 2000)
ECMA-317
Data Interchange on 300 mm Optical Disk Cartridges of Type WORM (Write Once Read Many) Using
Irreversible Effects - Capacity: 30 Gbytes per Cartridge (December 2000)
ECMA-318
Private Integrated Services Network (PISN) - Use of QSIG at the C Reference Point between a PINX and
an Interconnecting Network (December 2000)
ECMA-319
ECMA-320
ECMA-321
ECMA-322
ECMA-323
Data Interchange on 12,7 mm - 384- Track Magnetic Tape Cartridges - Ultrium-1 Format (June 2001)
Data Interchange on 12,7 mm - 448-Track Magnetic Tape Cartridges - SDLT1 Format (June 2001)
Streaming Lossless Data Compression Algorithm (SLDC) (June 2001)
Data Interchange on 130 mm Magneto-Optical Disk Cartridges - Capacity: 9,1 Gbytes per Cartridge
(June 2001)
XML Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III (June 2001)
ECMA-324
Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows Short Message Service (SMSSD) (June 2001)
ECMA-325
Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Short Message
Service (QSIG-SMS) (June 2001)
ECMA-326
Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call
Completion Supplementary Services (June 2001)
ECMA-327
ECMA-328
ECMAScript 3rd Edition Compact Profile (June 2001)
Detection and measurement of chemical emissions from electronic equipment (August 2001)
ECMA-329
8 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-3
Format (December 2001)
ECMA-330
120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM)
(December 2001)
ECMA-331
Case for 120 mm and 80 mm DVD-RAM Disks (December 2001)
ECMA-332
Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Basic
Services (December 2001)
ECMA-333
Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through
H.323 Networks (December 2001)
ECMA-334
ECMA-335
ECMA-336
C# Language Specification (December 2001)
Common Language Infrastructure (CLI) (December 2001)
Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through IP
Networks (Mapping/IP-QSIG) (June 2002)
Historisches
einige Jahreszahlen
1941 Zuse Z3, ab etwa 1960 Einführung von Dialogbetrieb ( Stapelbetrieb mit Operator )
1960 Ken Thompson, Dennis Ritchie (Bell Labs, AT&T) u. MIT-Forscher entwickelten MULTICS, ein MehrbenutzerBetriebssystem für General Electric ( Mainframe GE645 ) Trotz Nicht-Einsatzes von MULTICS ( techn. Mängel )
Weiter-Entwicklung durch Thompson ( "Space Travel", 2 Benutzer) Verballhornung durch Brian Kernighan
"UNICS"
1969, Betriebssystem UNICS, ab 1970: Unix ( Assembler ). Gleichzeitig: Thompson u. Ritchie entwickeln Sprache
A (BCPL-* basiert), verbesserte Version B, Weiterentw. zu C.
1973, Unix erstes BS größtenteils in einer Hochsprache ( kaum 1000 Zeilen Maschinencode, portierbar ), Keine
Vermarktung von Unix wg. US-Kartell-Bestimmungen
1975, BSD-UNIX: Abkürzung für Berkeley Software Distribution-UNIX. Bezeichnung für eine UNIX-Variante (
entwickelt an der Berkeley-Universität in Kalifornien, Abgabe an Universitäten zum Selbstkostenpreis )
1980, Xenix ( Microsoft, ab Mitte 80er: Santa Cruz Operation, etwa bis 1990 )
1981 IBM bringt den ersten PC ( mit MS-DOS ) heraus: 8088-CPU, 4.77 MHz, 64 KByte Speicher, 5.25"Diskettenlaufwerk. Microsoft entwickelt dazu eine erste Version des Betriebssystems MS-DOS. Hayes bringt ein
Modem mit 1200 Bit/s heraus. Herwig Feichtinger, heute bei Shamrock, gründet mit "mc" eine der ersten ComputerZeitschriften. Novell stellt ein Netzwerk vor, mit dem mehrere Computer auf eine gemeinsame Festplatte zugreifen
können. Hewlett-Packet konstruiert den ersten 32-Bit-Mikroprozessor.
1981 MS-DOS ( Microsoft-Disc Operating System, angelehtn an CP/M 80 für 160 KByte Disketten entwickelt, Version
1.25 ( ab 1982 ) benutzt zweiseitige Disketten ( 320 KByte Kapazität );
ab 1983 MS-DOS 2.11 mit FAT-Festplatten und User-Hardware-Anpassungen durch Treiber ( in der CONFIG.SYS
);
ab 1984 MS-DOS 3.2 mit HD-Disketten ( 5.25 Zoll, 720 KByte) und die Einbindung in Netzwerke. ab 1984 MSDOS 3.3 konnten Platten mit mehr als 32 MByte verwaltet werden;
ab 1988 gab es das fehlerbehaftete MS-DOS 4.X mit DOS-Shell, Festplatten bis 2 GByte, EMS-Speicher nach dem
LIM-Standard;
ab 1991 erschien MS-DOS 5.0 mit HMA und UMA ab 1993 MS-DOS 6.X mit Zusatzprogrammen, wie OnlineKomprimierer Doublespace, einem Virenschutz- und einem Backup-Programm, Memmaker-Speicher-Optimierer, ab
6.22 als Drivespace; )
1983 Apple bringt mit "Lisa" erstmals einen per Maus bedienbaren Computer mit grafischer Oberfläche heraus. Wegen des
hohen Preises von rund 75.000 Dollar wird er ein Flop. Microsoft kündigt Windows 1.0 an, es wird erst 1985
verfügbar. Sony kündigt die 3,5"-Diskette an. IBM und Microsoft entwickeln zusammen das Betriebssystem OS/2.
Novell bringt die Netware-Software heraus. Microcom erfindet ein fehlerkorrigierendes Modem-Protokoll (MNP).
1984 POSIX ( Portable Operating System Interface for UNIX ). Schnittstellen-Standard der IEEE, der von allen UNIXDerivaten benutzt wird, dementsprechend auch von Programmen, die unter UNIX laufen beziehungsweise
Übergänge zu UNIX-Rechnern herstellen.
1988 Normung zu ANSI-C ( Komitee X3J11 ).
1991 Linux 0.02 ( Linus Torvalds entwickelt einen Kern, FIN )
1985 1985, MS präsentiert Windows 1.01;
1987, Windows 2;
1987, OS/2 von IBM / MS, zeichenorientiert
1988, OS/2 von IBM/MS mit grafischer Oberfläche
1990, Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet die
Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste kommerzielle
Internet-Provider den Dienst auf. Unter Federführung der Bundespost entsteht der Treiber-Standard CAPI 1.1 für
ISDN-Karten. James Gosling und Bill Joy beginnen mit der Entwicklung der Programmiersprache Java;
1992, Windows 3.1;
1993, Windows 3.11;
1993 Windows NT ( Windows New Technology, 32-Bit-Betriebssystem, für Workstations Windows NT 3.1, für
Windows NT 3.1 Advanced Server und Netzwerke );
1996: Windows NT 3.5, und Windows NT 4.0;
1995, Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte Plug-and-Play-Technologie, mitgeliefert
wurde der Internet-Browser Internet Explorer );
1998, Windows 98 ( Update für Windows 95, Active Desktop bindet den Webbrowser Internet Explorer, unterstützt
werden: FAT32, DVD- und MMX-Technologie, AGP (siehe Graphikkarte) USB-Anschlüsse ( Universal Serial Bus
), AGP ( Accelerated Graphics Port, 1997 Intel, direkte Verbindung von der Grafikkarte zum Prozessor sowie zum
Arbeitsspeicher, Taktfrequenz 66 MHz, AGP 1X = 266 MByte/s, AGP 2X = 533 MByte/s, AGP 4X = 1066 MByte/s,
Pipelining, 8 zusätzliche Leitungen, DIME-Auslagerungsmodus für Texturen );
2000, Windows 2000 wird in 4 Zusammenstellungen ausgeliefert: Windows 2000 Professional ( für PC und
Notebook ),
Windows 2000 Server ( einfache Netzanwendungen ),
Windows 2000 Advanced Server ( Unternehmenskritische und komplexe Netzanwendungen )
Windows 2000 Datacenter Server ( für Rechenzentren, Lagerverwaltungssysteme und Finanzsysteme );
2001, Windows ME;
2002, Windows XP
Betriebssystem
Achtung! Hier werden lediglich einige Betriebssystem-Aspekte wiederholt ( vorrangig wird auf die Veranstaltung Betriebssysteme hingewiesen )!
Ein Computer-Hardwaresystem besteht aus Mikroprozessoren, Chips, Uhren, Schaltungen, Eingabegeräten, Tastatur, Maus, Laufwerk; Ausgabegeräten,
Bildschirm, Plattenlaufwerken; Peripheriegeräten, Drucker, Modem, Netzwerkkomponenten und weiteren Komponenten.
Moderne Prozessoren können eine aufwendige Architektur haben:
Moderne Prozessoren können verschiedene Speicher-Adressiersarten ( Memory-Management: Segnmentierung, Paging ) haben:
Moderne Prozessoren können Descriptoren ( Zugriffstypen, Zugriffrechte, Privilege Level, Call Gates, Interrupt and Exception-Handling, usw. ) haben:
Ein Betriebssystem ( Operating System, Systemsoftware, Basisprogramme ) besteht aus Software mit Basisroutinen für die Hardware - Ansteuerung und die
Hardware - Resourcen - Verwaltung. Ein Betriebssystem erfüllt 2 Aufgaben:
1. Virtuelle Maschine,
2. Resourcen-Verwalter
Die Betriebssystem - Architektur ( Instruktionssatz der zentralen Verarbeitungseinheit, der Speicher- organisation, Ein/Ausgabe auf Platten und Disketten,
Bildschirm ) erfordert die (schwierige) Programmierung der Kontrollerbausteine. Diese Maschinen - Programme, wie Unterbrechungen ( interrupt ), Zeitgeber (
timer ) und die Speicherverwaltung ( memory management ) sind in den BIOS enthalten. Für den Anwender ist die Benutzung dieser Programmteile einfacher,
als die direkte Programmierung der zugrundeliegende Hardware. Für den Anwender verhaelt sich das Betriebssystem wie eine Virtuelle Maschine.
Wenn auf einem Computer mehrere Benutzer gleichzeitig arbeiten wollen, entsteht die Notwendigkeit, Speicher, Ein-/Ausgabegeraete und andere ( teure )
Komponenten zu verwalten und zu sichern. Aus dieser Sicht hat das Betriebssystem die Aufgabe, festzustellen, wer welche Resourcen verwendet, Resourcen auf
Anforderung zu gewaehren, Unterbrechungens - Informationen zu sammeln und zwischen den gegenseitig sich überschneidenden Anforderungen mehrerer
Benutzer oder Programme zu vermitteln.
Die Software - Schichten:
1. Physikalische Geräte
2. Mikroprogrammierung
3. Maschinensprache
4. Betriebssystem
5. Kommando - Interpreter, Editoren, Compiler
6. Anwendungsprogramme
Die Punkte 1, 2, 3 werden auch zu einer Hardware - Schicht zusammengefaßt. Die Punkte 4, 5 bilden die Systemprogramme. Zu den Applikationen (
Anwendungsprogrammen 6 ) gehören Datenbanken, CAD, Spiele, Banksystem, Simulatoren, usw. ).
MS-DOS
Etwa 1980 hat Jim Paterson (ausgehend vom CP/M-80) ein 6 KB umfassendes Betriebssystem QDOS (Quick and Durty Operating System) entwickelt. IBM
wollte eine neue 16-Bit-Maschine auf Intel-Basis auf den Markt bringen. Mircosoft übernahm Jim Paterson und entwickelte MS-DOS unter strenger
Geheimhaltung die Version 1.0 (1981). 1983 war die Version 2.0 ( hierarchisches Dateisystem mit 9 Sektoren für 360 kB Laufwerke, installierbare
Geraetetreiber, Bildschirmtreiber ANSI.SYS, Backgroundprozessing ). 1984 entstand für den PC-AT die Version 3.0 ( Netzwerk, 20 MB Festplatte, 1.2 MB
Diskettenlaufwerke, Verbesserungen der Ausführungszeiten ).
Der interne Aufbau des DOS - Kerns
DOS-BIOS
(
: ROM)
DOS-Kern
( I/O : IBMDOS.COM)
Kommandoprozessor (Shell: COMMAND.COM)
Unter DOS ausführbare DOS-Programme sind z.B. *.EXE und *.COM. *.COM-Programme können maximal 64 KB Code enthalten. Beim Laden von *.EXE
Programmen werden die absoluten Speicher- bezüge angepasst.
Starten von DOS
Nach dem Einschalten wird geprüft ob im Laufwerk A: (falls leer dann B:, dann C:, usw.) eine Diskette ist. Der Boot-Sektor wird automatisch geladen, die BootRoutine wird ausgeführt und IBMBIO.COM und IBMDOS.COM geladen. Nun wird die Datei CONFIG.SYS gesucht und die in CONFIG.SYS enthaltenen
Treiber werden geladen (DEVICE-Befehl). Dadurch wird der Kern des Betriebssystems zusammengebaut (SYStem CONFIGurieren). Dann wird der Kommandoprozessor (COMMAND.COM) geladen, der automatisch die in
Beim Starten von DOS wird zuerst die Datei CONFIG.SYS (Gerätetreiber) und dann die Datei AUTOEXEC.BAT abgearbeitet. Die in AUTOEXEC.BAT
enthaltenen *.COM- und *.EXE-Programme der Reihe nach ausführt. *.Bat steht für eine BATch-Job-Stapeldatei.
Achtung! Das folgenden Beispiele ( DOS 5.0 ) können nicht kritiklos übernommen werden!
Beispiel für CONFIG.SYS
Beispiel für AUTOEXEC.BAT
shell =c:\dos\command.com c:\dos\ /e:256 /p
country=49,,c:\dos\country.sys
@ECHO OFF
device =c:\dos\himem.sys
set comspec=c:\dos\command.com
device =c:\dos\emm386.exe 2048 noems
path C:\DOS;c:\bc\bin;
dos=high,umb
append=c:\dos
lastdrive = g
in not "%prompt%"=="" goto ende
files =30
prompt $p$g
buffers=15
lh keyb gr
dh =c:\dos\smartdrv.sys 2048 1024
lh c:\dos\mouse.com
dh =c:\dos\ansi.sys
nc
dh =c:\dos\ramdrive.sys 1024 /e
:ende
install=c:\dos\share.exe
</td>
Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Diese Tabelle beginnt bei der Speicher-Adresse 0 und
enthält 256 Adressen. Jeder Adress-Eintrag verwendet 4 Byte. Wird ( durch ein Gerät ) dem Interrupt-Controller-Baustein ein Hardware - Interrupt angezeigt,
so legt das Gerät danach den Tabelle-Index auf den Datenbus. Der Tabelle wird dann die Ziel-Adresse entnommen. Ab der Zielstelle wird das unterbrechende
Programm ( ähnlich einem Unterprogramm ) ausgeführt.
Bei einem Software-Interrupt ( z.B. INT 21h ) enthält der INT-Maschinen-Befehl bereits den Tabellen-Index. Ab der Zielstelle wird das unterbrechende
Programm ( ähnlich einem Unterprogramm ) ausgeführt.
Speicher-Bild:
+----------------------------------+
|
|
|
|
Tabellen- |----|----|----| ... |----|----|----| ... |----|-- ... ---------Index
0.
1.
2.
33. 34. 35.
255.
Zielstelle
Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Dadurch ergeben sich die folgenden Vorteile: Wird das
Betriebssystem verbessert oder erweitert, so wird der Maschinencode an der Zielstelle geändert. Die Folge der Adressen an den Zielstellen verschieben sich.
Wenn Anwendungsprogramme die direkte Adresse der Zielstelle verwenden würden, so müßten bei jeder Betriebssystemänderung alle
Anwendungsprogramme angepaßt werden. Wenn ein Anwendungsprogramm Funktionen des Betriebssystems verwendet, so wird lediglich den Index der
Interrupt - Tabelle benutzt ( z.B. INT 21h ). Dadurch funktionieren die alten Anwendungsprogramme auch unter einer neueren Version des Betriebssystems.
UNIX
UNIX ist ein Mehrprogrammsystem. Die einzigen aktiven Einheiten in einem UNIX-System sind die ( sequeltiellen ) Prozesse. Jeder Prozess hat einen eigenen
Programmzähler. Viele Prozesse laufen im Hintergrund ( Dämon, z.B.Terminplanung mit cron ).
UNIX und C
Nachdem Ken Thomson aus dem MIT - Projekt ( MULTiplexed Information and Computing Service, PL/I ) verlassen hatte, schrieb er auf der PDP-7 ein
kleineres Betriebssystem UNICS ( UNiplexed Information and Computing Service, kastriertes MULTICS, späterer Name UNIX ). Die Übertragung des gesamten
Assembler - Codes auf PDP-11/20, PDP-11/45, PDP-11/70 war schwierig. Deshalb wurde ein Programmiersprache B ( vereinfachtes BCPL, stark vereinfachtes
PL/I ) entwickelt. B hatte keine Strukturen. Dennis Ritchie erweiterte B zu C.
Um das Betriessystem auf einen neuen Computer zu übertragen wurde zunächste ( mit mittleren Aufwand ) der C - Compiler portiert. Die meisten Software Anteile konnten dann übernommen werden. Der Quellcode wurde kostenlos an Universitäten abgegeben.
C wurde die Sprache der Systemprogrammierung.
Ausgehend von der typenlosen Sprache BCPL wurde die Programmiersprache C von Ken Thomson und Dennis Ritchie bei den Bell Laboratories auf einer PDP11 entwickelt. Das Betriebssystem UNIX ist weitgehend in C geschrieben. UNIX Ver. 6 ist zu 95% in C geschrieben. C ist eine einfache und universelle
Programmiersprache, die auch bei Mikrocontrollern als Assembler-Ersatz verwendbar ist. C ist heute i.a. die erste hoehere Programmiersprache, die auf einem
neuen Computer, Microcomputers, Minicomputers oder Mainframe laeuft. Wir wollen immer zwischen der Programmiersprache C und den Bibliotheken
unterscheiden. Bibliotheken enthalten eingebaute Funktionen und Dienstleistungen. Bei Projekten werden solche Bibliotheken mit Hilfe eines C-Compilers oft
selbst erstellt (z.B. Window-, Grafik-, Device-Bibliotheken). 1988 wurde ANSI-C X3J11 genormt.
C ist für Programmier-Anfaenger wegen der cryptischen-Schreibweise nicht so einfach wie z.B. BASIC. Mit C kann man flexibel bis auf Betriebssystem- und
Maschinenebene programmieren. Anders als z.B. bei OBERON gilt:
Die Verantwortung beim Programmieren mit C ( C++ ) liegt stets beim Programmierer!
UNIX-Standardisierungen
Die Universität Kalifornia in Berkeley nutzte den C - Quellcode und entwickelte eigene UNIX-Erweiterungen ( vi, csh, Compiler für Pascal und Lisp, usw. ). Sun
baute auf dem Berkeley-Unix auf. Es gab unterschiedliche Unix-Normungsgremien z.B. AT&T SVID ( System V Interface Definition ), BSD ( Berkeley
Sooftware Distribution ), IEEE POSIX 1003.1 ( Portaples Operating System ). OSF ( IBM und weitere, Open Software Foundation, starke Erweiterungen X11,
MOTIF, DCE, DME ), UI ( AT&T und weitere, Unix International ).
Für UNIX hat sich die sogenannte Mach Gruppe schon frühzeitig bemüht, einen Kernel weiter zu entwickeln, der die folgenden Eigenschaften vereint:
●
●
●
●
●
Beibehaltung Schnittstelle
abstraktes Modell der Speicherverwaltung ( großer und nicht dicht besetzter Adreßraum, memory mapped files, Speicherverwaltungsmodule für
den Benutzer,
Interprozeßkommunikation ( Transparenz im Netz, Schutzmechanismen, Austauschbare Datenmengen )
Beachtung von neuen Technologien ( Vernetzung, Mehrprozeßortechnik, enge und lose Kopplung, Prozeß in Tasks und Threads abbilden )
Werkzeuge ( im Kern eingebaute Testhilfe, Debugger, transparente Zugriffe auf andere Rechner, remote File access, remote Procedure Call für
C, Pascal und Common Lisp )
Windows
Windows ist überwiegend in ANSI - C geschrieben. Einige wenige zeitkritische Teile des Betriebssystem - Kerns für die Hardware Abstraktions Layer ( HAL )
sind in Assembler - Code geschrieben. Das Betriebssystem ist modular. Bei Bedarf werden die benötigten Teile ( DLL's ) geladen/entfernt.
Es gibt verschiedene Windows-Betriebssysteme:
1985
1987
1987
1988
1990
1992
1993
1993
1996
1995
MS präsentiert Windows 1.01;
Windows 2;
OS/2 von IBM / MS, zeichenorientiert
OS/2 von IBM/MS mit grafischer Oberfläche
Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg
( Trennung IBM – MS ). Im Oktober startet die Inmarsat-Organisation
eigene Satelliten für die maritime Kommunikation. In den USA nimmt
der erste kommerzielle Internet-Provider den Dienst auf.
Unter Federführung der Bundespost entsteht der Treiber-Standard
CAPI 1.1 für ISDN-Karten. James Gosling und Bill Joy beginnen
mit der Entwicklung der Programmiersprache Java;
Windows 3.1;
Windows 3.11;
Windows NT ( Windows New Technology, 32-Bit-Betriebssystem,
für Workstations Windows NT 3.1, für Windows NT 3.1 Advanced
Server und Netzwerke );
Windows NT 3.5, und Windows NT 4.0, Sicherheit, Erweiterbarkeit,
Stabilität und Skalierbarkeit, zentrale Administration,
NT-Server tritt in Konkurrenz zu Novell, Banyan oder UNIX
Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte
Plug-and-Play-Technologie, mitgeliefert wurde der Internet-Browser
Internet Explorer, für Heimmarkt = Small Office/Home Office;
1998 Windows 98 ( Update für Windows 95, Active Desktop bindet den
Webbrowser Internet Explorer, unterstützt werden: FAT32, DVDund MMX-Technologie, AGP (siehe Graphikkarte) USB-Anschlüsse
( Universal Serial Bus ), AGP ( Accelerated Graphics Port,
1997 Intel, direkte Verbindung von der Grafikkarte zum Prozessor
sowie zum Arbeitsspeicher, Taktfrequenz 66 MHz,
AGP 1X = 266 MByte/s, AGP 2X = 533 MByte/s, AGP 4X = 1066 MByte/s,
Pipelining, 8 zusätzliche Leitungen,
DIME-Auslagerungsmodus für Texturen );
2000 Windows 2000 wird in 4 Zusammenstellungen ausgeliefert:
Windows 2000 Professional ( für PC und Notebook ),
Windows 2000 Server ( einfache Netzanwendungen ),
Windows 2000 Advanced Server ( Unternehmenskritische und komplexe Netzanwendungen
)
Windows 2000 Datacenter Server ( für Rechenzentren, Lagerverwaltungssysteme und
Finanzsysteme );
2001 Windows ME;
2002 Windows XP
●
●
●
●
●
●
NT-Design Ziele
Kompatibilität: Durch seine Submodule ist Windows NT in der Lage,
Applikationen für die Betriebssyteme Windows 3.x, Windows 95, MSDOS, OS/2 und POSIX zu betreiben.
Portierbarkeit: Windows NT ist fast vollständig in C geschrieben. Für
eine neue Hardware Architektur muß deswegen lediglich eine neue
HAL (Hardware Abstraction Layer) geschrieben werden und ein NTkomformer Compiler verfügbar sein.
Skalierbarkeit: Windows NT unterstützt das symmetrische
Multiprocessing.
Sicherheit: Windows NT beinhaltet ein durchgängiges
Sicherheitskonzept, das darauf ausgelegt ist, die
Sicherheitsanforderungen des Amerikanischen
Verteidungsministeriums zu erfüllen (C2).
Verteilte Systeme: Windows NT hat schon im Betriebssystemkern
weitreichende Funktionalität, um Prozesse auf anderen Rechnern
ablaufen zu lassen.
Zuverlässigkeit und Stabilität: Durch sein Konzept unterscheidet
●
●
●
●
●
●
●
NT-Server
Die Server - Version unterstützt beliebig viele gleichzeitige Dateiund Druckerverbindungen, Datei- und Druckerserver auch für
Macintosh,
Die Benutzerinformationen stehen allen Servern zur Verfügung
(Domänen Konzept),
NT-Server ermöglicht eine zentrale Benutzeradministration,
Verzeichnis-Replikation,
TCP/IP Unterstützung ( DHCP, WINS, DNS, etc.),
NetWare Unterstützung ( GSNW, Migration Tool, FPNW
kompatibel ),
fehlertolerante Plattenkonzepte werden unterstützt ( Parity, RAID
5 ),
Multiuser Remote Access Service
●
Windows NT zwischen User und Kernel Prozessen. Dadurch ist es
normalerweise einer Applikation nicht möglich einen Windows NT
Rechner zu blockieren oder abzuschießen. Dadurch kann ein Server
auch dann weiter arbeiten wenn in einer Applikation ein Fehler
aufgetreten ist.
Erweiterbar: Da Windows NT sehr modular aufgebaut ist, ist es
einfach möglich neue Module einzuhängen oder zusätzliche
hinzuzufügen.
Architektur des NT-Betriebssystem
Wichtige Teile des Betriebssystems sind im ( privilegierten ) Executive Modus geschützt.
●
●
●
●
●
●
●
●
Hardware Abstraction Layer (HAL): Die HAL - Komponenten sind in Assembler geschrieben. Diese HAL - Schicht muß bei der Portierung von
Intel-Basis auf MIPS, Alpha, Power-PC und PA/RISC neu geschrieben werden.
Kern (Kernel): Dieser Mach-Kernel ist überwiegend in ANSI-C geschrieben. Der Kernel bearbeitet Unterbrechungen und AUsnahmen,
Laufzeitfestlegung von Threads, Synchronisation von Prozessoren und stellt Objekte und Schnittstellen bereit.
Objekt-Manager: Der Objekt-Manager verwaltet NT-Objekten ( Hardware, Prozesse, Threads, Ereignisse, Dateien, ... ).
Prozeß-Manager: Verwaltung der Prozesse.
Local Procedure Call-Facility (LPC): Variante der RPCs ( Remote Procedure Call ) zur Interprozeßkommunikation.
Virtual Memory Manager: Virtuelle Speicherverwaltung, Verwaltung von Auslagerungsdateien.
Sicherheitsmonitor: Überwachung der Sicherheit auf dem lokalen Computer.
Ein/Ausgabesystem: Gerätetreiber, Dateisysteme, allgemeine Eingabe/Ausgabe.
Struktur des NT 4.x-Betriebssystems
Struktur des NT 4.x-Betriebssystems
NT-Subsysteme
Darüber hinaus stellt Windows NT eine Reihe geschlossener Subsysteme zur Ausführung von Applikationen zur Verfügung. Sie alle kommunizieren mit dem
darunterliegenden Betriebssystem und regeln ihre Bildschirmausgaben über die Windows32-Graphikschnittstelle.
●
●
●
●
Win32: Ausführung von 32-Bit Windows-Programmen, beinhaltet das WOW-Modul (Windows-on-Windows) zur Ausführung von 16-BitProgrammen.
OS/2: OS/2 2.x Subsystem.
POSIX: Zeichenorientiertes POSIX-Subsystem.
Sicherheit: Subsystem zur Überwachung der Sicherheit der anderen Subsysteme
NT-Objekte
Resourcen als Objekte:
●
●
●
●
Dateien
Gemeinsam benutzter Speicher
Physikalische Geräte jeder Art
Prozesse/Threads
NT-Objekte
Ein NT-Thread:
●
●
●
teilt sich das Code- und DatenSegment eines Prozesses mit anderen
Threads,
hat seine eigenen CPU-Register, StackRaum und einen eigenen Instruktions Zähler,
erhält vom System eine gewisse CPU Zeit, so daß alle Threads des Prozesses
gleichzeitig ausgeführt werden.
NT-Objekte
Unterschiedliche Objekte sind:
●
●
●
●
Executive Objects
hat bereits Windows NT 3.5 mit Service Pack 3 die C2Zertifizierung für NT-Rechner ohne
Netzwerkanbindung erhalten.
NT ist für B1-Security ausgelegt.
Für jedes Objekt gibt es ein Zugriffstoken
Dateisysteme:
Die von Windows NT unterstützten Dateisysteme können parallel nebeneinander laufen.
●
●
●
NTFS: New Technology File System, das eigentliche 64-Bit-Dateisystem von Windows NT mit starkem Fokus auf Sicherheit. Maximale
Dateigröße: 17 Milliarden Gbytes
HPFS: High Performance File System, OS/2-Dateisystem. Maximal Dateigröße: 4 bis 8 Gbytes ( wird ab NT 4.0 nicht mehr unterstützt ).
FAT: File Allocation Table, DOS Dateisystem und Diskettenformat unter NT. Maximale Dateigröße: 4 Gbytes.
Datentypen
Alle binär gespeicherten Informationen bestehen aus kleinen, typisierten Einheiten. Jedem Buchstaben ist z.B. ein Bitmuster zugeordnet. Text besteht z.B. aus
Buchstaben und diese aus Binärcode. Maschinencode besteht z.B. aus kleinen binären Einheiten ( prozessor-spezifischen OpCode-Befehlen ). Zu einer ganzen
Zahl im Speicher gehört z.B. der Umfang von Bits, eine bestimmte Art des Bit-Muster-Aufbaues ( Interpretation dieser Bits ) und die Position, bei der diese Bits
im Speicher sind ( Speicheradresse, Zeiger ).
Zu jeder vorhandenen Information gehört ein Identifizierer ( physikalische RAM-Adresse, Entität, Ort der Information )
und ein Binärcode ( Bitmuster, Bedeutung, Semantik ).
Daten-Typen legen die elementare Bedeutung eines Speicher-Bit-Musters fest. Mit Daten-Typen sind sinnvolle Operationen möglich. Zu einer
Programmiersprache gehören Grundtypen, die für Zeichen, Zahlen, Strukturen verwendet werden können. Strukturen und Objekte legen die elementare
Bedeutung einer Kombination von Grundtypen fest.
Beispiel: Gleitpunktzahlen
Zahlen in wissenschaftlicher Notation bestehen aus Vorzeichen ( Sign Bit ) , Mantisse ( Significant ) und Exponent ( Biased Exponent ). Wir müssen daher bei en
sehr genau zwischen der Von der Größe einer Gleitpunktzahl ( Wert des Exponenten ) ist die Darstellungsgenauigkeit ( Anzahl der gespeicherten Ziffern ) zu
unterscheiden. Das Format von Gleitpunktzahlen ist in IEEE 754 ( Floating Point Standard ) festgelegt. Es gibt die Daten-Formate:
●
●
●
●
●
●
●
Word Integer ( Zweierkomplement, Bereich 104, Genauigkeit 16 Bit ),
Short Integer ( Zweierkomplement, Bereich 109, Genauigkeit 32 Bit ),
Long Integer ( Zweierkomplement, Bereich 1018, Genauigkeit 64 Bit ),
Packed BCD ( Bereich 1018, Genauigkeit 18 Digits ),
Single Precision ( 8 Bit für Exponenten, Bereich 10+<38; 24 Bits für Mantisse, Genauigkeit 24 Bit ),
Double Precision ( 11 Bit für Exponenten, Bereich 10+<308; 53 Bits für Mantisse, Genauigkeit 53 Bit ),
Extended Precision ( 16 Bit für Exponenten, Bereich 10+-4932; 64 Bits für Mantisse, Genauigkeit 64 Bit ).
Gleitpunktzahlen werden vielfältig benötigt ( naturwissenschaftlichen, technischen Anwendungen, Grafik, numerische Mathematik, usw. ). Wegen des
Zeitbedarfes werden Fließkommaoperationen von Gleitpunktzahlen (engl. Floating Point Numbers ) in digitalen Einheiten ( Coprozessor ) ausgeführt.
Bitweise Darstellung einer double-Zahl
63 .. 56
55 .. 48
47 .. 40
39 .. 32
31 .. 24
23 .. 16
15 .. 8
7 .. 0
3210987654321008765432109876543210987654321098765432109876543210
s
-
Wert = (-1)s * 2e-e0 * ( normalisierte Mantisse )
mit
e = Exponent ( -1022 ...1023 ),
e0 := 1023 und
1 <= normalisierte Mantisse < 2
Beispiel:
dez 25678.34 =
= dez 2.567834*104 =
= bin 0110 0100 0100 1110.0101 0111 =
= bin 0110 0100 0100 1110. 0101 0111 =
( . um 14 Positionen verschieben, begrenzen der Mantisse auf 3 Byte: )
= bin 1.1001 0001 0011 1001 0101 11oo * 2dez 14
( e0+14 = dez 1023 + 14 = dez 1037 = bin 100 0000 1101 )
010000001101100100010011100101011100............................
4
6
C
8
9
C
A
E
0
0
0
0
0
0
0
0
Beispiel: Unicode
Eine lesbare Schrift besteht aus Schriftzeichen. Eine Repräsentation von Bildern als Zeichen wird Font genannt. Outline-Typeface ist eine Konturschrift (
Vektoren, Zeichen nur aus Umrisslinien ). TrueType-Fonts wurden von Apple und Microsoft entwickelt ( Zeichen werden als Hüllkurven-Konturen ). BitmappedFonts entsprechen binären Bildern. Ein Font besteht z.B. aus einer "Bildersammlung" aus 256 einzelnen Elementen, die mit 8 Bits eindeutig identifiziert werden
können ( Code, z.B. ASCII ). Der Windows-ANSI-Zeichensatz enthält 256 Zeichen. Die ersten 32 Zeichen sind Steuerbefehle. Der ANSI-Zeichensatz ist von
Zeichen 32 bis Zeichen 127 mit dem ASCII-Zeichensatz identisch.
Unicode benutzt 16 Bits und kann 216 = 65536 verschieden Zeichen adressieren. Zu einem Zeichensatz gehören:
●
●
●
●
●
Steuerzeichen ( Silbentrennzeichen, Tabulatorzeichen )
Sonderzeichen und Einzelteile von Zeichen ( z.B. Doppelpunkt, deutsche Umlauten, usw. )
Zeichen für Zahlen ( mathematischer Formeln )
Silbenzeichen oder Wortzeichen für fernöstlicher Schriftkulturen
Schreibrichtung ( bei arabischen Zeichen etwa ist die Schreibrichtung von rechts nach links )
Bei der darstellung von Zeichen können diese auch dynamisch kombiniert werden ( z.B."ä" aus "a" und darüber gesetzten Doppelpunkt ).
Das Unicode-Konsortium ( gegründet 1991, Linguisten, Fachleute ) koordiniert die weltweiten Schrift-Zeichen-Standardisierungen. Zeichen-Codes sollten
systemunabhängig, programmunabhängig, sprachunabhängig sein und dennoch eine Vielfalt der Zeichen-Darstellung unterstützen.
●
●
●
●
●
US-ASCII: Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986.
ISO-646: International Standard--Information Processing--ISO 7-bit coded character set for information interchange, ISO 646:1983.
ISO-2022: International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension techniques, ISO 2022:1986.
ISO-8859: Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987. Part 2:
Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5:
Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part
8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990.
ISO/IEC 10646: Unicode
Die vergebenen Codes ( Zahl-Zeichenwert-Zuordnung ) haben verbindlichen Charakter. Das Unicode-System ( Version 2.0 ) ist eine internationale Norm
ISO/IEC 10646. Das Unicode-System ist in Zahlenbereiche aufgeteilt ( ASCII, Schriftkultur, Sonderzeichen, auch noch Platz für Zukünftiges ).
Windows-Zeichen-Typen
Generisch
TCHAR
LPTSTR
ANSI
UNICODE
ANSI
UNICODE
Explizit
CHAR
WCHAR
LPSTR
LPWSTR
Aufgelöst
char
wchar_t
char *
wchar_t
Unicode
Damit die generischen Typen den Unicode-Size verwenden, muß #define UNICODE ( vor den #include ) definiert sein.
ANSI-Zeichen werden auf dem Tastatur-Ziffernblock unter Windows erzeugt durch:
[Alt]-Taste drücken und die ANSI-Nummer mit vorangestellter [0] eingeben.
Beispiel: ø = [Alt]+[0]+[2]+[4]+[8].
C++Grundtypen
C++ kennt main() für Program Startup and Termination und die Standard-Streams: cin ( for standard input ), cout ( for standard output ), cerr ( for unbuffered
standard error output ), clog ( for buffered standard error output ).
C++ kennt die Header-Files ( bzw. subset ) : algorithm, bitset, cassert, cctype, cerrno, cfloat, ciso646, climits, clocale, cmath, complex, csetjmp, csignal, cstdarg,
cstddef, cstdio, cstdlib, cstring, ctime, cwchar, cwctype, deque, exception, fstream, functional, iomanip, ios, iosfwd, iostream, istream, iterator, limits, list, locale,
map, memory, numeric, ostream, queue, set, sstream, stack, stdexcept, streambuf, string, strstream, utility, valarray, vector
Unterschiedliche Maschinen haben unterschiedlich geeignete Darstellungen ( Speicherbedarf, Geschwindigkeit, Vorzeichen, Big/Little Endian, usw. ).
Typ
C++ garantiert die folgenden Relationen:
1 == sizeof(char) <= sizeof(short) <= sizeof(int)
<= sizeof(long) <= sizeof(float) <= sizeof(double)
Beispiel
Typen für Integer
char entspricht bei vielen Maschinen einem 8-Bit-signed-Wert;
char
char
char
char
//
char
//
//
//
//
//
char
//
t =
c0 =
*p =
c[5]
'\t'; /* 0x09 */
( char ) 0x61;/* 'a' */
&mp; c0; /* pStr -> c0 */
= {'A', 'B', 'C'};
0x41 0x42 0x43 0x00 0x00
*ptrs[5] = {"abc","ABC"};
ptrs[0] -> 0x61 0x62 0x63 0x00 0x00
ptrs[1] -> 0x41 0x42 0x43 0x00 0x00
ptrs[2] == NULL
ptrs[3] == NULL
ptrs[4] == NULL
*pStr = "ABC";
pStr -> 0x61 0x62 0x63 0x00
short int entspricht signed short int vorzeichbehaftete Zahl, bei 32 Bit Maschinen meist 2 Byte;
int entspricht signed int; all. darf int bei mehrfach Kombinationen weggelassen werden; bei 32 Bit Maschinen meist sizeof(int) = 4;
int i1 = 256+255; char ch = i1;/* ch=255 */ int i2 = ch; /* i2 = -1 oder 255 */
long int entspricht signed long int; bei 32 Bit Maschinen meist sizeof(long) = 4
Typen für Fließkommazahlen
float bei 32 Bit Maschinen meist sizeof(float) = 4
double bei 32 Bit Maschinen meist sizeof(double) = 8
long double bei 32 Bit Maschinen meist sizeof(double) = 8
Typen für vorzeichenlose Integer, logische Werte, Bitfelder, usw.
unsigned char entspricht bei 32 Bit Maschinen meist 1 Byte;
unsigned short int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 2 Byte; unsigned short int shorti = -1; liefert ...
unsigned int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned int ui = -1; liefert ...
unsigned long int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned long l = -1; liefert ...
Standard C- Bibliotheks-Header-Files
Hier sind einige C-Header-Files ( Funktionsnamen ).
Standard C++ Bibliotheks-Header-Files
Die C, C++-Prototypen von Funktionen, Macros, Datenstrukturen, usw. werden in Header-Files zusammengefaßt. Die beim Erstellen des Betriebssystems (
*.DLL's ) benutzten Header - Files werden zur Verfügung gestellt. Liegen auch die zugeordneten *.LIB - Files vor, so können die DLL - Funktionen in eigenen
Applikationen eingebunden werden.
Standard C++ library headers
algorithm.h for defining numerous templates that implement useful
algorithms
for enforcing assertions when functions execute
cassert.h
for testing error codes reported by library functions
cerrno.h
ciso646.h for programming in ISO 646 variant character sets
for adapting to different cultural conventions
clocale.h
complex.h for defining a template class that supports complex arithmetic
for controlling various exceptional conditions
csignal.h
cstddef.h for defining several useful types and macros
for performing a variety of operations
cstdlib.h
for converting between various time and date formats
ctime.h
cwctype.h for classifying wide characters
exception.h for defining several functions that control exception handling
functional.h for defining several templates that help construct predicates
for the templates defined in algorithm.h and numeric.h
bitset.h
for defining a template class that administers sets of bits
cctype.h
cfloat.h
climits.h
cmath.h
csetjmp.h
cstdarg.h
cstdio.h
cstring.h
cwchar.h
deque.h
fstream.h
for classifying characters
for testing floating-point type properties
for testing integer type properties
for computing common mathematical functions
for executing nonlocal goto statements
for accessing a varying number of arguments
for performing input and output
for manipulating several kinds of strings
for manipulating wide streams and several kinds of strings
for defining a template class that implements a deque container
for defining several iostreams template classes that manipulate
external files
for declaring several iostreams manipulators that take an
argument
iomanip.h
for defining the template class that serves as the base for many iosfwd.h
iostreams classes
iostream.h for declaring the iostreams objects that manipulate the standard iso646.h.h
streams
istream.h for defining the template class that performs extractions
iterator.h
ios.h
for testing numeric type properties
for defining several classes and templates that control localespecific
behavior, as in the iostreams classes
memory.h for defining several templates that allocate and free storage for
various container classes
numeric.h for defining several templates that implement useful numeric
functions
for defining a template class that implements a queue container
queue.h
limits.h
locale.h
list.h
map.h
for declaring several iostreams template classes before they are
necessarily defined
for programming in ISO 646 variant character sets
for defining several templates that help define and manipulate
iterators
for defining a template class that implements a list container
for defining template classes that implement associative
containers
new.h
for declaring several functions that allocate and free storage
ostream.h
for defining the template class that performs insertions
set.h
for defining template classes that implement associative
containers
with unique elements
for defining a template class that implements a stack container
for defining several iostreams template classes that manipulate stack.h
string containers
stdexcept.h for defining several classes useful for reporting exceptions
streambuf.h for defining template classes that buffer iostreams operations
for defining a template class that implements a string container strstream.h for defining several iostreams classes that manipulate instring.h
memory
character sequences
for defining several templates of general utility
typeinfo.h for defining class type_info, the result of the typeid operator
utility.h
for defining a template class that implements a vector container
valarray.h for defining several classes and template classes
vector.h
that support value-oriented arrays
sstream.h
Windows-Standard Typen
Ein Betriessystem ( im Gegensatz zur C++-Definition ) arbeitet mit ( exakt ) festgelegten Typen, Strukturen und Speicherabbildern.
Typ
Windows-Standard Typen der RTL ( Run-Time Library )
Beschreibung
deklariert in
clock_t structure
_complex structure
_dev_t short or unsigned
integer
div_t, ldiv_t structures
_exception structure
FILE structure
_finddata_t,
_wfinddata_t
_wfinddatai64_t
structures
_FPIEEE_RECORD
structure
fpos_t
(long integer, __int64,
or structure, depending
on the target platform)
_HEAPINFO structure
jmp_buf array
lconv structure
_off_t long integer
_onexit_t pointer
_PNH pointer to function
ptrdiff_t integer
sig_atomic_t integer
size_t unsigned integer
_stat structure
time_tlong integer
_timeb structure
tm structure
_utimbuf structure
Stores time values; used by clock.
Stores real and imaginary parts of complex numbers; used by _cabs.
Represents device handles.
TIME.H
MATH.H
SYS\TYPES.H
Store values returned by div and ldiv, respectively.
Stores error information for _matherr.
Stores information about current state of stream; used in all stream I/O
operations.
_finddata_t stores file-attribute information returned by _findfirst and
_findnext. _wfinddata_t stores file-attribute information returned by
_wfindfirst and _wfindnext. _wfinddatai64_t stores file-attribute information
returned by _wfindfirsti64 and _wfindnexti64.
Contains information pertaining to IEEE floating-point exception; passed to
user-defined trap handler by _fpieee_flt.
Used by fgetpos and fsetpos to record information for uniquely specifying
every position within a file.
STDLIB.H
MATH.H
STDIO.H
Contains information about next heap entry for _heapwalk.
Used by setjmp and longjmp to save and restore program environment.
Contains formatting rules for numeric values in different countries.
Represents file-offset value.
Returned by _onexit.
Type of argument to _set_new_handler.
Result of subtraction of two pointers.
Type of object that can be modified as atomic entity, even in presence of
asynchronous interrupts; used with signal.
Result of sizeof operator.
Contains file-status information returned by _stat and _fstat.
Represents time values in mktime and time.
Used by _ftime to store current system time.
Used by asctime, gmtime, localtime, mktime, and strftime to store and
retrieve time information.
Stores file access and modification times used by _utime to change filemodification dates.
MALLOC.H
SETJMP.H
LOCALE.H
SYS\TYPES.H
STDLIB.H
NEW.H
STDDEF.H
SIGNAL.H
_finddata_t: IO.H
_wfinddata_t: IO.H, WCHAR.H
_wfinddatai64_t: IO.H, WCHAR.H
FPIEEE.H
STDIO.H
STDDEF.H and other include files
SYS\STAT.H
TIME.H
SYS\TIMEB.H
TIME.H
SYS\UTIME.H
va_list structure
wchar_t internal
type of a wide character
wctrans_t integer
wctype_t integer
wint_t integer
Used to hold information needed by va_arg and va_end macros. Called
function declares variable of type va_list that can be passed as argument to
another function.
Useful for writing portable programs for international markets.
STDARG.H
Represents locale-specific character mappings.
Can represent all characters of any national character set.
Type of data object that can hold any wide character or wide end-of-file
value.
WCTYPE.H
WCHAR.H
WCHAR.H
STDDEF.H, STDLIB.H
Die Typen und Strukturen eines Betriessystems sind vielfältig und umfangreich. Windows-Typen werden u.a. für Funktions - Parameter, Funktions-RückgabeWerte, und für Nachrichten benötigt.
Handles werden benutzt, um mit einer Deskriptor-Tabelle auf geladenen Resourcen oder einen benötigten globalen Kontext zuzugreifen. Ein Handle entspricht
dem Index der Deskriptor-Tabelle. Ein 8-Byte Deskriptor-Eintrag enthält die Ziel-Byte-Adresse, den Byte-Umfang, die Zugriffsrechte.
In der folgenden Tabelle sind Daten-Typen für Character, Integer, Boolean, Pointer und Handles enthalten. Die meisten Pointer-Typen beginnen mit dem Prefix P
oder LP.
Windows benötigt viele Typen. Hier eine Auswahl ...
ATOM Atom (a reference to a character string in an atom
BOOL Boolean variable (should be TRUE or FALSE)
table)
BOOLEAN Boolean variable (should be TRUE or FALSE)
BYTE Byte (8 bits)
CCHAR Windows character
CHAR Windows character
COLORREF Red, green, blue (RGB) color value (32 bits)
CONST Variable whose value is to remain constant during
execution
CRITICAL_SECTION Critical-section object
CTRYID Country identifier
DLGPROC Pointer to an application-defined dialog box
DWORD Doubleword (32 bits)
callback procedure.
EDITWORDBREAKPROC Pointer to an application-defined callback function
ENHMFENUMPROC Pointer to an application-defined callback function
that the operating system calls when a multiline
that enumerates enhanced-metafile records
edit control needs to break a line of text. See
EditWordBreakProc for information on functions
of this type.
ENUMRESLANGPROC Pointer to an application-defined callback function
that enumerates resource languages
ENUMRESTYPEPROC Pointer to an application-defined callback function
that enumerates resource types
FLOAT Floating-point variable
GOBJENUMPROC Pointer to an application-defined callback function
that enumerates graphics device interface (GDI)
objects
HACCEL Handle of an accelerator table
HBITMAP Handle of a bitmap
HCONV Handle of a dynamic data exchange (DDE)
conversation
HCURSOR Handle of a cursor
HDDEDATA Handle of DDE data
HENHMETAFILE Handle of an enhanced metafile
HFONT Handle of a font
HGLOBAL Handle of a global memory block
HICON Handle of an icon
HKEY Handle of a registry key
HMENU Handle of a menu
HOOKPROC Pointer to an application-defined hook function
HPEN Handle of a pen
HRSRC Handle of a resource
HWINSTA Handle of a workstation
INT Signed integer
LCID Locale identifier
LINEDDAPROC Pointer to a callback function that processes line
coordinates
LP Pointer to a null-terminated Unicode™ string
LPBOOL Pointer to a Boolean variable
LPCCH Pointer to a constant Windows character
LPCFHOOKPROC Pointer to an application-defined hook function
LPCOLORREF Pointer to a COLORREF value
LPCSTR Pointer to a constant null-terminated Windows
character string
ENUMRESNAMEPROC Pointer to an application-defined callback function
that enumerates resource names
FARPROC Pointer to a callback function
FONTENUMPROC Pointer to an application-defined callback function
that enumerates fonts
GRAYSTRINGPROC Pointer to an application-defined callback function
that draws gray text
HANDLE Handle of an object
HBRUSH Handle of a brush
HCONVLIST Handle of a DDE conversation list
HDC Handle of a device context (DC)
HDWP Handle of a deferred window position structure
HFILE Handle of a file
HGDIOBJ Handle of a GDI object
HHOOK Handle of a hook
HINSTANCE Handle of an instance
HLOCAL Handle of a local memory block
HMETAFILE Handle of a metafile
HPALETTE Handle of a palette
HRGN Handle of a region
HSZ Handle of a DDE string
HWND Handle of a window
LANGID Language identifier
LCTYPE Locale type
LONG 32-bit signed value
LPARAM 32-bit message parameter
LPBYTE Pointer to a byte
LPCCHOOKPROC Pointer to an application-defined hook function
LPCH Pointer to a Windows character
LPCRITICAL_SECTION Pointer to a critical-section object
LPCTSTR Pointer to a constant null-terminated Unicode or
Windows character string
LPCWCH Pointer to a constant null-terminated Unicode
character
LPDWORD Pointer to an unsigned doubleword (32 bits)
LPHANDLE Pointer to a handle
LPINT Pointer to a signed integer
LPOFNHOOKPROC Pointer to an application-defined hook function
LPSETUPHOOKPROC Pointer to an application-defined hook function
LPTCH Pointer to a Unicode character or a Windows
character
LRESULT Signed result of message processing
LPWCH Pointer to a Unicode character
LPWSTR Pointer to a null-terminated Unicode character
string
MFENUMPROC Pointer to an application-defined callback function
that enumerates metafile records
NWPSTR Pointer to a null-terminated Unicode string
PBOOLEAN Pointer to a Boolean variable
PCCH Pointer to a constant Windows character
PCHAR Pointer to a Windows character
PCSTR Pointer to a constant null-terminated Windows
character string
PCWSTR Pointer to a constant null-terminated Unicode
character string
PFLOAT Pointer to a floating-point variable
PHANDLE Pointer to a handle
PHKEY Pointer to a registry key
PLONG Pointer to a signed long (32 bits)
PROPENUMPROC Pointer to an application-defined callback function
that enumerates window properties. See
PropEnumProc for information on functions of this
type.
PSHORT Pointer to a signed short (16 bits)
PSTR Pointer to a null-terminated Windows character
string
LPCWSTR Pointer to a constant null-terminated Unicode
character string
LPFRHOOKPROC Pointer to an application-defined hook function
LPHANDLER_FUNCTION Pointer to a handler function
LPLONG Pointer to a signed long (32 bits)
LPPRINTHOOKPROC Pointer to an application-defined hook function
LPSTR Pointer to a null-terminated Windows character
string
LPTSTR Pointer to a null-terminated Windows or Unicode
character string
LPVOID Pointer to any type
LPWORD Pointer to an unsigned word (16 bits)
LUID Locally unique identifier
NPSTR Pointer to a null-terminated Windows character
string
PBOOL Pointer to a Boolean variable
PBYTE Pointer to a byte
PCH Pointer to a Windows character
PCRITICAL_SECTION Pointer to a critical-section object
PCWCH Pointer to a constant Unicode character
PDWORD Pointer to an unsigned doubleword (32 bits)
PFNCALLBACK Pointer to a callback function
PHANDLER_ Pointer to a handler routine
ROUTINE
PINT Pointer to a signed integer
PLUID Pointer to a locally unique identifier (LUID)
PROPENUMPROCEX Pointer to an application-defined callback function
that enumerates window properties. See
PropEnumProcEx for information on functions of
this type.
PSID Pointer to a security identifier (SID)
PSZ Pointer to a null-terminated Windows character
string
PTCH Pointer to a Windows or Unicode character
PTSTR Pointer to a null-terminated Windows or Unicode
character string
PUINT Pointer to an unsigned integer
PUSHORT Pointer to an unsigned short (16 bits)
PWCH Pointer to a Unicode character
PWORD Pointer to an unsigned word (16 bits)
REGSAM Security access mask for registry key
SENDASYNCPROC Pointer to an application-defined callback function
that the operating system calls when the
SendMessageCallback function is called. The
system passes the message to the callback function
after passing the message to the destination
window procedure. See SendAsyncProc for
information on functions of this type.
SHORT Short integer
TCHAR Unicode character or Windows character
UCHAR Unsigned Windows character
ULONG Unsigned long integer (32 bits)
VOID Any type
WNDENUMPROC Pointer to an application-defined callback function
that enumerates windows
WORD Unsigned word (16 bits)
YIELDPROC Pointer to a yield callback function
PTCHAR Pointer to a Windows or Unicode character
PUCHAR Pointer to an unsigned Windows character
PULONG Pointer to an unsigned long (32 bits)
PVOID Pointer to any type
PWCHAR Pointer to a Unicode character
PWSTR Pointer to a null-terminated Unicode character
string
SC_HANDLE Handle of a service
SERVICE_STATUS_ Handle of a service status value
HANDLE
SPHANDLE Pointer to a handle
TIMERPROC Pointer to an application-defined timer callback
function
UINT Unsigned integer
USHORT Unsigned short integer (16 bits)
WCHAR Unicode character
WNDPROC Pointer to an application-defined window
procedure
WPARAM 32-bit message parameter
Windows-Header-Files
Das Betriessystem wurde überwiegend mit C/C++ entwickelt. Die System-Funktionen sind als Maschinencode in DLL's enthalten. Für die Entwicklung der
System-Funktionen wurden Header-Quelltext-Files benutzt. Diese Header-Files werden auch für die Programm-Entwicklungen verwendet. Es gibt zahlreiche
Windows-Header-Files:
_dbdao.h _entryid.h a.txt accctrl.h aclapi.h aclcls.h aclsid.h acsmgtc.h acssvcc.h activecf.h activeds.h activex.mak activex.rcv activex.ver activscp.h
activscp.idl addrlkup.h admex.h adminext.h adoid.h adoint.h adomd.h adomd.idl adptif.h ads.odl adsdb.h adserr.h adshlp.h adsiid.h adsnms.h adssts.h
advpub.h agtctl.h agtctl_i.c agterr.h agtsvr.h agtsvr_i.c algorithm alphaops.h amaudio.h amrtpdmx.h amrtpnet.h amrtpss.h amrtpuid.h amstream.h amstream.idl
amvideo.h amvpe.idl ansiapi.h appavcap.h appc_c.h appccfg.h appfftp.h asptlb.h assert.h atalkwsh.h attrname.h austream.h austream.idl avifmt.h aviriff.h
axcore.idl axextend.idl basemake.inc basetsd.h basetyps.h bdnapi.h bh.h bh.mak bhcommon.ver bherr.h bherr.inc bhfilter.h bhsupp.h bhtypes.h bhver.h bitset
bkoffice.mak blberr.h bpcpri.h bpcreg.h bpcsusp.h bradm.idl brerror.h bridge.h brprop.h brtest.h bttncur.h buffer.h callconv.inc cassert cctype cderr.h
cdialog.h cerrno certadm.h certcli.h certenc.h certexit.h certext.h certif.h certpol.h certsrv certsrv.h cfloat cguid.h chanmgr.h chanmgr.idl channelt.h
chanstr.h chprop.h cierror.h ciso646 climits clocale cluadmex.h cluadmex.idl clusapi.h clusmsg.h cmath cmc.h cmdproc.h codecs.h color.dlg colordlg.h
comcat.h comcat.idl comdef.h comip.h comlite.h commctrl.h commctrl.rh commdlg.h common.ver complex compobj.h computer.odl comutil.h conio.h control.h
control.odl convclss.h convcwrp.h convdll.h convdllc.h convdlle.h convengn.h convincl.h convreg.h convregh.h convstrc.h copyfile.mak core.odl cpl.h
cplext.h crtdbg.h csetjmp csignal cstdarg cstddef cstdio cstdlib cstring ctime ctl3d.h ctype.h custcntl.h customaw.h cutlist.h cwchar cwctype cwindow.h
cxq_cust.h d3d.h d3dcaps.h d3drm.h d3drmdef.h d3drmobj.h d3drmwin.h d3dtypes.h d3dvec.inl danim.h daogetrw.h dapi.h dapimsg.h data.h datapath.h dbcsstr.h
dbdao.h dbdaoerr.h dbdaoid.h dbdaoint.h dbsets.h dbt.h dde.h dde.rh ddeml.h ddkernel.h ddraw.h ddrawex.h ddstream.h ddstream.idl delayhlp.cpp delayimp.h
deque devenum.idl devguid.h devtype.h digitalv.h dinput.h direct.h dispatch.h dispdib.h dispex.h dispex.idl dlcapi.h dlgs.h docobj.h docobj.idl domain.odl
dos.h dplay.h dplobby.h dprintf.h drivinit.h dsetup.h dskquota.h dsnamesp.odl dsound.h dssclien.h dssenum.h dtchelp.h dv.h dvdevcod.h dvdif.idl dvdmedia.h
dvobj.h dvp.h dxmrtp.h edbback.h edbbcli.h edbmsg.h edevdefs.h edk.h edkafx.h edkcfg.h edkcode.h edkdebug.h edkevent.h edkguid.h edkmapi.h edkmdb.h
edkmsg.h edksetup.h edktrack.h edkutcpp.h edkutils.h effect.h eh.h emsabtag.h epgdisp.h epgdspid.h epgldrx.h episodet.h epprop.h errcpp.h errcppd.h errno.h
error.h errors.h evcode.h eventcpts.h eventcpts_i.c exadmin.h exception exchcli.h exchext.h exchform.h exchinst.h excpt.h exdisp.h exdisp.idl exdisp.odl
exdispid.h fastfile.h fcntl.h fileopen.dlg filter.h filterr.h findtext.dlg float.h fmi.h font.dlg fpieee.h frame.h fserv.odl fshare.odl fstream fstream.h
ftsiface.h functional g711uids.h genre.h gizmobar.h gl globlmak.mak group.odl gwmain.h gwreport.h header.h hlguids.h hliface.h hliface.idl hlink.h
hlink.idl htmlguid.h httpext.h httpfilt.h iaccess.h iaccess.idl iadmw.h iads.h iamovie.idl icm.h icmui.dlg icrsint.h idf.h idispids.h ih26xcd.h iiis.h
iimgctx.h iiscnfg.h il21dec.h ilogobj.hxx ils.idl ilsguid.h imagehlp.h ime.h imessage.h imm.h imsconf2.idl inetreg.h inetsdk.h inetsdk.idl inetsdk.mak
inilib.h initguid.h initoid.h intshcut.h io.h iomanip iomanip.h ios ios.h iosfwd iostream iostream.h ipifcons.h ipinfoid.h ipmcdefs.h ipmconv.h iprtrmib.h
ipxconst.h ipxrip.h ipxrtdef.h ipxsap.h ipxtfflt.h irtprph.h irtpsph.h isguids.h iso646.h issper16.h issperr.h istream istream.h iterator itvx.h javaattr.h
javadbg.h javaexec.h jdbgguid.h kerbcon.h kerberos.h ks.h ksuuids.h largeint.h limits limits.h list list.h listing.inc lm.h lmaccess.h lmalert.h lmapibuf.h
lmat.h lmaudit.h lmbrowsr.h lmchdev.h lmconfig.h lmcons.h lmdfs.h lmerr.h lmerrlog.h lmmsg.h lmremutl.h lmrepl.h lmserver.h lmshare.h lmsname.h lmstats.h
lmsvc.h lmuse.h lmuseflg.h lmwksta.h loadperf.h locale locale.h locality.odl lsapi.h lua_c.h lzexpand.h make.inc malloc.h map mapi.h mapicode.h mapidbg.h
mapidefs.h mapiform.h mapiguid.h mapihook.h mapinls.h mapioid.h mapispi.h mapitags.h mapiutil.h mapival.h mapivb.bas mapiwin.h mapiwz.h mapix.h math.h
mbctype.h mblogon.h mbstring.h mbxdata.h mciavi.h mcx.h mdcommsg.h mddefw.h mdmsg.h mdsi.h mdsimsgs.h memory memory.h mgmtapi.h midles.h mimeinfo.h
mimeinfo.idl minmax.h mlang.h mlang.idl mmc.h mmc.idl mmreg.h mmstream.h mmstream.idl mmsystem.h moniker.h monitor.h monshare.h mpconfig.h mpegtype.h
mprapi.h mprerror.h mprui.h mq.h mqoai.h msacm.h msacmdlg.dlg msacmdlg.h msado15.idl msclus.h msclus.idl msclus.tlb msconf.h mscpydis.h msdadc.h msdaguid.h
msdaora.h msdaosp.h msdasc.h msdasql.h msdatsrc.h msdetect.h msfs.h msgemit.h msgfiltr.h mshtmcid.h mshtmdid.h mshtmhst.h mshtmhst.idl mshtml.h mshtml.idl
msi.h msiquery.h msitool.mak mspab.h mspst.h msregdb.h msshared.h mssip.h msstkppg.h mstask.h mstask.idl msterr.h mstv.h mswsock.h msxml.h msxml.idl
msxmldid.h mtsevents.h mtsevents_i.c mtsgrp.h mtsgrp_i.c mtx.h mtxadmin.h mtxadmin_i.c mtxattr.h mtxdm.h mtxdm_i.c mtxspm.h multimon.h multinfo.h nal.h
naltypes.h namesps.odl nativcom.h native.h nb30.h nddeapi.h nddesec.h neterr.h network.h new new.h newpst.h nspapi.h ntlmsp.h ntmsapi.h ntmsmli.h ntquery.h
ntsdexts.h ntsecapi.h ntverp.h ntwin32.mak numeric oaidl.h oaidl.idl objbase.h objectty.h objerror.h objidl.h objidl.idl objmodel objsafe.h objsafe.idl
ocidl.h ocidl.idl ocmm.idl odbcinst.h odbcss.h odbcver.h oemnsvbh.inf oid.h oldplib.h ole.h ole2.h ole2ver.h oleacc.h oleauto.h olectl.h olectlid.h oledb.h
oledb11spec.hh oledberr.h oledberr.mc oledbjvs.inc oledbvbs.inc oledlg.dlg oledlg.h oleidl.h oleidl.idl olenls.h olesampl.mak olescrpt.h olestd.h
oletx2xa.h ostream ostream.h packet.h parser.h pbt.h pcrt32.h pdh.h pdhmsg.h penwin.h perf.h perf.inc perfsym.h perhist.h perhist.idl plan32.h playlist.h
poppack.h postmake.inc printer.odl printjob.odl prnsetup.dlg process.h propbag2.h propbag2.idl proptag.h protocol.h proxygen.h proxyinf.h prsht.h
pshpack1.h pshpack2.h pshpack4.h pshpack8.h qnetwork.h qos.h qosname.h qrycodes.h queue queue.h ras.h rasauth.h rasdlg.h raseapif.h raserror.h rassapi.h
rasshost.h rating.h ratings.h ratingsy.h rclsid.h recguids.h reconcil.h regstr.h rend.h resapi.h resource.odl retcode.h richedit.h richole.h rmfacade.h
rnderr.h rndnot.h routprot.h rpc.h rpcasync.h rpcbak.h rpcdce.h rpcdcep.h rpcndr.h rpcnsi.h rpcnsip.h rpcnterr.h rpcpri.h rpcproxy.h rpcpub.h rtflib.h
rtinfo.h rtm.h rtp.h rtutils.h rulecls.h sadapi.h scarddat.h scarddat.idl scarddat_i.c scarderr.h scardmgr.h scardmgr.idl scardmgr_i.c scardsrv.h
scardsrv.idl scardsrv_i.c schema.odl schnlsp.h scode.h scrnsave.h scrptids.h sdkbld.mak sdkpropbld.mak sdpblb.h sdperr.h search.h secext.h seclink.h
secpkg.h security.h sehmap.h semfperf.h serv.odl servprov.h servprov.idl session.h session.odl set setjmp.h setjmpex.h setupapi.h setupdd.h sgwdata.h
share.h shellapi.h shlguid.h shlobj.h shlwapi.h signal.h simpdata.h simpdata.idl sipbase.h smbdata.h smpab.h smpms.h smpxp.h smsapi.h smsinfo.h sna_cnst.h
sna_dlc.h snados.h snanls.h snapmon.h snmp.h sporder.h sql.h sqldb.h sqlext.h sqlfront.h sqlole.h sqloleid.h sqltypes.h sqlucode.h srv.h srvapi.h
srvconst.h srvdbtyp.h srvmisc.h srvstruc.h srvtok.h srvtypes.h sspguid.h sspi.h sspserr.h sspsidl.h sspsidl.idl sspsidl_i.c sstream stablize.h stack
station.h stats.h stattype.h stdarg.h stddef.h stdexcept stdexcpt.h stdio.h stdiostr.h stdlib.h stm.h storage.h streamb.h streambuf streamty.h string
string.h strmhelp.h strmif.h strmif.idl strstrea.h strstream subgenre.h subsmgr.h subsmgr.idl svcguid.h svrapi.h syncdtct.h sys tagnames.h tapi.h tapi3.h
tchar.h theme.h time.h timeslot.h tlhelp32.h tnef.h tpstart.h trace.h transact.h trkcom.h trkcom.idl trnsdt.h tspi.h tss.h tssadmin.odl tssqsec.h tssutil.h
tvdisp.h tvdisp.odl tvdispid.h txcoord.h txctx.h txdtc.h typeinfo typeinfo.h uastrfnc.h unknwn.h unknwn.idl urlhist.h urlhist.idl urlhlink.h urlmon.h
urlmon.idl use_ansi.h useoldio.h user.odl utassert.h util.h utility utlist.h utsem.h uuids.h valarray varargs.h variant.h vbsql.bas vbsql.bi vcr.h vdmdbg.h
vector ver.h verfile verinfo.h verinfo.ver version.h vfw.h vfwmsgs.h vidsvr.odl vidtypes.h vpconfig.h vpnotify.h vptype.h vsof.h vsop.h vsopcsid.h
w32chico.mk w32sut.h wab.h wabapi.h wabcode.h wabdefs.h wabiab.h wabmem.h wabnot.h wabtags.h wabutil.h wchar.h wctype.h wdbgexts.h wfext.h win32.mak
winable.h winappc.h winbase.h wincon.h wincpic.h wincrypt.h wincsv.h windef.h windows.h windowsx.h windowsx.h16 winerror.h wingdi.h wininet.h winioctl.h
winldap.h winlua.h winmgt.h winnetwk.h winnls.h winnls32.h winnt.h winnt.rh winperf.h winreg.h winres.h winresrc.h winrui.h winscard.h winsli.h winsmcrd.h
winsnmp.h winsock.h winsock2.h winspool.h winsvc.h wintrust.h winuser.h winuser.rh winver.h winwlx.h winwrap.h wownt16.h wownt32.h wpapi.h wpapimsg.h
wpcrsmsg.h wpftpmsg.h wpguid.h wpobj.h wpobj.idl wppstmsg.h wpspi.h wpspi.idl wpspihlp.h wptypes.h wpwizmsg.h wrpguid.h ws2atm.h ws2dnet.h ws2spi.h
ws2tcpip.h wshisotp.h wsipx.h wsnetbs.h wsnwlink.h wsvns.h wsvv.h wtypes.h wtypes.idl xa.h xactomsg.h xcmc.h xcmcext.h xcmcmsx2.h xcmcmsxt.h xcomplex
xiosbase xlocale xlocinfo xlocinfo.h xlocmon xlocnum xloctime xmemory xolehlp.h xstddef xstring xtree xutility ymath.h yvals.h zmouse.h
MACROS
Windows verwendet zahlreiche MACROS, die in C/C++-Header-File enthalten sind.
siehe z.B.: windowsx.h
=====================
Einige C-Header-Files
=====================
math.h
=====================
abs
Return absolute value of integer parameter
acos
Calculate arccosine
asin
Calculate arcsine
atan
Calculate arctangent
atan2
Calculate arctangent, 2 parameters
atof
Convert string to double
ceil
Return the smallest integer that is greater or equal to x
cos
Calculate cosine
cosh
Calculate hyperbolic cosine
exp
Calculate exponential
fabs
Return absolute value of floating-point
floor
Round down value
fmod
Return remainder of floating point division
frexp
Get mantissa and exponent of floating-point value
labs
Return absolute value of long integer parameter
ldexp
Get floating-point value from mantissa and exponent
log
Calculate natural logarithm
log10
Calculate logarithm base 10
modf
Spli floating-point value into fractional and integer parts
pow
Calculate numeric power
sin
Calculate sine
sinh
Calculate hyperbolic sine
sqrt
Calculate square root
tan
Calculate tangent
tanh
Calculate hyperbolic tangent
stdio.h
=====================
clearerr
Reset error indicators.
fclose
Close a stream.
feof
Check if End Of File has been reached.
ferror
Check for errors.
fflush
Flush a stream.
fgetc
Get next character from a stream.
fgetpos
Get position in a stream.
fgets
Get string from a stream.
fopen
Open a file.
fprintf
Print formatted data to a stream.
fputc
Write character to a stream.
fputchar
Write character to stdout.
fputs
Write string to a stream.
fread
Read block of data from a stream.
freopen
Reopen a file using a different file mode.
fscanf
Read formatted data from a stream.
fseek
Reposition stream's position indicator.
fsetpos
Reposition file pointer to a saved location.
ftell
Return the current position of the file pointer.
fwrite
Write block of data to a stream.
getc
Get the next character.
getchar
Get the next character from stdin.
gets
Get a string from stdin.
getw
Get the next int value from a stream.
perror
Print error message.
printf
Print formatted data to stdout.
putc
Write character to a stream.
putchar
Write character to stdout.
puts
Write a string to stdout.
putw
Write an integer to a stream.
remove
rename
rewind
scanf
setbuf
setvbuf
sprintf
sscanf
tmpfile
tmpnam
ungetc
Delete a file.
Rename a file or directory.
Reposition file pointer to the beginning of a stream.
Read formatted data from stdin.
Change stream buffering.
Change stream buffering.
Format data to a string.
Read formatted data from a string.
Open a temporary file.
Generate a unique temporary filename.
Push a character back into stream.
Streams.
Streams are an abstraction used in C and C++ for input and output operations through
I/O devices based on characters, like files, keyboard, printer, screen and I/O ports.
A stdio.h stream is represented by a pointer to a FILE structure that contains
internal info about properties and indicators of a file. Normally data contained
in these structures are not referred directly. When using stdio.h functions,
pointer to FILE structures are only used to be passed as parameters to I/O functions.
Properties.
A stream has some properties that defines which functions can be used with it
or how the functions will treat the stream. Most of them are defined in the
mode parameter when fopen function is called.
Access
Specifies if the operations performed with the stream will have read
and/or write access to the file.
Text / Binary
Text files are those where lines are delimited by the special character
EOL (End Of Line), and some translations occur when this special character
is read or written for that these file can be directly outputed to a console.
The End of a text file is defined by the first occurrence of the EOF character.
A binary file is a file where each byte is read or written as a character,
no translations occur, and the End of a binary file matches with the
physical End of the File.
Buffer
A buffer is a block of memory where data is accumulated before being physically read
or written to the file. Buffered stream causes I/O operations with the stream to be
faster because normally buffers are faster than physical devices like disks or ports.
A stream can be unbuffered so the data is directly read or written to the device.
The use of stream buffers can be specified using functions setbuf and setvbuf.
Indicators.
A stream has some indicators that specify the current state of it. These are
internally modified and affect the behavior of Input/Output functions:
Error Indicator
This indicator is set when an error has occurred in an operation related with the stream.
This indicator can be checked using ferror, and can be reset by a call to clearerr or by
any repositioning functions (rewind, fseek and fsetpos).
End-Of-File Indicator
When this indicator is set, the last reading or writing operation permormed has
reached the End of the file associated with the stream. This can be checked with
the feof function, and can be reset by calling to clearerr or by any repositioning
functions (rewind, fseek and fsetpos).
Position Indicator (File pointer)
This indicator is an internal pointer that points to the next character within the
stream that has to be read or written by the next I/O operation. This value can be
obtained by the ftell and fgetpos functions, and can be changed calling to rewind,
fseek and fsetpos unctions
Standard Streams
When a program that includes stdio.h begin its execution, three predefined streams
are opened:
stdin
This is the standard input stream. By default stdin corresponds to the keyboard,
but this can be redirected by the operating system.
stdout
This is the standard output stream. By default stdout is directed to the screen,
but the operating system can redirect it to a file or any other output device.
stderr
The standard error stream. This is an output stream specifically intendend to
receive error messages. By default is directed to the standard output (like stdout),
but it can be redirected to a log file or any other output device.
stdlib.h
===============
* = not ANSI-C, but supported by most compilers.
abort
Abort current process returning error code
abs
Return absolute value of integer parameter
atexit
Specifies a function to be executed at exit
atof
Convert string to double
atoi
Convert string to integer
atol
Convert string to long
bsearch
Binary search
calloc
Allocate array in memory
div
Divide two integer values
* ecvt
Convert floating point value to string
exit
Terminate calling process
* fcvt
Convert floating point value to string
free
Deallocate dynamically allocated memory
* gcvt
Convert floating point value to string
getenv
Get string from environment
* itoa
Convert integer to string
labs
Return absolute calue of long integer parameter
ldiv
Divide two long integer values
* lfind
Linear search
* lsearch Linear search
* ltoa
Convert long integer value to string
malloc
Allocate memory block
* max
Return the greater of two parameters
* min
Return the smaller of two parameters
* putenv Create or modify environment variable
qsort
Sort using quicksort algorithm
rand
Generate random number
realloc
Reallocate memory block
srand
Initialize random number generator
strtod
Convert string to double-precision floating-point value
strtol
Convert string to long integer
strtoul
Convert string to unsigned long integer
* swab
Swap bytes
system
Execute command
* ultoa
Convert unsigned long integer to string
===============
stdlib.h summary:
C stdlib.h library functions can be divided
in these groups depending on their utility:
conversion:
atof, atoi, atol, ecvt, fcvt, itoa,
ltoa, strtod, strtol, strtoul, ultoa
dynamic memory allocation/deallocation:
calloc, free, malloc, realloc
process control and environment variables:
abort, atexit, exit, getenv, putenv, system
sorting and searching:
bsearch, lfind, lsearch, qsort, swab
mathematical operations:
abs, div, labs, ldiv
string.h
=====================
memchr
Search buffer for a character
memcmp
Compare two buffers
memcpy
Copy bytes to buffer from buffer
memmove
Copy bytes to buffer from buffer
memset
Fill buffer with specified character
strcat
Append string
strchr
Find character in string
strcmp
Compare two strings
strcoll
Compare two strings using locale settings
strcpy
Copy string
strcspn
Search string for occurrence of charcter set
strerror
Get pointer to error message string
strlen
Return string length
strncat
Append substring to string
strncmp
Compare some characters of two strings
strncpy
Copy characters from one string to another
strpbrk
Scan string for specified characters
strrchr
Find last occurrence of character in string
strspn
Get length of substring composed of given characters
strstr
Find substring
strtok
Sequentially truncate string if delimiter is found
strxfrm
Transform string using locale settings
time.h
=====================
asctime
Convert tm structure to string
clock
Return number of clock ticks since process start
ctime
Convert time_t value to string
difftime
Return difference between two times
gmtime
Convert time_t value to tm structure as UTC time
localtime Convert time_t value to tm structure as local time
mktime
Convert tm structure to time_t value
time
Get current time
Types and constants:
CLK_TCK
Constant that defines the number of clock ticks per second.
Used by clock function.
clock_t and time_t
Data types returned by clock and time functions respectivelly.
They are generally defined as long int.
tm
Structure returned or used by asctime, gmtime, localtime and mktime.
/*****************************************************************************\
*
*
* windowsx.h - Macro APIs, window message crackers, and control APIs
*
*
*
*
Version Win32 / Windows NT
*
*
*
*
Copyright (c) 1992-1996, Microsoft Corp. All rights reserved.*
*
*
\*****************************************************************************/
#ifndef _INC_WINDOWSX
#define _INC_WINDOWSX
#ifdef __cplusplus
extern "C" {
/* Assume C declarations for C++ */
#endif /* __cplusplus */
/****** KERNEL Macro APIs ****************************************************/
#define
GetInstanceModule(hInstance) (HMODULE)(hInstance)
#define
GlobalPtrHandle(lp)
\
((HGLOBAL)GlobalHandle(lp))
#define
GlobalLockPtr(lp)
\
((BOOL)GlobalLock(GlobalPtrHandle(lp)))
GlobalUnlockPtr(lp)
\
GlobalUnlock(GlobalPtrHandle(lp))
#define
#define
#define
(flags))))
#define
GlobalAllocPtr(flags, cb)
\
(GlobalLock(GlobalAlloc((flags), (cb))))
GlobalReAllocPtr(lp, cbNew, flags)
\
(GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew),
GlobalFreePtr(lp)
\
(GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))
/****** GDI Macro APIs *******************************************************/
#define
#define
#define
DeletePen(hpen)
DeleteObject((HGDIOBJ)(HPEN)(hpen))
SelectPen(hdc, hpen)
((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
GetStockPen(i)
((HPEN)GetStockObject(i))
#define
#define
#define
DeleteBrush(hbr)
DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
SelectBrush(hdc, hbr)
((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr)))
GetStockBrush(i)
((HBRUSH)GetStockObject(i))
#define
DeleteRgn(hrgn)
#define
#define
RGN_AND)
#define
RGN_DIFF)
#define
RGN_OR)
#define
RGN_XOR)
CopyRgn(hrgnDst, hrgnSrc)
IntersectRgn(hrgnResult, hrgnA, hrgnB)
CombineRgn(hrgnDst, hrgnSrc, 0, RGN_COPY)
CombineRgn(hrgnResult, hrgnA, hrgnB,
SubtractRgn(hrgnResult, hrgnA, hrgnB)
CombineRgn(hrgnResult, hrgnA, hrgnB,
UnionRgn(hrgnResult, hrgnA, hrgnB)
CombineRgn(hrgnResult, hrgnA, hrgnB,
XorRgn(hrgnResult, hrgnA, hrgnB)
CombineRgn(hrgnResult, hrgnA, hrgnB,
#define
DeletePalette(hpal)
#define
#define
#define
DeleteFont(hfont)
DeleteObject((HGDIOBJ)(HFONT)(hfont))
SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
GetStockFont(i)
((HFONT)GetStockObject(i))
#define
#define
DeleteBitmap(hbm)
SelectBitmap(hdc, hbm)
DeleteObject((HGDIOBJ)(HRGN)(hrgn))
DeleteObject((HGDIOBJ)(HPALETTE)(hpal))
DeleteObject((HGDIOBJ)(HBITMAP)(hbm))
((HBITMAP)SelectObject((hdc), (HGDIOBJ)(HBITMAP)(hbm)))
#define
InsetRect(lprc, dx, dy) InflateRect((lprc), -(dx), -(dy))
/****** USER Macro APIs ******************************************************/
#define
GetWindowInstance(hwnd) ((HMODULE)GetWindowLong(hwnd, GWL_HINSTANCE))
#define
#define
GetWindowStyle(hwnd)
GetWindowExStyle(hwnd)
((DWORD)GetWindowLong(hwnd, GWL_STYLE))
((DWORD)GetWindowLong(hwnd, GWL_EXSTYLE))
#define
GetWindowOwner(hwnd)
GetWindow(hwnd, GW_OWNER)
#define
#define
#define
#define
#define
GetFirstChild(hwnd)
GetFirstSibling(hwnd)
GetLastSibling(hwnd)
GetNextSibling(hwnd)
GetPrevSibling(hwnd)
GetTopWindow(hwnd)
GetWindow(hwnd, GW_HWNDFIRST)
GetWindow(hwnd, GW_HWNDLAST)
GetWindow(hwnd, GW_HWNDNEXT)
GetWindow(hwnd, GW_HWNDPREV)
#define
GetWindowID(hwnd)
#define
SetWindowRedraw(hwnd, fRedraw) \
((void)SendMessage(hwnd, WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L))
#define
SubclassWindow(hwnd, lpfn)
\
((WNDPROC)SetWindowLong((hwnd), GWL_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))
#define
#define
#define
IsMinimized(hwnd)
IsMaximized(hwnd)
IsRestored(hwnd)
GetDlgCtrlID(hwnd)
IsIconic(hwnd)
IsZoomed(hwnd)
((GetWindowStyle(hwnd) & (WS_MINIMIZE | WS_MAXIMIZE)) == 0L)
#define
SetWindowFont(hwnd, hfont, fRedraw) FORWARD_WM_SETFONT((hwnd), (hfont), (fRedraw),
SendMessage)
#define
GetWindowFont(hwnd)
FORWARD_WM_GETFONT((hwnd), SendMessage)
#if (WINVER >= 0x030a)
#define
MapWindowRect(hwndFrom, hwndTo, lprc) \
MapWindowPoints((hwndFrom), (hwndTo), (POINT *)(lprc), 2)
#endif
#define
IsLButtonDown() (GetKeyState(VK_LBUTTON) < 0)
#define
IsRButtonDown() (GetKeyState(VK_RBUTTON) < 0)
#define
IsMButtonDown() (GetKeyState(VK_MBUTTON) < 0)
#define
SubclassDialog(hwndDlg, lpfn) \
((DLGPROC)SetWindowLong(hwndDlg, DWL_DLGPROC, (LPARAM)(DLGPROC)(lpfn)))
#define
SetDlgMsgResult(hwnd, msg, result) (( \
(msg) == WM_CTLCOLORMSGBOX
|| \
(msg) == WM_CTLCOLOREDIT
|| \
(msg) == WM_CTLCOLORLISTBOX
|| \
(msg) == WM_CTLCOLORBTN
|| \
(msg) == WM_CTLCOLORDLG
|| \
(msg) == WM_CTLCOLORSCROLLBAR
|| \
(msg) == WM_CTLCOLORSTATIC
|| \
(msg) == WM_COMPAREITEM
|| \
(msg) == WM_VKEYTOITEM
|| \
(msg) == WM_CHARTOITEM
|| \
(msg) == WM_QUERYDRAGICON
|| \
(msg) == WM_INITDIALOG
\
) ? (BOOL)(result) : (SetWindowLong((hwnd), DWL_MSGRESULT, (LPARAM)(LRESULT)(result)),
TRUE))
#define
DefDlgProcEx(hwnd, msg, wParam, lParam, pfRecursion) \
(*(pfRecursion) = TRUE, DefDlgProc(hwnd, msg, wParam, lParam))
#define
CheckDefDlgRecursion(pfRecursion) \
if (*(pfRecursion)) { *(pfRecursion) = FALSE; return FALSE; }
/****** Message crackers ****************************************************/
#define HANDLE_MSG(hwnd, message, fn)
\
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
/* void Cls_OnCompacting(HWND hwnd, UINT compactRatio) */
#define HANDLE_WM_COMPACTING(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam)), 0L)
#define FORWARD_WM_COMPACTING(hwnd, compactRatio, fn) \
(void)(fn)((hwnd), WM_COMPACTING, (WPARAM)(UINT)(compactRatio), 0L)
/* void Cls_OnWinIniChange(HWND hwnd, LPCTSTR lpszSectionName) */
#define HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_WININICHANGE(hwnd, lpszSectionName, fn) \
(void)(fn)((hwnd), WM_WININICHANGE, 0L, (LPARAM)(LPCTSTR)(lpszSectionName))
/* void Cls_OnSysColorChange(HWND hwnd) */
#define HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_SYSCOLORCHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_SYSCOLORCHANGE, 0L, 0L)
/* BOOL Cls_OnQueryNewPalette(HWND hwnd) */
#define HANDLE_WM_QUERYNEWPALETTE(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYNEWPALETTE(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYNEWPALETTE, 0L, 0L)
/* void Cls_OnPaletteIsChanging(HWND hwnd, HWND hwndPaletteChange) */
#define HANDLE_WM_PALETTEISCHANGING(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_PALETTEISCHANGING(hwnd, hwndPaletteChange, fn) \
(void)(fn)((hwnd), WM_PALETTEISCHANGING, (WPARAM)(HWND)(hwndPaletteChange), 0L)
/* void Cls_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange) */
#define HANDLE_WM_PALETTECHANGED(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_PALETTECHANGED(hwnd, hwndPaletteChange, fn) \
(void)(fn)((hwnd), WM_PALETTECHANGED, (WPARAM)(HWND)(hwndPaletteChange), 0L)
/* void Cls_OnFontChange(HWND hwnd) */
#define HANDLE_WM_FONTCHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_FONTCHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_FONTCHANGE, 0L, 0L)
/* void Cls_OnSpoolerStatus(HWND hwnd, UINT status, int cJobInQueue) */
#define HANDLE_WM_SPOOLERSTATUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SPOOLERSTATUS(hwnd, status, cJobInQueue, fn) \
(void)(fn)((hwnd), WM_SPOOLERSTATUS, (WPARAM)(status), MAKELPARAM((cJobInQueue), 0))
/* void Cls_OnDevModeChange(HWND hwnd, LPCTSTR lpszDeviceName) */
#define HANDLE_WM_DEVMODECHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_DEVMODECHANGE(hwnd, lpszDeviceName, fn) \
(void)(fn)((hwnd), WM_DEVMODECHANGE, 0L, (LPARAM)(LPCTSTR)(lpszDeviceName))
/* void Cls_OnTimeChange(HWND hwnd) */
#define HANDLE_WM_TIMECHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_TIMECHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_TIMECHANGE, 0L, 0L)
/* void Cls_OnPower(HWND hwnd, int code) */
#define HANDLE_WM_POWER(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam)), 0L)
#define FORWARD_WM_POWER(hwnd, code, fn) \
(void)(fn)((hwnd), WM_POWER, (WPARAM)(int)(code), 0L)
/* BOOL Cls_OnQueryEndSession(HWND hwnd) */
#define HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYENDSESSION(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYENDSESSION, 0L, 0L)
/* void Cls_OnEndSession(HWND hwnd, BOOL fEnding) */
#define HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_ENDSESSION(hwnd, fEnding, fn) \
(void)(fn)((hwnd), WM_ENDSESSION, (WPARAM)(BOOL)(fEnding), 0L)
/* void Cls_OnQuit(HWND hwnd, int exitCode) */
#define HANDLE_WM_QUIT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam)), 0L)
#define FORWARD_WM_QUIT(hwnd, exitCode, fn) \
(void)(fn)((hwnd), WM_QUIT, (WPARAM)(exitCode), 0L)
/* This
/* void
#define
#define
message is in Windows 3.1 only */
Cls_OnSystemError(HWND hwnd, int errCode) */
HANDLE_WM_SYSTEMERROR(hwnd, wParam, lParam, fn) 0L
FORWARD_WM_SYSTEMERROR(hwnd, errCode, fn) 0L
/* BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
#define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_CREATE, 0L, (LPARAM)(LPCREATESTRUCT)(lpCreateStruct))
/* BOOL Cls_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */
#define HANDLE_WM_NCCREATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPCREATESTRUCT)(lParam))
#define FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_NCCREATE, 0L, (LPARAM)(LPCREATESTRUCT)(lpCreateStruct))
/* void Cls_OnDestroy(HWND hwnd) */
#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DESTROY(hwnd, fn) \
(void)(fn)((hwnd), WM_DESTROY, 0L, 0L)
/* void Cls_OnNCDestroy(HWND hwnd) */
#define HANDLE_WM_NCDESTROY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_NCDESTROY(hwnd, fn) \
(void)(fn)((hwnd), WM_NCDESTROY, 0L, 0L)
/* void Cls_OnShowWindow(HWND hwnd, BOOL fShow, UINT status) */
#define HANDLE_WM_SHOWWINDOW(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam), (UINT)(lParam)), 0L)
#define FORWARD_WM_SHOWWINDOW(hwnd, fShow, status, fn) \
(void)(fn)((hwnd), WM_SHOWWINDOW, (WPARAM)(BOOL)(fShow), (LPARAM)(UINT)(status))
/* void Cls_OnSetRedraw(HWND hwnd, BOOL fRedraw) */
#define HANDLE_WM_SETREDRAW(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_SETREDRAW(hwnd, fRedraw, fn) \
(void)(fn)((hwnd), WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L)
/* void Cls_OnEnable(HWND hwnd, BOOL fEnable) */
#define HANDLE_WM_ENABLE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_ENABLE(hwnd, fEnable, fn) \
(void)(fn)((hwnd), WM_ENABLE, (WPARAM)(BOOL)(fEnable), 0L)
/* void Cls_OnSetText(HWND hwnd, LPCTSTR lpszText) */
#define HANDLE_WM_SETTEXT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_SETTEXT(hwnd, lpszText, fn) \
(void)(fn)((hwnd), WM_SETTEXT, 0L, (LPARAM)(LPCTSTR)(lpszText))
/* INT Cls_OnGetText(HWND hwnd, int cchTextMax, LPTSTR lpszText) */
#define HANDLE_WM_GETTEXT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (int)(wParam), (LPTSTR)(lParam))
#define FORWARD_WM_GETTEXT(hwnd, cchTextMax, lpszText, fn) \
(int)(DWORD)(fn)((hwnd), WM_GETTEXT, (WPARAM)(int)(cchTextMax), (LPARAM)(LPTSTR)(lpszText))
/* INT Cls_OnGetTextLength(HWND hwnd) */
#define HANDLE_WM_GETTEXTLENGTH(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)(hwnd)
#define FORWARD_WM_GETTEXTLENGTH(hwnd, fn) \
(int)(DWORD)(fn)((hwnd), WM_GETTEXTLENGTH, 0L, 0L)
/* BOOL Cls_OnWindowPosChanging(HWND hwnd, LPWINDOWPOS lpwpos) */
#define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
#define FORWARD_WM_WINDOWPOSCHANGING(hwnd, lpwpos, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_WINDOWPOSCHANGING, 0L, (LPARAM)(LPWINDOWPOS)(lpwpos))
/* void Cls_OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos) */
#define HANDLE_WM_WINDOWPOSCHANGED(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const LPWINDOWPOS)(lParam)), 0L)
#define FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, fn) \
(void)(fn)((hwnd), WM_WINDOWPOSCHANGED, 0L, (LPARAM)(const LPWINDOWPOS)(lpwpos))
/* void Cls_OnMove(HWND hwnd, int x, int y) */
#define HANDLE_WM_MOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_MOVE(hwnd, x, y, fn) \
(void)(fn)((hwnd), WM_MOVE, 0L, MAKELPARAM((x), (y)))
/* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */
#define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_SIZE(hwnd, state, cx, cy, fn) \
(void)(fn)((hwnd), WM_SIZE, (WPARAM)(UINT)(state), MAKELPARAM((cx), (cy)))
/* void Cls_OnClose(HWND hwnd) */
#define HANDLE_WM_CLOSE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CLOSE(hwnd, fn) \
(void)(fn)((hwnd), WM_CLOSE, 0L, 0L)
/* BOOL Cls_OnQueryOpen(HWND hwnd) */
#define HANDLE_WM_QUERYOPEN(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYOPEN(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYOPEN, 0L, 0L)
/* void Cls_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo) */
#define HANDLE_WM_GETMINMAXINFO(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPMINMAXINFO)(lParam)), 0L)
#define FORWARD_WM_GETMINMAXINFO(hwnd, lpMinMaxInfo, fn) \
(void)(fn)((hwnd), WM_GETMINMAXINFO, 0L, (LPARAM)(LPMINMAXINFO)(lpMinMaxInfo))
/* void Cls_OnPaint(HWND hwnd) */
#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_PAINT(hwnd, fn) \
(void)(fn)((hwnd), WM_PAINT, 0L, 0L)
/* BOOL Cls_OnEraseBkgnd(HWND hwnd, HDC hdc) */
#define HANDLE_WM_ERASEBKGND(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
#define FORWARD_WM_ERASEBKGND(hwnd, hdc, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_ERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
/* BOOL Cls_OnIconEraseBkgnd(HWND hwnd, HDC hdc) */
#define HANDLE_WM_ICONERASEBKGND(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
#define FORWARD_WM_ICONERASEBKGND(hwnd, hdc, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_ICONERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
/* void Cls_OnNCPaint(HWND hwnd, HRGN hrgn) */
#define HANDLE_WM_NCPAINT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HRGN)(wParam)), 0L)
#define FORWARD_WM_NCPAINT(hwnd, hrgn, fn) \
(void)(fn)((hwnd), WM_NCPAINT, (WPARAM)(HRGN)(hrgn), 0L)
/* UINT Cls_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS * lpcsp) */
#define HANDLE_WM_NCCALCSIZE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(0), (NCCALCSIZE_PARAMS *)(lParam))
#define FORWARD_WM_NCCALCSIZE(hwnd, fCalcValidRects, lpcsp, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_NCCALCSIZE, 0L, (LPARAM)(NCCALCSIZE_PARAMS *)(lpcsp))
/* UINT Cls_OnNCHitTest(HWND hwnd, int x, int y) */
#define HANDLE_WM_NCHITTEST(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam))
#define FORWARD_WM_NCHITTEST(hwnd, x, y, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_NCHITTEST, 0L, MAKELPARAM((x), (y)))
/* HICON Cls_OnQueryDragIcon(HWND hwnd) */
#define HANDLE_WM_QUERYDRAGICON(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd)
#define FORWARD_WM_QUERYDRAGICON(hwnd, fn) \
(HICON)(UINT)(DWORD)(fn)((hwnd), WM_QUERYDRAGICON, 0L, 0L)
#ifdef _INC_SHELLAPI
/* void Cls_OnDropFiles(HWND hwnd, HDROP hdrop) */
#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HDROP)(wParam)), 0L)
#define FORWARD_WM_DROPFILES(hwnd, hdrop, fn) \
(void)(fn)((hwnd), WM_DROPFILES, (WPARAM)(HDROP)(hdrop), 0L)
#endif /* _INC_SHELLAPI */
/* void Cls_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) */
#define HANDLE_WM_ACTIVATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (BOOL)HIWORD(wParam)), 0L)
#define FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, fn) \
(void)(fn)((hwnd), WM_ACTIVATE, MAKEWPARAM((state), (fMinimized)),
(LPARAM)(HWND)(hwndActDeact))
/* void Cls_OnActivateApp(HWND hwnd, BOOL fActivate, DWORD dwThreadId) */
#define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
#define FORWARD_WM_ACTIVATEAPP(hwnd, fActivate, dwThreadId, fn) \
(void)(fn)((hwnd), WM_ACTIVATEAPP, (WPARAM)(BOOL)(fActivate), (LPARAM)(dwThreadId))
/* BOOL Cls_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized) */
#define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), 0L, 0L)
#define FORWARD_WM_NCACTIVATE(hwnd, fActive, hwndActDeact, fMinimized, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_NCACTIVATE, (WPARAM)(BOOL)(fActive), 0L)
/* void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus) */
#define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_SETFOCUS(hwnd, hwndOldFocus, fn) \
(void)(fn)((hwnd), WM_SETFOCUS, (WPARAM)(HWND)(hwndOldFocus), 0L)
/* void Cls_OnKillFocus(HWND hwnd, HWND hwndNewFocus) */
#define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_KILLFOCUS(hwnd, hwndNewFocus, fn) \
(void)(fn)((hwnd), WM_KILLFOCUS, (WPARAM)(HWND)(hwndNewFocus), 0L)
/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_KEYDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_KEYDOWN(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_KEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags)))
/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_KEYUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_KEYUP(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_KEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags)))
/* void Cls_OnChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_CHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
/* void Cls_OnDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_DEADCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_DEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_SYSKEYDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSKEYDOWN(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_SYSKEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags)))
/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_SYSKEYUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSKEYUP(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_SYSKEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags)))
/* void Cls_OnSysChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SYSCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_SYSCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0))
/* void Cls_OnSysDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SYSDEADCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_SYSDEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0))
/* void Cls_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) */
#define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_MOUSEMOVE(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_MOUSEMOVE, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) */
#define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_LBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_LBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_RBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_RBUTTONDBLCLK : WM_RBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnRButtonUp(HWND hwnd, int x, int y, UINT flags) */
#define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_RBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_RBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_MBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_MBUTTONDBLCLK : WM_MBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) */
#define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnMButtonUp(HWND hwnd, int x, int y, UINT flags) */
#define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_MBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_MBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMOUSEMOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_NCMOUSEMOVE(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCMOUSEMOVE, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCLBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCLBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCLButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCLBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_NCLBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCLBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCRBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCRBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCRBUTTONDBLCLK : WM_NCRBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCRBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCRButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCRBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_NCRBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCRBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCMBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCMBUTTONDBLCLK : WM_NCMBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCMButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
#define FORWARD_WM_NCMBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCMBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* int Cls_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg) */
#define HANDLE_WM_MOUSEACTIVATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam),
(UINT)HIWORD(lParam))
#define FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg, fn) \
(int)(DWORD)(fn)((hwnd), WM_MOUSEACTIVATE, (WPARAM)(HWND)(hwndTopLevel),
MAKELPARAM((codeHitTest), (msg)))
/* void Cls_OnCancelMode(HWND hwnd) */
#define HANDLE_WM_CANCELMODE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CANCELMODE(hwnd, fn) \
(void)(fn)((hwnd), WM_CANCELMODE, 0L, 0L)
/* void Cls_OnTimer(HWND hwnd, UINT id) */
#define HANDLE_WM_TIMER(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam)), 0L)
#define FORWARD_WM_TIMER(hwnd, id, fn) \
(void)(fn)((hwnd), WM_TIMER, (WPARAM)(UINT)(id), 0L)
/* void Cls_OnInitMenu(HWND hwnd, HMENU hMenu) */
#define HANDLE_WM_INITMENU(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HMENU)(wParam)), 0L)
#define FORWARD_WM_INITMENU(hwnd, hMenu, fn) \
(void)(fn)((hwnd), WM_INITMENU, (WPARAM)(HMENU)(hMenu), 0L)
/* void Cls_OnInitMenuPopup(HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu) */
#define HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HMENU)(wParam), (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)), 0L)
#define FORWARD_WM_INITMENUPOPUP(hwnd, hMenu, item, fSystemMenu, fn) \
(void)(fn)((hwnd), WM_INITMENUPOPUP, (WPARAM)(HMENU)(hMenu),
MAKELPARAM((item),(fSystemMenu)))
/* void Cls_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags) */
#define HANDLE_WM_MENUSELECT(hwnd, wParam, lParam, fn)
\
((fn)((hwnd), (HMENU)(lParam), \
(int)(LOWORD(wParam)),
\
(HIWORD(wParam) & MF_POPUP) ? GetSubMenu((HMENU)lParam, LOWORD(wParam)) : 0L, \
(UINT)(((short)HIWORD(wParam) == -1) ? 0xFFFFFFFF : HIWORD(wParam))), 0L)
#define FORWARD_WM_MENUSELECT(hwnd, hmenu, item, hmenuPopup, flags, fn) \
(void)(fn)((hwnd), WM_MENUSELECT, MAKEWPARAM((item), (flags)), (LPARAM)(HMENU)((hmenu) ?
(hmenu) : (hmenuPopup)))
/* DWORD Cls_OnMenuChar(HWND hwnd, UINT ch, UINT flags, HMENU hmenu) */
#define HANDLE_WM_MENUCHAR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(LOWORD(wParam)), (UINT)HIWORD(wParam), (HMENU)(lParam))
#define FORWARD_WM_MENUCHAR(hwnd, ch, flags, hmenu, fn) \
(DWORD)(fn)((hwnd), WM_MENUCHAR, MAKEWPARAM(flags, (WORD)(ch)), (LPARAM)(HMENU)(hmenu))
/* void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) */
#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
(void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)),
(LPARAM)(HWND)(hwndCtl))
/* void Cls_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */
#define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
#define FORWARD_WM_HSCROLL(hwnd, hwndCtl, code, pos, fn) \
(void)(fn)((hwnd), WM_HSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)),
(LPARAM)(UINT)(hwndCtl))
/* void Cls_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */
#define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
#define FORWARD_WM_VSCROLL(hwnd, hwndCtl, code, pos, fn) \
(void)(fn)((hwnd), WM_VSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)),
(LPARAM)(HWND)(hwndCtl))
/* void Cls_OnCut(HWND hwnd) */
#define HANDLE_WM_CUT(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CUT(hwnd, fn) \
(void)(fn)((hwnd), WM_CUT, 0L, 0L)
/* void Cls_OnCopy(HWND hwnd) */
#define HANDLE_WM_COPY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_COPY(hwnd, fn) \
(void)(fn)((hwnd), WM_COPY, 0L, 0L)
/* void Cls_OnPaste(HWND hwnd) */
#define HANDLE_WM_PASTE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_PASTE(hwnd, fn) \
(void)(fn)((hwnd), WM_PASTE, 0L, 0L)
/* void Cls_OnClear(HWND hwnd) */
#define HANDLE_WM_CLEAR(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CLEAR(hwnd, fn) \
(void)(fn)((hwnd), WM_CLEAR, 0L, 0L)
/* void Cls_OnUndo(HWND hwnd) */
#define HANDLE_WM_UNDO(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_UNDO(hwnd, fn) \
(void)(fn)((hwnd), WM_UNDO, 0L, 0L)
/* HANDLE Cls_OnRenderFormat(HWND hwnd, UINT fmt) */
#define HANDLE_WM_RENDERFORMAT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HANDLE)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_RENDERFORMAT(hwnd, fmt, fn) \
(HANDLE)(UINT)(DWORD)(fn)((hwnd), WM_RENDERFORMAT, (WPARAM)(UINT)(fmt), 0L)
/* void Cls_OnRenderAllFormats(HWND hwnd) */
#define HANDLE_WM_RENDERALLFORMATS(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_RENDERALLFORMATS(hwnd, fn) \
(void)(fn)((hwnd), WM_RENDERALLFORMATS, 0L, 0L)
/* void Cls_OnDestroyClipboard(HWND hwnd) */
#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DESTROYCLIPBOARD(hwnd, fn) \
(void)(fn)((hwnd), WM_DESTROYCLIPBOARD, 0L, 0L)
/* void Cls_OnDrawClipboard(HWND hwnd) */
#define HANDLE_WM_DRAWCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DRAWCLIPBOARD(hwnd, fn) \
(void)(fn)((hwnd), WM_DRAWCLIPBOARD, 0L, 0L)
/* void Cls_OnPaintClipboard(HWND hwnd, HWND hwndCBViewer, const LPPAINTSTRUCT lpPaintStruct)
*/
#define HANDLE_WM_PAINTCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (const LPPAINTSTRUCT)GlobalLock((HGLOBAL)(lParam))),
GlobalUnlock((HGLOBAL)(lParam)), 0L)
#define FORWARD_WM_PAINTCLIPBOARD(hwnd, hwndCBViewer, lpPaintStruct, fn) \
(void)(fn)((hwnd), WM_PAINTCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer),
(LPARAM)(LPPAINTSTRUCT)(lpPaintStruct))
/* void Cls_OnSizeClipboard(HWND hwnd, HWND hwndCBViewer, const LPRECT lprc) */
#define HANDLE_WM_SIZECLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (const LPRECT)GlobalLock((HGLOBAL)(lParam))),
GlobalUnlock((HGLOBAL)(lParam)), 0L)
#define FORWARD_WM_SIZECLIPBOARD(hwnd, hwndCBViewer, lprc, fn) \
(void)(fn)((hwnd), WM_SIZECLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), (LPARAM)(LPRECT)(lprc))
/* void Cls_OnVScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */
#define HANDLE_WM_VSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_VSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
(void)(fn)((hwnd), WM_VSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code),
(pos)))
/* void Cls_OnHScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */
#define HANDLE_WM_HSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_HSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
(void)(fn)((hwnd), WM_HSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code),
(pos)))
/* void Cls_OnAskCBFormatName(HWND hwnd, int cchMax, LPTSTR rgchName) */
#define HANDLE_WM_ASKCBFORMATNAME(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam), (LPTSTR)(lParam)), 0L)
#define FORWARD_WM_ASKCBFORMATNAME(hwnd, cchMax, rgchName, fn) \
(void)(fn)((hwnd), WM_ASKCBFORMATNAME, (WPARAM)(int)(cchMax), (LPARAM)(rgchName))
/* void Cls_OnChangeCBChain(HWND hwnd, HWND hwndRemove, HWND hwndNext) */
#define HANDLE_WM_CHANGECBCHAIN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (HWND)(lParam)), 0L)
#define FORWARD_WM_CHANGECBCHAIN(hwnd, hwndRemove, hwndNext, fn) \
(void)(fn)((hwnd), WM_CHANGECBCHAIN, (WPARAM)(HWND)(hwndRemove), (LPARAM)(HWND)(hwndNext))
/* BOOL Cls_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg) */
#define HANDLE_WM_SETCURSOR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam),
(UINT)HIWORD(lParam))
#define FORWARD_WM_SETCURSOR(hwnd, hwndCursor, codeHitTest, msg, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_SETCURSOR, (WPARAM)(HWND)(hwndCursor),
MAKELPARAM((codeHitTest), (msg)))
/* void Cls_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) */
#define HANDLE_WM_SYSCOMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, fn) \
(void)(fn)((hwnd), WM_SYSCOMMAND, (WPARAM)(UINT)(cmd), MAKELPARAM((x), (y)))
/* HWND Cls_MDICreate(HWND hwnd, const LPMDICREATESTRUCT lpmcs) */
#define HANDLE_WM_MDICREATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (LPMDICREATESTRUCT)(lParam))
#define FORWARD_WM_MDICREATE(hwnd, lpmcs, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDICREATE, 0L, (LPARAM)(LPMDICREATESTRUCT)(lpmcs))
/* void Cls_MDIDestroy(HWND hwnd, HWND hwndDestroy) */
#define HANDLE_WM_MDIDESTROY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIDESTROY(hwnd, hwndDestroy, fn) \
(void)(fn)((hwnd), WM_MDIDESTROY, (WPARAM)(hwndDestroy), 0L)
/* NOTE: Usable only by MDI client windows */
/* void Cls_MDIActivate(HWND hwnd, BOOL fActive, HWND hwndActivate, HWND hwndDeactivate) */
#define HANDLE_WM_MDIACTIVATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(lParam == (LPARAM)hwnd), (HWND)(lParam), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIACTIVATE(hwnd, fActive, hwndActivate, hwndDeactivate, fn) \
(void)(fn)(hwnd, WM_MDIACTIVATE, (WPARAM)(hwndDeactivate), (LPARAM)(hwndActivate))
/* void Cls_MDIRestore(HWND hwnd, HWND hwndRestore) */
#define HANDLE_WM_MDIRESTORE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIRESTORE(hwnd, hwndRestore, fn) \
(void)(fn)((hwnd), WM_MDIRESTORE, (WPARAM)(hwndRestore), 0L)
/* HWND Cls_MDINext(HWND hwnd, HWND hwndCur, BOOL fPrev) */
#define HANDLE_WM_MDINEXT(hwnd, wParam, lParam, fn) \
(LRESULT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)lParam)
#define FORWARD_WM_MDINEXT(hwnd, hwndCur, fPrev, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDINEXT, (WPARAM)(hwndCur), (LPARAM)(fPrev))
/* void Cls_MDIMaximize(HWND hwnd, HWND hwndMaximize) */
#define HANDLE_WM_MDIMAXIMIZE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIMAXIMIZE(hwnd, hwndMaximize, fn) \
(void)(fn)((hwnd), WM_MDIMAXIMIZE, (WPARAM)(hwndMaximize), 0L)
/* BOOL Cls_MDITile(HWND hwnd, UINT cmd) */
#define HANDLE_WM_MDITILE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_MDITILE(hwnd, cmd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_MDITILE, (WPARAM)(cmd), 0L)
/* BOOL Cls_MDICascade(HWND hwnd, UINT cmd) */
#define HANDLE_WM_MDICASCADE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_MDICASCADE(hwnd, cmd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_MDICASCADE, (WPARAM)(cmd), 0L)
/* void Cls_MDIIconArrange(HWND hwnd) */
#define HANDLE_WM_MDIICONARRANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_MDIICONARRANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_MDIICONARRANGE, 0L, 0L)
/* HWND Cls_MDIGetActive(HWND hwnd) */
#define HANDLE_WM_MDIGETACTIVE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd)
#define FORWARD_WM_MDIGETACTIVE(hwnd, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDIGETACTIVE, 0L, 0L)
/* HMENU Cls_MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU hmenuWindow) */
#define HANDLE_WM_MDISETMENU(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(wParam), (HMENU)(wParam), (HMENU)(lParam))
#define FORWARD_WM_MDISETMENU(hwnd, fRefresh, hmenuFrame, hmenuWindow, fn) \
(HMENU)(UINT)(DWORD)(fn)((hwnd), WM_MDISETMENU, (WPARAM)((fRefresh) ? (hmenuFrame) : 0),
(LPARAM)(hmenuWindow))
/* void Cls_OnChildActivate(HWND hwnd) */
#define HANDLE_WM_CHILDACTIVATE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CHILDACTIVATE(hwnd, fn) \
(void)(fn)((hwnd), WM_CHILDACTIVATE, 0L, 0L)
/* BOOL Cls_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) */
#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)
#define FORWARD_WM_INITDIALOG(hwnd, hwndFocus, lParam, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_INITDIALOG, (WPARAM)(HWND)(hwndFocus), (lParam))
/* HWND Cls_OnNextDlgCtl(HWND hwnd, HWND hwndSetFocus, BOOL fNext) */
#define HANDLE_WM_NEXTDLGCTL(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)(lParam))
#define FORWARD_WM_NEXTDLGCTL(hwnd, hwndSetFocus, fNext, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_NEXTDLGCTL, (WPARAM)(HWND)(hwndSetFocus),
(LPARAM)(fNext))
/* void Cls_OnParentNotify(HWND hwnd, UINT msg, HWND hwndChild, int idChild) */
#define HANDLE_WM_PARENTNOTIFY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_PARENTNOTIFY(hwnd, msg, hwndChild, idChild, fn) \
(void)(fn)((hwnd), WM_PARENTNOTIFY, MAKEWPARAM(msg, idChild), (LPARAM)(hwndChild))
/* void Cls_OnEnterIdle(HWND hwnd, UINT source, HWND hwndSource) */
#define HANDLE_WM_ENTERIDLE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (HWND)(lParam)), 0L)
#define FORWARD_WM_ENTERIDLE(hwnd, source, hwndSource, fn) \
(void)(fn)((hwnd), WM_ENTERIDLE, (WPARAM)(UINT)(source), (LPARAM)(HWND)(hwndSource))
/* UINT Cls_OnGetDlgCode(HWND hwnd, LPMSG lpmsg) */
#define HANDLE_WM_GETDLGCODE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd, (LPMSG)(lParam))
#define FORWARD_WM_GETDLGCODE(hwnd, lpmsg, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_GETDLGCODE, (lpmsg ? lpmsg->wParam : 0),
(LPARAM)(LPMSG)(lpmsg))
/* HBRUSH Cls_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type) */
#define HANDLE_WM_CTLCOLORMSGBOX(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_MSGBOX)
#define FORWARD_WM_CTLCOLORMSGBOX(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORMSGBOX, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLOREDIT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_EDIT)
#define FORWARD_WM_CTLCOLOREDIT(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLOREDIT, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORLISTBOX(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_LISTBOX)
#define FORWARD_WM_CTLCOLORLISTBOX(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORLISTBOX, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORBTN(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_BTN)
#define FORWARD_WM_CTLCOLORBTN(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORBTN, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORDLG(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_DLG)
#define FORWARD_WM_CTLCOLORDLG(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORDLG, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORSCROLLBAR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_SCROLLBAR)
#define FORWARD_WM_CTLCOLORSCROLLBAR(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSCROLLBAR, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORSTATIC(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam), CTLCOLOR_STATIC)
#define FORWARD_WM_CTLCOLORSTATIC(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSTATIC, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
/* void Cls_OnSetFont(HWND hwndCtl, HFONT hfont, BOOL fRedraw) */
#define HANDLE_WM_SETFONT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HFONT)(wParam), (BOOL)(lParam)), 0L)
#define FORWARD_WM_SETFONT(hwnd, hfont, fRedraw, fn) \
(void)(fn)((hwnd), WM_SETFONT, (WPARAM)(HFONT)(hfont), (LPARAM)(BOOL)(fRedraw))
/* HFONT Cls_OnGetFont(HWND hwnd) */
#define HANDLE_WM_GETFONT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HFONT)(fn)(hwnd)
#define FORWARD_WM_GETFONT(hwnd, fn) \
(HFONT)(UINT)(DWORD)(fn)((hwnd), WM_GETFONT, 0L, 0L)
/* void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem) */
#define HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const DRAWITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_DRAWITEM(hwnd, lpDrawItem, fn) \
(void)(fn)((hwnd), WM_DRAWITEM, (WPARAM)(((const DRAWITEMSTRUCT *)lpDrawItem)->CtlID),
(LPARAM)(const DRAWITEMSTRUCT *)(lpDrawItem))
/* void Cls_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * lpMeasureItem) */
#define HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (MEASUREITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_MEASUREITEM(hwnd, lpMeasureItem, fn) \
(void)(fn)((hwnd), WM_MEASUREITEM, (WPARAM)(((MEASUREITEMSTRUCT *)lpMeasureItem)->CtlID),
(LPARAM)(MEASUREITEMSTRUCT *)(lpMeasureItem))
/* void Cls_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT * lpDeleteItem) */
#define HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const DELETEITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_DELETEITEM(hwnd, lpDeleteItem, fn) \
(void)(fn)((hwnd), WM_DELETEITEM, (WPARAM)(((const DELETEITEMSTRUCT *)(lpDeleteItem))>CtlID), (LPARAM)(const DELETEITEMSTRUCT *)(lpDeleteItem))
/* int Cls_OnCompareItem(HWND hwnd, const COMPAREITEMSTRUCT * lpCompareItem) */
#define HANDLE_WM_COMPAREITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (const COMPAREITEMSTRUCT *)(lParam))
#define FORWARD_WM_COMPAREITEM(hwnd, lpCompareItem, fn) \
(int)(DWORD)(fn)((hwnd), WM_COMPAREITEM, (WPARAM)(((const COMPAREITEMSTRUCT
*)(lpCompareItem))->CtlID), (LPARAM)(const COMPAREITEMSTRUCT *)(lpCompareItem))
/* int Cls_OnVkeyToItem(HWND hwnd, UINT vk, HWND hwndListbox, int iCaret) */
#define HANDLE_WM_VKEYTOITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam),
(int)(short)HIWORD(wParam))
#define FORWARD_WM_VKEYTOITEM(hwnd, vk, hwndListBox, iCaret, fn) \
(int)(DWORD)(fn)((hwnd), WM_VKEYTOITEM, MAKEWPARAM((vk), (iCaret)), (LPARAM)(hwndListBox))
/* int Cls_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret) */
#define HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam),
(int)(short)HIWORD(wParam))
#define FORWARD_WM_CHARTOITEM(hwnd, ch, hwndListBox, iCaret, fn) \
(int)(DWORD)(fn)((hwnd), WM_CHARTOITEM, MAKEWPARAM((UINT)(ch), (UINT)(iCaret)),
(LPARAM)(hwndListBox))
/* void Cls_OnQueueSync(HWND hwnd) */
#define HANDLE_WM_QUEUESYNC(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_QUEUESYNC(hwnd, fn) \
(void)(fn)((hwnd), WM_QUEUESYNC, 0L, 0L)
#if (WINVER >= 0x030a)
/* void Cls_OnCommNotify(HWND hwnd, int cid, UINT flags) */
#define HANDLE_WM_COMMNOTIFY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam), (UINT)LOWORD(lParam)), 0L)
#define FORWARD_WM_COMMNOTIFY(hwnd, cid, flags, fn) \
(void)(fn)((hwnd), WM_COMMNOTIFY, (WPARAM)(cid), MAKELPARAM((flags), 0))
#endif
/* void Cls_OnDisplayChange(HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT cyScreen) */
#define HANDLE_WM_DISPLAYCHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_DISPLAYCHANGE(hwnd, bitsPerPixel, cxScreen, cyScreen, fn) \
(void)(fn)((hwnd), WM_DISPLAYCHANGE, (WPARAM)(UINT)(bitsPerPixel),
(LPARAM)MAKELPARAM((UINT)(cxScreen), (UINT)(cyScreen)))
/* BOOL Cls_OnDeviceChange(HWND hwnd, UINT uEvent, DWORD dwEventData) */
#define HANDLE_WM_DEVICECHANGE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (UINT)(wParam), (DWORD)(wParam))
#define FORWARD_WM_DEVICECHANGE(hwnd, uEvent, dwEventData, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_DEVICECHANGE, (WPARAM)(UINT)(uEvent),
(LPARAM)(DWORD)(dwEventData))
/* void Cls_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos) */
#define HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_CONTEXTMENU(hwnd, hwndContext, xPos, yPos, fn) \
(void)(fn)((hwnd), WM_CONTEXTMENU, (WPARAM)(HWND)(hwndContext), MAKELPARAM((UINT)(xPos),
(UINT)(yPos)))
/****** Static control message APIs ******************************************/
#define Static_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define Static_GetText(hwndCtl, lpch, cchMax)
#define Static_GetTextLength(hwndCtl)
#define Static_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch), (cchMax))
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
#define Static_SetIcon(hwndCtl, hIcon)
STM_SETICON, (WPARAM)(HICON)(hIcon), 0L))
#define Static_GetIcon(hwndCtl, hIcon)
STM_GETICON, 0L, 0L))
((HICON)(UINT)(DWORD)SendMessage((hwndCtl),
((HICON)(UINT)(DWORD)SendMessage((hwndCtl),
/****** Button control message APIs ******************************************/
#define Button_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define Button_GetText(hwndCtl, lpch, cchMax)
#define Button_GetTextLength(hwndCtl)
#define Button_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch), (cchMax))
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
#define Button_GetCheck(hwndCtl)
0L, 0L))
#define Button_SetCheck(hwndCtl, check)
(WPARAM)(int)(check), 0L))
((int)(DWORD)SendMessage((hwndCtl), BM_GETCHECK,
#define Button_GetState(hwndCtl)
0L, 0L))
#define Button_SetState(hwndCtl, state)
(WPARAM)(int)(state), 0L))
((int)(DWORD)SendMessage((hwndCtl), BM_GETSTATE,
((void)SendMessage((hwndCtl), BM_SETCHECK,
((UINT)(DWORD)SendMessage((hwndCtl), BM_SETSTATE,
#define Button_SetStyle(hwndCtl, style, fRedraw) ((void)SendMessage((hwndCtl), BM_SETSTYLE,
(WPARAM)LOWORD(style), MAKELPARAM(((fRedraw) ? TRUE : FALSE), 0)))
/****** Edit control message APIs ********************************************/
#define Edit_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define Edit_GetText(hwndCtl, lpch, cchMax)
#define Edit_GetTextLength(hwndCtl)
#define Edit_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch), (cchMax))
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
#define Edit_LimitText(hwndCtl, cchMax)
(WPARAM)(cchMax), 0L))
((void)SendMessage((hwndCtl), EM_LIMITTEXT,
#define Edit_GetLineCount(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl),
EM_GETLINECOUNT, 0L, 0L))
#define Edit_GetLine(hwndCtl, line, lpch, cchMax) ((*((int *)(lpch)) = (cchMax)),
((int)(DWORD)SendMessage((hwndCtl), EM_GETLINE, (WPARAM)(int)(line), (LPARAM)(LPTSTR)(lpch))))
#define Edit_GetRect(hwndCtl, lprc)
(LPARAM)(RECT *)(lprc)))
#define Edit_SetRect(hwndCtl, lprc)
(LPARAM)(const RECT *)(lprc)))
#define Edit_SetRectNoPaint(hwndCtl, lprc)
(LPARAM)(const RECT *)(lprc)))
((void)SendMessage((hwndCtl), EM_GETRECT, 0L,
#define Edit_GetSel(hwndCtl)
0L))
#define Edit_SetSel(hwndCtl, ichStart, ichEnd)
(ichStart), (ichEnd)))
#define Edit_ReplaceSel(hwndCtl, lpszReplace)
((DWORD)SendMessage((hwndCtl), EM_GETSEL, 0L,
((void)SendMessage((hwndCtl), EM_SETRECT, 0L,
((void)SendMessage((hwndCtl), EM_SETRECTNP, 0L,
((void)SendMessage((hwndCtl), EM_SETSEL,
((void)SendMessage((hwndCtl), EM_REPLACESEL,
0L, (LPARAM)(LPCTSTR)(lpszReplace)))
#define Edit_GetModify(hwndCtl)
EM_GETMODIFY, 0L, 0L))
#define Edit_SetModify(hwndCtl, fModified)
(WPARAM)(UINT)(fModified), 0L))
((BOOL)(DWORD)SendMessage((hwndCtl),
#define Edit_ScrollCaret(hwndCtl)
EM_SCROLLCARET, 0, 0L))
((BOOL)(DWORD)SendMessage((hwndCtl),
#define Edit_LineFromChar(hwndCtl, ich)
EM_LINEFROMCHAR, (WPARAM)(int)(ich), 0L))
#define Edit_LineIndex(hwndCtl, line)
EM_LINEINDEX, (WPARAM)(int)(line), 0L))
#define Edit_LineLength(hwndCtl, line)
EM_LINELENGTH, (WPARAM)(int)(line), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define Edit_Scroll(hwndCtl, dv, dh)
(WPARAM)(dh), (LPARAM)(dv)))
((void)SendMessage((hwndCtl), EM_LINESCROLL,
#define Edit_CanUndo(hwndCtl)
EM_CANUNDO, 0L, 0L))
#define Edit_Undo(hwndCtl)
0L, 0L))
#define Edit_EmptyUndoBuffer(hwndCtl)
EM_EMPTYUNDOBUFFER, 0L, 0L))
((BOOL)(DWORD)SendMessage((hwndCtl),
#define Edit_SetPasswordChar(hwndCtl, ch)
EM_SETPASSWORDCHAR, (WPARAM)(UINT)(ch), 0L))
((void)SendMessage((hwndCtl),
((void)SendMessage((hwndCtl), EM_SETMODIFY,
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
((BOOL)(DWORD)SendMessage((hwndCtl), EM_UNDO,
((void)SendMessage((hwndCtl),
#define Edit_SetTabStops(hwndCtl, cTabs, lpTabs) ((void)SendMessage((hwndCtl), EM_SETTABSTOPS,
(WPARAM)(int)(cTabs), (LPARAM)(const int *)(lpTabs)))
#define Edit_FmtLines(hwndCtl, fAddEOL)
EM_FMTLINES, (WPARAM)(BOOL)(fAddEOL), 0L))
((BOOL)(DWORD)SendMessage((hwndCtl),
#define Edit_GetHandle(hwndCtl)
EM_GETHANDLE, 0L, 0L))
#define Edit_SetHandle(hwndCtl, h)
(WPARAM)(UINT)(HLOCAL)(h), 0L))
((HLOCAL)(UINT)(DWORD)SendMessage((hwndCtl),
#if (WINVER >= 0x030a)
#define Edit_GetFirstVisibleLine(hwndCtl)
EM_GETFIRSTVISIBLELINE, 0L, 0L))
((void)SendMessage((hwndCtl), EM_SETHANDLE,
((int)(DWORD)SendMessage((hwndCtl),
#define Edit_SetReadOnly(hwndCtl, fReadOnly)
((BOOL)(DWORD)SendMessage((hwndCtl),
EM_SETREADONLY, (WPARAM)(BOOL)(fReadOnly), 0L))
#define Edit_GetPasswordChar(hwndCtl)
EM_GETPASSWORDCHAR, 0L, 0L))
((TCHAR)(DWORD)SendMessage((hwndCtl),
#define Edit_SetWordBreakProc(hwndCtl, lpfnWordBreak) ((void)SendMessage((hwndCtl),
EM_SETWORDBREAKPROC, 0L, (LPARAM)(EDITWORDBREAKPROC)(lpfnWordBreak)))
#define Edit_GetWordBreakProc(hwndCtl)
((EDITWORDBREAKPROC)SendMessage((hwndCtl),
EM_GETWORDBREAKPROC, 0L, 0L))
#endif /* WINVER >= 0x030a */
/****** ScrollBar control message APIs ***************************************/
/* NOTE: flags parameter is a collection of ESB_* values, NOT a boolean! */
#define ScrollBar_Enable(hwndCtl, flags)
EnableScrollBar((hwndCtl), SB_CTL, (flags))
#define ScrollBar_Show(hwndCtl, fShow)
SW_SHOWNORMAL : SW_HIDE)
ShowWindow((hwndCtl), (fShow) ?
#define ScrollBar_SetPos(hwndCtl, pos, fRedraw)
(fRedraw))
SetScrollPos((hwndCtl), SB_CTL, (pos),
#define ScrollBar_GetPos(hwndCtl)
#define
SB_CTL,
#define
SB_CTL,
GetScrollPos((hwndCtl), SB_CTL)
ScrollBar_SetRange(hwndCtl, posMin, posMax, fRedraw)
(posMin), (posMax), (fRedraw))
ScrollBar_GetRange(hwndCtl, lpposMin, lpposMax)
(lpposMin), (lpposMax))
SetScrollRange((hwndCtl),
GetScrollRange((hwndCtl),
/****** ListBox control message APIs *****************************************/
#define ListBox_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define ListBox_GetCount(hwndCtl)
LB_GETCOUNT, 0L, 0L))
#define ListBox_ResetContent(hwndCtl)
LB_RESETCONTENT, 0L, 0L))
((int)(DWORD)SendMessage((hwndCtl),
((BOOL)(DWORD)SendMessage((hwndCtl),
#define ListBox_AddString(hwndCtl, lpsz)
((int)(DWORD)SendMessage((hwndCtl),
LB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz)))
#define ListBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl),
LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpsz)))
#define ListBox_AddItemData(hwndCtl, data)
((int)(DWORD)SendMessage((hwndCtl),
LB_ADDSTRING, 0L, (LPARAM)(data)))
#define ListBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl),
LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data)))
#define ListBox_DeleteString(hwndCtl, index)
LB_DELETESTRING, (WPARAM)(int)(index), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define ListBox_GetTextLen(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl),
LB_GETTEXTLEN, (WPARAM)(int)(index), 0L))
#define ListBox_GetText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl),
LB_GETTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer)))
#define ListBox_GetItemData(hwndCtl, index)
((LRESULT)(DWORD)SendMessage((hwndCtl),
LB_GETITEMDATA, (WPARAM)(int)(index), 0L))
#define ListBox_SetItemData(hwndCtl, index, data)
((int)(DWORD)SendMessage((hwndCtl),
LB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data)))
#if (WINVER >= 0x030a)
#define ListBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl),
LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl),
LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
#define ListBox_SetSel(hwndCtl, fSelect, index)
((int)(DWORD)SendMessage((hwndCtl),
LB_SETSEL, (WPARAM)(BOOL)(fSelect), (LPARAM)(index)))
#define ListBox_SelItemRange(hwndCtl, fSelect, first, last)
((int)(DWORD)SendMessage((hwndCtl), LB_SELITEMRANGE, (WPARAM)(BOOL)(fSelect),
MAKELPARAM((first), (last))))
#define ListBox_GetCurSel(hwndCtl)
LB_GETCURSEL, 0L, 0L))
#define ListBox_SetCurSel(hwndCtl, index)
LB_SETCURSEL, (WPARAM)(int)(index), 0L))
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
#define ListBox_SelectString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl),
LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_SelectItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl),
LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
#define ListBox_GetSel(hwndCtl, index)
LB_GETSEL, (WPARAM)(int)(index), 0L))
#define ListBox_GetSelCount(hwndCtl)
LB_GETSELCOUNT, 0L, 0L))
#define ListBox_GetTopIndex(hwndCtl)
LB_GETTOPINDEX, 0L, 0L))
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
#define ListBox_GetSelItems(hwndCtl, cItems, lpItems) ((int)(DWORD)SendMessage((hwndCtl),
LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int *)(lpItems)))
#define ListBox_SetTopIndex(hwndCtl, indexTop)
LB_SETTOPINDEX, (WPARAM)(int)(indexTop), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define ListBox_SetColumnWidth(hwndCtl, cxColumn)
((void)SendMessage((hwndCtl),
LB_SETCOLUMNWIDTH, (WPARAM)(int)(cxColumn), 0L))
#define ListBox_GetHorizontalExtent(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl),
LB_GETHORIZONTALEXTENT, 0L, 0L))
#define ListBox_SetHorizontalExtent(hwndCtl, cxExtent)
((void)SendMessage((hwndCtl),
LB_SETHORIZONTALEXTENT, (WPARAM)(int)(cxExtent), 0L))
#define ListBox_SetTabStops(hwndCtl, cTabs, lpTabs) ((BOOL)(DWORD)SendMessage((hwndCtl),
LB_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(int *)(lpTabs)))
#define ListBox_GetItemRect(hwndCtl, index, lprc)
((int)(DWORD)SendMessage((hwndCtl),
LB_GETITEMRECT, (WPARAM)(int)(index), (LPARAM)(RECT *)(lprc)))
#define ListBox_SetCaretIndex(hwndCtl, index)
LB_SETCARETINDEX, (WPARAM)(int)(index), 0L))
#define ListBox_GetCaretIndex(hwndCtl)
LB_GETCARETINDEX, 0L, 0L))
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
#define ListBox_FindStringExact(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_SetItemHeight(hwndCtl, index, cy)
((int)(DWORD)SendMessage((hwndCtl),
LB_SETITEMHEIGHT, (WPARAM)(int)(index), MAKELPARAM((cy), 0)))
#define ListBox_GetItemHeight(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl),
LB_GETITEMHEIGHT, (WPARAM)(int)(index), 0L))
#endif /* WINVER >= 0x030a */
#define ListBox_Dir(hwndCtl, attrs, lpszFileSpec)
((int)(DWORD)SendMessage((hwndCtl), LB_DIR,
(WPARAM)(UINT)(attrs), (LPARAM)(LPCTSTR)(lpszFileSpec)))
/****** ComboBox control message APIs ****************************************/
#define ComboBox_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define ComboBox_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))
#define ComboBox_GetTextLength(hwndCtl)
GetWindowTextLength(hwndCtl)
#define ComboBox_SetText(hwndCtl, lpsz)
SetWindowText((hwndCtl), (lpsz))
#define ComboBox_LimitText(hwndCtl, cchLimit)
CB_LIMITTEXT, (WPARAM)(int)(cchLimit), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define ComboBox_GetEditSel(hwndCtl)
((DWORD)SendMessage((hwndCtl), CB_GETEDITSEL,
0L, 0L))
#define ComboBox_SetEditSel(hwndCtl, ichStart, ichEnd) ((int)(DWORD)SendMessage((hwndCtl),
CB_SETEDITSEL, 0L, MAKELPARAM((ichStart), (ichEnd))))
#define ComboBox_GetCount(hwndCtl)
CB_GETCOUNT, 0L, 0L))
#define ComboBox_ResetContent(hwndCtl)
CB_RESETCONTENT, 0L, 0L))
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
#define ComboBox_AddString(hwndCtl, lpsz)
((int)(DWORD)SendMessage((hwndCtl),
CB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz)))
#define ComboBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl),
CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpsz)))
#define ComboBox_AddItemData(hwndCtl, data)
((int)(DWORD)SendMessage((hwndCtl),
CB_ADDSTRING, 0L, (LPARAM)(data)))
#define ComboBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl),
CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data)))
#define ComboBox_DeleteString(hwndCtl, index)
CB_DELETESTRING, (WPARAM)(int)(index), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define ComboBox_GetLBTextLen(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl),
CB_GETLBTEXTLEN, (WPARAM)(int)(index), 0L))
#define ComboBox_GetLBText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl),
CB_GETLBTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer)))
#define ComboBox_GetItemData(hwndCtl,
CB_GETITEMDATA, (WPARAM)(int)(index),
#define ComboBox_SetItemData(hwndCtl,
CB_SETITEMDATA, (WPARAM)(int)(index),
index)
((LRESULT)(DWORD)SendMessage((hwndCtl),
0L))
index, data) ((int)(DWORD)SendMessage((hwndCtl),
(LPARAM)(data)))
#define ComboBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl),
CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind)))
#define ComboBox_FindItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl),
CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
#define ComboBox_GetCurSel(hwndCtl)
CB_GETCURSEL, 0L, 0L))
#define ComboBox_SetCurSel(hwndCtl, index)
CB_SETCURSEL, (WPARAM)(int)(index), 0L))
((int)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
#define ComboBox_SelectString(hwndCtl, indexStart, lpszSelect)
((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszSelect)))
#define ComboBox_SelectItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(data)))
#define ComboBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), CB_DIR,
(WPARAM)(UINT)(attrs), (LPARAM)(LPCTSTR)(lpszFileSpec)))
#define ComboBox_ShowDropdown(hwndCtl, fShow)
CB_SHOWDROPDOWN, (WPARAM)(BOOL)(fShow), 0L))
((BOOL)(DWORD)SendMessage((hwndCtl),
#if (WINVER >= 0x030a)
#define ComboBox_FindStringExact(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ComboBox_GetDroppedState(hwndCtl)
((BOOL)(DWORD)SendMessage((hwndCtl),
CB_GETDROPPEDSTATE, 0L, 0L))
#define ComboBox_GetDroppedControlRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl),
CB_GETDROPPEDCONTROLRECT, 0L, (LPARAM)(RECT *)(lprc)))
#define ComboBox_GetItemHeight(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl),
CB_GETITEMHEIGHT, 0L, 0L))
#define ComboBox_SetItemHeight(hwndCtl, index, cyItem) ((int)(DWORD)SendMessage((hwndCtl),
CB_SETITEMHEIGHT, (WPARAM)(int)(index), (LPARAM)(int)cyItem))
#define ComboBox_GetExtendedUI(hwndCtl)
CB_GETEXTENDEDUI, 0L, 0L))
#define ComboBox_SetExtendedUI(hwndCtl, flags)
CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L))
#endif /* WINVER >= 0x030a */
((UINT)(DWORD)SendMessage((hwndCtl),
((int)(DWORD)SendMessage((hwndCtl),
/****** Alternate porting layer macros ****************************************/
/* USER MESSAGES: */
#define GET_WPARAM(wp, lp)
#define GET_LPARAM(wp, lp)
(wp)
(lp)
#define GET_X_LPARAM(lp)
#define GET_Y_LPARAM(lp)
((int)(short)LOWORD(lp))
((int)(short)HIWORD(lp))
#define
#define
#define
#define
GET_WM_ACTIVATE_STATE(wp, lp)
LOWORD(wp)
GET_WM_ACTIVATE_FMINIMIZED(wp, lp)
(BOOL)HIWORD(wp)
GET_WM_ACTIVATE_HWND(wp, lp)
(HWND)(lp)
GET_WM_ACTIVATE_MPS(s, fmin, hwnd)
\
(WPARAM)MAKELONG((s), (fmin)), (LONG)(hwnd)
#define
#define
#define
#define
GET_WM_CHARTOITEM_CHAR(wp, lp)
(TCHAR)LOWORD(wp)
GET_WM_CHARTOITEM_POS(wp, lp)
HIWORD(wp)
GET_WM_CHARTOITEM_HWND(wp, lp)
(HWND)(lp)
GET_WM_CHARTOITEM_MPS(ch, pos, hwnd) \
(WPARAM)MAKELONG((pos), (ch)), (LONG)(hwnd)
#define
#define
#define
#define
GET_WM_COMMAND_ID(wp, lp)
LOWORD(wp)
GET_WM_COMMAND_HWND(wp, lp)
(HWND)(lp)
GET_WM_COMMAND_CMD(wp, lp)
HIWORD(wp)
GET_WM_COMMAND_MPS(id, hwnd, cmd)
\
(WPARAM)MAKELONG(id, cmd), (LONG)(hwnd)
#define WM_CTLCOLOR
0x0019
#define
#define
#define
#define
#define
GET_WM_CTLCOLOR_HDC(wp, lp, msg)
GET_WM_CTLCOLOR_HWND(wp, lp, msg)
GET_WM_CTLCOLOR_TYPE(wp, lp, msg)
GET_WM_CTLCOLOR_MSG(type)
GET_WM_CTLCOLOR_MPS(hdc, hwnd, type) \
(WPARAM)(hdc), (LONG)(hwnd)
(HDC)(wp)
(HWND)(lp)
(WORD)(msg - WM_CTLCOLORMSGBOX)
(WORD)(WM_CTLCOLORMSGBOX+(type))
#define
#define
#define
#define
GET_WM_MENUSELECT_CMD(wp, lp)
GET_WM_MENUSELECT_FLAGS(wp, lp)
GET_WM_MENUSELECT_HMENU(wp, lp)
GET_WM_MENUSELECT_MPS(cmd, f, hmenu) \
(WPARAM)MAKELONG(cmd, f), (LONG)(hmenu)
LOWORD(wp)
(UINT)(int)(short)HIWORD(wp)
(HMENU)(lp)
/* Note: the following are for interpreting MDIclient to MDI child messages. */
#define GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wp, lp) (lp == (LONG)hwnd)
#define GET_WM_MDIACTIVATE_HWNDDEACT(wp, lp)
(HWND)(wp)
#define GET_WM_MDIACTIVATE_HWNDACTIVATE(wp, lp)
(HWND)(lp)
/* Note: the following is for sending to the MDI client window. */
#define GET_WM_MDIACTIVATE_MPS(f, hwndD, hwndA)\
(WPARAM)(hwndA), 0
#define GET_WM_MDISETMENU_MPS(hmenuF, hmenuW) (WPARAM)hmenuF, (LONG)hmenuW
#define
#define
#define
#define
GET_WM_MENUCHAR_CHAR(wp, lp)
GET_WM_MENUCHAR_HMENU(wp, lp)
GET_WM_MENUCHAR_FMENU(wp, lp)
GET_WM_MENUCHAR_MPS(ch, hmenu, f)
\
(WPARAM)MAKELONG(ch, f), (LONG)(hmenu)
#define
#define
#define
#define
#define
#define
(TCHAR)LOWORD(wp)
(HMENU)(lp)
(BOOL)HIWORD(wp)
GET_WM_PARENTNOTIFY_MSG(wp, lp)
GET_WM_PARENTNOTIFY_ID(wp, lp)
GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp)
GET_WM_PARENTNOTIFY_X(wp, lp)
GET_WM_PARENTNOTIFY_Y(wp, lp)
GET_WM_PARENTNOTIFY_MPS(msg, id, hwnd) \
(WPARAM)MAKELONG(id, msg), (LONG)(hwnd)
#define GET_WM_PARENTNOTIFY2_MPS(msg, x, y) \
(WPARAM)MAKELONG(0, msg), MAKELONG(x, y)
LOWORD(wp)
HIWORD(wp)
(HWND)(lp)
(int)(short)LOWORD(lp)
(int)(short)HIWORD(lp)
#define
#define
#define
#define
(int)(short)LOWORD(wp)
HIWORD(wp)
(HWND)(lp)
GET_WM_VKEYTOITEM_CODE(wp, lp)
GET_WM_VKEYTOITEM_ITEM(wp, lp)
GET_WM_VKEYTOITEM_HWND(wp, lp)
GET_WM_VKEYTOITEM_MPS(code, item, hwnd) \
(WPARAM)MAKELONG(item, code), (LONG)(hwnd)
#define GET_EM_SETSEL_START(wp, lp)
#define GET_EM_SETSEL_END(wp, lp)
#define GET_EM_SETSEL_MPS(iStart, iEnd) \
(WPARAM)(iStart), (LONG)(iEnd)
#define GET_EM_LINESCROLL_MPS(vert, horz)
(WPARAM)horz, (LONG)vert
(INT)(wp)
(lp)
\
#define GET_WM_CHANGECBCHAIN_HWNDNEXT(wp, lp)
(HWND)(lp)
#define
#define
#define
#define
GET_WM_HSCROLL_CODE(wp, lp)
GET_WM_HSCROLL_POS(wp, lp)
GET_WM_HSCROLL_HWND(wp, lp)
GET_WM_HSCROLL_MPS(code, pos, hwnd)
\
(WPARAM)MAKELONG(code, pos), (LONG)(hwnd)
LOWORD(wp)
HIWORD(wp)
(HWND)(lp)
#define
#define
#define
#define
GET_WM_VSCROLL_CODE(wp, lp)
GET_WM_VSCROLL_POS(wp, lp)
GET_WM_VSCROLL_HWND(wp, lp)
GET_WM_VSCROLL_MPS(code, pos, hwnd)
\
(WPARAM)MAKELONG(code, pos), (LONG)(hwnd)
LOWORD(wp)
HIWORD(wp)
(HWND)(lp)
/****** C runtime porting macros ****************************************/
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
_ncalloc
_nexpand
_ffree
_fmalloc
_fmemccpy
_fmemchr
_fmemcmp
_fmemcpy
_fmemicmp
_fmemmove
_fmemset
_fmsize
_frealloc
_fstrcat
_fstrchr
_fstrcmp
_fstrcpy
_fstrcspn
_fstrdup
_fstricmp
_fstrlen
_fstrlwr
_fstrncat
_fstrncmp
_fstrncpy
_fstrnicmp
_fstrnset
_fstrpbrk
_fstrrchr
_fstrrev
_fstrset
_fstrspn
_fstrstr
_fstrtok
_fstrupr
_nfree
_nmalloc
_nmsize
_nrealloc
_nstrdup
hmemcpy
calloc
_expand
free
malloc
_memccpy
memchr
memcmp
memcpy
_memicmp
memmove
memset
_msize
realloc
strcat
strchr
strcmp
strcpy
strcspn
_strdup
_stricmp
strlen
_strlwr
strncat
strncmp
strncpy
_strnicmp
_strnset
strpbrk
strrchr
_strrev
_strset
strspn
strstr
strtok
_strupr
free
malloc
_msize
realloc
_strdup
MoveMemory
#define DECLARE_HANDLE32
DECLARE_HANDLE
#ifdef __cplusplus
}
/* End of extern "C" { */
#endif
/* __cplusplus */
#endif
/* !_INC_WINDOWSX */
Entwicklungsumgebung
Um aus ASCII-Files ein lauffaehiges *.EXE-Programm zu erstellen werden Programme wie z.B. für die Übersetzungsvorgänge benötigt. Ein
direkter Entwurf der Bitmuster des Maschinencodes ist wegen des Umfanges und der Komplexität nicht möglich.
Einbettungen von Tools
Werzeuge
Dateien-Endungen
●
●
●
●
●
●
●
●
●
●
Editor ( einfache bzw. auswendige Textbearbeitung und gestaltung ),
Quelltext-Generierung ( Assistenten ),
Assembler ( übersetzt von Assembler nach Maschinencode
),
Compiler ( übersetzt in Assembler bzw. Maschinencode ),
Linker ( fügt compilierte Files zusammen ),
Projektverwaltung ( überwacht den Build-Prozess ),
Resourcen - Tools ( erstellt, übersetzt Properties ),
Debugger ( schrittweiser Programmablauf ) ,
Nachrichten - Verfolgung ( Spy - Tools ),
On-Line-Hilfe ( Dokumentation )
●
●
●
●
●
●
●
●
●
*.asm für Assembler - Quelltexte, *.c für C-Quell-Texte,
*.cpp für C++-Quell-Texte,
*.obj für binärer OpCode nach dem Compilieren,
*.lib für Bibliotheks-Routinen und Dll-Zuordnungen,
*.rc für Resourcen - Quelltexte,
*.res für binärere Resourcen - Files,
*.map für die DLL - Adressen,
*.exe für den executierbarer File,
*.rtf für ASCII-Rich-Text-File incl. Formatierung,
*.hlp für binärer HeLP-Files
Moderne Werkzeuge bestehen aus Software - Komponenten zur Programmentwicklung. Anstatt diese Programme einzeln zu verwenden, ist es
günstiger, eine interaktive, integrierende Bedienungsumgebung zu verwenden. Es bestehen vielschichtige Abhängigkeiten zu ( standardisierten )
Software - Systemen. Je moderner und komplexer ein Entwicklungssystem ist, um so größer ist die Zahl der Einstellungen und Variationen.
Ungarische Notation
In Ungarn wird ( anstelle von "Hans Müller" ) der Familien - Name zuerst genannt ( "Müllers Hans" ). Bei Win16 existierten viele verschiedene
Speicher - Modelle. Damit bei größeren Programmen an der Window - Variablen der zughörige Typ erkennbar ist, wurden dem Variablen - Namen
Prä - Character voran gestellt. Z.B. steht "lp" für "long Pointer", "lpsz" für "long Pointer auf \0 begrenzten String", "dw" für "Doppel Wort", "h"
für "Handle", "n" für "Anzahl", "f" für "Flag", usw.
Ein Beispiel ist der Aufruf von CreateWindowEx().
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
//
//
//
//
//
extended window style
pointer to registered class name
pointer to window name
window style
horizontal position of window
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
//
//
//
//
//
//
//
vertical position of window
window width
window height
handle to parent or owner window
handle to menu, or child-window identifier
handle to application instance
pointer to window-creation data
);
Prefix Naming Conventions
Prefix Type
Description
Example
ch
char
8-bit character
chGrade
ch
TCHAR
16-bit character
if _UNICODE is defined chName
b
BOOL
Boolean value
bEnabled
n
int
Integer (size dependent on operating system)
nLength
n
UINT
Unsigned value (size dependent on operating system) nLength
w
WORD
16-bit unsigned value
wPos
l
LONG
32-bit signed integer
lOffset
dw
DWORD
32-bit unsigned integer
dwRange
p
*
Pointer
pDoc
lp
FAR*
Far pointer
lpDoc
lpsz
LPSTR
32-bit pointer to character string
lpszName
lpsz
LPCSTR
32-bit pointer to constant character string
lpszName
lpsz
LPCTSTR 32-bit pointer to constant character string
if _UNICODE is defined lpszName
h
handle
Handle to Windows object
hWnd
lpfn
callback
Far pointer to CALLBACK function
lpfnAbort
Windows verwendet für Nachrichten-, Style-, Control- Konstanten die folgenden Gruppen:
BM_
Button Control Messages
BN_
User Button Notification Codes
BS_
Button Control Styles
CBS_
Combo Box styles
CCS_
LVS_
TVS_
TCS_
ACS_
COMMON CONTROL STYLES
CS_
Class styles
CF_
Predefined Clipboard Formats
DS_
Dialog Styles
ES_
Edit Control Styles
HELP_
Commands to pass to WinHelp()
HT
WM_NCHITTEST,
MOUSEHOOKSTRUCT Mouse Pos
ID
Dialog Box Command IDs
IDI_
Standard Icon IDs
LANG_
language IDs.
LBS_
Listbox Styles
MA_
WM_MOUSEACTIVATE Return Codes
MF_
Menu flags for
Add/Check/EnableMenuItem()
MFS_
Menu flags for
Add/Check/EnableMenuItem()
MK_
Key State Masks for Mouse Messages
OBM_
OEM Resource Ordinal Numbers
PWR_
wParam for WM_POWER
SBS_
Scroll Bar Styles
System Menu Command Values
SC_
SORT_ Sorting IDs.
SIZE_
WM_SIZE message wParam values
SS_
Static Control Constants
SW_
ShowWindow() Commands
TBS_
Tab style
VK_
Virtual Keys, Standard Set
WA_
WM_ACTIVATE state values
WM_
Window Messages
WM_DDE_ DDE - Mesages
WS_
Window Styles
WS_EX_
WVR_
WM_NCCALCSIZE return values
Extended Window Styles
Handle
Win32 nutzt die 32-Bit-CPU-Architektur. Bei Win32 entspricht das Datensegment-Register DS nicht mehr einer direkten Adresse auf das aktuelle
Datensegment.
●
●
DS entspricht einem Index für die Deskriptor - Tabelle.
Es gibt lokale Deskriptortabellen LDT und eine globale Deskriptortabellen GDT.
Ein 8 - Byte - Element aus der Deskriptor - Tabelle enthält die endgültige Byte - Zieladresse und das Sicherheits - Byte.
Beim erstmaligen Benutzen wird mit dem DS - Index das 8 - Byte - Element aus der Deskriptor - Tabelle geholt und in die CPU übertragen. Jeder
CPU - Befehl kann damit ( ohne Verzögerung ) das Element innerhalb der CPU nutzen ( Sicherheitsbyte, Protected Mode, Privileg Level ).
Beinahe jede Window - Funktion benötigt globale Window - Daten, Fenstergröße, Device - Kontext, usw. Damit die Funktion richtig ausgeführt
wird, muß vorher das Handle beschafft werden. Nur dann kann die Windows - Funktion die benötigten globalen Daten erreichen und nutzen.
●
●
●
Hinter dem Handle verbirgt sich der Index in eine Deskriptortabelle.
Ein Win16/Win32 - Handle bnutzt 16/32 Bit.
Ein Handle mit dem Wert 0 wird nicht verwendet und dient zur Fehler - Erkennung.
*.LIB - Files
Windows.h enthält die Funktions - Prototypen. Dadurch kann der Compiler die Schreibweise ( Syntax ) in dem eigenen Programm überprüfen.
Damit der Linker dnden kann, sind außerdem z.B. die folgenden Bibliotheken
●
●
●
●
●
kernel32.lib
user32.lib
gdi32.lib
coredll.lib
msvcrt.lib
in das Projekt aufzunehmen. Soll zusätzlich die "messaging functionality" in das eigene Programm aufgenommen werden, so ist #include
Msgstore.h erforderlich. Soll zusätzlich die "e-mail functionality" in das eigene Programm aufgenommen werden, so ist #include Addrstor.h
erforderlich. Natürlich sind auch die zugehörigen *.lib - Files in die Entwicklungs - Umgebung aufzunehmen. Oft werden die folgenden (
voreingstellten ) *.lib - Files verwerdet:
kernel32.lib
winspool.lib
shell32.lib
uuid.lib
user32.lib
comdlg32.lib
ole32.lib
odbc32.lib
gdi32.lib
advapi32.lib
oleaut32.lib
odbccp32.lib
Linker - Fehler
Von den Entwicklungs - Werkzeugen mußte der Linker immer mehr Aufgaben übernehmen. Die Linker - Zeiten übersteigen vielfach die Compiler Zeiten. Eine Teilung der Linker - Aufgaben in traditionelles Linken und der Resourcen - Erstellung ist angezeigt.
Der Linker fügt Binärcode aneinander und verbindet die wechselseitigen Zuordnungen ( Adressen ). Bei einem Linker - Fehler ist der
Zusammenhang mit dem lesbaren ASCII - Quelltext verloren. Der Linker gibt im Fehlerfall die Namen der nicht gefundenen bzw. doppelt
vorhanden Symbole aus. Weil bei C und C++ - Code gemäß
#ifdef __cplusplus
extern "C" {
#endif
...
...
#ifdef __cplusplus
}
#endif
gemischt werden können, ist zur Fehlererkennung vielfach auf die Schreibweise der ausgegebenen Namen zu beachten.
LinkerFehlerAnzeige
Diagnose
myFkt$int$int Es wurde mit C++ compiliert, bzw. eine C++ Bibliothek wird verwendet.
MYFKT
Es wurde mit PASCAL deklariert compiliert, bzw. Linkerschalter auf Großbuchstaben, bzw. Win16 - Bibliothek wird
verwendet.
_myFkt
Es wurde mit C, CDECL compiliert, bzw. es werden C - Bibliotheken verwendet.
*.RC - Files
Windows - Applikationen benötigen viele statische Daten ( Fenstergröße, Farbe, Controls, ... ). In den meisten Fällen werden die Geometrie Resourcen mit Hilfe visueller, interaktiver Tools ( z.B. Resourcen Workshop ) erstellt.
Diese Resourcen können im *.RC - ASCII - File ( oder in einem binären *.RCT - Template - File ) gespeichert werden.
Ein RC - Compiler übersetzt diesen *.RC - ASCII - File in einen binären *.RES - File, der durch den Linker dem *.EXE - File hinzugefügt wird.
Weil eine standardisierte Binärform benutzt wird, ist es mit dem Resourcen Workshop auch möglich, aus einem *.EXE - Programm den *.RC ASCII - File zu erhalten.
Übersetzungsvorgang
Für den Übersetzungsvorgang von Windows - Applikationen werden die Header-Files
#define STRICT
#include <windows.h>
#include <commdlg.h>
#include <windowsx.h>
mit den Funktions - Prototypen in den C, C++ - Quelltext eingebunden. Dadurch kann bereits der Compiler in unseren *.C, *.CPP - Files die
richtige Schreibweise der Window - Typen und -Funktionen überprüfen. Der Compiler übersetzt die *.CPP - Files in *.OBJ - Files. Wenn der
Linker-Pfad zu *.LIB richtig gesetzt ist, kann der Linker aus den Window-Bibliotheken *.LIB die Einsprüngen in die Window-dll´s entnehmen
und in unser Programm einbauen. Unser Programm verwendet dann die benötigten Window-DLL’s. Der Resourcen-Compiler erzeugt aus *.RC
den binären *.RES-File:
*.C, *.CPP
*.H, *.RC
*.OBJ, *.DEF
(*.EXE), *.RES
===>
===>
===>
===>
Compiler
Resourcen-Compiler
Linker
Resourcen-Compiler
===>
===>
===>
===>
*.OBJ
*.RES
(*.EXE)
*.EXE
Die Steuerung des Übersetzungs-Vorganges wird i.a. von der Projekt - Entwicklungs - Umgebeung oder von make.exe ( nmake.exe ) übernommen.
Der Übersetzungsvorgang kann auch die automatische Hyphertext - Help - Erzeugung enthalten ( autoduck.exe ).
Betriebssystem-Kern
Der eigentliche Betriebssystem - Kern besteht aus den drei Dateien
●
●
●
KRNL386.EXE ( 85 kB, 377 kB ),
USER.EXE ( 47 kB, 321 kB ),
GDI.EXE ( 21 kB, 162 kB )
Bei diesen Dateien handelt es sich um sogenannte DLL’s ( Dynamic Link Libarys ). Dies sind binäre Funktionsbibliotheken. Zum Betriebssystem
gehören noch weitere Komponenten, wie z.B.
●
●
●
●
●
●
●
●
●
●
COMMDLG: Common Dialog Boxen,
DDEML: Dynamic Datat Exchange Management Library,
DIB.DRV: Device independent bitmap driver,
OLECLI.DLL, OLESVR.DLL: Objekt linking and embedding,
SHELL.DLL: Drag-drop-feature, Registrations-Basis,
LZEXPAND.DLL: Daten decompression,
TOOLHELP.DLL: Tool help,
VER.DLL, VER.LIB: File Installation and versions checking, usw.
Installable drivers,
True Type fonts,
DLL’s sind binäre Instanzen von Objekte und enthalten Daten ( Properties ) und Methoden ( Funktionen ). Benötigt eine Applikation eine DLL, so
wird diese geladen und die benötigte Funktion ausgeführt. Falls die Dateiendung nicht *.DLL ist ( z.B. *.EXE ), so muß die Datei explizit
geladen/freigegeben werden.
Ist die DLL bereits geladen, so wird in der DLL lediglich ein Zähler hochgezählt. Ein DLL darf bei Bedarf aus dem Speicher entfernt werden,
wenn dieser Zäher 0 ist. Eine DLL wird nur einmal geladen, auch wenn diese DLL von mehreren Anwendungen benutzt wird. Der Zugriff auf eine
Funktion und deren Ausführung kann über die ASCII - Namen - Tabelle ( langsamer ) oder den Index der Funktions - Adress - Tabelle ( schneller )
erfolgen. Der hinterlegte Wert in der Funktions - Tabelle zeigt auf den Anfang der eigentlichen Funktion. Diese Zugriffsart ist schneller, als der
Zugriff über die ASCII - Namen - Tabelle.
| Adress-Tabelle |
| Tabelle |
| der enthaltenen |
| der
|
| Funktionen
| Dat1 | Dat2 | Func1 | Func2 | Func3 | Func4 | Namen
|
---|-----------------|------|------|-------|-------|-------|-------|---------|--DLL
Dat1
Dat2
Func1
Func1
Func1
Func1
Tab
Adr
Adr
Adr
Adr
Adr
Adr
Adr
Adr
Die DOS - Interrupttabelle ist grob mit der DLL - Funktionstabelle vergleichbar (die Zuordnung von Interruptzeiger zu Interruptserviceroutinen).
Bei interoperablen Systemen ( UNIX - WINDOWS ) wird der Zugriff über die ASCII - Namen - Tabelle benutzt. Bevor eine DLL - Funktion
ausgeführt wird, werden die Funktionsparameter auf den Stack des aurufenden Programmes gelegt.
DLL-Funktionsaufrufe erfolgen
über den Benutzerstack.
Die Funktions - Adress - Tabelle bedingt, daß das aurufende Programm ( Applikation ) den gewünschten Index der DLL - Funktions - Adress Tabelle kennt. Die Namen - Index - Zuordnungen sind in LIB - Dateien ( Libary ) enthalten. Beim Erstellen eines Programmes werden diese
Indizes der DLL - Funktions - Adress - Tabelle in den Maschinencode eingefügt. Der Linker trägt den Index in das Maschinenprogramm ein. Der
DLL - Name wird nur einmal in das Applikationsprogramm eingetragen.
KRNL386.EXE
Die Dateien KRNL386.EXE ist eine DLL ( Dynamic Link Libarys ). KRNL386.EXE
●
●
●
kontrolliert und verwaltet den Speicher,
lädt Applikationen,
verteilt die Resourcen an Programme und Tasks.
In KRNL386.EXE sind binäre Funktionen enthalten. Die wesentlichen Funktionen sind in der folgende Tabelle zusammengefaßt.
Object Creator function
Destroyer function
Change
notification FindFirstChangeNotification FindCloseChangeNotification
Communications
Object Creator function
Destroyer function
device GetStdHandle
CloseHandle
CreateEvent,
Event
OpenEvent
CloseHandle
OpenEventLog,
Event log RegisterEventSource, CloseEventLog
OpenBackupEventLog
File CreateFile
CloseHandle,
DeleteFile
File CreateFileMapping,
mapping OpenFileMapping
Find file FindFirstFile
FindClose
Mailslot CreateMailslot
CloseHandle
Module
LoadLibrary,
GetModuleHandle
FreeLibrary
CloseHandle
Pipe
CreateNamedPipe,
CreatePipe
CloseHandle,
DisconnectNamedPipe
CreateSemaphore,
OpenSemaphore
CloseHandle
Mutex
CreateMutex,
OpenMutex
Heap HeapCreate
CloseHandle
CreateProcess,
Process OpenProcess,
GetCurrentProcess
CloseHandle,
TerminateProcess
Semaphore
CreateThread,
Thread CreateRemoteThread,
GetCurrentThread
CloseHandle,
TerminateThread
Timer
Update resource BeginUpdateResource
HeapDestroy
CreateWaitableTimer,
CloseHandle
OpenWaitableTimer
EndUpdateResource
USER.EXE
Der File USER.EXE ist eine DLL, die die auf dem Bildschirm die Fenster erzeugt und manipuliert ( create, move, size, remove), die Icons und
andere Komponenten des Benutzer-Interface behandelt, die Eingaben ( dispatch ) von Keyboard, Mause und anderen Eingabe-Geräten an die
zugehörige Applikation verteilt. Mit den Funktionen von USER.EXE können interaktive Fenster ( desktop - shell ) erstellt werden. Die User
Interface Services
●
●
●
erzeugen und manipulieren Bildschirm - Fenster ( Screen Windows ),
behandeln Icons und andere Komponenten des Benutzerinterfaces,
verteilen die Eingabe von Keyboard, Maus und anderen Geräten an die zugehörigen Applikationen
USER.EXE enthält
Funktionen für die
Programmierschnittstelle
lesbare Daten ( Resources
Dialogelemente ( Controls
( Shell and Common
) sind:
):
Controls ):
Auslöseknöpfe ( Buttons ),
Textboxen ( List Boxes ),
aufklappbare Textboxen (
Combo Boxes ), Text Editor ( Edit Controls ),
RTF - Text - Bearbeitung (
Rich Edit Controls ),
Rollbalken ( Scroll Bars ),
feste Texte ( Static Controls
)
Textcursor ( Carets ),
Mauscursor ( Cursors ),
kleines Symbolbild ( Icons
), Menus, benutzerdefinierte
Resourcen-Daten
Windows Shell API,
standardisierter
Dialogelemente ( Common
Controls ), Wizard97
Specifications
Benutzer-Eingaben
( User Input )
Fensternhirachie (
Windowing )
Nachrichtenzugriff (
Accessibility ),
Mauseingaben ( Mouse
Input ), Tasten - Code der
Tastatur ( Keyboard Input ),
standardisierter Tastencode
( Virtual-Key Codes ), AltTasten ( Keyboard
Accelerators ), fertige
Dialoge ( Common Dialog
Box Library )
Fensterbehandlung (
Windows ) Datenzuordnung
zu Fenstern ( Window
Properties ), mehrere
Fenster mit gleichen
Eigenschhaften ( Window
Classes ),
Nachrichtenbearbeitung (
Message and Message
Queues ),
ereignisgesteuerter
Funktionsaufruf ( Callback,
Window Procedures ),
Behandlung von Dialogen (
Dialog Boxes ), alle Fenster
innerhalb des Eltern Fenster
( Multiple Document
Interface )
Die folgenden Funktionen werden zum Erzeugen und Manipulieren von Fenstern benutzt.
AdjustWindowRect
AdjustWindowRectEx
BringWindowToTop
CascadeWindows
ChildWindowFromPoint
DeferWindowPos
DestroyWindow
EnumChildWindows
EnumThreadWindows
EnumThreadWndProc
GetClientRect
GetDesktopWindow
GetTopWindow
GetWindow
GetWindowTextLength
GetWindowThreadProcessId IsChild
IsWindowVisible
IsZoomed
MoveWindow
SetWindowPlacement
SetWindowPos
ShowWindowAsync
TileWindows
WindowFromPoint
AnimateWindow
ArrangeIconicWindows
BeginDeferWindowPos
ChildWindowFromPointEx CloseWindow
EnableWindow
EndDeferWindowPos
CreateWindow
EnumChildProc
CreateWindowEx
EnumWindows
GetForegroundWindow
GetWindowPlacement
EnumWindowsProc
GetLastActivePopup
GetWindowRect
FindWindow
GetNextWindow
GetWindowText
FindWindowEx
GetParent
IsIconic
IsWindow
IsWindowUnicode
OpenIcon
SetWindowText
SetForegroundWindow
ShowOwnedPopups
SetParent
ShowWindow
SetWindowLong
WinMain
GDI.EXE
GDI ist eine Abkürzung für (G)raphic (D)evice (I)nterface. Der File GDI.EXE ist eine DLL, die das Graphics Device Interface ( GDI ) mit den
Funktionen zur Bild - Erzeugung und Bild - Anzeige ( nicht nur Screen ) enthält. Hierher gehören z.B. auch Fonts und Device - Kontext.
●
●
●
Bilderzeugung und Bildanzeige ( nicht nur auf dem Bildschirm, auch auf z.B. Druckern ).
Fonts
Device - Kontext
Den Device Kontext benutzen die folgenden Funktionen.
CancelDC
DeleteObject
EnumObjectsProc
GetDCPenColor
ReleaseDC
SetDCPenColor
ChangeDisplaySettings
DeviceCapabilities
GetCurrentObject
GetDeviceCaps
ResetDC
CreateCompatibleDC
DrawEscape
GetDC
GetGraphicsMode
RestoreDC
Mit Fonts und Texten werden die folgenden Funktionen benutzt:
CreateDC
EnumDisplayDevices
GetDCBrushColor
GetObject
SaveDC
CreateIC
EnumDisplaySettings
GetDCEx
GetObjectType
SelectObject
DeleteDC
EnumObjects
GetDCOrgEx
GetStockObject
SetDCBrushColor
AddFontResource
DrawText
ExtTextOut
GetCharacterPlacement
GetFontLanguageInfo
GetKerningPairs
GetTextAlign
GetTextExtentPoint32
RemoveFontResource
SetTextColor
CreateFont
DrawTextEx
GetAspectRatioFilterEx
GetCharWidth32
GetFontUnicodeRanges
GetOutlineTextMetrics
GetTextCharacterExtra
GetTextFace
SetMapperFlags
SetTextJustification
Nicht mehr benutzt werden sollten:
EnumFontFamilies EnumFontFamProc EnumFonts
CreateFontIndirect
EnumFontFamiliesEx
GetCharABCWidths
GetCharWidthFloat
GetGlyphIndices
GetRasterizerCaps
GetTextColor
GetTextMetrics
SetTextAlign
TabbedTextOut
EnumFontsProc
CreateScalableFontResource
EnumFontFamExProc
GetCharABCWidthsFloat
GetFontData
GetGlyphOutline
GetTabbedTextExtent
GetTextExtentExPoint
PolyTextOut
SetTextCharacterExtra
TextOut
GetCharWidth
GetTextExtentPoint
Im Zusammenhang mit der Paint - Nachricht werden die folgenden Funktionen benutzt:
BeginPaint
DrawState
GdiGetBatchLimit
GetUpdateRect
InvalidateRgn
SetBkMode
ValidateRect
DrawAnimatedRects
DrawStateProc
GdiSetBatchLimit
GetUpdateRgn
LockWindowUpdate
SetBoundsRect
ValidateRgn
DrawCaption
DrawTextEx
GetBkColor
GetWindowDC
OutputProc
SetRectRgn
WindowFromDC
DrawEdge
EndPaint
GetBkMode
GetWindowRgn
PaintDesktop
SetROP2
DrawFocusRect
ExcludeUpdateRgn
GetBoundsRect
GrayString
RedrawWindow
SetWindowRgn
DrawFrameControl
GdiFlush
GetROP2
InvalidateRect
SetBkColor
UpdateWindow
Beispiel: GetDeviceCaps()
Als ein Beispiel für den Umfang einer Funktion soll hier GetDeviceCaps() angegeben werden. GetDeviceCaps() gibt Informationen zum Device
Kontext zurück.
int GetDeviceCaps(
HDC hDC,
// device-context handle
int nIndex
// index of capability to query
);
Für den Parameter nIndex kann eine der folgenden Zahlen gewählt werden. Die eingerückten Konstanten kennzeichnen die zugehörigen
Rückgabewerte.
DRIVERVERSION The device driver version.
TECHNOLOGY Device technology:
DT_PLOTTER Vector plotter,
DT_RASDISPLAY Raster display,
DT_RASPRINTER Raster printer,
DT_RASCAMERA Raster camera,
DT_CHARSTREAM Character stream,
DT_METAFILE Metafile und GetObjectType(),
DT_DISPFILE Display file
HORZSIZE Width, in millimeters, of the physical screen.
VERTSIZE Height, in millimeters, of the physical screen.
HORZRES Width, in pixels, of the screen.
VERTRES Height, in raster lines, of the screen.
LOGPIXELSX Number of pixels per logical inch along the screen width.
LOGPIXELSY Number of pixels per logical inch along the screen height.
BITSPIXEL Number of adjacent color bits for each pixel.
PLANES Number of color planes.
NUMBRUSHES Number of device-specific brushes.
NUMPENS Number of device-specific pens.
NUMFONTS Number of device-specific fonts.
NUMCOLORS Number of entries in the device's color table,
ASPECTX Relative width of a device pixel used for line drawing.
ASPECTY Relative height of a device pixel used for line drawing.
ASPECTXY Diagonal width of the device pixel used for line drawing.
PDEVICESIZE Reserved.
CLIPCAPS Flag that indicates the clipping capabilities of the device.
SIZEPALETTE Number of entries in the system palette.
NUMRESERVED Number of reserved entries in the system palette.
COLORRES Actual color resolution of the device, in bits per pixel.
PHYSICALWIDTH For printing devices: the width of the physical page, in device units.
PHYSICALHEIGHT For printing devices: the height of the physical page, in device units.
PHYSICALOFFSETX For printing devices: the distance from the left edge of the
physical page to the left edge of the printable area, in device units.
PHYSICALOFFSETY For printing devices: the distance from the top edge of the
physical page to the top edge of the printable area, in device units.
VREFRESH Windows NT only: For display devices: the current vertical refresh
rate of the device, in cycles per second (Hz).
DESKTOPHORZRES Windows NT only: Width, in pixels, of the virtual desktop.
DESKTOPVERTRES Windows NT only: Height, in pixels, of the virtual desktop.
BLTALIGNMENT Windows NT only: Preferred horizontal drawing alignment, expressed
as a multiple of pixels.
RASTERCAPS Value that indicates the raster capabilities of the device:
RC_BANDING Requires banding support.
RC_BITBLT Capable of transferring bitmaps.
RC_BITMAP64 Capable of supporting bitmaps larger than 64K.
RC_DI_BITMAP Capable of supporting the SetDIBits and GetDIBits functions.
RC_DIBTODEV Capable of supporting the SetDIBitsToDevice function.
RC_FLOODFILL Capable of performing flood fills.
RC_GDI20_OUTPUT Capable of supporting features of Windows 2.0.
RC_PALETTE Specifies a palette-based device.
RC_SCALING Capable of scaling.
RC_STRETCHBLT Capable of performing the StretchBlt function.
RC_STRETCHDIB Capable of performing the StretchDIBits function.
CURVECAPS Value that indicates the curve capabilities of the device:
CC_NONE Device does not support curves.
CC_CHORD Device can draw chord arcs.
CC_CIRCLES Device can draw circles.
CC_ELLIPSES Device can draw ellipses.
CC_INTERIORS Device can draw interiors.
CC_PIE Device can draw pie wedges.
CC_ROUNDRECT Device can draw rounded rectangles.
CC_STYLED Device can draw styled borders.
CC_WIDE Device can draw wide borders.
CC_WIDESTYLED Device can draw borders that are wide and styled.
LINECAPS Value that indicates the line capabilities of the device:
LC_NONE Device does not support lines.
LC_INTERIORS Device can draw interiors.
LC_MARKER Device can draw a marker.
LC_POLYLINE Device can draw a polyline.
LC_POLYMARKER Device can draw multiple markers.
LC_STYLED Device can draw styled lines.
LC_WIDE Device can draw wide lines.
LC_WIDESTYLED Device can draw lines that are wide and styled.
POLYGONALCAPS Value that indicates the polygon capabilities of the device:
PC_NONE Device does not support polygons.
PC_INTERIORS Device can draw interiors.
PC_POLYGON Device can draw alternate-fill polygons.
PC_RECTANGLE Device can draw rectangles.
PC_SCANLINE Device can draw a single scanline.
PC_STYLED Device can draw styled borders.
PC_WIDE Device can draw wide borders.
PC_WIDESTYLED Device can draw borders that are wide and styled.
PC_WINDPOLYGON Device can draw winding-fill polygons.
TEXTCAPS Value that indicates the text capabilities of the device:
TC_OP_CHARACTER Device is capable of character output precision.
TC_OP_STROKE Device is capable of stroke output precision.
TC_CP_STROKE Device is capable of stroke clip precision.
TC_CR_90 Device is capable of 90-degree character rotation.
TC_CR_ANY Device is capable of any character rotation.
TC_SF_X_YINDEP Device can scale independently in the x- and y-directions.
TC_SA_DOUBLE Device is capable of doubled character for scaling.
TC_SA_INTEGER Device uses integer multiples only for character scaling.
TC_SA_CONTIN Device uses any multiples for exact character scaling.
TC_EA_DOUBLE Device can draw double-weight characters.
TC_IA_ABLE Device can italicize.
TC_UA_ABLE Device can underline.
TC_SO_ABLE Device can draw strikeouts.
TC_RA_ABLE Device can draw raster fonts.
TC_VA_ABLE Device can draw vector fonts.
TC_RESERVED Reserved; must be zero.
TC_SCROLLBLT Device cannot scroll using a bit-block transfer.
Beispiel: GetSystemMetrics()
Mit der Funktion GetSystemMetrics köennen ( geometrische ) Fenster - und Screen - Werte abgefragt werden. Durch
RECT rc ; //Dialog mittig zentrieren
GetWindowRect ( hWnd , & rc ) ;
rc.left = ( GetSystemMetrics ( SM_CXSCREEN ) - rc.right + rc.left ) / 2 ;
rc.top = ( GetSystemMetrics ( SM_CYSCREEN ) - rc.bottom + rc.top ) / 2 ;
SetWindowPos ( hWnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER
);
wird ein Fenster zentriert.
Win - Grundgerüst
Weil bereits ein erstes Programm unübersichtlich ist, wird das Grundgerüst zunächst im Pseudocode betrachtet. Ein einfaches Programm hat die
folgende Struktur:
WinMain(), //Startup-Code
RegisterClassEx (..., CALLBACK-Funktion, ...),
CreateWindowEx( ),
ShowWindow( ),
//Nachrichtenschleife
while ( GetMessage( & msg, NULL, 0, 0 ) ) {
TranslateMessage( & msg ) ;
DispatchMessage( & msg ) ;
}
Wegen der vielen Parameter wird der C - Quelltext z.T. bereits unuebersichtlich. Auch verfuegbare Klassen - Bibliotheken verwenden den gleichen
Aufbau ( und sind ebenfalls unuebersichtlich! ).
"Hallo Welt"
Das folgende Beispiel besteht aus der WinMain() und der WndProc() - CALLBACK - Funktion. Es wird ein Hauptfenster angelegt und Text
zentriert hinein geschrieben.
#include <windows.h>
//======================================
LRESULT CALLBACK WndProc( HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps ; HDC hDC ; RECT rect ;
switch ( iMsg ) {
case WM_CREATE : break ;//return 0;
case WM_PAINT :
hDC = BeginPaint( hWnd, & ps ) ;
GetClientRect
( hWnd, & rect ) ;
DrawText
( hDC, "Hallo, Win32!", -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
EndPaint
( hWnd, & ps ) ;
break ; //return 0;
case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0;
}
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
//======================================
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int
iShowMain )
{
WNDCLASSEX wc = { 0 } ; MSG msg ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInst ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
HWND hWndMain = CreateWindowEx( WS_EX_LEFT, "my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInst,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow ( hWndMain, iShowMain ) ;
UpdateWindow ( hWndMain ) ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return msg.wParam ;
}
Diese Programm besteht aus 2 Teilen:
●
●
der CLALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM
lParam ) { ... } und
der Funktion int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { ... }
WinMain entspricht der main() - Funktion in C. Der (W)indow -(S)tyle WS_OVERLAPPEDWINDOW entspricht
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
#define WS_POPUPWINDOW
(WS_POPUP|WS_BORDER|WS_SYSMENU)
WinMain()
Die Start - Adresse einer Window - Applikation ist die WinMain() - Funktion( APIENTRY ). WinMain ist der Haupt - Eintritts - Punkt für eine
Windows - Anwendung. Diese Funktion entspricht der Funktion main() bei einem C-Programm. Der WinMain - Startup - Code ruft die WinMainFunktion durch den Namen auf. Windows verwendet diese Funktion als "initial entry point" APIENTRY). Beim Start wird der Startup-Code
ausgeführt, der u.a. die Windows-Funktionen
●
●
●
InitTask ( KRNL386 ),
InitApp ( USER ) und
WaitEvent( KERNEL)
aufruft. Danach ruft der Startup - Code unsere WinMain - Funktion auf. Diese Schritte bei Start eines Win - Programmes können grob skizziert
werden:
WinMain() initialisiert Register
InitTask füllt bei Win16 die folgenden Register mit Werten, die beim Laden der Applikation auf den Stack gelegt werden:
BX
CX
DI
SI
ES
=
=
=
=
=
Stack-Grösse,
Heap-Grösse,
Instanz-Handle,
vorherige Instanz,
PSP-Adresse
WinMain() initialisiert den Stack
Außerdem initialisiert InitTask pStackTop, pStackMin, pStackBottom im Task - Header der aufrufenden Tastk. DLL´s sind keine Task´s, rufen
aber in ihrem Startup-Code auch InitTask auf.
WinMain() richtet Application-Message-Queue ein
Durch InitApp ( USER ) wird eine User - Nachrichten - Warte - Schlange ( Application - Message - Queue ) eingerichtet. Die Nachrichten der
Application - Message - Queue haben ein einheitliches Format.
Die Nachrichten, die zu unserem Programm gehören, werden durch Windows der
●
●
●
System - Message - Queue entnommen,
auf ein einheitliches Format gebracht und
in unsere Application - Message - Queue
gelegt.
WinMain() initialisiert die C - Laufzeit - Bibliothek
Die C-Laufzeit-Bibliothek wird initialisiert. Die statischen Konstruktoren von C++ werden initialisiert. Der Startup-Code legt die WinMain Parameter auf den Stack und ruft WinMain auf.
WinMain() entfernt Prä - Nachrichten
WaitEvent ( KRNL386 ) prüft ( PostEvent, Reschedule ), ob bereits ein Ereignis an die aktuelle Task ( 0 ) geschickt wurde. Wenn das Ereignis
abgeschickt und noch nicht eingetroffen ist, so wird gewartet und dann die bisher eingetroffenen Ereignisse gelöscht.
siehe: Start-Up-Code
WNDCLASSEX-Struktur
Hat eine Applikation mehrere Fenster, so gibt es Daten, die von allen Fenstern benötigt werden. Diese Daten werden in der WNDCLASSEX Struktur gespeichert. The WNDCLASSEX structure is similar to the WNDCLASS structure. There are two differences. WNDCLASSEX includes
the cbSize member, which specifies the size of the structure, and the hIconSm member, which contains a handle to a small icon associated with the
window class.
typedef struct _WNDCLASSEX {
UINT
cbSize;
// sizeof( WNDCLASSEX ) ;
UINT
style;
// CS_HREDRAW, CS_VREDRAW,
CS_DBLCLKS,CS_CLASSDC,CS_OWNDC,
// CS_PARENTDC,CS_BYTEALIGNWINDOW,CS_BYTEALIGNCLIENT,
// CS_NOCLOSE,CS_GLOBALCLASS,CS_SAVEBITS
WNDPROC lpfnWndProc;
// CALLBACK-Funktion
int
cbClsExtra;
// < 40 Byte
int
cbWndExtra;
// < 40 Byte
HANDLE hInstance;
// von WinMain()
HICON
hIcon;
// LoadIcon ( NULL, IDI_APPLICATION );
HCURSOR hCursor;
// LoadCursor( NULL, IDC_ARROW );
HBRUSH hbrBackground; // ( HBRUSH ) GetStockObject( WHITE_BRUSH );
LPCTSTR lpszMenuName;
// NULL
LPCTSTR lpszClassName; // static char szAppName[] = "HelloWin" ;
HICON
hIconSm;
// LoadIcon( NULL, IDI_APPLICATION );
} WNDCLASSEX;
Damit später mit ( CreateWindow oder CreateWindowEx ) spezielle Fenster angelegt werden können, müssen vorher der Speicherbereich für die
gemeinsamen Daten angelegt und initialisiert werden.
WNDCLASSEX wc
= { 0 };
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= ...
wc.lpfnWndProc
= ...
...
wc.lpszClassName = ...
if ( ! RegisterClass( & wc ) ) Fehler;
Die hinterlegten Daten können mit GetClassInfoEx() erhalten werden.
RegisterClassEx()
Damit bei einem Aufruf von RegisterClassEx() ( oder RegisterClass() ) nicht 13 Parameter übergeben werden müssen, werden die Eingabewerte in
eine WNDCLASSEX - Struktur geschrieben, die dann an die Funktion
ATOM RegisterClassEx( CONST WNDCLASSEX *lpwcx );
übergeben wird. Wenn kein Speicher für die Daten angelegt werden konnte und diese Funktion erfolglos war, wird 0 zurück gegeben. In diesem
Fall kann der Fehler mit GetLastError() näher untersucht werden. Achtung! Ist RegisterClassEx() in einer DLL, so wird beim 'unloaden' der
Speicher nicht automatisch freigegeben. Es ist unRegisterClassEx() erforderlich.
●
Das System kennt bereits die Klassen BUTTON, COMBOBOX, EDIT, LISTBOX, MDICLIENT, SCROLLBAR, STATIC.
CreateWindowEx()
Bis auf dwExStyle ist CreateWindowEx() identisch mit CreateWindow(). CreateWindowEx() kann ein Overlapped -, Pop - Up -, oder Child Window erstellen.
●
CreateWindowEx() sendet die WM_NCCREATE-, WM_NCCALCSIZE-, WM_CREATE-Nachrichten zu dem angelegten Fenster.
Der Rückgabewert ist das Handle des neuen Fensters.
Dabei ist das Fenster noch nicht sichtbar, obwohl das Handle != NULL den allokierten Speicher referenziert und Fenster-Daten eingetragen
wurden.
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
//
//
//
//
//
//
//
//
//
//
extended window style
pointer to registered class name
pointer to window name
window style
horizontal position of window
vertical position of window
window width
window height
handle to parent or owner window
handle to menu, or child-window identifier
HINSTANCE hInstance,
LPVOID lpParam
// handle to application instance
// pointer to window-creation data
);
dwExStyle spezifiziert erweiterte Styles:
WS_EX_ACCEPTFILES,
WS_EX_APPWINDOW,
WS_EX_CLIENTEDGE,
WS_EX_CONTEXTHELP,
WS_EX_CONTEXTHELP,
WS_EX_CONTROLPARENT, WS_EX_DLGMODALFRAME(double border),
WS_CAPTION,
WS_EX_LEFT,
WS_EX_LEFTSCROLLBAR, WS_EX_LTRREADING, WS_EX_MDICHILD,
WS_EX_NOPARENTNOTIFY,WS_EX_OVERLAPPEDWINDOW,
WS_EX_PALETTEWINDOW, WS_EX_RIGHT,
WS_EX_RIGHTSCROLLBAR,WS_EX_RTLREADING,
WS_EX_STATICEDGE,
WS_EX_TOOLWINDOW,
WS_EX_TOPMOST,
WS_EX_TRANSPARENT,
WS_EX_WINDOWEDGE
lpClassName zeigt auf einen "null-terminated string" der den Window - Class - Namen spezifiziert oder ist ein integer atom ( GlobalAddAtom ).
lpClassName zeigt auf einen "null-terminated string" der den Window - Namen spezifiziert ( Titelzeile, Text eines Controls ). dwStyle spezifiziert
den Style des Fensters und Funktionalität:
WS_BORDER,
WS_CLIPSIBLINGS,
WS_DISABLED,
WS_MAXIMIZE,
WS_MAXIMIZEBOX,
WS_POPUP,
WS_THICKFRAME,
WS_TILED,
WS_CAPTION,
WS_CHILD,
WS_CHILDWINDOW, WS_CLIPCHILDREN,
WS_DLGFRAME,
WS_GROUP,
WS_HSCROLL,
WS_MINIMIZE,
WS_MINIMIZEBOX,WS_OVERLAPPED,
WS_POPUPWINDOW, WS_SIZEBOX,
WS_SYSMENU,
WS_TILEDWINDOW, WS_VISIBLE,
WS_ICONIC,
WS_OVERLAPPEDWINDOW,
WS_TABSTOP,
WS_VSCROLL
Alle Fenster haben bereits die WS_CLIPSIBLINGS und WS_CLIPCHILDREN Styles. lpParam kann in der CREATESTRUCT - Struktur unter
WM_CREATE an die CALLBACK - Funktion weitergereicht werden.
In CreateWindowEx() können für die horizontale/vertikale Fenster - Position anstelle von festen int x-, y-, nWidth-, nHeight- Werten auch
Bildschirm - bezogene Werte ( z.B. GetSystemMetrics(SM_CXSCREEN)*1/8, GetSystemMetrics(SM_CYSCREEN)*1/5,
GetSystemMetrics(SM_CXSCREEN)*6/8, GetSystemMetrics(SM_CYSCREEN)*6/5 ) verwendet werden.
Nachrichtenschleife
// Die Nachrichtenschleife
while ( GetMessage( & msg,
TranslateMessage( & msg
DispatchMessage ( & msg
}
enthält:
NULL, 0, 0 ) ) {
) ;
) ;
GetMessage()
GetMessage() holt aus dem Applikations - Buffer ( thread's message queue ) die nächste Nachricht und stellt diese in der MSG - Struktur zur
Verfügung. GetMessage() erhält keine Nachrichten von einer anderen Applikation. Entnimmt GetMessage() dem Buffer die WM_QUIT Nachricht, so sendet die aufgerufene DefWindowProc() WM_DESTROY und PostQuitMessage(); beendet die Haupt-Nachrichtenschleife.
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
//
//
//
//
address of structure with message
handle of window
first message
last message
Wenn mit PostThreadMessage() per Programm eine Nachricht versendet wird, so ist hWnd == NULL, sonst identifiziert hWnd das Fenster.
wMsgFilterMin, wMsgFilterMax werden zum Eingrenzen der Nachrichten verwendet ( z.B. WM_KEYFIRST, WM_KEYLAST,
WM_MOUSEFIRST, WM_MOUSELAST ).
TranslateMessage()
Die Funktion BOOL TranslateMessage( CONST MSG *lpMsg ) wandelt eine Virtual-Key-Nachricht in eine Zeichen-Nachricht um (
WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP ). WM_KEYDOWN und WM_KEYUP Kombinationen ergeben
WM_CHAR oder WM_DEADCHAR - Nachrichten. WM_SYSKEYDOWN und WM_SYSKEYUP Kombinationen ergeben WM_SYSCHAR
oder WM_SYSDEADCHAR - Nachrichten. Die Zeichen - Nachricht wird in die Applikations - Nachrichten - Buffer gestellt. Mit GetMessage()
oder PeekMessage() wird diese Nachricht geholt.
DispatchMessage()
Aus dem Handle der Nachricht kann das Fenster ersehen werden. DispatchMessage() bestimmt das Fenster und leitet eine gültige Nachricht an die
CALLBACK - Funktion des Fensters. LONG DispatchMessage( CONST MSG *lpmsg ). Wenn lpmsg auf eine WM_TIMER - Nachricht zeigt
wird anstelle der Window - CALLBACK - Funktion die Funktion lParam() != NULL aufgerufen.
CALLBACK - Funktion
Das System verwaltet die Tastatur, die Maus und den Bildschirm. Wenn z.B. eine Taste gedrückt wird, so tritt ein Ereignis ein. Dieses Ereignis
kommt über den einen System-Buffer in den Applikations-Nachrichten-Buffer, wird dort entnommen und ruft die CALLBACK - Funktion
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) des Fensters mit
DispatchMessage() auf. Aus dem Handle der Tasten-Nachricht kann das Fenster ersehen werden. DispatchMessage() bestimmt das Fenster und
ruft die CALLBACK - Funktion des Fenster auf.
●
Kurz-Sprechweise:
Die Tasten-Nachricht wird an das Fenster geschickt.
Vor dem Aufruf der Fensters - CALLBACK - Funktion werden ( durch das Windows - System ) die Parameter der Nachricht auf den Stack
gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. Nachrichten rufen dieFenster CALLBACK Funktion auf. Die Nachrichten werden innerhalb der CALLBACK - Funktion bearbeitet oder an die DefWindowProc() weiter geleitet.
Beispiel: WM_PAINT - Nachricht
Ist z.B. ein Teilbereich des Bildschirm - Fensters verdeckt und wird die Überdeckung beseitigt, so entsteht ein "weißes Rechteck". Das Windows System legt die WM_PAINT - Nachricht in den Applikations - Message - Buffer. In der Hauptnachrichten - Schleife wird durch
DispatchMessage() die CALLBACK - Funktion aufgerufen. Wenn Windows oder eine andere Applikation ein Neuzeichnen wünscht, so wird eine
WM_PAINT - Nachricht gesendet. In der CALLBACK - Funktion kann
iMsg = WM_PAINT
hdc = (HDC) wParam;
benutzt werden. Wenn z.B. das Fenster vergrößert wird, so wird automatisch die WM_PAINT - Nachricht durch das Windows - System gesendet.
Die WM_PAINT - Nachricht ist eine nachrangige Nachricht. Sind neben WM_PAINT weitere Nachrichten im Applikations - Nachrichten Buffer, so werden diese zuerst abgearbeitet. Die WM_PAINT - Nachricht wird auch durch die Funktionen UpdateWindow(), RedrawWindow()
ausgelöst. Eine WM_PAINT - Nachricht steht in Zusammenhang mit den WM_ERAEBKGND -, WM_NCPAINT - Nachrichten und den
Funktionen DispatchMessage(), DefWindowProc(), BeginPaint(), EndPaint(), GetUpdateRect(), UpdateWindow(), RedrawWindow()
Wann wird WM_PAINT ausgelöst?
Eine Applikation zeichnet und aktualisiert ein Fenster
●
●
●
●
●
●
●
nachdem die Fenster - Daten allokiert und initialisiert wurden ( WM_CREATE ),
nachdem sich die Fenstergröße ändert ( WM_SIZE ),
nachdem Fenster - Anteile in den Vordergrund erscheinen,
nachdem das Fenster zum Icon wird ( WM_MINIMIZED ),
nachdem das Fenster zur Vollbild - Größe wird ( WM_MAXIMIZED ),
nachdem das Fenster gescrollt wurde ( WM_ ),
nachdem dar Fenster - Inhalt geändert wurde,
BeginPaint(), EndPaint()
Eine WM_PAINT - Nachricht wird meist verarbeitet durch
case WM_PAINT :
hDC = BeginPaint( hWnd, & ps ) ;
GetClientRect( hWnd, & rect ) ;
DrawText
( hDC, "Hallo, Win32!",1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint
( hWnd, & ps ) ;
break ; //return 0;
Der Hintergrund wird gelöscht und der Text wird erneut durch DrawText() zentriert ausgegeben. Die BeginPaint() - Funktion wird benutzt, um
gemäß hDC = BeginPaint( hWnd, & ps ) ;
●
●
●
●
den Text - Cursor ( Caret ) zu verbergen,
das Updating - Clipping - Rechteck in PAINTSTRUCT.rcPaint zu setzen,
den Device - Kontext zu ermitteln und
falls erforderlich WM_NCPAINT und WM_ERASEBKGND ( Title Bar, System Menu, Scroll Bars ) auszulösen.
Der Device - Kontext enthält globale Daten, die von vielen GDI - Funktionen zum Zeichnen gebraucht werden. Praktisch alle GDI - Funktionen
benötigen den Device - Kontext.
Durch EndPaint ( hWnd, & ps )
●
●
●
wird das Update - Rechteck auf NULL gesetzt ( keine WM_PAINT - Rekursion ),
wird der Device - Kontext wieder frei gegeben,
wird das Caret wieder angezeigt.
BeginPaint() und EndPaint() benutzen PAINTSTRUCT
typedef struct tagPAINTSTRUCT { // ps
HDC hdc;
BOOL fErase;
// TRUE: erase background
// with hbrBackground of WNDCLASSEX
RECT rcPaint;
// painting rectangle
BOOL fRestore;
// Reserved; used internally
BOOL fIncUpdate;
// Reserved; used internally
BYTE rgbReserved[32];// Reserved; used internally
} PAINTSTRUCT;
Das Update- Rechteck wird in einer
RECT- Struktur gespeichert
typedef struct _RECT { // rc
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
Ein Handle auf den Device-Context hDC ( das zum gesamten Client - Bereich gehört ), wird erhalten durch
hDC = GetDC( hWnd ) ;
...
ReleaseDC( hWnd, hDC ) ;
Das Update - Recheck ( validates ) wird auch gelöscht durch den Aufruf von DefWindowProc(), die ( falls erforderlich ) WM_NCPAINT,
WM_ERASEBKGND - Nachrichten sendet.
InvalidateRect(), ValidateRect(), GetUpdateRect()
Mit der GetUpdateBeginPaint() ... EndPaint() erforderlich. Wenn die Update - Rechteck nicht leer ist, so sendet Windows eine WM_PAINT Nachricht zu dem Fenster. Durch die InvalidateRect() kann ein Rechteck zu dem Update - Fenster - Rechteck hinzugefügt werden.
Durch InvalidateRect( hWnd, NULL, TRUE ) wird der gesamte Fenster - Client - Bereich zur Update - Rechteck hinzugefügt, d.h. mit
WM_PAINT - Nachricht soll der Fenster - Hintergrund gelöscht und das gesamte Fenster neu gezeichnet werden. Durch BeginPaint(),
ValidateRect()/ValidateRgn() wird das Update - Rechteck/Region gelöscht.
BOOL InvalidateRect(
HWND hWnd,
// handle of window with changed update Rect
CONST RECT *lpRect, // address of rectangle coordinates
BOOL bErase
// TRUE: BeginPaint() erased background
);
Mit der GetUpdateRect() kann untersucht werden, ob eine Update Rechteck vorhanden ist. Falls GetUpdateRect den wert 0 zurück gibt, so ist kein
BeginPaint() ... EndPaint() erforderlich. Falls ein Update Rechteck vorhanden ist, so sendet die UpdateWindow( hWndMain ) eine synchrone
WM_PAINT - Nachricht. Ebenso die RedrawWindow( hWndMain ) Funktion, die eine erweiterte Kontrolle ( not Client, BackGround ) erlaubt.
Sichtbarkeit von Fenstern
Ein Fenster kann in den Vordergrund geholt werden. Beispiel:
BOOL bVisible = IsWindowVisible(hwnd);
SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW
|(bVisible ? SWP_NOACTIVATE : 0));
if (wParam == TRUE) SetForegroundWindow(hwnd);
WM_CLOSE - Nachricht
Wird durch einen
x - Mausklick die iMsg = WM_CLOSE - Nachricht ausgelöst,
so wird die CALLBACK - Funktion
●
LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam )
mit iMsg = WM_CLOSE aufgerufen. Um mit Hilfe eines Anzeige - Fensters ( MessageBox ) eine Rückfrage zu ermöglichen wird unter
WM_CLOSE
case WM_CLOSE:
if ( GetParent( hWnd ) != NULL ) break;
char buf[256];
GetWindowText( hWnd, buf, 256 ) ; // Text der Titelzeile wird nach buf kopiert
if ( MessageBox ( hWnd, "Do you want to Exit?", buf, MB_ICONQUESTION |
MB_YESNO) == IDYES ) {
DestroyWindow( hWnd ); //sendet WM_DESTROY
} return 0;
case WM_DESTROY: // Hauptfenster schliessen, zerstoert automatisch die ChildWindows.
PostQuitMessage( 0 );
return 0;
ausgeführt. Falls der MessageBox - Rückgabewert TRUE ist, so wurde der "YES" - Button gedrück. Dann wird durch DestroyWindow( hWnd ) die
WM_DESTROY - Nachricht gesendet, d.h. die
●
LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam )
Funktion wird mit iMsg = WM_DESTROY aufgerufen. Infolge von PostQuitMessage( 0 ) wird das Fenster geschlossen.
DefWindowProc()
Einige Nachrichten werden in der eigenen CALL-Klassen-CALBACK-Funktionen behandelt. Alle anderen Nachrichten werden an die "default Windows - CALLBACK - Funktion" DefWindowProc() übergeben. DefWindowProc() ist wie eine Applikations - CALLBACK - Funktion
aufgebaut. DefWindowProc() behandelt die folgenden Nachrichten:
WM_NCCREATE,
WM_NCCALCSIZE,
WM_NCHITTEST,
WM_NCPAINT,
WM_NCACTIVATE,
WM_CANCELMODE,
WM_SETTEXT,
WM_GETTEXT,
WM_ICONERASEBKGND, WM_SYNCPAINT,
WM_WINDOWPOSCHANGED,WM_CTLCOLOR,
WM_NCLBUTTONUP,
WM_NCLBUTTONDBLCLK,
WM_SYSKEYUP,
WM_SYSCHAR,
WM_CHARTOITEM,
WM_VKEYTOITEM,
WM_QUERYDROPOBJECT, WM_DROPOBJECT,
WM_GETTEXTLENGTH,
WM_SYSCOMMAND,
WM_SETCURSOR,
WM_NCMOUSEMOVE,
WM_CLOSE,
WM_DRAWITEM,
WM_PAINT,
WM_ACTIVATE,
WM_MOUSEACTIVATE,
WM_KEYDOWN,
WM_QUERYOPEN,
WM_GETHOTKEY,
WM_PAINTICON,
WM_SETREDRAW,
WM_SHOWWINDOW,
WM_SYSKEYDOWN,
WM_QUERYENDSESSION,
WM_SETHOTKEY,
WM_ERASEBKGND,
WM_WINDOWPOSCHANGING,
WM_NCLBUTTONDOWN,
WM_KEYUP,
WM_ISACTIVEICON,
WM_QUERYDRAGICON,
/***
*crt0.c - C runtime initialization routine
*
*
Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
This the actual startup routine for apps. It calls the user's main
*
routine [w]main() or [w]WinMain after performing C Run-Time Library
*
initialization.
*
*
(With ifdef's, this source file also provides the source code for
*
wcrt0.c, the startup routine for console apps with wide characters,
*
wincrt0.c, the startup routine for Windows apps, and wwincrt0.c,
*
the startup routine for Windows apps with wide characters.)
*
*******************************************************************************/
#ifdef _WIN32
#ifndef CRTDLL
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<cruntime.h>
<dos.h>
<internal.h>
<stdlib.h>
<string.h>
<rterr.h>
<windows.h>
<awint.h>
<tchar.h>
<dbgint.h>
/*
* wWinMain is not yet defined in winbase.h. When it is, this should be
* removed.
*/
int
WINAPI
wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nShowCmd
);
#ifdef WPRFLAG
_TUCHAR * __cdecl _wwincmdln(void);
#else /* WPRFLAG */
_TUCHAR * __cdecl _wincmdln(void);
#endif /* WPRFLAG */
/*
* command line, environment, and a few other globals
*/
#ifdef WPRFLAG
wchar_t *_wcmdln;
#else /* WPRFLAG */
char *_acmdln;
#endif /* WPRFLAG */
/* points to wide command line */
/* points to command line */
char
*_aenvptr = NULL; /* points to environment block */
wchar_t *_wenvptr = NULL; /* points to wide environment block */
void (__cdecl * _aexit_rtn)(int) = _exit;
/* RT message return procedure */
static void __cdecl fast_error_exit(int);
/*
* _error_mode and
* written out.
*/
int __error_mode =
#ifdef _WINMAIN_
int __app_type =
#else
int __app_type =
#endif
/* Error exit via ExitProcess */
_apptype, together, determine how error messages are
_OUT_TO_DEFAULT;
_GUI_APP;
/* _WINMAIN_ */
_CONSOLE_APP;
/* _WINMAIN_ */
/***
*BaseProcessStartup(PVOID Peb)
*
*Purpose:
*
This routine does the C runtime initialization, calls main(), and
*
then exits. It never returns.
*
*Entry:
*
PVOID Peb - pointer to Win32 Process Environment Block (not used)
*
*Exit:
*
This function never returns.
*
*******************************************************************************/
#ifdef _WINMAIN_
#ifdef
void
#else
void
#endif
WPRFLAG
wWinMainCRTStartup(
/* WPRFLAG */
WinMainCRTStartup(
/* WPRFLAG */
#else
/* _WINMAIN_ */
#ifdef
void
#else
void
#endif
WPRFLAG
wmainCRTStartup(
/* WPRFLAG */
mainCRTStartup(
/* WPRFLAG */
#endif
/* _WINMAIN_ */
void )
{
int mainret;
#ifdef _WINMAIN_
_TUCHAR *lpszCommandLine;
STARTUPINFO StartupInfo;
#endif /* _WINMAIN_ */
/*
* Get the full Win32 version
*/
_osver = GetVersion();
_winminor = (_osver >> 8) & 0x00FF ;
_winmajor = _osver & 0x00FF ;
_winver = (_winmajor << 8) + _winminor;
_osver = (_osver >> 16) & 0x00FFFF ;
#ifdef _MT
if ( !_heap_init(1) )
/* _MT */
if ( !_heap_init(0) )
#endif /* _MT */
fast_error_exit(_RT_HEAPINIT);
/* initialize heap */
#else
#ifdef _MT
if( !_mtinit() )
fast_error_exit(_RT_THREAD);
#endif /* _MT */
/* initialize heap */
/* write message and die */
/* initialize multi-thread */
/* write message and die */
/*
* Guard the remainder of the initialization code and the call
* to user's main, or WinMain, function in a __try/__except
* statement.
*/
__try {
_ioinit();
/* initialize lowio */
#ifdef WPRFLAG
/* get wide cmd line info */
_wcmdln = (wchar_t *)__crtGetCommandLineW();
/* get wide environ info */
_wenvptr = (wchar_t *)__crtGetEnvironmentStringsW();
#else
_wsetargv();
_wsetenvp();
/* WPRFLAG */
/* get cmd line info */
_acmdln = (char *)GetCommandLineA();
/* get environ info */
_aenvptr = (char *)__crtGetEnvironmentStringsA();
#endif
_setargv();
_setenvp();
/* WPRFLAG */
_cinit();
/* do C data initialize */
#ifdef _WINMAIN_
StartupInfo.dwFlags = 0;
GetStartupInfo( &StartupInfo );
#ifdef WPRFLAG
lpszCommandLine = _wwincmdln();
mainret = wWinMain(
#else /* WPRFLAG */
lpszCommandLine = _wincmdln();
mainret = WinMain(
#endif /* WPRFLAG */
GetModuleHandleA(NULL),
NULL,
lpszCommandLine,
StartupInfo.dwFlags & STARTF_USESHOWWINDOW
? StartupInfo.wShowWindow
: SW_SHOWDEFAULT
);
#else /* _WINMAIN_ */
#ifdef WPRFLAG
__winitenv = _wenviron;
mainret = wmain(__argc, __wargv, _wenviron);
#else
/* WPRFLAG */
__initenv = _environ;
mainret = main(__argc, __argv, _environ);
#endif /* WPRFLAG */
#endif
/* _WINMAIN_ */
exit(mainret);
}
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
/*
* Should never reach here
*/
_exit( GetExceptionCode() );
} /* end of try - except */
}
/***
*_amsg_exit(rterrnum) - Fast exit fatal errors
*
*Purpose:
*
Exit the program with error code of 255 and appropriate error
*
message.
*
*Entry:
*
int rterrnum - error message number (amsg_exit only).
*
*Exit:
*
Calls exit() (for integer divide-by-0) or _exit() indirectly
*
through _aexit_rtn [amsg_exit].
*
For multi-thread: calls _exit() function
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _amsg_exit (
int rterrnum
)
{
#ifdef _WINMAIN_
if ( __error_mode == _OUT_TO_STDERR )
#else /* _WINMAIN_ */
if ( __error_mode != _OUT_TO_MSGBOX )
#endif /* _WINMAIN_ */
_FF_MSGBANNER();
/* write run-time error banner */
_NMSG_WRITE(rterrnum);
_aexit_rtn(255);
/* write message */
/* normally _exit(255) */
}
/***
*fast_error_exit(rterrnum) - Faster exit fatal errors
*
*Purpose:
*
Exit the process with error code of 255 and appropriate error
*
message.
*
*Entry:
*
int rterrnum - error message number (amsg_exit only).
*
*Exit:
*
Calls ExitProcess.
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl fast_error_exit (
int rterrnum
)
{
#ifdef _WINMAIN_
if ( __error_mode == _OUT_TO_STDERR )
#else /* _WINMAIN_ */
if ( __error_mode != _OUT_TO_MSGBOX )
#endif /* _WINMAIN_ */
_FF_MSGBANNER();
/* write run-time error banner */
_NMSG_WRITE(rterrnum);
ExitProcess(255);
/* write message */
/* normally _exit(255) */
}
#ifndef WPRFLAG
#endif
/* WPRFLAG */
#endif
/* CRTDLL */
#else
/* _WIN32 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<cruntime.h>
<internal.h>
<stdlib.h>
<msdos.h>
<string.h>
<setjmp.h>
<dbgint.h>
<macos\types.h>
<macos\segload.h>
<macos\gestalte.h>
<macos\osutils.h>
<macos\traps.h>
<mpw.h>
static void __cdecl Inherit(void);
/* local function */
int __cdecl main(int, char **, char **);
/*generated by compiler*/
unsigned long _GetShellStack(void);
static char * __cdecl _p2cstr_internal ( unsigned char * str );
extern MPWBLOCK * _pMPWBlock;
extern int __argc;
extern char **__argv;
/***
*__crt0()
*
*Purpose:
*
This routine does the C runtime initialization, calls main(), and
*
then exits. It never returns.
*
*Entry:
*
*Exit:
*
This function never returns.
*
*******************************************************************************/
void __cdecl __crt0 (
)
{
int mainret;
char szPgmName[32];
char *pArg;
char *argv[2];
#ifndef _M_MPPC
void *pv;
/* This is the magic stuff that MPW tools do to get info from MPW*/
pv = (void *)*(int *)0x316;
if (pv != NULL && !((int)pv & 1) && *(int *)pv == 'MPGM') {
pv = (void *)*++(int *)pv;
if (pv != NULL && *(short *)pv == 'SH') {
_pMPWBlock = (MPWBLOCK *)pv;
}
}
#endif
/* _M_MPPC */
_environ = NULL;
if (_pMPWBlock == NULL) {
__argc = 1;
memcpy(szPgmName, (char *)0x910, sizeof(szPgmName));
pArg = _p2cstr_internal(szPgmName);
argv[0] = pArg;
argv[1] = NULL;
__argv = argv;
#ifndef _M_MPPC
_shellStack = 0;
#endif /* _M_MPPC */
}
#ifndef _M_MPPC
else {
_shellStack = _GetShellStack();
_shellStack += 4;
__argc = _pMPWBlock->argc;
__argv = _pMPWBlock->argv;
#endif
Inherit();
}
/* _M_MPPC */
/* force ExitToShell */
//return current a6, or first a6
//a6 + 4 is the stack pointer we want
/* Inherit file handles - env is set up by _envinit if needed */
/*
* call run time initializer
*/
__cinit();
mainret = main(__argc, __argv, _environ);
exit(mainret);
}
#ifndef _M_MPPC
/***
*Inherit() - obtain and process info on inherited file handles.
*
*Purpose:
*
*
Locates and interprets MPW std files. For files we just save the
*
file handles.
For the console we save the device table address so
*
we can do console I/O. In the latter case, FDEV is set in the _osfile
*
array.
*
*Entry:
*
Address of MPW param table
*
*Exit:
*
No return value.
*
*Exceptions:
*
*******************************************************************************/
static void __cdecl Inherit (void )
{
MPWFILE *pFile;
int i;
pFile = _pMPWBlock->pFile;
if (pFile == NULL) {
return;
}
for (i = 0; i < 3; i++) {
switch ((pFile->pDevice)->name) {
case 'ECON':
_osfile[i] |= FDEV | FOPEN;
_osfhnd[i] = (int)pFile;
break;
case 'FSYS':
_osfile[i] |= FOPEN;
_osfhnd[i] = (*(pFile->ppFInfo))->ioRefNum;
break;
}
pFile++;
}
}
#endif
/* _M_MPPC */
static char * __cdecl _p2cstr_internal (unsigned char * str)
{ int cch;
unsigned char *pchSrc;
unsigned char *pchDst;
if ( str && *str ) {
pchDst = str;
pchSrc = str + 1;
for ( cch=*pchDst; cch; --cch ) { *pchDst++ = *pchSrc++;}
*pchDst = '\0';
} return( str );
}
#endif
/* _WIN32 */
Assembler
Mnemonische Codes in Assembler: Ein gespeichertes Maschinenprogramm besteht aus einer Folge von Bitmustern. Der Reihe nach
holt sich der Prozessor das nächste Bitmuster ( den nächsten Befehl ). Ein Befehl für den Prozessor ist ein Bitmuster, das der
Prozessor interpretiert ( "versteht" ).
Ein Programm erstellen heißt, für den Prozessor die richtige Folge von Bitmuster-Befehlen erstellen und
speichern.
Das Bitmuster für ca. 100 OpCode-Befehle sind unübersichtlich.
Jedem Bitmuster des Maschinen-Befehlsvorrates wird ein lesbares Kurzwort ( OpCode, Assembler-Befehl )
zugeordnet. Zu jedem Befehl in Assembler gehört ein Mikroprozessor-Befehl. Jede Prozessorfamilie hat eigene
Bit-Befehlsmuster und somit eigene Assembler-Befehle.
Ein Mnemonik ist die Bezeichnung des in Assembler verwendeten Ein Befehlskürzels ( meist 3 bis 4 Zeichen ) beschreibt die
Prozessor-Operation eines Maschinen-Befehls und wird auch als Mnemonik bezeichnet. Ein moderner Computer ist ein komplexes
System von Komponenten. Diese tauschen mit elektrischen Signalen Informationen aus. Um die grundlegenden Funktionen zu
verstehen, benötigen wir ein einfaches Modell. Ein grundlegendes Modell besteht aus Prozessor, Speicher und allen anderen
Komponenten. Auch der Prozessor enthält einige, wenige, interne Speicher ( Register ). Die Prozessor - Befehle stehen als Bitmuster
im Speicher und bilden das Maschinen - Programm. Eine Maschinen - Befehl kann nur vom Prozessor ausgeführt werden. Ein
Programm wird ausgeführt, wenn nacheinander Maschinen - Befehle ( OpCode ) von Speicher zum Prozessor geschickt werden und
der Prozessor diese Befehle ausführt. Das Programm bleibt im Speicher erhalten. Auf die Leitungen ( Datenbus ) zwischen Speicher
und Prozessor wird immer eine Kopie des OpCodes gelegt. Wurde ein Befehl ausgeführt ( interpretiert ), so holt sich der Prozessor
den nächsten Befehl aus dem Speicher. Die Prozessor - Frequenz und Bus - Frequenz bestimmen die Geschwindigkeit der Befehls Ausführung und Befehls - Übertragung.
Enviroment Prozessor Speicher
Die Assemblerbefehle sind einfach aufgebaut. Beim Intel 80x86 kann ein Assemblerbefehl durch folgendes Schema beschrieben
werden:
[Präfix] Mnemonik [Operand 1] [, Operand 2]
●
●
●
●
●
Der Maschinencode bildet ein Maschinenprogramm
Der Maschinencode steuert den Prozessor
Der Maschinencode besteht aus OpCode
An dem Bitmuster des OpCode erkennt der Prozessor den Befehl
Der OpCode wird mit Binärziffern ( Bin : 0, 1 )
oder Hexa- Dezimal - Ziffern ( Hex : 0, 1, 2, ..., 9, A, B, C, D, E, F )
angegeben.
Beispiel eines Assemblerbefehls
Soll in das AX - Register des Prozessors eine 10 geschieben werden, so muß das Bitmuster "1011 1000 1010 000 000 000" ( bzw. die
Hex-Zahlen "B8 0A 00" mit einem Hex nach Binär - Wandlung ) im Speicher hinterlegen werden. Es wird ein
Übersetzungsprogramm ( Assembler ) benutzt, das die Mnemoniks in das Bitmuster umwandelt. In Assembler-Quelltext wird z.B.
"MOV AX, 0Ah" geschrieben. Mit Hilfe eines Übersetzungsprogrammes ( Assembler ) wird diese ( dem Menschen eher
verständliche Kurz- ) Schreibweise in ein Bitmuster umgewandelt, das von dem Prozessor "verstanden" wird. Ein solches kurzes
Bitmuster im Speicher ( Maschinenprogramm ) hat z.B. die folgende Darstellung, wobei beim Assembler-Programm die Mnemonics
benutzt werden:
Programm in Speicher ( RAM )
Bin: 0001 1110 1011 1000 0000 0000 0000 0000 0101 0000 1111 1100 1000 1100 1100 1000
Hex:
1E
B8
Mnemonics: PUSH DS
00
00
MOV AX, 0
50
FC
PUSH AX
CLD
8C
C8
MOV AX, CS
Inline-Assembler
Kleinere Teile von großen Projekte werden in Assembler ( heute meistens Inline-Assembler ) geschrieben. Gründe sind:
●
●
●
Optimierung der Geschwindigkeit von kritischen Teilen,
direkten Hardware-Zugriff ( device driver ),
für prolog/epilog - Code von naked - Calls.
Die folgenden Schreibweisen sind möglich:
__asm
{
mov al, 2
mov dx, 0xD007
out al, dx
}
// oder
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx
// oder
__asm mov al,2
__asm mov dx,0xD007
__asm out al,dx
Beim Inline - Assembler können verwendet werden:
●
●
●
●
●
●
Symbole ( einschließlich Labels, Variablen, Funktionsnamen ),
Konstanten ( einschließlich Symbolischen Konstanten und Enum ),
Macros und Preprocessor - Direktiven,
Kommentare ( /* */ und // ),
type Namen ( falls MASM Type ),
typedef Namen ( Operatoren wie PTR, TYPE oder spezifischen Structure oder union members ),
Die folgenden Ergebnisee ( LENGTH, SIZE, TYPE ) beziehen sich auf int arr[8]:
int arr[8];
__asm
C/C++
Ergebnis
LENGTH arr
sizeof(arr)/sizeof(arr[0])
8
SIZE arr
sizeof(arr)
16
TYPE arr
sizeof(arr[0])
2
Den Zugriff auf C/C++ - Variablen zeigt das folgende Beispiel:
int var = 100; // C
__asm mov eax, var
// Inline - Assembler
Soll in das 6. Element des int array[8] - Array die Zahl 100 geschrieben werden, so kann dies etwa gemäß
__asm
C/C++
__asm mov array[6 * TYPE int], 100
array[6] = 100;
erfolgen. Den Zugriff auf C/C++ - Strukturen zeigt das folgende Beispiel:
struct T1 {
char * p;
int same;
};
struct T2 {
int xxxx;
long same;
};
struct T1 t1;
struct T2 t2;
__asm
{
mov ebx, OFFSET t1
mov ecx, [ebx]t1.same ; Must use t1
mov esi, [ebx].p
; Can omit t1
}
Beispiel
C/C++ - Macros können __asm Blöcke enthalten.
#define PORTIO __asm
{
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx
}
\
\
\
\
\
Obwohl die {} - Klammern gesetzt sind, so werden die letzten drei __asm werden benötigt, weil ein C/C++ - Macro in einer einzigen
logischen Text - Zeile expandiert. Ein C - Macro- __asm Block kann Argumente enthalten, aber keine Rückgabewerte, d.h. diese
Macros können nicht in einem C - Ausdruck verwendet werden.
Die _emit Pseudo - Instruktion ist ähnlich zu der DB - Assembler - Direktiven. Mit _emit kann an der aktuellen Code - Stelle ( im
Text - Segment ) ein Byte hinterlegt werden.
Beispiel
$ entspricht der aktuellen Adresse. Durch jne $+5 kann ein far - Jump übersprungen werden.
jne $+5
jmp farLabel
// hier ist $+5
.
.
.
farLabel:
Beispiel
#define randasm __asm _emit 0x4A __asm _emit 0x43 __asm _emit 0x4B
.
.
__asm {
randasm
}
Beispiel
Verwendet eine C/C++ - Funktion Inline - Assembler - Instruktionen, so können die Register
●
●
●
●
●
EAX, EBX, EDX ohne Store/Restore bei __stdcall,
ECX, EDX mit Store/Restore bei __fastcall,
ECX mit Store/Restore für this bei #ifdef __cplusplus und __stdcall,
EDS, ESS, EES, ESP, EBP mit Store/Restore,
( ESI, EDI auch STD/CLD ) mit Store/Restore
verwendet werden.
#include <stdio.h>
int power2( int num, int power ) {
__asm
{
mov eax, num
mov ecx, power
shl eax, cl
}
/* Return with result in EAX */
}
void main( void )
{
printf( "3 * 2^5 ist %d\n", power2( 3, 5) );
}
Beispiel
Das folgende Inline - Assembler - Stück ruft printf() auf. Die C - Bibliotheks - Funktionen ( C library functions ) sind mit extern "C"
gebunden ( gelinkt ).
#include <stdio.h>
char format[] = "\n%s %s";
char hallo[] = "Hallo";
char welt[]
= "Welt";
void main( void ) {
__asm
{
mov eax, offset welt
push eax
mov eax, offset hallo
push eax
mov eax, offset format
push eax
call printf
}
}
Dies entspricht dem C - Aufruf printf( "\n%s %s", "Hallo", "Welt" ). Die Parameter werden von rechts nach links auf den Stack
gelegt. Wegen dem this - Parameter können überladene C++ - Funktionen i.a. nicht
Anmerkung:
Win16 unterscheidet verschiedene Speicher - Modelle ( Tiny, Small, Medium, Compact, Large, Hughe ). Diese Modelle ermöglichen
2 Byte - und 4 - Byte Adressenbildung ( Zeiger ). Kurze Sprünge sind schneller. Bei Win32 werden lineare Adressen ( 4 Byte je
Adresse ) verwendet.
jmp
weiter
...
weiter:
Folgendes Beispiel zeigt den direkten Win16 - Speicherzugriff mittels Inline Assembler ( für Microsoft C muß asm durch _asm
ersetzt werden ). Ein Speichebereich wird von der Adresse * src ( source ) zur Zielstelle *dst ( Destination ) kopiert.
void ram_move ( void *
asm push ds
asm lds si, src
asm les di, dst
asm mov cx, anz_byte
asm cld
asm shr cx,1
asm rep movsw
asm adc cx,cx
asm pop ds
}
src, void * dst, int anz_byte) {
//
//
//
//
// aufsteigend
// cx = Anzahl der Worte, cx-// bis cx != 0
// cx = carry => Anzahl der Worte gerade oder ungerade ?
Windows-Parameter-Übergabe
Auf Maschinenebene werden C/C++Parameter werden i.a. vor der Rücksprungadresse der Funktion auf den User-Stack gelegt.
●
●
●
●
●
●
●
●
Der Win32 - Compiler generiert Prolog- und Epilog-Code.
Mit Naked Function Calls kann der Prolog - und Epilog - Code geändert werden.
Die Parameter einer Funktion werden von rechts nach links auf den Stack gepushed.
Bei Funktionen müssen die Register ESI, EDI, EBX, EBP gesichert werden.
Alle Argumente werden auf 32 - Bit - Grenzen erweitert.
Rückgabe - Werte ( <= 4 Byte ) werden auf 32 - Bit - Grenzen erweitert ( EAX ).
Rückgabe - Strukturen ( <= 8 Byte ) werden in EDX:EAX zurück gegeben.
Rückgabe - Strukturen ( > 8 Byte ) werden mit EAX als Zeiger zurück gegeben.
Die folgende Tabelle zeigt für Win32 die __cdecl, __stdcall, __fastcall - Unterschiede.
Keyword
Parameter
__cdecl
von rechts nach links auf Stack
__stdcall
von rechts nach links auf Stack
__fastcall
in Register, Rest auf Stack
C++ mit this
von rechts nach links auf Stack, this in ECX
Beispiel
void _cdecl foo(char c, short s, int i, double f );
foo(
'x',
12, 8192,
2.7183 );
_foo
ECX : nicht benutzt
EDX : nicht benutzt
-------|------|------|------|------|-------------|
Stack: |retAdr|
x | 12 | 8192 |
2.7183
|
-------|------|------|------|------|-------------|
ESP + | 00 | 04 | 08 | 0C | 10 | 14 |
-------|------|------|------|------|-------------|
void __stdcall foo(char c, short s, int i, double f );
foo(
'x',
12, 8192,
2.7183 );
_foo@20.
ECX : this(thiscall)
EDX : nicht benutzt
-------|------|------|------|------|-------------|
Stack: |retAdr|
x | 12 | 8192 |
2.7183
|
-------|------|------|------|------|-------------|
ESP + | 00 | 04 | 08 | 0C | 10 | 14 |
-------|------|------|------|------|-------------|
void __fastcall foo(char c, short s, int i, double f );
foo(
'x',
12, 8192,
2.7183 );
ECX:
x
EDX:
12
-------|------|------|------|------|
Stack: |retAdr| 8192 |
2.7183
|
-------|------|------|------|------|
ESP + | 00 | 04 | 08 | 0C |
-------|------|------|------|------|
Vor einem Funktions - Aufruf werden die Parameter auf den Stack des aufrufenden Programmes gelegt. Eine DLL - Funktion benutzt
den Stack des aufrufenden Programmes.
Für Win3.x gilt die folgende Tabelle:
Funktion
CDCL
PASCAL
C++
Bei dynamischer C++ - Bindung
wird vor der Rücksprungadresse
zusätzlich der this - Zeiger. auf
den Stack gelegt.
int fkt (
int i,
int j
)
Zuerst wird j dann i auf den Stack
gelegt, dann die
Rücksprungadresse. Weil die
Stackkorrektur im aufrufenden
Programm erfolgt, kann die
Parameter - Anzahl variieren ( ... ).
Der Assembler-Name der Funktion
ist _fkt
Zuerst wird i dann j auf den Stack
gelegt, dann die
Rücksprungadresse. Weil die
Stackkorrektur in der aufgerufenen
Funktion erfolgt, kann die
Parameteranzahl nicht variieren.
Der Assembler-Name der Funktion
ist FKT
Ein eindeutiger Funktionsname
von int fkt ( int i, int j ) wird
durch das aneinander fügen von
fkt$int$int gebildet. Ein
Überladen des Funktionsnamen
fkt bedeutet, daß zwar der gleiche
Name fkt aber andere
Parametertypen oder andere
Parameterfolgen verwendet
werden. Dadurch ergeben sich im
Überladungsfall eindeutige
Maschinenadressen.
Der Assembler-Name der
Funktion ist fkt$int$int
Win3.x verwendet ( praktisch immer ) PASCAL deklarierte Funktionen.
Link zum main()-Start-Up-Code
Dank an Mike Schmit!
Top Ten Rules
for Pairing Pentium Instructions
1. Both instructions must be simple.
2. Shifts or rotates can only pair in the U pipe.
(SHL, SHR, SAL, SAR, ROL, ROR, RCL or RCR)
3. ADC and SBB can only pair in the U pipe.
4. JMP, CALL and Jcc can only pair in the V pipe. (Jcc = jump on condition code).
5. Neither instruction can contain BOTH a displacement and an immediate operand. For example:
mov
mov
[bx+2], 3
mem1, 4
; 2 is a displacement, 3 is immediate
; mem1 is a displacement, 4 is immediate
6. Prefixed instructions can only pair in the U pipe. This includes extended instructions that start with 0Fh except for the
special case of the 16-bit conditional jumps of the 386 and above. Examples of prefixed instructions:
mov
mov
mov
ES:[bx],
eax, [si]
ax, [esi]
; 32-bit operand in 16-bit code segment
; 16-bit operand in 32-bit code segment
7. The U pipe instruction must be only 1 byte in length or it will not pair until the second time it executes from the cache.
8. There can be no read-after-write or write-after-write register dependencies between the instructions except for special
cases for the flags register and the stack pointer (rules 9 and 10).
mov
add
mov
mov
ebx, 2
; writes to EBX
ecx, ebx ; reads EBX and ECX, writes to ECX
; EBX is read after being written, no pairing
ebx, 1
; writes to EBX
ebx, 2
; writes to EBX
; write after write, no pairing
9. The flags register exception allows an ALU instruction to be paired with a Jcc even though the ALU instruction writes
the flags and Jcc reads the flags. For example:
cmp
je
dec
jnz
al, 0
addr
cx
loop1
;
;
;
;
CMP modifies the flags
JE reads the flags, but pairs
DEC modifies the flags
JNZ reads the flags, but pairs
10. The stack pointer exception allows two PUSHes or two POPs to be paired even though they both read and write to the
SP (or ESP) register.
push
eax
; ESP is read and modified
push
ebx
; ESP is read and modified, but still pairs
Simple Instructions (for Pentium pairing)
The following is a list of simple instructions, as required by rule #1 above.
Instruction format 16-bit example
32-bit example
-----------------------------------------------------------MOV reg, reg
mov ax, bx
mov eax, edx
MOV reg, mem
mov ax, [bx]
mov eax, [edx]
MOV reg, imm
mov ax, 1
mov eax, 1
MOV mem, reg
mov [bx], ax
mov [edx], eax
MOV mem, imm
mov [bx], 1
mov [edx], 1
alu reg, reg
add ax, bx
cmp eax, edx
alu reg, mem
add ax, [bx]
cmp eax, [edx]
alu reg, imm
add ax, 1
cmp eax, 1
alu mem, reg
add [bx], ax
cmp [edx], eax
alu mem, imm
add [bx], 1
cmp [edx], 1
where alu = add, adc, and, or, xor, sub, sbb, cmp, test
INC
INC
DEC
DEC
PUSH
POP
LEA
JMP
CALL
Jcc
reg
mem
reg
mem
reg
reg
reg, mem
near
near
near
inc
inc
dec
dec
push
pop
lea
jmp
call
jz
ax
var1
bx
[bx]
ax
ax
ax, [si+2]
label
proc
lbl
inc
inc
dec
dec
push
pop
lea
jmp
call
jnz
eax
[eax]
ebx
var2
eax
eax
eax, [eax+4*esi+8]
lable2
proc2
lbl2
where Jcc = ja, jae, jb, jbe, jg, jge, jl, jle, je, jne, jc, js,
jnp, jo, jp, jnbe, jnb, jnae, jna, jnle, jnl, jnge,
jng, jz, jnz, jnc, jns, jpo, jno, jpe
NOP
shift
shift
shift
shift
reg,
mem,
reg,
mem,
1
1
imm
imm
nop
shl
shr
sal
sar
ax, 1
[bx], 1
ax, 2
ax, 15
nop
rcl
rcr
rol
ror
eax, 1
[ebx], 1
esi, 2
[esi], 31
where shift = shl, shr, sal, sar, rcl, rcr, rol, ror
Notes:
●
●
●
rcl and rcr are not pairable with immediate counts other than 1
all memory-immediate (mem, imm) instructions are not pairable with a displacement in the memory operand
instructions with segment registers are not pairable
Pentium® Optimization Cross-Reference by Instruction
The following is a list of optimizations that may come in handy. Each one is listed alphabetically (more or less) in the first column.
The second column lists the CPU or CPU's that this optimization is applicable to; alternatively it may be noted as applicable to 16-bit
code or 32-bit code. The third column contains one or more replacement sequences of code that is either faster or smaller (sometimes
both) than the first column. For some obscure optimizations, the action of the first column instruction is explained. The forth column
contains a description and/or examples.
replacement
instruction
CPU's
or action
description/notes
--------------------------------------------------------------------------aad (imm8)
all
AL = AL+(AH*imm8)
AH = 0
If imm8 is blank uses 10.
AAD is almost always slower,
but only 2 bytes long.
aam (imm8)
all
AH = AL/imm8
AL = AL MOD imm8
Same as AAD.
add
16-bit
lea reg, [reg+reg+disp]
Use LEA to add
base + index + displacement
Also preserves flags;
for example:
add bx, 4
can be replaced by:
lea
bx, [bx+4]
when the flags must not
be changed.
add
32-bit
lea reg, [reg+reg*scale+disp]
Use LEA to add
base + scaled index + disp
Also preserves flags.
(See previous example).
The 32-bit form of LEA
is much more powerful
than the 16-bit version
because of the scaling
and the fact that almost
all of the 8 General purpose
registers can be used
as base and index registers.
and reg, reg
Pent
test reg, reg
Use TEST instead of AND
on the Pentium because
fewer register conflict
will result in better pairing
bswap
Pent
ror eax, 16
Pairs in U pipe, BSWAP
doesn't pair.
disadvantage: modifies flags
(Not a direct replacement)
call dest1
jmp dest2
286+
push offset dest2
jmp dest1
When CALL is followed by
a JMP, change the return
address to the JMP destination.
call dest1
ret
all
jmp
When a CALL is followed by a
RET, the CALL can be replaced
by a JMP.
cbw
386+
mov ah, 0
When you know AL < 128
use MOV AH, 0 for speed.
But use CBW for smaller
code size.
cdq
486+
xor edx, edx
When you know EAX is positive
Faster, better pairing.
dest1
disadvantage: modifies flags
Pent
mov edx, eax
sar edx, 31
When EAX value could be
positive or negative
because of better pairing
cmp mem, reg
286
cmp reg, mem
reg, mem is 1 cycle faster
cmp reg, mem
386
cmp mem, reg
mem, reg is 1 cycle faster
dec reg16
lea reg16, [reg16 - 1]
Use to preserve flags
for BX, BP, DI, SI
dec reg32
lea reg32, [reg32 - 1]
Use to preserve flags
for EAX, EBX, ECX, EDX
EDI, ESI, EBP
div <op>
8088
shr accum, 1
When <op> resolves to 2, use
shift for division.
(use CL for 4, 8, etc.)
div <op>
186+
shr accum, n
When <op> resolves to a power
of 2 use shifts for division.
enter imm16, 0
286+
push bp
mov bp, sp
sub sp, imm16
386+
32-bit
push ebp
mov ebp, esp
sub esp, imm16
ENTER is always slower
and 4 bytes in length
if imm16 = 0 then push/mov
is smaller
inc reg16
lea reg16, [reg16 + 1]
inc reg32
lea reg32, [reg32 + 1]
jcxz <dest>:
486+
test cx, cx
je
<dest>:
Use to preserve flags
for BX, BP, DI, SI
Use to preserve flags
for EAX, EBX, ECX, EDX
EDI, ESI, EBP
JCXZ is faster and
smaller on 8088-286.
On the 386 it is the
about the same speed
test ecx, ecx
je
<dest>:
Never use JCXZ on 486
or Pentium except for
compactness
8088-286
mov reg, OFFSET mem
MOV reg, imm is faster
on 8088 - 286. 386+
they are the same.
lea reg, mem
486+
Note: There are many uses for LEA, see: add, inc, dec, mov, mul
leave
486+
mov sp, bp
pop bp
mov esp, ebp
pop ebp
LEAVE is only 1 byte
long and is faster
on the 186-386. The
MOV/POP is much faster
on 486 and Pentium
lodsb
486+
mov al, [si]
inc si
LODS is only 1 byte long
and is faster on 8088-386,
much slower on the 486.
On the Pentium the MOV/INC
or MOV/ADD instructions
pair, taking only 1 cycle.
lodsw
486+
mov ax, [si]
add si, 2
see lodsb
lodsd
486+
mov eax, [esi]
add esi, 4
see lodsb
dec cx
jnz <dest>:
LOOP is faster and
smaller on 8088-286.
on 386+ DEC/JNZ is
much faster. On the Pentium
the DEC/JNZ instructions
pair taking only 1 cycle.
loop <dest>:
386+
loopd <dest>:
dec ecx
jnz <dest>:
loopXX <dest>:
486+
( XX = e,ne,z or nz)
je $+5
dec cx
jnz <dest>:
loopdXX <dest>:
je $+5
dec ecx
jnz <dest>:
486+
The 3 replacement instructions
are much faster on the 486+.
LOOPxx is smaller and
faster on 8088-286
The speed is about the
same on the 386.
mov reg2, reg1 286+
followed by:
inc/dec/add/sub reg2
lea reg2, [reg1+n]
LEA is faster, smaller and
preserves flags. This is a
way to do a MOV and ADD/SUB
of a constant, n.
mov acc, reg
xchg acc, reg
Use XCHG for smaller code
when one of the registers
all
final value can be ignored.
Note that acc = AL, AX or EAX.
mov mem, 1
Pent
lea bx, mem
mov [bx], 1
mov ax, 1
mov mem, ax
mov [bx+2], 1
Pent
mov ax, 1
mov [bx+2], ax
Displacement/immediate does
not pair. LEA/MOV can be used
if other code can be placed
inbetween to prevent AGI's.
MOV/MOV may be easier to pair.
Better pairing because
displacement/immediate
instructions do not pair.
lea bx, [bx+2]
mov [bx], 1
movsb
486+
mov
inc
mov
inc
al, [si]
si
[di], al
di
MOVS is faster and
smaller to move a single
byte, word or dword
on the 8088-386.
On the 486+ the MOV/INC
method is faster.
NOTE: REP MOVS is always
faster to move a large block.
movsw
486+
mov
add
mov
add
ax, [si]
si, 2
[di], ax
di, 2
see MOVSB
movsd
486+
mov
add
mov
add
eax, [esi]
esi, 4
[edi], eax
edi, 4
see MOVSB
movzx r16, rm8
486+
xor bx, bx
mov bl, al
movzx r32, rm8
486+
xor ebx, ebx
mov bl, al
movzx r32, rm16 486+
xor ebx, ebx
mov bx, ax
mul n
8088+
shl ax, cl
Use shifts or ADDs instead of
multiply when n is a power of 2
mul n
Pent
add ax, ax
ADD is better than single
shift because it pairs better.
mul
32-bit
lea
Use LEA to multiply by
2, 3, 4, 5, 7, 8, 9
MOVZX is faster and
smaller on the 386.
On the 486+ XOR/MOV
is faster. Possible
pairing on the Pentium.
(source can be reg or mem)
disadvantage: modifies flags
lea eax, [eax+eax*4] (ex: multiply EAX * 5)
LEA is better than SHL on the
Pentium because it pairs in
both pipes, SHL pairs only in
the U pipe.
or reg, reg
Pent
test reg, reg
Better pairing because
OR writes to register.
(This is for src = dest.)
pop mem
486+
pop reg
mov mem, reg
Faster on 486+
Better pairing on Pentium
push mem
486+
mov reg, mem
push reg
Faster on 486
Better pairing on Pentium
pushf
486+
rcr reg, 1
To save only the carry flag
use a rotate (RCR or RCL)
into a register. RCR and RCL
are pairiable (U pipe only)
and take 1 cycle. PUSHF is
slow and not pairable.
or
rcl reg, 1
popf
486+
rcl reg, 1
or
rcr reg, 1
To restore only the carry flag.
See PUSHF.
rep scasb
Pent
loop1:
mov al, [di]
inc di
cmp al, reg2
je exit
dec cx
jnz loop1
exit:
REP SCAS is faster and
smaller on 8088-486.
Expanded code is faster
on Pentium due to pairing.
shl reg, 1
Pent
add reg, reg
ADD pairs better. SHL
only pairs in the U pipe.
stosb
486+
mov [di], al
inc di
stosw
486+
mov [di], ax
add di, 2
STOS is faster and smaller
on the 8088-286, and the same
speed on the 386. On the 486+
the MOV/INC is slightly
faster.
stosd
486+
mov [edi], eax
add edi, 4
REP STOS is faster on 8088-386.
MOV/INC or MOV/ADD is faster
on the 486+
Note: use LEA SI, [SI+n]
to advance LEA without
changing the flags.
xchg
all
xchg reg1, reg2 Pent
Use xchg acc, reg to do a
1 byte MOV when one register
can be ignored.
push
push
pop
pop
reg1
reg2
reg1
reg2
pushes and pops are 1 cycle
faster on Pentium due to
pairing.
disadvantage: uses stack
Pent
mov
mov
mov
reg3, reg1
reg1, reg2
reg2, reg3
xlatb
486+
mov bh, 0
mov bl, al
mov al, [bx]
xlatb
486+
xor ebx, ebx
mov bl, al
mov al, [ebx]
Faster and better pairing
if reg3 is available.
XLAT is faster and smaller
on 8088-386. MOV's are faster
on 486+. Best to rearrange
instructions to prevent AGI's
and get pairing on Pentium.
Force high part of BX/EBX
to zero outside of loop.
disadvantage: modifies flags
80x86 Integer Instruction Set (8088 - Pentium)
Legend:
General
reg
=
r8
=
r16
=
r32
=
imm
=
imm8 =
imm16 =
mem
=
mem8 =
mem16 =
mem32 =
mem48 =
dest =
short =
acc
= AL, AX or EAX unless specified otherwise
any general register
any 8-bit register
any general purpose 16-bit register
any general purpose 32-bit register
immediate data
8-bit immediate data
16-bit immediate data
memory address
address of 8-bit data item
address of 16-bit data item
address of 32-bit data item
address of 48-bit data item
16/32-bit destination
8-bit destination
Integer instruction timings:
n - generally refers to a number of repeated counts
m
-
in a jump or call;
286: bytes in next instruction
386/486: number of components
(each byte of opcode) + 1 (if immed data) + 1 (if displacement)
EA = cycles to calculate the Effective Address
8088/8086:
base
= 5
BP+DI or BX+SI = 7
BP+DI+disp or BX+SI+disp = 11
index = 5
BX+DI or BP+SI = 8
BX+DI+disp or BP+SI+disp = 12
disp
= 6
segment override = +2
286 - 486:
base+index+disp = +1
all others, no penalty instruction length:
The byte count includes the opcode length and length of any required
displacement or immediate data. If the displacement is optional, it
is shown as d() with the possible lengths in parentheses. If the
immediate data is optional, it is shown as i() with the possible
lengths in parentheses.
pairing categories for
NP = not pairable
UV = pairable in the U
PU = pairable in the U
PV = pairable in the V
Pentium:
pipe or V pipe
pipe only
pipe only
Instruction formats, clock cycles and
Pentium® Pairing info
AAA
ASCII adjust after addition
bytes
1
Example:
8088
8
186
8
286
3
386
4
486
3
Pentium
3
NP
AAD
aaa
ASCII adjust AX before division (second byte is divisor)
bytes
2
Example:
8088
60
186
15
286
14
386
19
486
14
Pentium
10
NP
AAM
aad
ASCII adjust AX after multiply (second byte is divisor)
bytes
2
Example:
8088
83
186
19
286
16
386
17
486
15
Pentium
18
NP
AAS
aam
ASCII adjust AL after subtraction
bytes
1
Example:
8088
8
186
7
286
3
386
4
486
3
Pentium
3
NP
ADC
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
Pentium
1
PU
3
PU
2
PU
1
PU
3
PU*
4
3
2
1
aas
Integer add with carry
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
4
1
PU
* = not pairable if there is a displacement and immediate
Example:
ADD
adc
eax, ebx
Integer addition
operands
bytes
8088
186
286
386
486
Pentium
reg,
mem,
reg,
reg,
mem,
reg
reg
mem
imm
imm
acc, imm
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
3
24+EA
13+EA
4
23+EA
3
10
10
4
16
2
7
7
3
7
2
7
6
2
7
1
3
2
1
3
1
3
2
1
3
UV
UV
UV
UV
UV*
4
3
2
1
1
UV
4
* = not pairable if there is a displacement and immediate
Example:
AND
add
eax, ebx
Logical AND
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
4
3
2
1
4
Pentium
1
UV
3
UV
2
UV
1
UV
3
UV*
1
UV
* = not pairable if there is a displacement and immediate
Example:
ARPL
and
eax, ebx
Adjust RPL field of selector (286+)
operands
reg, reg
mem, reg
Example:
bytes
2
2+d(0-2)
BOUND
arpl
286
10
11
386
20
21
486
9
9
Pentium
7
NP
7
NP
386
10
486
7
Pentium
8
NP
386
10+3n
10+3n
10+3n
10+3n
486
6-42
6-42
7-43
7-43
Pentium
6-34 NP
6-42 NP
6-35 NP
6-43 NP
386
10+3n
10+3n
10+3n
10+3n
486
6-103
7-104
6-103
7-104
Pentium
7-39 NP
7-71 NP
7-40 NP
7-72 NP
ax, bx
Check array index against bounds (186+)
operands
reg, mem
Example:
bytes
4
BSF
bound
186
35
286
13
bx, array
Bit scan forward (386+)
operands
r16, r16
r32, r32
r16, m16
r32, m32
Example:
bytes
3
3
3+d(0,1,2)
3+d(0,1,2,4)
BSR
bsf
eax, [esi]
Bit scan reverse (386+)
operands
r16, r16
r32, r32
r16, m16
r32, m32
Example:
BSWAP
bytes
3
3
3+d(0,1,2)
3+d(0,1,2,4)
bsr
eax, [esi]
Byte swap (486+)
operand
r32
Example:
bytes
2
BT
bswap
486
1
Pentium
1
NP
386
3
12
3
6
486
3
8
3
3
Pentium
4
NP
9
NP
4
NP
4
NP
386
6
13
6
8
486
6
13
6
8
Pentium
7
NP
13
NP
7
NP
8
NP
eax
Bit test (386+)
operands
reg, reg
mem, reg
reg, imm8
mem, imm8
Example:
BTC
bytes
3
3+d(0,1,2,4)
3+i(1)
3+d(0,1,2,4)+i(1)
bt
eax, 4
Bit test and complement (386+)
operands
reg, reg
mem, reg
reg, imm8
mem, imm8
bytes
3
3+d(0,1,2,4)
3+i(1)
3+d(0,1,2,4)+i(1)
Example:
BTR
btc
eax, 4
Bit test and reset (386+)
operands
reg, reg
mem, reg
reg, imm8
mem, imm8
Example:
bytes
3
3+d(0,1,2,4)
3+i(1)
3+d(0,1,2,4)+i(1)
BTS
btr
386
6
13
6
8
486
6
13
6
8
Pentium
7
NP
13
NP
7
NP
8
NP
386
6
13
6
8
486
6
13
6
8
Pentium
7
NP
13
NP
7
NP
8
NP
386
7+m
7+m
10+m
17+m
22+m
486
3
5
5
18
17
Pentium
1
PV
2
NP
2
NP
4
NP
4
NP
386
34+m
38+m
486
20
20
Pentium
4-13 NP
5-14 NP
eax, 4
Bit test and set (386+)
operands
reg, reg
mem, reg
reg, imm8
mem, imm8
Example:
bytes
3
3+d(0,1,2,4)
3+i(1)
3+d(0,1,2,4)+i(1)
CALL
bts
eax, 4
Call subroutine
operand
near
reg
mem16
far
mem32
bytes
3
2
2+d(0-2)
5
2+d(0-2)
8088
23
20
29+EA
36
53+EA
186
14
13
19
23
38
286
7+m
7+m
11+m
13+m
16+m
Protected Mode
operand
far
mem32
bytes
5
2+d(0-2)
286
26+m
29+m
cycles not shown for calls through call and task gates
Example:
CBW
call
my_function
Convert byte to word
bytes
1
Example:
8088
2
(AL --> AX)
186
2
286
2
386
3
486
3
Pentium
3
NP
CWDE
386
3
486
3
Pentium
3
NP
386
2
486
3
Pentium
2
NP
386
2
486
3
Pentium
2
NP
386
2
486
2
Pentium
2
NP
cbw
Convert word to dword (386+)
(AX --> EAX)
bytes
1
Example:
CWD
cwde
Convert word to double
bytes
1
Example:
8088
5
(AX --> DX:AX)
186
4
286
2
CDQ
cwd
Convert double to quad
(EAX --> EDX:EAX)
bytes
1
Example:
CLC
cdq
Clear the carry flag
bytes
1
Example:
8088
2
186
2
286
2
CLD
clc
Clear the direction flag (set to forward direction)
bytes
1
Example:
cld
8088
2
186
2
286
2
386
2
486
2
Pentium
2
NP
CLI
Clear the interrupt flag (disable interrupts)
bytes
1
Example:
8088
2
186
2
286
3
386
3
486
5
Pentium
7
NP
CLTS
286
2
386
5
486
7
Pentium
10
NP
186
2
286
2
386
2
486
2
Pentium
2
NP
186
3
10
10
4
10
286
2
7
6
3
6
386
2
5
6
2
5
486
1
2
2
1
2
Pentium
1
UV
2
UV
2
UV
1
UV
2
UV*
4
3
2
1
cli
Clear task switched flag in CR0 (286+)
bytes
2
Example:
CMC
clts
Complement carry flag
bytes
1
Example:
8088
2
CMP
cmc
Compare two operands
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
13+EA
13+EA
4
14+EA
4
1
UV
* = not pairable if there is a displacement and immediate
Example:
cmp
CMPS/CMPSB/CMPSW/CMPSD
variations
cmpsb
cmpsw
cmpsd
repX cmpsb
repX cmpsw
repX cmpsd
bytes
1
1
1
2
2
2
eax, 3
Compare string operands
8088
30
9+30n
9+30n
-
186
22
5+22n
5+22n
-
286
8
5+9n
5+9n
-
386
10
10
10
5+9n
5+9n
5+9n
486
8
8
8
7+7n*
7+7n*
7+7n*
Pentium
5
NP
5
NP
5
NP
9+4n NP
9+4n NP
9+4n NP
486
6
7-10
Pentium
5
NP
6
NP
repX = repe, repz, repne or repnz
* : 5 if n = 0
Example:
repne cmpsb
CMPXCHG
Compare and Exchange (486+)
operands
reg, reg
mem, reg
Example:
bytes
3
3+d(0-2)
cmpxchg ebx, edx
CMPXCHG8B
Compare and Exchange 8 bytes (Pentium+)
operands
mem, reg
Example:
bytes
3+d(0-2)
Pentium
10
NP
CPUID
cmpxchg8b [ebx], edx
CPU identification (Pentium+)
bytes
2
Example:
Pentium
14
NP
DAA
cpuid
Decimal adjust AL after addition
bytes
1
Example:
8088
4
186
4
286
3
386
4
486
2
Pentium
3
NP
DAS
386
4
486
2
Pentium
3
NP
daa
Decimal adjust AL after subtraction
bytes
1
Example:
das
8088
4
186
4
286
3
DEC
Decrement
operand
r8
r16
r32
mem
bytes
2
1
1
2+d(0,2)
186
3
3
3
15
286
2
2
2
7
386
2
2
2
6
486
1
1
1
3
Pentium
1
UV
1
UV
1
UV
3
UV
operand
bytes
8088
186
r8
2
80-90
29
r16
2
144-162
38
r32
2
mem8
2+d(0-2)
86-96+EA 35
mem16
2+d(0-2) 150-168+EA 44
mem32
2+d(0-2)
-
286
14
22
17
25
-
386
14
22
38
17
25
41
486
16
24
40
16
24
40
Pentium
17
NP
25
NP
41
NP
17
NP
25
NP
41
NP
Example:
DIV
dec
8088
3
3
3
23+EA
eax
Unsigned divide
implied
dividend
AX
/
DX:AX
/
EDX:EAX /
operand
byte
word
dword
Example:
ENTER
div
quotient
=
=
=
remainder
AL
AX
EAX
AH
DX
EDX
ebx
Make stack frame for procedure parameters (186+)
operands bytes
imm16, 0
3
imm16, 1
4
imm16, imm8 4
Example:
ESC
enter
8088
186
15
25
22+16n
n = imm8-1;
286
11
15
12+4n
i = imm8
386
10
12
15+4n
486
14
17
17+3i
Pentium
11
NP
15
NP
15+2i NP
1, 0
Escape
escape opcodes D8 - DF are used by floating point instructions
HLT
Halt
bytes
1
Example:
8088
2
186
2
386
5
486
4
Pentium
4
NP
486
19
27
43
20
28
44
Pentium
22
NP
30
NP
46
NP
22
NP
30
NP
46
NP
486
13-18
13-26
13-42
13-18
13-26
13-42
Pentium
11
NP
11
NP
10
NP
11
NP
11
NP
10
NP
hlt
IDIV
Signed divide
operand
bytes
8088
r8
2
101-112
r16
2
165-184
r32
2
mem8
2+d(0-2) 107-118+EA
mem16 2+d(0-2) 171-190+EA
mem32 2+d(0-2)
-
implied
dividend
AX
/
DX:AX
/
EDX:EAX /
operand
byte
word
dword
Example:
IMUL
286
2
idiv
186
44-52
53-61
50-58
59-67
-
quotient
=
=
=
AL
AX
EAX
286
17
25
20
28
-
386
19
27
43
22
30
46
remainder
AH
DX
EDX
ebx
Signed multiply
Accumulator Multiplies
operand
bytes
8088
r8
2
80-98
r16
2
128-154
r32
2
mem8
2+d(0-2) 86-104+EA
mem16
2+d(0-2) 134-160+EA
mem32
2+d(0-2)
-
implied
operand
multiplicand (multiplier)
AL
AX
*
*
byte
word
186
25-28
34-37
32-34
40-43
-
result
=
=
AX
DX:AX
286
13
21
16
24
-
386
9-14
9-22
9-38
12-17
12-25
12-41
EAX
*
Example:
dword
=
imul
EDX:EAX
ebx
2 and 3 operand Multiplies
operands
r16, imm
r32, imm
r16,r16,imm
r32,r32,imm
r16,m16,imm
bytes
186
2+i(1,2)
2+i(1,2)
2+i(1,2) 22/29
2+i(1,2)
2+d(0-2) 25/32
+i(1,2)
2+d(0-2)+i(1,2)
2+i(1,2)
2+i(1,2)
2+d(0-2)+i(1,2)
2+d(0-2)+i(1,2)
r32,m32,imm
r16, r16
r32, r32
r16, m16
r32, m32
286
386
486
21 9-14/9-22 13-18/13-26
9-38
13-42
21 9-14/9-22 13-18/13-26
9-38
13-42
24 12-17/12-25 13-18/13-26
-
12-41
9-22
9-38
12-25
12-41
all forms: dest, src
or
dest, src1, src2
Example:
IN
imul
13-42
13-18/13-26
13-42
13-18/13-26
13-42
cycles for:
Pentium
10
NP
10
NP
10
NP
10
NP
10
NP
10
10
10
10
10
NP
NP
NP
NP
NP
byte/word
dword
eax, ebx, 10
Input from port
operands
al, imm8
ax, imm8
eax, imm8
al, dx
ax, dx
eax, dx
bytes
2
2
2
1
1
1
8088
14
14
12
12
-
186
10
10
8
8
-
286
5
5
5
5
-
386
12
12
12
13
13
13
486
14
14
14
14
14
14
Pentium
7
NP
7
NP
7
NP
7
NP
7
NP
7
NP
486
9/29/27
8/28/27
Pentium
4/21/19 NP
4/21/19 NP
Protected mode
operands
acc, imm
acc, dx
bytes
2
1
386
6/26/26
7/27/27
cycles for: CPL <= IOPL / CPL > IOPL / V86
Example:
INC
in
al, dx
Increment
operand
r8
r16
r32
mem
Example:
bytes
2
1
1
2+d(0,2)
8088
3
3
3
23+EA
inc
286
2
2
2
7
386
2
2
2
6
486
1
1
1
3
Pentium
1
UV
1
UV
1
UV
3
UV
486
17
17
17
Pentium
9
NP
9
NP
9
NP
ebx
INS/INSB/INSW/INSD
variations
insb
insw
insd
186
3
3
3
15
Input from port to string
bytes
1
1
1
8088
-
186
14
14
-
286
5
5
-
386
15
15
15
Protected Mode
bytes
1
386
486
Pentium
9/29/29 10/32/30 6/24/22 NP
cycles for: CPL <= IOPL / CPL > IOPL / V86
Example:
INT
rep insb
Call interrupt procedure
operands
3
imm8
bytes
1
2
8088
72
71
186
45
47
286
23+m
23+m
386
33
37
486
26
30
Pentium
13
NP
16
NP
Protected mode
Example:
INTO
bytes
1
8088
-
int
21h
186
-
286
386
(40-78)+m 59-99
Call interrupt procedure if overflow
486
44-71
Pentium
27-82 NP
bytes
1
8088
4/73
186
4/48
286
3/24+m
386
3/35
486
3/28
Pentium
4/13 NP
486
44-71
Pentium
27-56 NP
Protected mode
bytes
1
286
386
(40-78)+m 59-99
Task switch clocks not shown
Example:
INVD
into
Invalidate data cache (486+)
bytes
2
Example:
8088
-
186
-
286
-
386
-
486
4
Pentium
15
NP
INVLPG
486
12
Pentium
25
NP
486
15
Pentium
8-27 NP
486
15
Pentium
10-27 NP
486
1/3
1/3
Pentium
1
PV
1
PV
invd
Invalidate TLB entry (486+)
operands
mem32
bytes
5
Example:
IRET
invlpg
[eax]
Return from interrupt
bytes
1
8088
44
186
28
286
17+m
386
22
Task switch clocks not shown
Example:
IRETD
iret
32-bit return from interrupt (386+)
bytes
1
386
22
Task switch clocks not shown
Example:
Jcc
iretd
Jump on condition code
operand
near8
near16
bytes
2
3
8088
4/16
-
186
4/13
-
cycles for:
286
3/7+m
-
386
3/7+m
3/7+m
no jump/jump
conditional jump instructions:
ja
jae
jb
jbe
jg
jge
jl
jle
jump
jump
jump
jump
jump
jump
jump
jump
je
jne
jc
js
jnp
jo
jp
jnbe
jnb
jnae
jna
jnle
jnl
jnge
jng
jump
jump
jump
jump
jump
jump
jump
jump
jump if equal
jump if not equal
jz
jnz
jump if zero
jump if not zero
jump
jump
jump
jump
jump
jnc
jns
jpo
jno
jpe
jump
jump
jump
jump
jump
Example:
if
if
if
if
if
if
if
if
if
if
if
if
if
above
above or equal
below
below or equal
greater
greater or equal
less
less or equal
carry
sign
no parity (odd)
overflow
parity (even)
jne
JCXZ/JECXZ
operand
dest
dest
JMP
if
if
if
if
if
not
not
not
not
not
not
not
not
below or equal
below
above or equal
above
less or equal
less
greater or equal
greater
not carry
not sign
parity odd
not overflow
parity even
not_equal
Jump if CX/ECX = 0
bytes
2
2
8088
6/18
-
186
5/16
-
cycles for:
Example:
if
if
if
if
if
if
if
if
jcxz
cx_is_zero
Unconditional jump
286
4/8+m
no jump/jump
386
5/9+m
5/9+m
486
5/8
5/8
Pentium
5/6 NP
5/6 NP
operand
short
near
far
r16
mem16
mem32
bytes
2
3
5
2
2+d(0,2)
2+d(4)
r32
mem32
mem48
2
2+d(0,2)
2+d(6)
8088
15
15
15
11
18+EA
24+EA
186
13
13
13
11
17
26
286
7+m
7+m
11+m
7+m
11+m
15+m
386
7+m
7+m
12+m
7+m
10+m
12+m
486
3
3
17
5
5
13
-
-
7+m
10+m
12+m
5
5
13
-
Pentium
1
PV
1
PV
3
NP
2
NP
2
NP
4
NP
2
2
4
NP
NP
NP
cycles for jumps through call gates not shown
Example:
LAHF
jmp
target_address
Load flags into AH
bytes
1
Example:
8088
4
186
2
286
2
386
2
486
3
Pentium
2
NP
LAR
286
14
16
-
386
15
15
16
16
486
11
11
11
11
Pentium
8
NP
8
NP
8
NP
8
NP
286
7
386
7
486
6
Pentium
4
NP
286
7
386
7
486
6
Pentium
4
NP
386
7
486
6
Pentium
4
NP
386
7
486
6
Pentium
4
NP
386
7
486
6
Pentium
4
NP
386
2
2
486
1-2
1-2
Pentium
1
UV
1
UV
386
4
486
5
Pentium
3
NP
lahf
Load access rights byte (286+)
operands
r16, r16
r32, r32
r16, m16
r32, m32
Example:
bytes
3
3
3
3
LDS
lar
eax, ebx
Load far pointer
operands
reg, mem
Example:
bytes
2+d(2)
LES
lds
8088
24+EA
186
18
si, ptr_1
Load far pointer
operands
reg, mem
Example:
bytes
2+d(2)
LFS
les
8088
24+EA
186
18
di, ptr_2
Load far pointer (386+)
operands
reg, mem
Example:
bytes
3+d(2,4)
LGS
lfs
si, ptr_3
Load far pointer (386+)
operands
reg, mem
Example:
bytes
3+d(2,4)
LSS
lgs
si, ptr_4
Load stack segment and offset
operands
reg, mem
Example:
bytes
3+d(2,4)
LEA
lss
bp, ptr_5
Load effective address
operands
r16, mem
r32, mem
Example:
LEAVE
bytes
2+d(2)
2+d(2)
8088
2+EA
-
lea
eax, [eax+ebx*2+3]
286
3
-
High level procedure exit (186+)
bytes
1
Example:
LGDT
186
6
-
186
8
286
5
leave
Load global descriptor table register (286+)
operand
mem48
Example:
bytes
5
286
11
LIDT
lgdt
386
11
486
11
Pentium
6
NP
486
11
Pentium
6
NP
descriptor[ebx]
Load interrupt descriptor table register (286+)
operand
mem48
Example:
bytes
5
286
12
LLDT
lidt
386
11
descriptor[ebx]
Load local descriptor table register (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0-2)
LMSW
lldt
286
17
19
386
20
24
486
11
11
Pentium
9
NP
9
NP
286
3
6
386
10
13
486
13
13
Pentium
8
NP
8
NP
386
0
486
1
Pentium
1
NP
ax
Load machine status word (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0-2)
LOCK
lmsw
ax
Lock bus on next instruction (prefix)
bytes
1
8088
2
186
2
286
0
(Note: xchg always is locked whether it is specified or not)
Example:
lock
mov
LODS/LODSB/LODSW/LODSD
variations
lodsb
lodsw
lodsd
Example:
bytes
1
1
1
Load string operand
8088
16
16
-
186
10
10
-
286
5
5
-
386
5
5
5
486
5
5
5
Pentium
2
NP
2
NP
2
NP
286
4/8+m
386
11+m
486
6/7
Pentium
5/6 NP
386
11+m
486
6/9
Pentium
7/8 NP
386
11+m
486
6/9
Pentium
7/8 NP
386
486
Pentium
lodsb
LOOP
Loop control with CX counter
operand
short
loopw short
loopd short
Example:
operand
short
loopew
loopzw
looped
loopzd
bytes
2
8088
5/17
short
short
short
short
Example:
loop_start
Loop while equal (or zero)
bytes
2
(uses
(uses
(uses
(uses
8088
6/18
short
short
short
short
Example:
286
4/8
loop_start
Loop while not equal (or not zero)
operand bytes
short
2
loopnew
loopnzw
loopned
loopnzd
186
5/16
CX in 32-bit mode)
CX in 32-bit mode)
ECX in 16-bit mode)
ECX in 16-bit mode)
loope
LOOPNE/LOOPNZ
186
5/15
(uses CX in 32-bit mode)
(uses ECX in 16-bit mode)
loop
LOOPE/LOOPZ
LSL
mem, 1
(uses
(uses
(uses
(uses
8088
5/19
186
5/16
286
4/8
CX in 32-bit mode)
CX in 32-bit mode)
ECX in 16-bit mode)
ECX in 16-bit mode)
loopne
loop_start
Load segment limit (286+)
operands
bytes
286
r16,
r32,
r16,
r32,
r16
r32
m16
m32
Example:
3
3
3+d(0,2)
3+d(0,2)
LTR
lsl
14
16
-
20/25
20/25
21/26
21/26
10
10
10
10
8
8
8
8
NP
286
17
19
386
23
27
486
20
20
Pentium
10
NP
10
186
2
9
12
12-13
286
2
3
5
3
386
2
2
4
2
486
1
1
1
1
Pentium
1
UV
1
UV
1
UV
1
UV*
3-4
2
2
1
1
UV
8
9
5
3
4
2
1
1
1
1
UV
UV
eax, ebx
Load task register (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0,2)
MOV
ltr
ax
Move data
operands
reg, reg
mem, reg
reg, mem
mem, imm
reg, imm
bytes
2
2+d(0-2)
2+d(0-2)
2+d(0-2)
+i(1,2)
2+i(1,2)
acc, mem
mem, acc
3
3
8088
2
13+EA
12+EA
14+EA
4
14
14
* = not pairable if there is a displacement and immediate
Example:
mov
eax, ebx
Segment Register Moves
operands
seg, r16
seg, m16
r16, seg
m16, seg
Example:
bytes
8088
2
2
2+d(0,2) 12+EA
2
2
2+d(0,2) 13+EA
mov
Real Mode
186
286
2
2
9
5
2
2
11
3
386
2
5
2
2
486
3
3
3
3
Pentium
2-11
NP
3-12
NP
1
NP
1
NP
ds, ax
Protected Mode Differences
286
386
486
Pentium
17
18
9
2-11* NP
19
19
9
3-12* NP
* = add 8 if new descriptor; add 6 if SS
operands
seg, r16
seg, m16
bytes
2
2+d(0,2)
MOVE to/from special registers (386+)
operands
r32, cr32
cr32, r32
bytes
3
3
386
6
4/10*
486
4
4/16*
Pentium
4
NP
12/22* NP
2/12* NP
11/12* NP
r32, dr32
dr32, r32
3
3
14/22*
16/22*
10
11
r32, tr32
tr32, r32
3
3
12
12
3/4*
4/6*
-
NP
NP
* = cycles depend on which special register
Example:
mov
cr0, eax
MOVS/MOVSB/MOVSW/MOVSD
variations
movsb
movsw
movsd
rep movsb
rep movsw
rep movsd
bytes
1
1
1
2
2
2
Move data from string to string
8088
18
26
9+17n
9+25n
-
186
9
9
8+8n
8+8n
-
286
5
5
5+4n
5+4n
-
386
7
7
7
7+4n
7+4n
7+4n
486
7
7
7
12+3n*
12+3n*
12+3n*
Pentium
4
NP
4
NP
4
NP
3+n NP
3+n NP
3+n NP
486
3
3
Pentium
3
NP
3
NP
* = 5 if n=0, 13 if n=1
(n = count of bytes, words or dwords)
Example:
MOVSX
rep movsb
Move with sign-extend (386+)
operands
reg, reg
reg, mem
bytes
3
3+d(0,1,2,4)
386
3
6
(Note: destination reg is 16 or 32-bits; source is 8 or 16 bits)
Example:
MOVZX
movsx
ebx, ax
Move with zero-extend (386+)
operands
reg, reg
reg, mem
bytes
3
3+d(0,1,2,4)
386
3
6
486
3
3
Pentium
3
NP
3
NP
(Note: destination reg is 16 or 32-bits; source is 8 or 16 bits)
Example:
MUL
movzx
ebx, ax
Unsigned multiply
operand
bytes
8088
r8
2
70-77
r16
2
118-133
r32
2
mem8
2+d(0-2) 76-83+EA
mem16
2+d(0-2) 124-139+EA
mem32
2+d(0-2)
implied
operand
multiplicand (multiplier)
AL
* byte
=
AX
* word
=
EAX
* dword
=
Example:
NEG
mul
186
26-28
35-37
32-34
41-43
-
286
13
21
16
24
-
386
9-14
9-22
9-38
12-17
12-25
12-41
486
13-18
13-26
13-42
13-18
13-26
13-42
Pentium
11
NP
11
NP
10
NP
11
NP
11
NP
10
NP
186
3
13
286
2
7
386
2
6
486
1
3
Pentium
1
NP
3
NP
186
3
286
3
386
3
486
1
Pentium
1
UV
186
3
13
286
2
7
386
2
6
486
1
3
Pentium
1
NP
3
NP
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
Pentium
1
UV
3
UV
2
UV
1
UV
3
UV*
4
3
2
1
result
AX
DX:AX
EDX:EAX
ebx
Two's complement negation
operand
reg
mem
Example:
bytes
2
2+d(0-2)
NOP
neg
8088
3
24+EA
eax
No operation
bytes
1
Example:
8088
3
NOT
nop
One's complement negation
operands
reg
mem
Example:
bytes
2
2+d(0-2)
OR
not
8088
3
24+EA
eax
Logical inclusive or
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
4
1
UV
* = not pairable if there is a displacement and immediate
Example:
OUT
or
eax, ebx
Output to port
operands
imm8, al
imm8, ax
imm8, eax
dx, al
dx, ax
dx, eax
bytes
2
2
2
1
1
1
8088
14
14
12
12
-
186
9
9
7
7
-
286
3
3
3
3
-
386
10
10
10
11
11
11
486
16
16
16
16
16
16
Pentium
12
NP
12
NP
12
NP
12
NP
12
NP
12
NP
Protected Mode
operands
imm8, acc
dx, acc
bytes
2
1
386
486
Pentium
4/24/24 11/31/29 9/26/24 NP
5/25/25 10/30/29 9/26/24 NP
cycles for: CPL <= IOPL / CPL > IOPL / V86
Example:
out
dx, al
OUTS/OUTSB/OUTSW/OUTSD
variations
outsb
outsw
outsd
Output string to port
bytes
1
1
1
186
14
14
-
286
5
5
-
386
14
14
14
486
17
17
17
Pentium
13
NP
13
NP
13
NP
Protected Mode
bytes
1
386
486
Pentium
8/28/28 10/32/30 10/27/25 NP
cycles for: CPL <= IOPL / CPL > IOPL / V86
Example:
POP
rep outsw
Pop a word/dword from the stack
operand
reg
mem
seg
FS/GS
bytes
1
2+d(0-2)
1
2
8088
12
25+EA
12
-
186
10
20
8
-
286
5
5
5
-
386
4
5
7
7
486
1
6
3
3
Pentium
1
UV
3
NP
3
NP
3
NP
386
21
21
21
486
9
9
9
Pentium
3-12 NP
8-17 NP
3-12 NP
486
9
9
Pentium
5
NP
5
NP
386
5
5
486
9
9
Pentium
6
NP
6
NP
286
5
-
386
5
5
486
6
6
Pentium
4
NP
4
NP
286
3
5
3
3
-
386
2
5
2
2
2
486
1
4
3
1
3
Pentium
1
UV
2
NP
1
NP
1
NP
1
NP
486
11
11
Pentium
5
NP
5
NP
486
4
Pentium
9
NP
Protected Mode
operand
CS/DS/ES
SS
FS/GS
bytes
1
1
2
Example:
pop
POPA/POPAD
286
20
20
eax
Pop all (186+)/Pop all double (386+)
variations
popa
popad
bytes
1
1
186
51
-
286
19
-
386
24
24
popa = pop di, si, bp, sp, bx, dx, cx, ax
popad = pop edi, esi, ebp, esp, ebx, edx, ecx, eax
(sp and esp are discarded)
Example:
POPF/POPFD
popa
Pop flags/Pop flags double (386+)
variations
popf
popfd
bytes
1
1
8088
12
-
186
8
-
286
5
-
Protected Mode
popf
popfd
Example:
PUSH
bytes
1
1
popf
push a word/dword to the stack
operand
bytes
reg
1
mem
2+d(0-2)
seg
1
imm
1+i(1,2)
FS/GS
2
Example:
push
8088
15
24+EA
14
-
186
10
16
9
-
eax
PUSHA/PUSHAD
Push all (186+)/Push all double (386+)
variations bytes
186
286
386
pusha
1
36
17
18
pushad
1
18
pusha = push ax, cx, dx, bx, sp, bp, si, di,
pushad = push eax, ecx, edx, ebx, esp, ebp, esi, edi
Example:
PUSHF/PUSHFD
variations
pushf
pusha
Push flags/Push flags double (386+)
bytes
1
8088
14
186
9
286
3
386
4
pushfd
1
-
-
-
4
4
9
NP
286
3
-
386
4
4
486
3
3
Pentium
3
NP
3
NP
286
2
7
5+n
8+n
5+n
8+n
386
9
10
9
10
9
10
486
3
4
8-30
9-31
8-30
9-31
Pentium
1
PU
3
PU
7-24 NP
9-26 NP
8-25 NP
10-27 NP
286
2
7
5+n
8+n
5+n
8+n
386
9
10
9
10
9
10
486
3
4
8-30
9-31
8-30
9-31
Pentium
1
PU
3
PU
7-24 NP
9-26 NP
8-25 NP
10-27 NP
286
2
7
5+n
8+n
5+n
8+n
386
3
7
3
7
3
7
486
3
4
3
4
2
4
Protected Mode
pushf
pushfd
Example:
bytes
1
1
RCL
pushf
Rotate bits left with CF
operands
reg, 1
mem, 1
reg, cl
mem, cl
reg, imm
mem, imm
Example:
bytes
8088
186
2
2
2
2+d(0,2) 23+EA
15
2
8+4n
5+n
2+d(0,2) 28+EA+4n 17+n
3
5+n
3+d(0,2)
17+n
RCR
rcl
eax, 16
Rotate bits right with CF
operands
reg, 1
mem, 1
reg, cl
mem, cl
reg, imm
mem, imm
Example:
bytes
8088
186
2
2
2
2+d(0,2) 23+EA
15
2
8+4n
5+n
2+d(0,2) 28+EA+4n 17+n
3
5+n
3+d(0,2)
17+n
ROL
rcr
eax, 16
Rotate bits left
operands
reg, 1
mem, 1
reg, cl
mem, cl
reg, imm
mem, imm
bytes
8088
186
2
2
2
2+d(0,2) 23+EA
15
2
8+4n
5+n
2+d(0,2) 28+EA+4n 17+n
3
5+n
3+d(0,2)
17+n
Pentium
1
PU
3
PU
4
NP
4
NP
1
PU
3
PU*
* = not pairable if there is a displacement and immediate
Example:
ROR
rol
eax, 16
Rotate bits right
operands
reg, 1
mem, 1
reg, cl
mem, cl
reg, imm
mem, imm
bytes
8088
186
2
2
2
2+d(0,2) 23+EA
15
2
8+4n
5+n
2+d(0,2) 28+EA+4n 17+n
3
5+n
3+d(0,2)
17+n
286
2
7
5+n
8+n
5+n
8+n
386
3
7
3
7
3
7
486
3
4
3
4
2
4
Pentium
1
PU
3
PU
4
NP
4
NP
1
PU
3
PU*
* = not pairable if there is a displacement and immediate
Example:
RDMSR
ror
eax, 16
Read from model specific register (Pentium+)
bytes
2
Example:
REP
See:
See:
REPE
See:
See:
REPNE
See:
See:
Pentium
20-24 NP
rdmsr
Repeat string operation
MOVS (rep movs)
STOS (rep stos)
move block
fill block
Repeat while equal (or zero) string operation
CMPS (repe cmps)
CMPS (repe scas)
find non-matching memory items
find non-acc matching byte in memory
Repeat while not equal (or not zero) string operation
CMPS (repne cmps)
SCAS (repne scas)
RET/RETN/RETF
find first matching memory items
find first matching memory item to acc
Return from procedure
variations/
operands
retn
retn imm16
retf
retf imm16
bytes
1
1+d(2)
1
1+d(2)
8088
20
24
34
33
186
16
18
22
25
286
11+m
11+m
15+m
15+m
386
10+m
10+m
18+m
18+m
486
5
5
13
14
Pentium
2
NP
3
NP
4
NP
4
NP
RET is coded by the assembler as near or far based on the
procedure declaration and program model, as:
RETN (return near)
RETF (return far)
Example:
ret
Protected Mode
variations/
operands
bytes
retf
1
retf imm16 1+d(2)
286
25+m/55
25+m/55
386
486
32+m/62 18/33
32+m/68 17/33
Pentium
4-13/23 NP
4-13/23 NP
cycles for: same privilege level/lower privilege level
RSM
Resume from system management mode (Pentium+)
bytes
2
Example:
Pentium
83
NP
rsm
SAL/SHL/SAR/SHR
operands
reg, 1
mem, 1
reg, cl
mem, cl
reg, imm
mem, imm
Shift bits
bytes
8088
186
2
2
2
2+d(0,2) 23+EA
15
2
8+4n
5+n
2+d(0,2) 28+EA+4n 17+n
3
5+n
3+d(0,2)
17+n
286
2
7
5+n
8+n
5+n
8+n
386
3
7
3
7
3
7
486
3
4
3
4
2
4
Pentium
1
PU
3
PU
4
NP
4
NP
1
PU
3
PU*
* = not pairable if there is a displacement and immediate
sal = shift arithmetic left
shl = shift left (same as sal)
Example:
SAHF
shl
sar =
shr =
shift arithmetic right
shift right
eax, 1
Store AH into flags
bytes
1
Example:
8088
4
186
3
286
2
386
3
486
2
Pentium
2
NP
SBB
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
Pentium
1
PU
3
PU
2
PU
1
PU
3
PU*
4
3
2
1
sahf
Integer subtraction with borrow
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
4
1
PU
* = not pairable if there is a displacement and immediate
Example:
sbb
eax, ebx
SCAS/SCASB/SCASW/SCASD
variations
scasb
scasw
scasd
repX scasb
repX scasw
repX scasd
bytes
1
1
1
2
2
2
Scan string data
8088
19
19
9+15n
9+19n
-
186
15
15
5+15n
5+15n
-
286
7
7
5+8n
5+8n
-
386
7
7
7
5+8n
5+8n
5+8n
486
6
6
6
7+5n*
7+5n*
7+5n*
repX = repe or repz or repne or repnz
* = 5 if n=0
(n = count of bytes, words or dwords)
Example:
repne
scasb
Pentium
4
NP
4
NP
4
NP
8+4n NP
8+4n NP
8+4n NP
SET
Set byte to 1 on condition else set to 0 (386+)
operand
r8
mem8
bytes
3
3+d(0-2)
386
4
5
Cycles are for:
486
4/3
3/4
Pentium
1/2 NP
1/2 NP
486
10
Pentium
4
NP
true/false
setCC = one of:
seta
setg
setnb
setnl
seto
setae
setge
setnbe
setnle
setp
Example:
setb
setl
setnc
setno
setpe
SGDT
setne
setc
setna
setng
setns
sets
sete
setnae
setnge
setnz
setz
al
Store global descriptor table register (286+)
operand
mem48
Example:
bytes
5
286
11
sgdt
SIDT
386
9
descriptor[ebx]
Store interrupt descriptor table register (286+)
operand
mem48
Example:
bytes
5
286
12
sidt
SHLD
386
9
486
10
Pentium
4
NP
386
3
7
3
7
486
2
3
3
4
Pentium
4
NP
4
NP
4
NP
5
NP
386
3
7
3
7
486
2
3
3
4
Pentium
4
NP
4
NP
4
NP
5
NP
386
2
2
486
2
3
Pentium
2
NP
2
NP
286
2
3
386
2
3
486
2
3
Pentium
4
NP
4
NP
286
2
386
2
486
2
Pentium
2
NP
descriptor[ebx]
Double precision shift left (386+)
operands
reg, reg,
mem, reg,
reg, reg,
mem, reg,
Example:
bytes
4
4+d(0-2)
4
4+d(0-2)
imm
imm
cl
cl
shld
SHRD
eax, ebx, 16
Double precision shift right (386+)
operands
reg, reg,
mem, reg,
reg, reg,
mem, reg,
Example:
bytes
4
4+d(0-2)
4
4+d(0-2)
imm
imm
cl
cl
shrd
SLDT
eax, ebx, 16
Store local descriptor table register (286+)
operands
r16
mem16
Example:
bytes
3
3+d(0-2)
sldt
SMSW
286
2
3
ax
Store machine status word (286+)
operands
r16
mem16
Example:
bytes
3
3+d(0-2)
smsw
STC
ax
Set the carry flag
bytes
1
Example:
8088
2
186
2
stc
STD
Set direction flag (set to reverse string direction)
bytes
1
Example:
STI
setbe
setle
setne
setnp
setpo
8088
2
186
2
286
2
386
2
486
2
Pentium
2
NP
286
386
486
Pentium
std
Set interrupt flag (enable)
bytes
8088
186
1
Example:
2
2
2
3
5
7
NP
sti
STOS/STOSB/STOSW/STOSD
variations
stosb
stosw
stosd
rep stosb
rep stosw
rep stosd
bytes
1
1
1
2
2
2
Store string data
8088
11
15
9+10n
9+14n
-
186
10
10
6+9n
6+9n
-
286
3
3
4+3n
4+3n
-
386
4
4
4
5+5n
5+5n
5+5n
486
5
5
5
7+4n*
7+4n*
7+4n*
Pentium
3
NP
3
NP
3
NP
3+n NP
3+n NP
3+n NP
* = 5 if n=0, 13 if n=1
(n = count of bytes, words or dwords)
Example:
STR
rep
stosd
Store task register (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0-2)
SUB
str
286
2
3
386
2
2
486
2
3
Pentium
2
NP
2
NP
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
Pentium
1
UV
3
UV
2
UV
1
UV
3
UV*
4
3
2
1
bx
Integer subtraction
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
4
1
UV
* = not pairable if there is a displacement and immediate
Example:
TEST
sub
eax, ebx
Logical compare
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
acc, imm 1+i(1,2)
8088
3
13+EA
13+EA
5
11+EA
286
2
6
6
3
6
386
2
5
5
2
5
486
1
2
2
1
2
4
3
2
1
4
186
3
10
10
4
10
Pentium
1
UV
2
UV
2
UV
1
UV
2
UV*
1
UV
* = not pairable if there is a displacement and immediate
Example:
VERR
sub
eax, ebx
Verify a segment for reading (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0,2)
VERW
verr
286
14
16
386
10
11
486
11
11
Pentium
7
NP
7
NP
286
14
16
386
15
16
486
11
11
Pentium
7
NP
7
NP
286
3
386
6
486
1-3
Pentium
1
NP
486
5
Pentium
2000+ NP
ax
Verify a segment for writing (286+)
operand
r16
mem16
Example:
bytes
3
3+d(0,2)
WAIT
verr
ax
Wait for co-processor
bytes
1
Example:
8088
4
186
6
WBINVD
wait
Write-back and invalidate data cache (486+)
bytes
2
Example:
wbinvd
WRMSR
Write to model specific register (PENTIUM+)
bytes
2
Example:
Pentium
30-45 NP
XADD
wrmsr
Exchange and add (486+)
operands
reg, reg
mem, reg
bytes
3
3+d(0-2)
Example:
XCHG
xadd
486
3
4
Pentium
3
NP
4
NP
Pentium
3
NP
3
NP
3
NP
eax, ebx
Exchange register/memory with register
operands
reg, reg
reg, mem
mem, reg
bytes
8088
2
4
2+d(0-2) 25+EA
2+d(0-2) 25+EA
acc, reg
reg, acc
1
1
286
3
5
5
386
3
5
5
486
3
5
5
3
3
3
3
3
3
3
3
186
11
286
5
386
5
486
4
Pentium
4
NP
186
3
10
10
4
16
286
2
7
7
3
7
386
2
7
6
2
7
486
1
3
2
1
3
Pentium
1
UV
3
UV
2
UV
1
UV
3
UV*
4
3
2
1
3
3
186
4
17
17
2
2
NP
NP
in above: acc = AX or EAX only
Example:
xchg
XLAT/XLATB
ax, dx
Table look-up translation
bytes
1
Example:
8088
11
XOR
xlat
Logical exclusive or
operands
reg, reg
mem, reg
reg, mem
reg, imm
mem, imm
acc, imm
bytes
2
2+d(0,2)
2+d(0,2)
2+i(1,2)
2+d(0,2)
+i(1,2)
1+i(1,2)
8088
3
24+EA
13+EA
4
23+EA
4
1
UV
* = not pairable if there is a displacement and immediate
Example:
xor
eax, ebx
x86 Glossary of Terms
Address:
Location of a data item in memory. Also see Linear address, Physical address.
AGI:
Address Generation Interlock. On the 486 and Pentium processors the pipeline is stalled for
one cycle if a component of an address is loaded or calculated in the previous machine cycle.
Arithmetic Logic Unit:
The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR
and CMP.
Alignment:
The placement of data or code on a specific address boundary (i.e. a 2, 4, or 8 byte evenly
divisible address).
ALU:
See Arithmetic Logic Unit.
Arithmetic Logic Unit:
The portion of the CPU that performs the integer operations such as ADD, SUB, AND, OR
and CMP.
ASCII:
American Standard Code for Information Interchange. A standard code for representing
English characters and symbols with various extensions for foreign characters.
Assembler:
A program that translates an assembly language program to machine language (or object
code).
Assembly Language:
A programming language, based on the architecture of a particular machine, where most
statements translate into one machine instruction.
Base address:
The address at the start of a structure or of data array.
Base register:
A register that contains a base address. Usually BX (EBX) or BP (EBP) is a base register. For
16-bit code the base register must be BX or BP, for 32-bit code any of EAX, EBX, ECX,
EDX, ESI, EDI, EBP or ESP.
Base:
Also See base address. In number systems, used to specify the number of digits in a system,
i.e. base 10 has ten digits, base 2 has two, etc.
BCD:
Binary Coded Decimal. See also Packed BCD. This is a format for encoding base 10 numbers
where the low order 4 bits are used to store the numercial value.
Big-endian:
A method of storing multi-byte data types where the low-order byte is stored at the highest
address and the high-order byte is stored at the lower address.
BIOS:
Basic Input/Output System. Built-in software (usually stored in ROM) that is used to start up
the computer and controls low-level functionality of devices such as the keyboard, screen,
disks and I/O ports.
Bit:
A binary digit. Can be a zero or a one.
Byte:
A data type consisting of 8 bits.
Cache:
A small fast memory buffer that holds a copy of the most recently used or most active portions
of the larger slower memory. Also see Disk Cache.
Central Processor Unit:
The main processing unit in a computer. Sometimes referred to as the processor, the chip or
the computer.
Character String:
A data type that is an array of characters. Usually followed by a byte of 0 in assembly
language or C.
Character:
A data type that is the same as a byte.
Checksum:
A simple error detection scheme where values are added (summed) into a variable to be
compared with a similar previously calculated value.
Chip:
A small piece of semiconducting material on which an electronic circuit is placed. A CPU
chip is also known as a microprocessor.
CISC:
See Complex Instruction Set Computer.
Clock Speed:
The speed that a processor executes instructions.
Code Segment:
The addressable area of memory defined by the segment in the CS register.
Compiler:
A program that translates a high level language (such as C, Pascal or Fortran) into machine
language or sometimes into assembly language.
Processors designed with many complex and sometimes irregular instructions, especially
Complex Instruction Set Computer: instructions that access memory operands and operate on them. The 80x86 architecture is
considered CISC. See RISC.
CP/M:
Control Program for Microcomputers. An operating system originally designed for 8080 and
Z-80 based computers.
CPU:
See Central Processor Unit.
CRC:
Cyclic redundancy check. A complex error detection scheme, similar to a checksum, but each
value is operated on in a position-dependent manner. This increases the reliability of the error
detection.
Cycles:
Periodic pulses created by an electronic clock that causes CPU activity.
Data Segment:
The addressable area of memory defined by the segment in the DS register.
Data Structure:
A scheme for organizing related data items.
Debugger:
A program that allows executing, monitoring and modifying a program's code and data to
enable a programmer to locate program errors (or bugs).
Directive:
An assembler statement that contains information for the use of the assembler rather than an
instruction to be assembled and executed as part of the program.
Disassembler:
A program that attempts the difficult task of reconstructing an assembly language source file
from machine language.
Disk Cache:
A program and/or areas of memory set aside keep frequently used or most recently used data
from a disk for quicker access.
Displacement:
The constant part of an effective address (EA).
DOS:
Disk Operating System. Also called MS-DOS or PC-DOS.
DRAM:
Dynamic RAM. The type of memory chip used in most computers. It is called dynamic
because it must continually be refreshed or the contents will be lost.
Dword:
A data type consisting of a double word or 32-bits.
EA:
See Effective Address
Editor:
A program that allows the user to create and edit files.
Effective Address:
The combination of any or all of a base register, index register and displacement used to
produce an offset within a segment.
Emulator:
A program that attempts to emulate, or work the same as, another program or machine.
Endian:
See Little-endian and Big-endian.
Exception:
A forced call to an interrupt routine that handles error conditions.
External Cache:
A memory cache not physically located on the same chip as the CPU.
Extra Segment:
The addressable area of memory defined by the segment in the ES register.
Far Pointer:
A reference to memory consisting of a segment and an offset. In real mode the segment is the
upper 16 bits of a 20-bit segment starting address. In protected mode the segment is a selector.
Fault:
An exception that is called with the return address on the stack of the instruction that caused
the fault.
File:
An organized collection of data or information, usually stored on a disk with a specific name
or filename.
Flat Model:
A program model where all segment registers are the same and are usually set to be larger
than 64K segments.
Floating Point Unit:
The portion of the 80486 or Pentium that performs the floating point operations like the
floating point processor.
FPP:
See Floating Point Processor.
Floating Point Processor:
A floating point math processor. The processing unit that performs IEEE 754 floating point
arithmetic on 32-bit, 64-bit and 80-bit signed numbers with exponents.
FPU:
See Floating Point Unit.
Hertz:
A frequency of one cycle per second.
HLL:
High Level Language. Such as C, Basic, Pascal and Fortran.
Hz:
Abbreviation for Hertz.
IEEE:
Institute of Electrical and Electronic Engineers. An organization best known for developing
electrical and electronic standards for the computer industry.
Index register:
A register that contains an index value. Usually SI (ESI) or DI (EDI) is an index register. For
16-bit code the index register must be SI or DI, for 32-bit code any of EAX, EBX, ECX,
EDX, ESI, EDI or EBP.
Integer:
A positive whole number, negative whole number or zero. On computers integers have a
limited range, for example byte integers have a range of -128 to +127.
Interpreter:
A program that executes another program by reading each program statement and interpreting
the actions to be taken.
Interrupt Handler:
A routine specifically designed to respond to an interrupt.
Interrupt Vector Table:
An array of 256 far pointers to interrupt handlers. Located at address 0000:0000.
I/O:
Input/Output.
IVT:
See Interrupt Vector Table
Label:
An identifier used in assembly language programs to specify a memory address by name
rather than by its actual numerical address.
LDT:
See Local Descriptor Table.
Library:
A collection of programs or subroutines stored in object file format, usually in a .LIB file.
Linear Address:
A 20-, 24-, or 32-bit address into a large unsegmented memory space. With paging (virtual
memory) disabled the linear address is the physical address. With paging enabled the paging
mechanism translates the linear address to a physical address.
Link:
The complex process of combining object files and hooking, or linking together, subroutines
or data in one file that are referenced in another file.
Linker:
A program that links one or more object files into an executable program file, usually a .EXE
file.
Little-endian:
A method of storing multi-byte data types where the low-order byte is stored at the lowest
address and the high-order byte is stored at the highest address. The Intel 80x86 processor use
this format.
Logical Address:
A segment and offset combine to generate a logical address. The segmentation unit translates
the logical address into a linear address.
Long Integer:
See integer. An integer data format consisting of 32-bits.
Machine Language:
The binary codes that a machine (CPU) can execute.
Mask:
A bit pattern constructed to be logically combined with a data value to allow only some bits of
the original data value to show through (i.e. the others are masked out).
Math Coprocessor:
A floating point math processor. Termed a "co-processor" when added as an optional separate
chip.
MegaHertz:
A million hertz; A million cycles per second.
Mhz:
MegaHertz.
Microprocessor:
A computer processor fully contained on one integrated circuit (or chip).
Module:
Part of a program, usually one file, containing one or more procedures or subroutines and/or
data values.
MS-DOS:
Microsoft DOS (Disk Operating System).
Near Pointer:
A reference to memory containing only the offset portion of the address. The offset must be
combined with a segment or selector in one of the segment registers.
Nibble:
4 bits. There are two nibbles in a byte. (Also nybble)
NPX:
Numerical Processor Extension. Original name for the 8087 floating point co-processor.
Numeric Coprocessor:
A floating point math processor.
Object code:
An intermediate form of machine language produced by assemblers and compilers that is
structured so that it can be linked together.
Offset:
A 16-bit number that specifies the byte number beyond the start of a segment. On the 80386
and above segments may have 32-bit offsets.
Operand:
Data provided in a register, in memory or immediately with an instruction to be used in the
processing of the instruction.
Operating System:
The program(s) that load applications and control access to memory, disk files, I/O ports, etc.,
such as DOS, Windows, OS/2 and UNIX.
OS:
See Operating System.
Packed BCD:
Packed Binary Coded Decimal. A data format that stores one decimal digit in each nibble of a
byte.
Page:
A 4K-byte block of memory. This is the size of memory block used for paging.
Paging:
A method of managing memory, by an operating system, to implement a virtual memory
system. Pages of memory are stored on a disk when not in use and recalled later when needed.
Pairing:
The process of issuing two instructions at the same time to each of the U and V pipelines of
the Pentium.
Paragraph:
16 bytes of memory.
Parity:
An error detection system commonly used in data communications where the sum of the set
bits in a data packet is odd or even.
PC-DOS:
Personal Computer DOS. IBM's version of MS-DOS.
Physical Address:
The actual hardware address of memory issued by the processor. The maximum physical
address is determined by the number of address pins on the processor.
Port:
A channel, or connection, for data to enter or leave the CPU.
Prefix:
One of several machine language codes that can be placed in front of other instructions to
modify their actions or default conditions.
Processor:
Short for microprocessor. The part of the computer that actually performs the arithmetic,
logical and control functions of a computer.
Protected Mode:
A CPU mode where memory address ranges are protected from being read and/or written to
by unauthorized segments of code.
Pseudo-op:
Another term for assembler directives.
Quadword:
A data type consisting of 8 bytes or 64-bits.
RAM:
Random Access Memory. The read/write memory used by the computer, usually consisting of
DRAM chips.
Re-entrant:
A quality of a procedure or program that allows it to be interrupted and called or run again and
both logical instances remain intact and properly execute independently of each other.
Real Mode:
The only CPU mode of the 8088 and 8086 and the startup mode for the 80286 and above.
There is no memory protection as in the protected mode.
Register:
A storage area in a CPU. Each register usually has a number of operations that can be directly
performed on it by the CPU, unlike a memory storage location.
Reduced Instruction Set Computer:
Processors designed with the general concepts of a load/store architecture, few addressing
modes, many registers, fixed length instructions and the "simple is faster" design criteria.
Segment Override:
A prefix for an instruction that causes a segment register, other than the normal default
segment register to be used during the execution of the following instruction.
Segment:
Real mode: A portion of memory specified by a 20-bit starting address of which the low 4 bits
are always zero and whose length can be up to 64K. Protected mode: A portion of memory
described by a descriptor table entry.
Selector:
In protected mode, a pointer to a segment descriptor. A selector is a 16-bit value and is used in
protected mode instead of a paragraph address in a segment register.
SRAM:
Static RAM. Faster and more stable than DRAM, but requires more power and is more
expensive. Usually used in memory caches.
Stack Segment:
A portion of memory pointed to by the stack segment register for use as the system stack.
Stack:
A last-in first-out data data structure in memory used for saving return addresses, temporary
variables and system status information. A system can have any number of stacks, but only
one may be in use at any time
String:
Any consectutive bytes of memory can be a string. HLL's specify rules for defining strings. In
the C language strings must end with a byte containing a value of zero.
Superscalar:
A CPU that can complete more than one instruction per machine cycle.
Task:
One of many programs currently executing or waiting to execute in a multi-tasking system.
Two's Complement:
A mathematical operation where a binary value is multiplied by -1. Each bit is changed to the
opposite value and then one is added to the entire value.
Unsigned Integer:
A positive whole number or zero. On computers unsigned integers have a limited ranged, for
example an 8-bit unsigned integer has a range of 0 to 255.
V86 Mode:
See Virtual-8086 Mode.
Virtual Memory:
A scheme used that allows programs to logically allocate and use more memory than is
physically available by moving and swapping portions that are not currently needed or
infrequently used to a hard disk.
Virtual-8086 Mode:
A mode on 386 and above processors that provides for the emulation of the 8086 architecture.
An operating system may run a mix of protected mode tasks amd virtual-8086 mode tasks.
Word:
A data type consisting of two bytes or 16 bits. (On non-x86 architectures a word usually refers
to a data element the size of the accumulator and registers, typically 32 bits.
Console - Applikation
Eine Console - Applikation hat eine main() - Funktion. Es kann in C/C++ programmiert werden. Die Standard - Klassen Bibliotheken sind verfügbar. Es können die folgenden Console-Funktionen und Console-Strukturen benutzt werden:
Console-Funktionen
AllocConsole
FreeConsole
GenerateConsoleCtrlEvent
GetConsoleScreenBufferInfo
GetConsoleTitle
HandlerRoutine
PeekConsoleInput
ReadConsoleOutputCharacter
ScrollConsoleScreenBuffer
SetConsoleCursorPosition
SetConsoleMode
WriteConsoleInput
WriteConsoleOutput
CreateConsoleScreenBuffer
FillConsoleOutputAttribute
FillConsoleOutputCharacter FlushConsoleInputBuffer
GetConsoleCP
GetConsoleCursorInfo
GetConsoleMode
GetLargestConsoleWindowSize
GetNumberOfConsoleInputEvents GetNumberOfConsoleMouseButtons GetStdHandle
ReadConsole
ReadConsoleInput
GetConsoleOutputCP
ReadConsoleOutput
ReadConsoleOutputAttribute
SetConsoleActiveScreenBuffer SetConsoleCP
SetConsoleCtrlHandler
SetConsoleCursorInfo
See
SetConsoleWindowInfo
SetStdHandle
WriteConsole
WriteConsoleOutputAttribute
WriteConsoleOutputCharacter
Console-Strukturen
CHAR_INFO
COORD
KEY_EVENT_RECORD
SMALL_RECT
CONSOLE_CURSOR_INFO
FOCUS_EVENT_RECORD
MENU_EVENT_RECORD
WINDOW_BUFFER_SIZE_RECORD
CONSOLE_SCREEN_BUFFER_INFO
INPUT_RECORD
MOUSE_EVENT_RECORD
WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben
#define
#define
#define
#define
#define
#define
#define
#define
FOREGROUND_BLUE
FOREGROUND_GREEN
FOREGROUND_RED
FOREGROUND_INTENSITY
BACKGROUND_BLUE
BACKGROUND_GREEN
BACKGROUND_RED
BACKGROUND_INTENSITY
0x0001
0x0002
0x0004
0x0008
0x0010
0x0020
0x0040
0x0080
//
//
//
//
//
//
//
//
text color
text color
text color
text color
background
background
background
background
contains blue
contains green
contains read
is intensified
color contains blue
color contains green
color contains red
color is intensified
Gelbe Textschrift auf blauem Hintergrund wird z.B. durch
( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE )
in FillConsoleOutputAttribute() eingestellt.
Eine Console-Applikation hat als Startpunkt die main()-Funktion: int main() { ... return 0; }. Es kann in C/C++
programmiert werden. Die Standard-Klassen-Bibliotheken sind verfügbar.
Beispiel
// in2bat.c
// bricht Eingabezeilen bei sep_char = '&'; um
// ( z.B. nützlich für NMAKE.EXE nach BAT )
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
char in_buf [ MAXLINE ]; // = {0};
char sep_char = '&';
int main(int argc, char **argv) {
if ( argc != 1 || argv[1] ) {// Hilfetext
printf("Usage: in2bat.exe < getippte_Eingabe > output_file_Name\n"
"Für Eingabe von Hand braucht das Programm keine Argumente\n" );
return 1;
} printf ( "@echo off\n" ) ;
//hole und bearbeite jede Eingabe-Zeile
while ( fgets(in_buf, sizeof( in_buf ), stdin ) ) {
char * pNext, * pStart = in_buf ;
char * pFinish = pStart + strlen( pStart ) ;
//printf ( "\n--- %s", pStart ) ;
// Entferne newline char
if ( ( pFinish
> pStart)
&& ( pFinish[-1] == '\n' ) ) pFinish[-1] = '\0' ;
do {
// skip blanks und tabs ( whitespaces )
while ( * pStart == ' ' || * pStart == '\t' ) ++ pStart ;
// finde das nächsten command separator sep_char='&' oder end of line
pNext = strchr(pStart, sep_char) ;
if (! pNext) pNext = pStart + strlen(pStart) ;
pFinish = pNext ; if (pStart == pNext) break ;
// skip führende whitespace
while ( ( pFinish > pStart )
&& ( pFinish [ -1 ] == ' '
||
pFinish [ -1 ] == '\t' ) ) -- pFinish ;
// Kopiere nach stdout
while ( pStart < pFinish ) putchar(*pStart++) ;
putchar ( '\n' ) ; pStart = pNext ;
} while ( *pStart++ ) ;
} return 0 ;
}
Eine Windows-Console-Applikation kann zusätlich zu den Standard-Klassen die folgenden Console-Funktionen verwenden:
AllocConsole
FillConsoleOutputAttribute
FillConsoleOutputCharacter
GenerateConsoleCtrlEvent
GetConsoleMode
GetConsoleScreenBufferInfo
GetConsoleTitle
GetNumberOfConsoleInputEvents
GetNumberOfConsoleMouseButtons
PeekConsoleInput
ReadConsoleOutput
ReadConsoleOutputCharacter
ScrollConsoleScreenBuffer
SetConsoleCtrlHandler
SetConsoleCursorPosition
SetConsoleMode
SetStdHandle
WriteConsoleOutput
WriteConsoleOutputCharacter
CreateConsoleScreenBuffer
FlushConsoleInputBuffer
GetConsoleCP
GetConsoleOutputCP
FreeConsole
GetConsoleCursorInfo
GetLargestConsoleWindowSize
GetStdHandle
ReadConsole
ReadConsoleOutputAttribute
HandlerRoutine
ReadConsoleInput
SetConsoleActiveScreenBuffer
SetConsoleCursorInfo
SetConsoleCP
See
SetConsoleWindowInfo
WriteConsole
WriteConsoleInput
WriteConsoleOutputAttribute
Diese Funktionen verwenden die Console - Strukturen:
CHAR_INFO
COORD
KEY_EVENT_RECORD
SMALL_RECT
CONSOLE_CURSOR_INFO
FOCUS_EVENT_RECORD
MENU_EVENT_RECORD
WINDOW_BUFFER_SIZE_RECORD
CONSOLE_SCREEN_BUFFER_INFO
INPUT_RECORD
MOUSE_EVENT_RECORD
Für den Text - Bildschirm sind in WINCON.H die folgenden Attribute - Flags für die Bildschirm - Farben definiert:
#define
#define
#define
#define
#define
#define
#define
FOREGROUND_BLUE
FOREGROUND_GREEN
FOREGROUND_RED
FOREGROUND_INTENSITY
BACKGROUND_BLUE
BACKGROUND_GREEN
BACKGROUND_RED
0x0001
0x0002
0x0004
0x0008
0x0010
0x0020
0x0040
//
//
//
//
//
//
//
text color
text color
text color
text color
background
background
background
contains blue
contains green
contains read
is intensified
color contains blue
color contains green
color contains red
#define BACKGROUND_INTENSITY 0x0080 // background color is intensified
Gelbe Text - Schrift auf blauem Hintergrund wird z.B. durch ( FOREGROUND_INTENSITY | FOREGROUND_GREEN |
FOREGROUND_RED | BACKGROUND_BLUE ) in FillConsoleOutputAttribute() eingestellt.
Beispiel
... einige windows-typedef's ...
typedef struct _CHAR_INFO {
union {
WCHAR UnicodeChar;
CHAR
AsciiChar;
} Char;
WORD Attributes;
} CHAR_INFO;
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD;
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
} CONSOLE_SCREEN_BUFFER_INFO;
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL
bVisible;
} CONSOLE_CURSOR_INFO;
typedef struct _INPUT_RECORD {
WORD EventType;
union {
KEY_EVENT_RECORD KeyEvent;
MOUSE_EVENT_RECORD MouseEvent;
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
MENU_EVENT_RECORD MenuEvent;
FOCUS_EVENT_RECORD FocusEvent;
} Event;
} INPUT_RECORD;
typedef struct _SMALL_RECT {
SHORT Left;
SHORT Top;
SHORT Right;
SHORT Bottom;
} SMALL_RECT;
typedef struct _KEY_EVENT_RECORD {
BOOL bKeyDown;
WORD wRepeatCount;
WORD wVirtualKeyCode;
WORD wVirtualScanCode;
union {
WCHAR UnicodeChar;
CHAR
AsciiChar;
} uChar;
DWORD dwControlKeyState;
} KEY_EVENT_RECORD;
Verwendung der typdefs's in einem Console-TEST-Programm
////////////////////////////////////////////////////////////////
#define UNICODE
// Unicode fuer Win32-Headerfiles einschalten
#define _UNICODE // Die C-Header brauchen eine separate Einladung
#define STRICT
// Striktere Typ-Pruefungen einschalten
#define WIN32_LEAN_AND_MEAN // Nur wichtige Headerfiles compilieren
#include <windows.h>
#include <stdio.h>
#include <tchar.h> //Unicode
////////////////////////////////////////////////////////////////
typedef struct tagMYSCREEN { //eigene globale Struktur
HANDLE hOut;
HANDLE hIn ;
CONSOLE_SCREEN_BUFFER_INFO screen ; //screen.dwSize.X, Y
} MYSCREEN ;
///////////////////////////////////////////////////////////////
VOID Console_Init( MYSCREEN * mScreen ) {
mScreen->hOut = GetStdHandle( STD_OUTPUT_HANDLE ) ;
mScreen->hIn = GetStdHandle( STD_INPUT_HANDLE ) ;
SetConsoleMode( mScreen->hIn, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT ) ;
GetConsoleScreenBufferInfo( mScreen->hOut, & mScreen->screen ) ;
return;
}
////////////////////////////////////////////////////////////////
VOID Cursor_Off( MYSCREEN *mScreen ) {
CONSOLE_CURSOR_INFO
cursor ;
GetConsoleCursorInfo( mScreen->hOut, & cursor ) ;
cursor.bVisible = FALSE ;
SetConsoleCursorInfo( mScreen->hOut, & cursor ) ;
}
////////////////////////////////////////////////////////////////
VOID Cursor_On( MYSCREEN *mScreen ) {
CONSOLE_CURSOR_INFO cursor ;
cursor.bVisible = TRUE ;
SetConsoleCursorInfo( mScreen->hOut, & cursor ) ;
}
////////////////////////////////////////////////////////////////
VOID Cursor_Set( MYSCREEN *mScreen, SHORT x, SHORT y ) {
COORD point; point.X = x; point.Y = y;
SetConsoleCursorPosition( mScreen->hOut, point ) ;
}
////////////////////////////////////////////////////////////////
int Cursor_GetX( MYSCREEN *mScreen ) { return mScreen->screen.dwCursorPosition.X; }
int Cursor_GetY( MYSCREEN *mScreen ) { return mScreen->screen.dwCursorPosition.Y; }
int Screen_GetX( MYSCREEN *mScreen ) { return mScreen->screen.dwSize.X; }
int Screen_GetY( MYSCREEN *mScreen ) { return mScreen->screen.dwSize.Y; }
////////////////////////////////////////////////////////////////
INPUT_RECORD Read_Input( MYSCREEN *mScreen, DWORD * nIn ) {
INPUT_RECORD evt ;
DWORD n; if ( nIn == NULL ) nIn = & n;
ReadConsoleInput( mScreen->hIn, & evt, 1, nIn ) ;
return evt;
}
////////////////////////////////////////////////////////////////
DWORD Write_Attr( MYSCREEN *mScreen, int x, int y, DWORD anz, WORD Attr ) {
DWORD nOut ; COORD point; point.X = ( SHORT) x; point.Y = ( SHORT) y;
if ( anz <= 0 ) anz = 1;
FillConsoleOutputAttribute( mScreen->hOut, Attr, anz, point, & nOut ) ;
return nOut;
}
////////////////////////////////////////////////////////////////
DWORD Write_Str( MYSCREEN *mScreen, int x, int y, DWORD anz, TCHAR * pStr ) {
DWORD nOut ; COORD point; point.X = ( SHORT) x; point.Y = ( SHORT) y;
if ( anz <= 0 ) anz = 1;
WriteConsoleOutputCharacter( mScreen->hOut, pStr, anz, point, & nOut ) ;
return nOut;
}
////////////////////////////////////////////////////////////////
// Einen Teil des Bildschirms scrollen
VOID Scroll_Screen( MYSCREEN *mScreen, int xNew, int yNew, SMALL_RECT * pRect, CHAR_INFO fillChar )
{ COORD newPoint; newPoint.X = ( SHORT) xNew; newPoint.Y = ( SHORT) yNew;
ScrollConsoleScreenBuffer( mScreen->hOut,
pRect,
// Groesse des Scrollbereichs
NULL,
// Clipping-Rechteck, nicht verwendet
newPoint, // neue Position des Scrollbereichs
& fillChar // Fuellzeichen und -attribut fuer den freiwerdenen Bereich
) ;
}
////////////////////////////////////////////////////////////////
// Fuellt den kompletten Schirm mit einem Vordergrund/Hintergrundattribut
VOID Fill_Screen_Attr( MYSCREEN *mScreen, WORD Attr ) {
DWORD nOut ; COORD point = { 0, 0 }; // d.h. point.X=0; point.Y=0;
FillConsoleOutputAttribute( mScreen->hOut, Attr,
( mScreen->screen.dwSize.X ) * ( mScreen->screen.dwSize.Y ), point, & nOut );
}
////////////////////////////////////////////////////////////////
VOID Fill_Screen_Char( MYSCREEN *mScreen, TCHAR c ) { // Fuellt Bildschirm mit einem Zeichen
DWORD nOut ; COORD point = { 0, 0 }; // d.h. point.X=0; point.Y=0;
FillConsoleOutputCharacter( mScreen->hOut, c, (mScreen->screen.dwSize.X)*(mScreen->screen.dwSize.Y), point, & nOut ) ;
}
////////////////////////////////////////////////////////////////
TCHAR Key_Hit1( MYSCREEN *mScreen ) {// Wartet auf eine Taste ( Ctrl/Shift bewirken nichts )
TCHAR c ; DWORD nIn ;
ReadConsole( mScreen->hIn, & c, 1, & nIn, NULL ) ;
return c;
}
////////////////////////////////////////////////////////////////
INPUT_RECORD Key_Hit( MYSCREEN *mScreen ) { INPUT_RECORD evt ; DWORD nIn ;
do { // Wartet auf Taste ( auch Ctrl usw. )
ReadConsoleInput( mScreen->hIn, & evt, 1, & nIn ) ;
if ( ( evt.EventType
== KEY_EVENT )
&&
( evt.Event.KeyEvent.bKeyDown == TRUE
) ) break ;
} while ( TRUE ) ;
return evt;
}
////////////////////////////////////////////////////////////////
int main() {
////////////////////////////////////////////////////////////////
TCHAR pStr[]
= TEXT( "ESC beendet" );
TCHAR szEmpty[] = TEXT( "
" ) ;
COORD point ;
SMALL_RECT rect ; CHAR_INFO fillChar ; INPUT_RECORD evt ;
TCHAR iChar[]
= TEXT( " " ) ;
DWORD i ;
MYSCREEN ms;
Console_Init( &ms );
_tprintf( TEXT( "ScreenCol: %d\n"), Screen_GetX(&ms) );
_tprintf( TEXT( "ScreenRow: %d\n"), Screen_GetY(&ms) );
_tprintf( TEXT( "Cursor-Pos: (%d,%d)\n" ), Cursor_GetX(&ms),Cursor_GetY(&ms) );
_tprintf( TEXT( "Bitte Taste fuer Fill_Screen_Attr(): gelb auf blau\n" )); Key_Hit(&ms) ;
Fill_Screen_Attr( &ms,FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | BACKGROUND_BLUE ) ;
_tprintf( TEXT( "Bitte Taste fuer ScreenCode-Ausgabe mit Write_Str()\n" ));
for ( i = 0 ; i < 512 ; i ++ ) { iChar[0] = (TCHAR)i;
Key_Hit(&ms) ;
Write_Str( &ms, i%64, 10 + i/64, 1, iChar );
}
_tprintf( TEXT( "Bitte Taste fuer Fill_Screen_Char( TEXT(' '), Write_Attr(), Write_Str() )\n") );
Cursor_Set( &ms, 0, 0 ); evt = Key_Hit(&ms) ;
Fill_Screen_Char( &ms, TEXT(' ') ) ; // Bildschirm loeschen
for (i = 0 ; i < 6 ; i ++ ) {
Write_Attr( &ms, i*3, i, _tcslen( pStr ), FOREGROUND_BLUE | BACKGROUND_RED );
Write_Str ( &ms, i*3, i, _tcslen( pStr ), pStr );
}
_tprintf( TEXT( "Bitte Taste fuer Scroll_Screen()\n" ));
Key_Hit(&ms) ;
#ifdef UNICODE //CHAR_INFO fillChar ;
fillChar.Char.UnicodeChar = L'#' ;
fillChar.Attributes = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ;
#else
fillChar.Char.AsciiChar = '#' ;
fillChar.Attributes = FOREGROUND_INTENSITY | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ;
#endif
for ( i = 0 ; i < (DWORD) Screen_GetY(&ms) - 16 ; i ++ ) {
rect.Left = (short)i ; rect.Right = (short)i+22 ;
rect.Top = (short)i ; rect.Bottom = (short)i+6 ;
Scroll_Screen( &ms, i + 1, i + 1, & rect, fillChar ) ;
Sleep( 500 ) ; // 500 ms
}
_tprintf( TEXT( "\n\nBitte mit Maus aufziehen\n" ) );
point.X = 9 ;
point.Y = 9 ;
Cursor_Off(&ms);
do {
evt = Read_Input( &ms, NULL ) ;
if ( evt.EventType == MOUSE_EVENT ) { // Mausaktivitaet
if ( memcmp( & point, & evt.Event.MouseEvent.dwMousePosition, sizeof(COORD))) {
Write_Str( &ms, point.X, point.Y, _tcslen( szEmpty ), szEmpty );
point = evt.Event.MouseEvent.dwMousePosition ;
Write_Str( &ms, point.X, point.Y, _tcslen( pStr ), pStr );
}
}
} while ( evt.Event.KeyEvent.wVirtualKeyCode != 27 ) ; // bis escape kommt
Cursor_On(&ms);
return 0 ;
}
////////////////////////////////////////////////////////////////
Nachrichten
Windows ist ein Nachrichten - gesteuertes System. Die Behandlung von Nachrichten ist ein zentraler Bestandteil des Betriebssystems.
System-Message-Queue
Die Maus- und Tastatur - Ereignisse werden der System - Message - Queue( Hardware - Buffer ) entnommen und in ein einheitliches
MSG - Format gebracht. Dann werden die Nachrichten in die Application - Message - Queue( Nachrichten an unser Fenster ) gestellt.
Durch GetMessage() werden die Nachrichten dem Application - Buffer entnommen. Sollen z.B. sämtliche Nachrichten an alle
Anwendungen abgehorcht werden, so ist direkt hinter der System - Message - Queue ( Hardware - Buffer ) ein Hook ( z.B.
CallNextHookEx ) einzubauen.
Application-Message-Queue
Jede Anwendung hat eine eigene Application - Message - Queue. Ist diese leer, so können in der Zwischenzeit andere Programme
ausgeführt werden ( kooperatives Multitasking ).
●
●
Mit der Window - Funktion PostMessage() kann per Programm eine Nachricht hinten in die Application - Message Queue geschrieben werden.
Mit SendMessage() kann per Programm eine Nachricht direkt an unser Fenster geschickt werden. SendMessage()
überholt alle Nachrichten, die sich in der eigene Application - Message - Queue befinden.
Für die Nachrichten verwendet Windows den MSG-Typ:
typedef struct tagMSG {
HWND hwnd ;
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
} MSG ;
MSG msg ;
Die msg-Nachricht enthält auch msg.message. Durch message wird die Art der Nachricht eindeutig spezifiziert.
Jede Nachricht kann in msg.wParam, msg.lParam zusätzliche Informationen hinterlegen. Die genaue Bedeutung der msg.wParam,
msg.lParam - Bits hängt von msg.message ab. Für viele einfache Nachrichten reichen die Bits von wParam, lParam aus. In msg.lParam
kann auch ein Zeiger auf benötigte Informationen enthalten sein.
msg.time enthält die Ereignis - Zeit.
Die Cursor - Koordinaten ( zur Ereignis-Zeit ) werden in pt übergeben.
Soll z.B. die nächste Nachricht aus der Application-Message-Queue geholt werden, so wird mit GetMessage( & msg ) diese Nachricht
in die ( vorher angelegte ) Variable
MSG msg ;
gespeichert. Haupt - Nachrichten - Schleife ( nach WinMain ) ist eine ( beinahe ) Unendlich-Schleife, die nur durch die WM_QUIT Nachricht verlassen werden kann.
while ( GetMessage( & msg, NULL, 0, 0 ) ) {
...
DispatchMessage ( & msg ) ;
}
Durch RegisterClass() wurde unsere ( Klassen - ) CALLBACK - Funktion WNDCLASS. lpfnWndProc = ( WNDPROC ) WndProc ;
eingetragen. Durch DispatchMessage ( & msg ) wird die aktuelle Nachricht an diese Funktion weiter gereicht, d.h. die WndProc() wird
mit den msg - Paramtern aufgerufen. Jedes Fenster hat ein eindeutiges Handle. Deshalb kann DispatchMessage ( & msg ) mit Hilfe von
msg.hWnd die Nachricht über die ( globalen ) Klassen - Daten - Struktur an die CALLBACK - Funktion weiter geben. Die Haupt Nachrichten - Schleife wird bei einer WM_QUIT - Botschaft abgebrochen. Nach dem Eintreffen von WM_DESTROY fügen wir in der
Application - Message - Queue durch PostQuitMessage() die Nachricht WM_QUIT ein. Wenn GetMessage() die WM_QUIT Nachricht entnimmt, so wird die Haupt - Nachrichten - Schleife beendet.
Message - Cracker - Macros
In windowsX.h sind die Message - Cracker - Macros enthalten. Durch diese Macros wird das Nachrichten - Carsting vermieden und die
Win16/Win32 - Portabilität erhöht.
Beispiele für soche Macros sind:
#define HANDLE_MSG(hWnd, iMsg, fn)
\
case (iMsg): return HANDLE_##iMsg((hWnd), (wParam), (lParam), (fn))
Ein HANDLE_MSG(hWnd, WM_CHAR, fn) - Macro - Aufruf enpandiert in ein weiteres ( in WindowsX.h enthaltenes )
HANDLE_WM_CHAR() - Macro:
/* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_CHAR( hWnd, wParam, lParam, fn) \
((fn)(( hWnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_CHAR( hWnd, ch, cRepeat, fn) \
(void)(fn)(( hWnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
Viele HANDLE_ - Macros ( z.B. HANDLE_WM_CHAR ) zerlegen die Nachrichten typentreu in die enthaltenen Nachrichten Parameter und rufen damit die Funktion ( hier fn ) auf. Die FORWARD_ - Macros machen diesen Vorgang rückgängig und erzeugen
wieder die ursprüngliche ( hWnd, iMsg, wParam, lParam ) - Nachricht.
Mit dem HANDLE_MSG - Macro hat eine CALLBACK - Funktion etwa den folgenden Aufbau:
LRESULT CALLBACK myCallbackProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg) {
HANDLE_MSG( hWnd, WM_CHAR, myOnChar);
HANDLE_MSG( ... );
...
default:
return myOrgProc( hWnd, iMsg, wParam, lParam);
}
}
Vielfach wird myOrgProc() der DefWindowProc() von Windows entsprechen. Die Funktion myOnChar() wird etwa wie folgt
aufgebaut:
void myOnChar( HWND hWnd, UINT ch, int cRepeat) {
if ( ch == testvalue ) { // handle it here
} else {
FORWARD_WM_CHAR( hWnd, ch, cRepeat, myOrgProc);
}
}
Das FORWARD_ - Macro setzt die zerlegte Nachricht wieder zur ursprünglichen ( hWnd, iMsg, wParam, lParam ) - Nachricht
zusammen.
In WindowsX.h sind ( als Kommentar ) die Funktions - Parameter für myOnChar() angegeben.
/* void Cls_OnChar( HWND hWnd, TCHAR ch, int cRepeat) */
Soll für myOrgProc() nicht DefWindowProc() sondern die orginal Klassen - CALLBACK - Funktion lpOrgProc aufgerufen werden,
so kann myOrgProc definiert werden durch:
LRESULT myOrgProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
return CallWindowProc( lpOrgProc, hWnd, iMsg, wParam, lParam);
}
CallWindowProc() ruft die Funktion lpOrgProc auf. In WindowsX.h ist
#define Sumy_classWindow( hWnd, lpfn)
\
((WNDPROC)SetWindowLong(( hWnd), GWL_WNDPROC, \
(LPARAM)(WNDPROC)MakeProcInstance((FARPROC)(lpfn),GetModuleHandle(NULL))))
enthalten. Damit kann ein Sumy_classing gemäß
WNDPROC lpOrgProc = NULL;
lpOrgProc = Sumy_classWindow( hWnd, myCallbackProc));
...
erfolgen.
Portabilität
Beim Übergang von WIN16 auf WIN32 hat sich das Nachrichten - Format geändert. Bei WIN16 war wParam ein WORD - Typ, bei
WIN32 ist wParam ein LONG - Typ. Bei WIN32 benötigt ein Handle 32 Bits.
Win32
32 Bit
32 Bit
|---------------------------------|---------------------------------|
|
wParam
|
lParam
|
|----------------|----------------|---------------------------------|
|
|
|
|
|
wmCMD
|
wmID
|
wmHWND
|
Win16
16 Bit
32 Bit
|----------------|---------------------------------|
|
wParam
|
lParam
|
|----------------|---------------------------------|
|
|
|
|
|
wmID
|
wmCMD
|
wmHWND
|
Der Button sendet Nachrichten an das Parent - Window, wenn sich sein Zustand ändert. Der Button - Identifizierer wird mit wmID, die
Notification Messages ( z.B. BN_CLICKED ) wird mit wmCMD und das Control - Handle mit wmHWND bezeichnet. Wegen der
WIN16/WIN32 - Portabilität sind die windoesX.h - Macros sinnvoll:
Nachrichten - Casting
WindosX.h-Macros
#ifdef WIN16
int wmCMD = HIWORD( lParam ) ;
#else
int wmCMD = HIWORD( wParam ) ;
#endif
int wmID = LOWORD( wParam );
HWND wmHWND= (HWND)(UINT)lParam;
int wmCMD = GET_WM_COMMAND_CMD (wParam,lParam);
int wmID = GET_WM_COMMAND_ID (wParam,lParam);
HWND wmHWND= GET_WM_COMMAND_HWND(wParam,lParam);
Tastatur - Nachrichten
Wenn Prozessen mit unterschiedlicher Ausführungs - Geschwindigkeit synchronisiert werden müssen, so werden Warteschlangen (
Buffer ) benötigt. Der schreibende Prozeß hinterlegt die unregelmäßig eintreffenden Ereignisse in einem Buffer. Der lesende Prozeß
holt sich die Nachrichten und verarbeitet diese mit der eigenen Geschwindigkeit. Bei dem Windows - System - Tastatur - Buffer
handelt es sich um einen Ring - Buffer. Bei DOS enthält der Tastatur - Buffer 32 Worte ( 64 Byte ).
●
Tastaturereignis ==> int 9h ==> Zeichen in Puffer ==> int 16h ==> Buffer auslesen
#include <stdio.h>
extern key_read( int*, int* );
void main( ) {
int *ascii_ptr, *scan_ptr, num, num1; num = 0; num1 = 0;
ascii_ptr = &num; scan_ptr = &num1; // initialize pointers to zero
key_read( ascii_ptr, scan_ptr ); // call assembly routine
// print the high byte - ASCII code, and the low byte - extended code
// of the character placed in the keyboard buffer
printf( "ASCII Code hex %x or decimal %d\n", *ascii_ptr,"
" *ascii_ptr);
printf( "EXTENDED Code hex %x "
"or decimal %d\n", *scan_ptr,
*scan_ptr);
}
******************************************************
.model small,c
.data
.code
PUBLIC
key_read
key_read PROC
PUSH bp
;save the base pointer
MOV
bp, sp
; Invoke Int 21h Function Ch to clear the keyboard buffer before ;
; accepting a keystroke.
MOV
ah, 0CH
MOV
al, 0
INT
21h
; Invoke Int 16h Function 0h to place the character code in the AX ; register.
MOV
ah, 0H
INT
16H
MOV
bx, [bp+4] ;ASCII returned
MOV
[bx], al
MOV
bx, [bp+6] ;Extended code returned
MOV
[bx], ah
POP
bp
RET
key_read ENDP
END
Tasten - Scan - Code
Der folgende Tasten - Scan - Code ist festgelegt worden:
Bei Windows kann der System - Tastatur - Buffer 60 Zeichen aufnehmen.
Im System - Nachrichten - Buffer kommt der Tasten - Scan - Code. Die Tasten - Nachricht wird aufbereitet ( einheitliches MSG Format ) und in den Applikations - Nachrichten - Buffer gestellt.
Bei Windows hat ein Fenster den Focus. Dieses Fenster ist i.a. an der blauen Titel - Zeile erkennbar. Die Tasten - Nachrichten werden
in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die CALLBACK - Funktion des
Fensters wird mit der Tasten - Nachricht ( iMsg, wParam, lParam ) aufgerufen, d.h.
●
die Tasten - Nachrichten werden an das Fenster geschickt.
Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den
Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster (
genauer: der Speicher für die Fensterdaten ) erreichbar. In iMsg ist die Tasten - Nachricht eindeutig identifizierbar. Mit wParam, lParam
können die Tasten unterschieden werden.
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) {
switch ( iMsg ) {
...
case WM_CHAR : {
switch ( LOWORD(wParam) ) {
case ‘\b’
case ‘\t’
case ‘\n’
default :
: Rücktaste; break;
: Tabulatortaste; break;
: LF-Taste; break;
//normales Zeichen bearbeiten
}
}
...
}
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
In dem obigen Beispiel werden nur einige WM_CHAR - Nachrichten behandelt.
Tabelle der WM - Tastatur - Nachrichten
Es gibt die folgenden Keyboard - Nachrichten:
TastenNachricht
wParam, lParam enthalten ...
WM_ACTIVATE
fActive = LOWORD(wParam); // activation flag
fMinimized = (BOOL) HIWORD(wParam); // minimized flag
hwndPrevious = (HWND) lParam; // window handle
WM_SETFOCUS
// handle of window losing focus
hwndLoseFocus = (HWND) wParam;
WM_KILLFOCUS
// handle of window receiving focus
hwndGetFocus = (HWND) wParam;
WM_KEYDOWN
WM_KEYUP
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam; // key data
WM_CHAR
WM_SYSCHAR
chCharCode = (TCHAR) wParam; // character code
lKeyData = lParam; // key data
WM_HOTKEY
idHotKey = (int) wParam; // identifier of hot key
fuModifiers = (UINT) LOWORD(lParam); // key-modifier flags
uVirtKey = (UINT) HIWORD(lParam); // virtual-key code
WM_GETHOTKEY
wParam = 0; // not used; must be zero
lParam = 0; // not used; must be zero
WM_SETHOTKEY
// virtual-key code and modifiers of hot key
wParam = (WPARAM) MAKEWORD(vkey, modifiers)
lParam = 0; // not used; must be zero
WM_DEADCHAR
chCharCode = (TCHAR) wParam; // character code
lKeyData = lParam; // key data
WM_SYSDEADCHAR
chCharCode = (TCHAR) wParam; // character code
lKeyData = lParam; // key data
WM_SYSKEYDOWN
WM_SYSKEYUP
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam; // key data
Virtual - Tasten - Code
●
Je Taste werden mehr als eine Nachricht generiert.
Wird z.B. der Klein - Buchstabe a auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden
die folgenden 3 Nachrichten generiert:
●
●
●
WM_KEYDOWN ( virtuelle Taste ),
WM_CHAR ( wParam enthält ASCII von a ),
WM_KEYUP ( virtuelle Taste )
Wird z.B. der Groß - Buchstabe A auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach aufgerufen, d.h. es werden
die folgenden 5 Nachrichten generiert:
●
●
●
●
●
WM_KEYDOWN ( virtuelle Taste VK_SHIFT ),
WM_KEYDOWN ( virtuelle Taste a ),
WM_CHAR ( wParam enthält ASCII von A ),
WM_KEYUP ( virtuelle Taste a ),
WM_KEYUP ( virtuelle Taste VK_SHIFT )
Die (V)irtuellen (K)ey - Nachrichten ( VK_... ) können in der CALLBACK WndProc - Funktion etwa wie folgt benutzt werden.
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) {
switch ( iMsg ) {
...
case WM_KEYDOWN : {
switch ( LOWORD(wParam) ) {
...
case VK_LEFT:
//die Caret-nach-links-Taste ( Pfeilchen-Taste )
//wurde gedrückt, jetzt soll ...
break ;
case VK_F1: ...
} ...
} ...
} ...
}
Die RETURN - Tasten können unterschieden werden durch das 24. Bit von lParam.
switch ( iMsg ) {
case WM_KEYDOWN : {
switch ( LOWORD(wParam) ) {
...
case VK_RETURN:
if ( lParam & 0x01000000L ) { // Enter-Taste ( numeric keypad )
} else {
// Enter-Taste ( standard keypad )
} break ;
} ...
} ...
} ...
}
Tabelle der Virtual - Tasten - Codes
Bei einer WM_KEYDOWN - Nachricht wird in LOWORD(wParam) der ( standardisierte ) Virtual - Key - Code übergeben. Die
folgende Tabelle enthält die #define`s.
VK_LBUTTON
= 0x01
VK_RBUTTON
= 0x02
VK_CANCEL
= 0x03
VK_MBUTTON
= 0x04
VK_BACK
= 0x08
VK_TAB
= 0x09
VK_CLEAR
= 0x0C
VK_RETURN
= 0x0D
VK_SHIFT
= 0x10
VK_CONTROL
= 0x11
VK_MENU
= 0x12
VK_PAUSE
= 0x13
VK_CAPITAL
= 0x14
VK_ESCAPE
= 0x1B
VK_SPACE
= 0x20
VK_PRIOR
= 0x21
VK_NEXT
= 0x22
VK_END
= 0x23
VK_HOME
= 0x24
VK_LEFT
= 0x25
VK_UP
= 0x26
VK_RIGHT
= 0x27
VK_DOWN
= 0x28
VK_SELECT
= 0x29
VK_PRINT
= 0x2A
VK_EXECUTE
= 0x2B
VK_SNAPSHOT
= 0x2C
VK_INSERT
= 0x2D
VK_DELETE
= 0x2E
VK_HELP
= 0x2F
VK_0
..VK_9
= 0x30
...0x39
VK_A
..VK_Z
= 0x41
..0x5A
VK_LWIN
= 0x5B
VK_RWIN
= 0x5C
VK_APPS
= 0x5D
VK_NUMPAD0
= 0x60
VK_NUMPAD1
= 0x61
VK_NUMPAD2
= 0x62
VK_NUMPAD3
= 0x63
VK_NUMPAD4
= 0x64
VK_NUMPAD5
= 0x65
VK_NUMPAD6
= 0x66
VK_NUMPAD7
= 0x67
VK_NUMPAD8
= 0x68
VK_NUMPAD9
= 0x69
VK_MULTIPLY
= 0x6A
VK_ADD
= 0x6B
VK_SEPARATOR
= 0x6C
VK_SUBTRACT
= 0x6D
VK_DECIMAL
= 0x6E
VK_DIVIDE
= 0x6F
VK_F1
= 0x70
VK_F2
= 0x71
VK_F3
= 0x72
VK_F4
= 0x73
VK_F5
= 0x74
VK_F6
= 0x75
VK_F7
= 0x76
VK_F8
= 0x77
VK_F9
= 0x78
VK_F10
= 0x79
VK_F11
= 0x7A
VK_F12
= 0x7B
VK_F13
= 0x7C
VK_F14
= 0x7D
VK_F15
= 0x7E
VK_F16
= 0x7F
VK_F17
= 0x80
VK_F18
= 0x81
VK_F19
= 0x82
VK_F20
= 0x83
VK_F21
= 0x84
VK_F22
= 0x85
VK_F23
= 0x86
VK_F24
= 0x87
VK_NUMLOCK
= 0x90
VK_SCROLL
= 0x91
VK_LSHIFT
= 0xA0
VK_RSHIFT
= 0xA1
VK_LCONTROL
= 0xA2
VK_RCONTROL
= 0xA3
VK_LMENU
= 0xA4
VK_RMENU
= 0xA5
VK_PROCESSKEY
WINVER<=0x0400
= 0xE5
VK_ATTN
= 0xF6
VK_CRSEL
= 0xF7
VK_EXSEL
= 0xF8
VK_EREOF
= 0xF9
VK_PLAY
= 0xFA
VK_ZOOM
= 0xFB
VK_NONAME
= 0xFC
VK_PA1
= 0xFD
VK_OEM_CLEAR
= 0xFE
Z.B. wird durch die Alt - Taste die wParam = VK_MENU - Nachricht generiert.
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den
GetAsyncKeyState(), GetKeyState() - Funktionen benutzt.
Tasten - Zustand - Flags
Der aktuelle Zustand aller Tasten wird in einem Buffer protokolliert. Auch die Applikation kann diese Einträge lesen/schreiben, wobei
zwischen synchron/asynchron unterschieden wird. Wird eine neue Tasten - Nachricht in den Applikations - Nachrichten Warteschlange ( Applikations - Buffer ) eingetragen, so ändert sich der asynchron Keyboard - Zustand. Der synchron Keyboard Zustand entspricht dem momentanen Zustand der Tastatur.
Wie kann eine gedrücke SHIFT - Taste abgefragt
werden?
if ( GetKeyState ( VK_SHIFT ) & 0x80000000L ) {
// SHIFT - Taste gedrückt
}
GetKeyState() ( imGegensatz zu GetAsyncKeyState ) liefert den Zustand ohne Verzögerung zurück. Durch GetKeyState (
VK_LBUTTON ) wird z.B. der aktuelle Zustand der linken Maustaste abgefragt.
Wie kann eine Berechnung abgebrochen werden?
Dauert z.B. eine Berechnung zu lange und soll diese Berechnung durch
●
●
die Escape - Taste oder
die linke Maus - Taste
abgebrochen werden, so kann dies mit der ( asynchronen ) GetAsyncKeyState() - Funktion
if ( ( GetAsyncKeyState (
|| ( GetAsyncKeyState (
) {
// ... z.B. exit (
// ... SendMessage
}
VK_LBUTTON ) < 0 ) // linke Maus - Taste down
VK_ESCAPE ) < 0 ) // Escape Taste
-1 ); oder
( hWnd, WM_CLOSE, 0, 0 )
erfolgen. Um den Zustand von mehreren Tasten zu untersuchen, wie z.B. die
●
●
●
Shift - Taste ( VK_SHIFT, VK_LSHIFT, VK_RSHIFT ),
Ctrl - Taste ( VK_CONTROL, VK_LCONTROL, VK_RCONTROL ),
Alt - Taste ( VK_MENU, VK_LMENU, VK_RMENU )
können alle 256 Virtual Keys in einen Buffer buf kopiert werden. Die Funktionen GetKeyboardState(), SetKeyboardState(),
GetAsyncKeyState(), GetKeyState(), MapVirtualKey() werden benutzt. Es kann dann z.B. zwischen linken und rechten SHIFT Tasten unterschieden werden. Die GetKeyboardState( buf ) - Funktion kopiert alle 256 Virtual Keys in einen Buffer buf. Eine Taste ist
gerade gedrückt, wenn das 7. Bit gesetzt ist ( sonst 0 ). Der Gedrückt/Losgelassen - Zustand hat gewechselt, wenn das 0. Bit gleich 1 ist
( tggled ). Normalerweise ist eine Taste nicht gedrückt, dann ist das 0. Bit gleich 1.
Wie kann eine gedrückte CTRL - Taste
( VK_CONTROL ) per Programm simuliert
werden?
BYTE buf[256];
GetKeyboardState( buf ); // hole VK_ - Keys
buf[VK_CONTROL] |= 0x80;
// setze "gedrückt" bei VK_CONTROL - Taste
SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
Wie kann die CAPS - LOCK - Taste
( VK_CAPITAL ) invertiert werden?
BYTE buf[256];
GetKeyboardState( buf );
if ( buf[VK_CAPITAL] & 1 ) buf[VK_CAPITAL] &= 0xFE;
else
buf[VK_CAPITAL] |= 0x01;
SetKeyboardState( buf );
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den
GetAsyncKeyState(), GetKeyState() - Funktionen benutzt.
Wie kann ein "floating-pop-up-menu"
nach der Anzeige sichtbar bleiben?
case WM_RBUTTONDOWN: {
BYTE buf[256];
GetKeyboardState( buf ); // hole VK_ - Keys
buf[VK_RBUTTON] = 0x00; // setze "losgelassen" bei VK_RBUTTON - Maus - Taste
SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
... create - pop - up - Menu ...
... call TrackPopUp
...
break; }
lParam - Tastenflags
TranslateMessage() benutzt die Funktion ToAsciiEx() um den virtuellen Key - Code ( z.B. für die WM_KEYDOWN - Nachricht ) zu
erzeugen. Eine Nachricht enthält in LOWORD( lParam ) die Anzahl von automatischen Tasten - Wiederholungen. Durch diesen
Anschlag - Wiederholungs - Zähler werden Überflutungen von Nachrichten vermieden.
In HIWORD( lParam ) sind interessante Tasten - Flags, die im folgenden erklärt werden. Eine Nachricht enthält in HIWORD( lParam )
interessante Tasten - Flags, die im folgenden erklärt werden.
Bit HIWORD( lParam ) - Bit
Bit HIWORD( lParam ) - Bit
Bit HIWORD( lParam ) - Bit
Bit HIWORD( lParam ) - Bit
1 if the key is up;
15
0 if the key is down.
1 if the key was previously
up;
14
0 if the key was previously
down.
13 1 if the ALT key is down.
12
1 if Windows displays a
menu.
8
1 if the key is extended;
0 if it is not.
11
1 if Windows displays a
dialog box.
10 Not used.
9 Not used.
7 generally 0.
hardware-scan code
6..0 ( used mainly in the translation of ALT+number-pad character
code input )
Maus - Nachrichten
Die Maus - Nachrichten werden in der Haupt - Nachrichten - Schleife aus dem Applikations - Buffer geholt ( GetMessage ) und die
CALLBACK - Funktion des Fensters wird mit der Maus - Nachricht ( iMsg, wParam, lParam ) aufgerufen, d.h.
●
die Maus - Nachrichten werden an das Fenster geschickt.
Vor dem Aufruf der Fensters - CALLBACK - Funktion werden durch das Windows - System die Parameter der Nachricht auf den
Stack gelegt, d.h. die Nachricht wird über den Aufrufer - Stack an die CALLBACK - Funktion übergeben. An hWnd ist das Fenster (
genauer: der Speicher für die Fensterdaten ) erreichbar. In iMsg ist die Maus - Nachricht eindeutig identifizierbar. Typische iMsg sind:
WM_LBUTTONDOWN, WM_RBOTTOMDOWN, WM_MOUSEMOVE, WM_NCLBUTTONDBLCLICK.
Die Behandlung von Maus - Ereignisses geschieht vielfach in der CALLBACK - Funktion. In lParam wird die aktuelle Maus - Position
an die CALLBACK - Funktion übergeben.
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) {
switch ( iMsg ) {
...
case WM_LBUTTONDOWN :
x = LOWORD(lparam); // 16 BIT
y = HIWORD(lparam) // pt = MAKEPOINT(lparam); // 32 BIT, pt vom Typ Point
break;
...
}
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
Für einen Doppel - Klick muß nach WM_LBUTTONDOWN ein Zähler gestartet werden. Deshalb ist für einen Doppelklick ein
Eintrag
WNDCLASSEX wc={ 0 };
wc.cbSize=sizeof(WNDCLASSEX);
...
wc.style = ... | CS_DBLCLKS; // Zeitgeber ½ sec.
RegisterClass( & wc );
erforderlich.
WM_MOUSE - Nachrichten
Ein Fenster besteht aus dem Fenster - Inneren ( Client - Bereich ) und dem Nicht Client - Bereich ( NC ). Auch der Fenster - Rand
gehört zu NC. Maus-Nachricht
nHittest see WM_
NC
HITTEST
Nachricht
WM_CAPTURECHANGED
wParam, lParam enthalten ...
hwndNewCapture = (HWND) lParam; // handle of window to gain mouse capture
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_RBUTTONDOWN
WM_RBUTTONUP
WM_MBUTTONDOWN
WM_MBUTTONUP
WM_LBUTTONDBLCLK
WM_MBUTTONDBLCLK
WM_RBUTTONDBLCLK
fwKeys = wParam; // key flags
xPos = LOWORD(lParam); // horizontal position of cursor
yPos = HIWORD(lParam); // vertical position of cursor
fwKeys:
MK_CONTROL Set if the CTRL key is down.
MK_LBUTTON Set if the left mouse button is down.
MK_MBUTTON Set if the middle mouse button is down.
MK_RBUTTON Set if the right mouse button is down.
MK_SHIFT Set if the SHIFT key is down.
WM_MOUSEACTIVATE
hwndTopLevel = (HWND) wParam; // handle of top-level parent
nHittest = (INT) LOWORD(lParam); // hit-test value
uMsg = (UINT) HIWORD(lParam); // mouse message
nHittest is the return value of DefWindowProc:
MA_ACTIVATE Activates the window, and does not discard the mouse message.
MA_ACTIVATEANDEAT Activates the window, and discards the mouse message.
MA_NOACTIVATE Does not activate the window, and does not discard the mouse message.
MA_NOACTIVATEANDEAT Does not activate the window, but discards the mouse message
WM_MOUSEWHEEL
fwKeys = LOWORD(wParam); // key flags
zDelta = (short) HIWORD(wParam); // wheel rotation
xPos = (short) LOWORD(lParam); // horizontal position of pointer
yPos = (short) HIWORD(lParam); // vertical position of pointer
fwKeys:
MK_CONTROL Set if the CTRL key is down.
MK_LBUTTON Set if the left mouse button is down.
MK_MBUTTON Set if the middle mouse button is down.
MK_RBUTTON Set if the right mouse button is down.
MK_SHIFT Set if the SHIFT key is down.
WM_NCHITTEST
xPos = LOWORD(lParam); // horizontal screen position of cursor
yPos = HIWORD(lParam); // vertical screen position of cursor
Value Location of hot spot is the return value of DefWindowProc:
HTBORDER In the border of a window that does not have a sizing border
HTBOTTOM In the lower horizontal border of a window
HTBOTTOMLEFT In the lower-left corner of a window border
HTBOTTOMRIGHT In the lower-right corner of a window border
HTCAPTION In a title bar
HTCLIENT In a client area
HTCLOSE In a close button HTERROR On the screen background or on a dividing line between
windows
(same as HTNOWHERE, except that the DefWindowProc
function produces a system beep to indicate an error)
HTGROWBOX In a size box (same as HTSIZE) HTHELP In a Help button
HTHSCROLL In a horizontal scroll bar
HTLEFT In the left border of a window
HTMENU In a menu
HTMAXBUTTON In Maximize button
HTMINBUTTON In Minimize button
HTNOWHERE On the screen background or on a dividing line between windows
HTREDUCE In a Minimize button
HTRIGHT In the right border of a window
HTSIZE In a size box (same as HTGROWBOX)
HTSYSMENU In a System menu or in a Close button in a child window
HTTOP In the upper horizontal border of a window
HTTOPLEFT In the upper-left corner of a window border
HTTOPRIGHT In the upper right corner of a window border
HTTRANSPARENT In a window currently covered by another window
HTVSCROLL In the vertical scroll bar
HTZOOM In a Maximize button
WM_NCLBUTTONDBLCLK nHittest = (INT) wParam; // hit-test value
WM_NCLBUTTONDBLCLK pts = MAKEPOINTS(lParam); // position of cursor
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCMBUTTONDBLCLK
WM_NCMBUTTONDOWN
WM_NCMBUTTONUP
WM_NCMOUSEMOVE
WM_NCRBUTTONDBLCLK
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP
Das Maus - Rad ( WM_MOUSEWHEEL ) kann z.B. zur Steuerung von Scroll - Bars eingesetzt werden.
// Window Messages
#define WM_NULL
#define WM_CREATE
#define WM_DESTROY
#define WM_MOVE
#define WM_SIZE
0x0000
0x0001
0x0002
0x0003
0x0005
#define WM_ACTIVATE
0x0006
// WM_ACTIVATE state values
#define
WA_INACTIVE
0
#define
WA_ACTIVE
1
#define
WA_CLICKACTIVE 2
#define WM_SETFOCUS
#define WM_KILLFOCUS
#define WM_ENABLE
#define WM_SETREDRAW
#define WM_SETTEXT
#define WM_GETTEXT
#define WM_GETTEXTLENGTH
#define WM_PAINT
#define WM_CLOSE
#define WM_QUERYENDSESSION
#define WM_QUIT
#define WM_QUERYOPEN
#define WM_ERASEBKGND
#define WM_SYSCOLORCHANGE
#define WM_ENDSESSION
#define WM_SHOWWINDOW
#define WM_WININICHANGE
#if(WINVER >= 0x0400)
#define WM_SETTINGCHANGE
#endif /* WINVER >= 0x0400 */
0x0007
0x0008
0x000A
0x000B
0x000C
0x000D
0x000E
0x000F
0x0010
0x0011
0x0012
0x0013
0x0014
0x0015
0x0016
0x0018
0x001A
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_DEVMODECHANGE
WM_ACTIVATEAPP
WM_FONTCHANGE
WM_TIMECHANGE
WM_CANCELMODE
WM_SETCURSOR
WM_MOUSEACTIVATE
WM_CHILDACTIVATE
WM_QUEUESYNC
0x001B
0x001C
0x001D
0x001E
0x001F
0x0020
0x0021
0x0022
0x0023
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_GETMINMAXINFO
WM_PAINTICON
WM_ICONERASEBKGND
WM_NEXTDLGCTL
WM_SPOOLERSTATUS
WM_DRAWITEM
WM_MEASUREITEM
WM_DELETEITEM
WM_VKEYTOITEM
WM_CHARTOITEM
WM_SETFONT
WM_GETFONT
WM_SETHOTKEY
WM_GETHOTKEY
0x0024
0x0026
0x0027
0x0028
0x002A
0x002B
0x002C
0x002D
0x002E
0x002F
0x0030
0x0031
0x0032
0x0033
WM_WININICHANGE
#define WM_QUERYDRAGICON
#define WM_COMPAREITEM
0x0037
0x0039
#define
#define
#define
#define
0x0041
0x0044
0x0046
0x0047
WM_COMPACTING
WM_COMMNOTIFY
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED
#define WM_POWER
/* no longer suported */
0x0048
// wParam for WM_POWER window message and DRV_POWER driver notification
#define PWR_OK
1
#define PWR_FAIL
(-1)
#define PWR_SUSPENDREQUEST 1
#define PWR_SUSPENDRESUME
2
#define PWR_CRITICALRESUME 3
#define WM_COPYDATA
#define WM_CANCELJOURNAL
0x004A
0x004B
#if(WINVER >= 0x0400)
#define WM_NOTIFY
#define WM_INPUTLANGCHANGEREQUEST
#define WM_INPUTLANGCHANGE
#define WM_TCARD
#define WM_HELP
#define WM_USERCHANGED
#define WM_NOTIFYFORMAT
0x004E
0x0050
0x0051
0x0052
0x0053
0x0054
0x0055
#define
#define
#define
#define
NFR_ANSI
NFR_UNICODE
NF_QUERY
NF_REQUERY
1
2
3
4
#define WM_CONTEXTMENU
#define WM_STYLECHANGING
#define WM_STYLECHANGED
#define WM_DISPLAYCHANGE
#define WM_GETICON
#define WM_SETICON
#endif /* WINVER >= 0x0400 */
0x007B
0x007C
0x007D
0x007E
0x007F
0x0080
#define
#define
#define
#define
#define
#define
#define
WM_NCCREATE
WM_NCDESTROY
WM_NCCALCSIZE
WM_NCHITTEST
WM_NCPAINT
WM_NCACTIVATE
WM_GETDLGCODE
0x0081
0x0082
0x0083
0x0084
0x0085
0x0086
0x0087
#define
#define
#define
#define
#define
WM_NCMOUSEMOVE
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCLBUTTONDBLCLK
WM_NCRBUTTONDOWN
0x00A0
0x00A1
0x00A2
0x00A3
0x00A4
#define
#define
#define
#define
#define
WM_NCRBUTTONUP
WM_NCRBUTTONDBLCLK
WM_NCMBUTTONDOWN
WM_NCMBUTTONUP
WM_NCMBUTTONDBLCLK
0x00A5
0x00A6
0x00A7
0x00A8
0x00A9
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_KEYFIRST
WM_KEYDOWN
WM_KEYUP
WM_CHAR
WM_DEADCHAR
WM_SYSKEYDOWN
WM_SYSKEYUP
WM_SYSCHAR
WM_SYSDEADCHAR
WM_KEYLAST
0x0100
0x0100
0x0101
0x0102
0x0103
0x0104
0x0105
0x0106
0x0107
0x0108
#if(WINVER >= 0x0400)
#define WM_IME_STARTCOMPOSITION
#define WM_IME_ENDCOMPOSITION
#define WM_IME_COMPOSITION
#define WM_IME_KEYLAST
#endif /* WINVER >= 0x0400 */
0x010D
0x010E
0x010F
0x010F
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_INITDIALOG
WM_COMMAND
WM_SYSCOMMAND
WM_TIMER
WM_HSCROLL
WM_VSCROLL
WM_INITMENU
WM_INITMENUPOPUP
WM_MENUSELECT
WM_MENUCHAR
WM_ENTERIDLE
0x0110
0x0111
0x0112
0x0113
0x0114
0x0115
0x0116
0x0117
0x011F
0x0120
0x0121
#define
#define
#define
#define
#define
#define
#define
WM_CTLCOLORMSGBOX
WM_CTLCOLOREDIT
WM_CTLCOLORLISTBOX
WM_CTLCOLORBTN
WM_CTLCOLORDLG
WM_CTLCOLORSCROLLBAR
WM_CTLCOLORSTATIC
0x0132
0x0133
0x0134
0x0135
0x0136
0x0137
0x0138
#define WM_MOUSEFIRST
#define WM_MOUSEMOVE
#define WM_LBUTTONDOWN
#define WM_LBUTTONUP
#define WM_LBUTTONDBLCLK
#define WM_RBUTTONDOWN
#define WM_RBUTTONUP
#define WM_RBUTTONDBLCLK
#define WM_MBUTTONDOWN
#define WM_MBUTTONUP
#define WM_MBUTTONDBLCLK
#if(_WIN32_WINNT >= 0x0400)
#define WM_MOUSEWHEEL
#endif /* _WIN32_WINNT >= 0x0400 */
0x0200
0x0200
0x0201
0x0202
0x0203
0x0204
0x0205
0x0206
0x0207
0x0208
0x0209
0x020A
#if (_WIN32_WINNT < 0x0400)
#define WM_MOUSELAST
0x0209
#else
#define WM_MOUSELAST
0x020A
#endif /* if (_WIN32_WINNT < 0x0400) */
#if(_WIN32_WINNT >= 0x0400)
#define WHEEL_DELTA
#endif /* _WIN32_WINNT >= 0x0400 */
#if(_WIN32_WINNT >= 0x0400)
#define WHEEL_PAGESCROLL
#endif /* _WIN32_WINNT >= 0x0400 */
#define
#define
#define
#define
#define
WM_PARENTNOTIFY
MENULOOP_WINDOW
MENULOOP_POPUP
WM_ENTERMENULOOP
WM_EXITMENULOOP
#if(WINVER >= 0x0400)
#define WM_NEXTMENU
#define WM_SIZING
#define WM_CAPTURECHANGED
#define WM_MOVING
#define WM_POWERBROADCAST
#define WM_DEVICECHANGE
120
(UINT_MAX) /* Scroll one page */
0x0210
0
1
0x0211
0x0212
0x0213
0x0214
0x0215
0x0216
0x0218
0x0219
#define WM_IME_SETCONTEXT
#define WM_IME_NOTIFY
#define WM_IME_CONTROL
#define WM_IME_COMPOSITIONFULL
#define WM_IME_SELECT
#define WM_IME_CHAR
#define WM_IME_KEYDOWN
#define WM_IME_KEYUP
#endif /* WINVER >= 0x0400 */
0x0281
0x0282
0x0283
0x0284
0x0285
0x0286
0x0290
0x0291
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_MDICREATE
WM_MDIDESTROY
WM_MDIACTIVATE
WM_MDIRESTORE
WM_MDINEXT
WM_MDIMAXIMIZE
WM_MDITILE
WM_MDICASCADE
WM_MDIICONARRANGE
WM_MDIGETACTIVE
0x0220
0x0221
0x0222
0x0223
0x0224
0x0225
0x0226
0x0227
0x0228
0x0229
#define
#define
#define
#define
#define
WM_MDISETMENU
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
WM_DROPFILES
WM_MDIREFRESHMENU
0x0230
0x0231
0x0232
0x0233
0x0234
#if(_WIN32_WINNT >= 0x0400)
/* Value for rolling one detent */
#define WM_MOUSEHOVER
#define WM_MOUSELEAVE
#endif /* _WIN32_WINNT >= 0x0400 */
0x02A1
0x02A3
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
0x0300
0x0301
0x0302
0x0303
0x0304
0x0305
0x0306
0x0307
0x0308
0x0309
0x030A
0x030B
0x030C
0x030D
0x030E
0x030F
0x0310
0x0311
0x0312
WM_CUT
WM_COPY
WM_PASTE
WM_CLEAR
WM_UNDO
WM_RENDERFORMAT
WM_RENDERALLFORMATS
WM_DESTROYCLIPBOARD
WM_DRAWCLIPBOARD
WM_PAINTCLIPBOARD
WM_VSCROLLCLIPBOARD
WM_SIZECLIPBOARD
WM_ASKCBFORMATNAME
WM_CHANGECBCHAIN
WM_HSCROLLCLIPBOARD
WM_QUERYNEWPALETTE
WM_PALETTEISCHANGING
WM_PALETTECHANGED
WM_HOTKEY
#if(WINVER >= 0x0400)
#define WM_PRINT
#define WM_PRINTCLIENT
0x0317
0x0318
#define WM_HANDHELDFIRST
#define WM_HANDHELDLAST
0x0358
0x035F
#define WM_AFXFIRST
#define WM_AFXLAST
#endif /* WINVER >= 0x0400 */
0x0360
0x037F
#define WM_PENWINFIRST
#define WM_PENWINLAST
0x0380
0x038F
#if(WINVER >= 0x0400)
#define WM_APP
#endif /* WINVER >= 0x0400 */
0x8000
/* NOTE: All Message Numbers below 0x0400 are RESERVED.
* Private Window Messages Start Here:
*/
#define WM_USER
#define WM_DDE_FIRST
#define WM_DDE_INITIATE
0x0400
0x03E0
(WM_DDE_FIRST)
#define
#define
#define
#define
#define
#define
#define
#define
#define
WM_DDE_TERMINATE
WM_DDE_ADVISE
WM_DDE_UNADVISE
WM_DDE_ACK
WM_DDE_DATA
WM_DDE_REQUEST
WM_DDE_POKE
WM_DDE_EXECUTE
WM_DDE_LAST
(WM_DDE_FIRST+1)
(WM_DDE_FIRST+2)
(WM_DDE_FIRST+3)
(WM_DDE_FIRST+4)
(WM_DDE_FIRST+5)
(WM_DDE_FIRST+6)
(WM_DDE_FIRST+7)
(WM_DDE_FIRST+8)
(WM_DDE_FIRST+8)
=============================================
ACHTUNG! Nicht lauffähig! Nur Pseudo Code!
=============================================
LRESULT API IDefWindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) {
int i; HBRUSH hbr; HWND hWndT;
switch ( iMsg ) {
case WM_NCCREATE:
// If WS_HSCROLL or WS_VSCROLL, initialize storage for scroll positions.
// NOTE: Scroll bar storage and text storage will be freed automatically
//by Windows during CreateWindow()
if (TestWF(hWnd, (WFHSCROLL | WFVSCROLL))) { // Initialize extra storage for
if (InitPwSB(hWnd) == NULL) return((LONG)FALSE);
}
// Store window text if present.
return((LRESULT)(LONG)DefSetText(hWnd, ((LPCREATESTRUCT)lParam)->lpszName));
case WM_NCCALCSIZE:
// wParam = fCalcValidRects
// lParam = LPRECT rgrc[3]:
//
lprc[0] = rcWindowNew = New window rectangle
//
if fCalcValidRects:
//
lprc[1] = rcWindowOld = Old window rectangle
//
lprc[2] = rcClientOld = Old client rectangle
// On return:
//
rgrc[0] = rcClientNew = New client rect
//
if fCalcValidRects:
//
rgrc[1] = rcValidDst = Destination valid rectangle
//
rgrc[2] = rcValidSrc = Source valid rectangle
CalcClientRect(hWnd, (LPRECT)lParam); break;
case WM_NCHITTEST: // Determine what area the passed coordinate is in.
return((LRESULT)(DWORD)FindNCHit(hWnd, (LONG)lParam));
case WM_NCPAINT: // Do non-client area drawing.
DWP_DoNCPaint(hWnd, (HRGN)wParam); break;
case WM_NCACTIVATE: // Do non-client drawing in response to activation or deactivation.
DWP_DoNCActivate(hWnd, (BOOL)wParam);
return (LRESULT)(DWORD)TRUE;
case WM_CANCELMODE: // Terminate any modes the system might be in,
//such as scrollbar tracking, menu mode, button capture, etc.
DWP_DoCancelMode(hWnd); break;
case WM_SETTEXT: // Set the new text and redraw the caption or icon title window.
DefSetText(hWnd, (LPCSTR)lParam);
DWP_RedrawTitle(hWnd); break;
case WM_GETTEXT: // If the buffer size is > 0, copy as much of the window text as
// will fit (making sure to zero terminate the result).
if (wParam){
if (hWnd->hName)
return (LRESULT)(LONG)TextCopy(hWnd->hName, (LPSTR)lParam, (int)wParam);
// No string: make sure we return an empty string.
((LPSTR)lParam)[0] = 0;
} return (0L);
case WM_GETTEXTLENGTH: // Just return the length of the window text (excluding 0
terminator)
if (hWnd->hName) return((LRESULT)(LONG)lstrlen(TextPointer(hWnd->hName)));
return(0L);
case WM_PAINT:
case WM_PAINTICON:
DWP_Paint( iMsg, hWnd); break;
case WM_ERASEBKGND:
case WM_ICONERASEBKGND:
return (LRESULT)(LONG)DWP_EraseBkgnd(hWnd, iMsg, (HDC)wParam);
case WM_SYNCPAINT:
// This message is sent when SetWindowPos() is trying to get the screen
// looking nice after window rearrangement, and one of the windows involved
// is of another task. This message avoids lots of inter-app message traffic
// by switching to the other task and continuing the recursion there.
// wParam
= flags
// LOWORD(lParam) = hrgnClip
// HIWORD(lParam) = hWndSkip (not used; always NULL)
// hWndSkip is now always NULL.
// NOTE: THIS MESSAGE IS FOR INTERNAL USE ONLY! ITS BEHAVIOR
// IS DIFFERENT IN 3.1 THAN IN 3.0!!
DoSyncPaint(hWnd, NULL, ((WORD)wParam | DSP_WM_SYNCPAINT)); break;
case WM_SYSCOMMAND: SysCommand(hWnd, (int)wParam, lParam);
break;
case WM_ACTIVATE: // By default, windows set the focus to themselves when activated.
if ((BOOL)wParam) SetFocus(hWnd); break;
case WM_SETREDRAW:
// Set or clear the WS_VISIBLE bit, without invalidating the window.
// (Also performs some internal housekeeping to ensure that window
// DC clip regions are computed correctly).
DWP_SetRedraw(hWnd, (BOOL)wParam); break;
case WM_WINDOWPOSCHANGING:
// If the window's size is changing, and the window has
// a size border (WS_THICKFRAME) or is a main window (WS_OVERLAPPED),
// then adjust the new width and height by sending a WM_MINMAXINFO message.
#define ppos ((WINDOWPOS FAR *)lParam)
if (!(ppos->flags & SWP_NOSIZE))
AdjustSize(hWnd, &ppos->cx, &ppos->cy);
#undef ppos
break;
case WM_WINDOWPOSCHANGED:
// If (!(lpswp->flags & SWP_NOCLIENTMOVE)
//
send WM_MOVE message
// If (!(lpswp->flags & SWP_NOCLIENTSIZE)
//
send WM_SIZE message with wParam set based on
//
current WS_MINIMIZED/WS_MAXIMIZED style.
// If DefWindowProc() is not called, WM_MOVE and WM_SIZE messages
// will not be sent to the window.
HandleWindowPosChanged(hWnd, (WINDOWPOS FAR *)lParam);break;
case WM_CTLCOLOR:
// Set up the supplied DC with the foreground and background
// colors we want to use in the control, and return a brush
// to use for filling.
switch (HIWORD(lParam)) {
case CTLCOLOR_SCROLLBAR:
// Background = white
// Foreground = black
// brush = COLOR_SCROLLBAR.
SetBkColor((HDC)wParam, RGB(255, 255, 255));
SetTextColor((HDC)wParam, RGB(0, 0, 0));
hbr = sysClrObjects.hbrScrollbar;
// The scroll bar color may be dithered, so unrealize it.
UnrealizeObject(hbr); break;
default:
// Background = COLOR_WINDOW
// Foreground = COLOR_WINDOWTEXT
// Brush = COLOR_WINDOW
SetBkColor((HDC)wParam, sysColors.clrWindow);
SetTextColor((HDC)wParam, sysColors.clrWindowText);
hbr = sysClrObjects.hbrWindow;
}
return((LRESULT)(DWORD)(WORD)hbr);
case WM_SETCURSOR:
// wParam == hWndHit == hWnd that cursor is over
// lParamL == codeHT == Hit test area code (result of WM_NCHITTEST)
// lParamH == msg
== Mouse message number (may be 0)
// Strategy: First forward WM_SETCURSOR message to parent. If it
// returns TRUE (i.e., it set the cursor), just return. Otherwise,
// set the cursor based on codeHT and msg.
return (LRESULT)(LONG)DWP_SetCursor(hWnd, (HWND)wParam,
LOWORD(lParam), HIWORD(lParam));
case WM_MOUSEACTIVATE:// First give the parent a chance to process the message.
hWndT = GetChildParent(hWnd);
if (hWndT) {
i = (int)(DWORD)SendMessage(hWndT, WM_MOUSEACTIVATE, wParam, lParam);
if (i != 0) return (LRESULT)(LONG)i;
}
// If the user clicked in the title bar, don't activate now:
// the activation will take place later when the move or size occurs.
if (LOWORD(lParam) == HTCAPTION) return((LRESULT)(LONG)MA_NOACTIVATE);
return((LRESULT)(LONG)MA_ACTIVATE);
case WM_SHOWWINDOW:
// If we are being called because our owner window is being shown,
// hidden, minimized, or un-minimized, then we must hide or show
// show ourself as appropriate.
//
// This behavior occurs for popup windows or owned windows only.
// It's not designed for use with child windows.
if (LOWORD(lParam) != 0 && (TestwndPopup(hWnd) || hWnd->hWndOwner)) {
// The WFHIDDENPOPUP flag is an internal flag that indicates
// that the window was hidden because its owner was hidden.
// This way we only show windows that were hidden by this code,
// not intentionally by the application.
//
// Go ahead and hide or show this window, but only if:
//
// a) we need to be hidden, or
// b) we need to be shown, and we were hidden by
//
an earlier WM_SHOWWINDOW message
if ((!wParam && TestWF(hWnd, WFVISIBLE)) ||
(wParam && !TestWF(hWnd, WFVISIBLE) && TestWF(hWnd, WFHIDDENPOPUP)))
// Remember that we were hidden by WM_SHOWWINDOW processing
ClrWF(hWnd, WFHIDDENPOPUP);
if (!wParam) SetWF(hWnd, WFHIDDENPOPUP);
ShowWindow(hWnd, (wParam ? SW_SHOWNOACTIVATE : SW_HIDE));
}
{
}
break;
case
case
case
case
WM_NCLBUTTONDOWN:
WM_NCLBUTTONUP:
WM_NCLBUTTONDBLCLK:
WM_NCMOUSEMOVE:
// Deal with mouse messages in the non-client area.
DWP_NCMouse(hWnd, message, wParam, lParam); break;
case WM_KEYDOWN:
// Windows 2.0 backward compatibility:
// Alias F10 to the menu key
// (only for apps that don't handle WM_KEY* messages themselves)
if ((WORD)wParam == VK_F10) fF10Status = TRUE;
break;
case WM_SYSKEYDOWN:
// Is the ALT key down?
if (HIWORD(lParam) & SYS_ALTERNATE) {
// Toggle only if this is not an autorepeat key
if ((HIWORD(lParam) & SYS_PREVKEYSTATE) == 0) {
if (((WORD)wParam == VK_MENU) && (!fMenuStatus)) fMenuStatus = TRUE;
else
fMenuStatus = FALSE;
}
fF10Status = FALSE;
DWP_ProcessVirtKey((WORD)wParam);
} else {
if ((WORD)wParam == VK_F10) { fF10Status = TRUE;
} else
{
if ((WORD)wParam == VK_ESCAPE) {
if (GetKeyState(VK_SHIFT) < 0) {
SendMessage(hWnd, WM_SYSCOMMAND,(WPARAM)SC_KEYMENU,
(LPARAM)(DWORD)MENUSYSMENU);
}
}
}
} break;
case WM_KEYUP:
case WM_SYSKEYUP:
// Press and release F10 or ALT. Send this only to top-level
// windows, otherwise MDI gets confused. The fix in which
// DefMDIChildProc() passed up the message was insufficient in the
// case a child window of the MDI child had the focus.
//
if ( ((WORD)wParam == VK_MENU && (fMenuStatus == TRUE)) ||
((WORD)wParam == VK_F10 && fF10Status) ) {
SendMessage(GetTopLevelWindow(hWnd), WM_SYSCOMMAND,(WPARAM)SC_KEYMENU, 0L);
}
fF10Status = fMenuStatus = FALSE; break;
case WM_SYSCHAR:
// If syskey is down and we have a char... */
fMenuStatus = FALSE;
if ((WORD)wParam == VK_RETURN && TestWF(hWnd, WFMINIMIZED)) {
// If the window is iconic and user hits RETURN, we want to restore this window.
PostMessage(hWnd, WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L); break;
}
if ((HIWORD(lParam) & SYS_ALTERNATE) && wParam) {
if ((WORD)wParam == VK_TAB || (WORD)wParam == VK_ESCAPE) break;
// Send ALT-SPACE only to top-level windows.
if (((WORD)wParam == MENUSYSMENU) && (TestwndChild(hWnd)))
SendMessage(hWnd->hWndParent, message, wParam, lParam);
else
SendMessage(hWnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU,
(LPARAM)(DWORD)(WORD)wParam);
} else {
// Ctrl-Esc produces a WM_SYSCHAR, but should not beep
if ((WORD)wParam != VK_ESCAPE) MessageBeep(0);
} break;
case WM_CLOSE: // Default WM_CLOSE handling is to destroy the window.
DestroyWindow(hWnd); break;
case WM_QUERYOPEN:
case WM_QUERYENDSESSION:
return((LRESULT)(LONG)TRUE);
case WM_ISACTIVEICON:
return ((LRESULT)(DWORD)(BOOL)(TestWF(hWnd, WFFRAMEON) != 0));
case WM_CHARTOITEM:
case WM_VKEYTOITEM:
// Return -1 to cause default processing
return((LRESULT)-1L);
case WM_DRAWITEM:
#define lpdis
((LPDRAWITEMSTRUCT)lParam)
if (lpdis->CtlType == ODT_LISTBOX)
LBDefaultListboxDrawItem(lpdis);
#undef lpdis
break;
case WM_GETHOTKEY:
return((LRESULT)(LONG)DWP_GetHotKey(hWnd));
break;
case WM_SETHOTKEY:
return((LRESULT)(LONG)SetHotKey(hWnd, (WORD)wParam));
break;
case WM_QUERYDRAGICON:
return((LRESULT)(DWORD)(WORD)DWP_QueryDragIcon(hWnd));
break;
case WM_QUERYDROPOBJECT:
// If the application is WS_EX_ACCEPTFILES, return TRUE.
if (TestWF(hWnd, WEFACCEPTFILES)) return (LRESULT)(DWORD)TRUE;
return (LRESULT)(DWORD)FALSE;
case WM_DROPOBJECT:
return (LRESULT)(DWORD)DO_DROPFILE;
}
// end switch
return(0L);
}
=============================================
ACHTUNG! Nicht lauffähig! Nur Pseudo Code!
=============================================
LRESULT API IDefDlgProc( HWND hWnd, WORD iMsg, WPARAM wParam, LPARAM lParam) {
HWND hWndT1; HWND hWndT2; BOOL result; ((PDLG)hWnd)->resultWP = 0L; result = FALSE;
// Call the dialog proc if it exists
if (((PDLG)hWnd)->lpfnDlg == NULL || !(result = CallDlgProc(hWnd, iMsg, wParam, lParam))) {
// Make sure window still exists.
if (!IsWindow(hWnd)) {
DebugErr(DBF_ERROR, "Dialog window destroyed in dialog callback");
goto ReturnIt;
}
switch (iMsg) {
case WM_ERASEBKGND:
FillWindow(hWnd, hWnd, (HDC)wParam, (HBRUSH)CTLCOLOR_DLG);
return((LRESULT)(LONG)TRUE);
case WM_SHOWWINDOW:
// If hiding the window, save the focus. If showing the window
// by means of a SW_* command and the fEnd bit is set, do not
// pass to DWP so it won't get shown.
if (!wParam) SaveDlgFocus(hWnd);
else if (LOWORD(lParam) && pdlg->fEnd) break;
return(DefWindowProc(hWnd, iMsg, wParam, lParam));
case WM_SYSCOMMAND:
// If we're minimizing and a dialog control has the focus,
// save the hWnd for that control
if ((int) wParam == SC_MINIMIZE) SaveDlgFocus(hWnd);
return( DefWindowProc ( hWnd, iMsg, wParam, lParam ) ) ;
case WM_ACTIVATE:
if ( fDialog = ( wParam != 0 ) ) RestoreDlgFocus( hWnd ) ;
else
SaveDlgFocus( hWnd ) ;
break;
case WM_SETFOCUS:
if (!pdlg->fEnd && !RestoreDlgFocus(hWnd)) DlgSetFocus(GetFirstTab(hWnd));
break;
case WM_CLOSE:
// Make sure cancel button is not disabled before sending the
// IDCANCEL. Note that we need to do this as a message instead
// of directly calling the dlg proc so that any dialog box
// filters get this.
hWndT1 = GetDlgItem( hWnd, IDCANCEL ) ;
if ( hWndT1 && TestWF( hWndT1, WFDISABLED ) ) MessageBeep(0);
else PostMessage(hWnd, WM_COMMAND, (WPARAM)IDCANCEL, MAKELPARAM(hWndT1,
BN_CLICKED));
break;
case WM_NCDESTROY:
fDialog = FALSE;
/* clear this flag */
// Make sure we are going to terminate the mode loop, in case DestroyWindow
// was called instead of EndDialog. We'll RIP in DialogBox2.
((PDLG)hWnd)->fEnd = TRUE;
if (!(hWnd->style & DS_LOCALEDIT)) {
if (((PDLG)hWnd)->hData) {
GlobalUnlock(((PDLG)hWnd)->hData);
ReleaseEditDS(((PDLG)hWnd)->hData);
((PDLG)hWnd)->hData = NULL;
}
}
// Delete the user defined font if any
if (((PDLG)hWnd)->hUserFont) {
DeleteObject((HANDLE)((PDLG)hWnd)->hUserFont);
((PDLG)hWnd)->hUserFont = NULL;
}
// Always let DefWindowProc do its thing to ensure that
// everything associated with the window is freed up.
DefWindowProc(hWnd, iMsg, wParam, lParam);
break;
case DM_SETDEFID:
if (!(((PDLG)hWnd)->fEnd)) {
// Make sure that the new default button has the highlight.
// We need to ignore this if we are ending the dialog box
// because hWnd->result is no longer a default window id but
// rather the return value of the dialog box.
//
// Catch the case of setting the defid to null or setting
// the defid to something else when it was initially null.
//
CheckDefPushButton(hWnd,
(((PDLG)hWnd)->result ? GetDlgItem(hWnd, ((PDLG)hWnd)->result) : NULL),
(wParam
? GetDlgItem(hWnd, (int) wParam
) : NULL) );
((PDLG)hWnd)->result = (int)wParam;
} return((LRESULT)(DWORD)TRUE);
case DM_GETDEFID:
if (!((PDLG)hWnd)->fEnd && ((PDLG)hWnd)->result)
return(MAKELRESULT(((PDLG)hWnd)->result, DC_HASDEFID));
else return(0L);
case WM_NEXTDLGCTL:
// This message is so TAB-like operations can be properly handled
// (simple SetFocus won't do the default button stuff)
//
hWndT2 = hWndFocus;
if (LOWORD(lParam)) {
if (hWndT2 == NULL) hWndT2 = hWnd;
// wParam contains the hWnd of the ctl to set focus to
hWndT1 = (hWnd)wParam;
} else {
if (hWndT2 == NULL) { // Set focus to the first tab item.
hWndT1 = GetFirstTab(hWnd);
hWndT2 = hWnd;
} else { // If window with focus not a dlg ctl, ignore message.
if (!IsChild(hWnd, hWndT2)) return((LRESULT)(LONG)TRUE);
// wParam = TRUE for previous, FALSE for next
hWndT1 = GetNextDlgTabItem(hWnd, hWndT2, (BOOL)wParam);
}
}
DlgSetFocus(hWndT1);
CheckDefPushButton(hWnd, hWndT2, hWndT1);
return((LRESULT)(LONG)TRUE);
case WM_ENTERMENULOOP:
case WM_LBUTTONDOWN:
case WM_NCLBUTTONDOWN:
// PLEASE NOTE: The following code is a VERY UGLY compatibility
// hack. NEVER write code that looks at the window proc address
// in order to determine the window type. The following code will
// not work with subclassed combo or edit controls.
//
if (hWndT1 = hWndFocus) {
if (hWndT1->pcls->lpfnWndProc == ComboBoxCtlWndProc) {
// If user clicks anywhere in dialog box and a combo box (or
// the editcontrol of a combo box) has the focus, then hide
// it's listbox.
SendMessage(hWndT1, CB_SHOWDROPDOWN, FALSE, 0L);
} else {
if (hWndT1->pcls->lpfnWndProc == EditWndProc &&
hWndT1->hWndParent->pcls->lpfnWndProc==ComboBoxCtlWndProc)
{
SendMessage(hWndT1->hWndParent,CB_SHOWDROPDOWN, FALSE, 0L);
}
}
} return(DefWindowProc(hWnd, iMsg, wParam, lParam));
case WM_GETFONT:
return (LRESULT)(DWORD)(WORD)((PDLG)hWnd)->hUserFont;
// We don't want to pass the following messages to DefWindowProc:
// instead, return the value returned by the dialog proc (FALSE)
case WM_VKEYTOITEM:
case WM_COMPAREITEM:
case WM_CHARTOITEM:
case WM_INITDIALOG:
break;
default:
return(DefWindowProc(hWnd, iMsg, wParam, lParam));
}
}
ReturnIt:
// These messages are special cased in an unusual way: the return value
// of the dialog function is not BOOL fProcessed, but instead it's the
// return value of these messages.
//
if (iMsg == WM_CTLCOLOR ||
iMsg == WM_COMPAREITEM ||
iMsg == WM_VKEYTOITEM ||
iMsg == WM_CHARTOITEM ||
iMsg == WM_QUERYDRAGICON ||
iMsg == WM_INITDIALOG) {
return((LRESULT)(DWORD)result);
}
return(((PDLG)hWnd)->resultWP);
}
BOOL SaveDlgFocus(HWND hWnd) {
if (hWndFocus && IsChild(hWnd, hWndFocus) && !((PDLG)hWnd)->hWndFocusSave) {
((PDLG)hWnd)->hWndFocusSave = hWndFocus;
RemoveDefaultButton(hWnd, hWndFocus);
return(TRUE);
}
return(FALSE);
}
BOOL RestoreDlgFocus(HWND hWnd) {
BOOL fRestored = FALSE;
if (((PDLG)hWnd)->hWndFocusSave && !TestWF(hWnd, WFMINIMIZED)) {
if (IsWindow(((PDLG)hWnd)->hWndFocusSave)) {
CheckDefPushButton(hWnd, hWndFocus, ((PDLG)hWnd)->hWndFocusSave);
SetFocus(((PDLG)hWnd)->hWndFocusSave);
fRestored = TRUE;
} ((PDLG)hWnd)->hWndFocusSave = NULL;
} return(fRestored);
}
Objekte
Windows-Objekte werden mit einem Handle identifiziert. Ein Zugriff auf intern von Windows gespeicherten Daten ist nur mit
Zugriffsfunktionen möglich ( Sytem - Konsistenz, GetWindowLong(),SetWindowLong(), GetClassLong(),SetClassLong() ).
●
●
●
●
Ein Objekt hat nur ein Handle.
Ein Duplizieren eines Handles ist nicht sinnvoll.
Handles sind public für alle Prozesse.
Ein Benutzer kann maximal 65536 Handles verwenden.
Die folgende Tabelle enthält ( Benutzer - ) Objekte.
User
Objects
Creator function
Accelerator CreateAcceleratorTable
table
Destroyer function
User Objects
Creator function
Destroyer function
DestroyAcceleratorTable Cursor
LoadCursor, GetCursor,
CreateCursor SetCursor
DestroyCursor
GetThreadDesktop
Applications cannot
delete this object.
DDE
conversation
DdeConnect, DdeConnectList,
DdeQueryNextServer,
DdeReconnect
DdeDisconnect,
DdeDisconnectList
Hook
SetWindowsHook,
SetWindowsHookEx
UnhookWindowsHook, Menu
UnhookWindowsHookEx
CreateMenu,
CreatePopupMenu, GetMenu,
GetSubMenu,
GetSystemMenu,LoadMenu,
LoadMenuIndirect
DestroyMenu
Window
CreateWindow,
CreateWindowEx,
CreateDialogParam,
CreateDialogIndirectParam,
CreateMDIWindow,
FindWindow, GetWindow,
GetClipboardOwner,
GetDesktopWindow,
GetDlgItem,
GetForegroundWindow,
GetLastActivePopup,
GetOpenClipboardWindow,
GetTopWindow,
WindowFromDC,
WindowFromPoint, and others
DestroyWindow
BeginDeferWindowPos
EndDeferWindowPos
Window
station
GetProcessWindowStation
Applications cannot
delete this object.
Desktop
Window
position
Lebensdauer von Objekten
Applikationen können Objekte erzeugen und verwenden. Objekte entsprechen Instanzen ( Bitmuster im Speicher ). Ein Objekt kann auch von
mehreren Applikationen benutzt werden ( shared ). Das Betriessystem erzeugt und nutzt ( Stock - ) Objekte, die von Applikationen ( ohne
Freigabe ) genutzt werden können.
Typ
Gebunden durch
Sichtbarkeit
Lebensdauer
Overhead
Automatic
Compiler
Funktion
Funktion
0 (Stackwort)
Static
Linker
( Lader )
Programm, Block
Programm
0 (Allignment)
Heap
System
allokiert
Programm, Block
Programm, Block
32 Byte
( System bei shared ) bis zur Freigabe
( System bei shared )
Resourcen
RC-Compiler
( Linker, Lader )
GDI Objekte
USER-Funktionen
System
( Linker mit *.lib, Lader ) ( Programm )
User Objekte Linker
Programm, Block
(System bei stock)
Programm, Block
Programm
(System bei stock)
ca. 32 Byte
Programm, Block
bis zur Freigabe
( System bei stock )
ca. 30-50 Byte
Programm, Block
bis zur Freigabe
ca. 30-50 Byte
Bei Win16 gibt es den lokalen Heap ( schnell, klein, gehört dem Programm, 6 Byte Overhead ) und den globalen Heap ( groß, gehört dem
Programm/System, 24 Byte Overhead ).
Gegenüberstellung
Viele C Run-time Funktionen haben ein Win32-Äquivqlent ( API: application programming interface ). Funktionen mit (*) existieren nur bei 16bit C Run-time. Im folgenden werden statische C-run-time Funktionen und dynamischen Win32-Funktionen gegenüber gestellt.
String Manipulation
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
lstrcat
none
lstrcmp
strcat, wcscat
strchr, wcschr
strcmp, wcscmp
lstrcpy
none
strcpy, wcscpy
strcspn, wcscspn none
_strdup, _wcsdup
FormatMessage _strerror
FormatMessage _stricmp, _wcsicmp lstrcmpi
strerror
CharLower,
lstrlen
none
strlen, wcslen
_strlwr, _wcslwr
strncat, wcsncat
CharLowerBuffer
strncmp, wcsncmp none
strncpy, wcsncpy none
_strnicmp, _wcsnicmp none
FillMemory,
none
_strnset, _wcsnset
strpbrk, wcspbrk none
strrchr, wcsrchr
ZeroMemory
FillMemory,
none
_strrev, _wcsrev none
_strset, _wcsset
strspn, wcsspn
ZeroMemory
CharUpper,
none
none
strstr, wcsstr
strtok, wcstok
_strupr, _wcsupr
CharUpperBuffer
Buffer Manipulation
C-Run-time Win32 C-Run-time
Win32
C-Run-time Win32 C-Run-time
Win32
none
CopyMemory
_memccpy none memchr
memcmp none
memcpy
FillMemory,
none
_memicmp none memmove MoveMemory memset
_swab
ZeroMemory
C-Runtime
Win32
isalnum
IsCharAlphaNumeric
__iscsym
none
islower
isupper
_tolower
IsCharLower,
GetStringTypeW
(Unicode)
IsCharUpper,
GetStringTypeW
(Unicode)
none
Character Classification
C-RunC-Run-time
Win32
time
IsCharAlpha,
GetStringTypeW
isalpha
__isascii
(Unicode)
__iscsymf
none
isdigit
isprint
none
ispunct
isxdigit
toupper
none,
GetStringTypeW
(Unicode)
CharUpper
Win32
none
none,
GetStringTypeW
(Unicode)
none,
GetStringTypeW
(Unicode)
__toascii
none
_toupper
none
C-Runtime
Win32
iscntrl
none,
GetStringTypeW
(Unicode)
isgraph
none
isspace
none,
GetStringTypeW
(Unicode)
tolower
CharLower
Directory Control
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
SetCurrentDirectory
SetCurrentDirectory
GetCurrentDirectory
GetCurrentDirectory
_chdir
_chdrive
_getcwd
_getdrive
CreateDirectory
RemoveDirectory _searchenv SearchPath
_mkdir
_rmdir
File Handling
C-Run-time Win32 C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
none
SetFileAttributes _chsize
SetEndOfFile
GetFileSize
_access
_chmod
_filelength
See Note 5 _fullpath GetFullPathName _get_osfhandle none
GetFileType
_fstat
_isatty
LockFileEx _makepath none
GetTempFileName _open_osfhandle none
_locking
_mktemp
DeleteFile rename
MoveFile
none
none
remove
_setmode
_splitpath
none
none
DeleteFile
_stat
_umask
_unlink
Creating Text Output Routines
C-Run-time
Win32
C-Run-time
Win32
SetConsoleCursorInfo
_displaycursor*
_gettextcolor* GetConsoleScreenBufferInfo
GetConsoleCursorInfo
_gettextcursor*
_gettextposition* GetConsoleScreenBufferInfo
WriteConsole
_gettextwindow* GetConsoleWindowInfo _outtext*
SetConsoleTextAttribute
_scrolltextwindow* ScrollConsoleScreenBuffer _settextcolor*
SetConsoleCursorInfo
_settextcursor*
_settextposition* SetConsoleCursorPosition
SetConsoleMode
_settextwindow* SetConsoleWindowInfo
_wrapon*
C-Run-time
Win32
none
clearerr
none
feof
_fgetchar none
none
_flushall
Stream Routines
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
CloseHandle
none
fclose
_fcloseall none
_fdopen
none
FlushFileBuffers fgetc
none
ferror
fflush
none
none
none
fgetpos
fgets
_fileno
CreateFile
none
none
fopen
fprintf
fputc
freopen
none
ReadFile
SetStdHandle
fputs
fread
(std handles)
SetFilePointer
SetFilePointer _fsopen
CreateFile
fseek
fsetpos
_fputchar
none
fscanf
none
SetFilePointer
fwrite
(check return value)
none
_getw
none
puts
none
scanf
none
sprintf
none
tmpnam
none
_vsnprintf
ftell
gets
putchar
_rmtmp
_snprintf
tmpfile
vprintf
WriteFile
getc
none
printf
none
_putw
none
setbuf
wsprintf
sscanf
GetTempFileName ungetc
none
vsprintf
none
getchar
none
none
none
none
none
none
wvsprintf
putc
rewind
setvbuf
_tempnam
vfprintf
none
SetFilePointer
none
GetTempFileName
none
Low-Level I/O
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
_lclose, CloseHandle _commit
FlushFileBuffers _creat
_lcreat, CreateFile
DuplicateHandle
_close
_dup
none
none
_llseek, SetFilePointer _open
_lopen, CreateFile
_dup2
_eof
_lseek
SetFilePointer
_lread, ReadFile
CreateFile
_lread
_read
_sopen
_tell
_write
(check return value)
C-Run-time
Win32
none
_cgets
Console and Port I/O Routines
C-Run-time
Win32
C-Run-time Win32 C-Run-time
Win32
none
none _cscanf
none
_cprintf
_cputs
_getch
_kbhit
_ungetch
ReadConsoleInput _getche
PeekConsoleInput _outp
none
ReadConsoleInput _inp
none
_outpw
none
none
_inpw
_putch
none
WriteConsoleInput
Memory Allocation
C-RunC-Run-time
Win32
C-Run-time Win32
Win32
C-Run-time
Win32
time
none
GlobalAlloc
_alloca
_bfreeseg* none
_bheapseg* none
calloc
none
GlobalFree _freect*
GlobalMemoryStatus _halloc*
GlobalAlloc
_expand
free
none
none
_heapadd
_heapchk none
_heapmin none
_heapset
none
GlobalFree malloc
GlobalAlloc
GlobalMemoryStatus
_heapwalk
_hfree*
_memavl
GlobalMemoryStatus _msize*
GlobalSize realloc
GlobalReAlloc
_memmax
_set_new_handler none
_set_hnew_handler* none
_stackavail* none
Process and Environment Control Routines
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
C-Run-time Win32
none
none
none
none
abort
assert
atexit
_cexit
none
ExitProcess
ExitProcess
_c_exit
_exec functions none
exit
_exit
GetEnvironmentVariable _getpid
GetCurrentProcessId
none
none
getenv
longjmp
_onexit
FormatMessage
SetEnvironmentVariable raise
RaiseException setjmp
none
perror
_putenv
signal
SetConsoleCtrlHandler _spawn functions CreateProcess
CreateProcess
system
(ctrl-c only)
Klassen - Objekte
Fenster - Objekte
Alle existierenden Fenster-Objekte können in einer Schleife durchlaufen werden. Im folgenden Beispiel wird von einem existierenden hWndFenster gestartet und das erste Fensterhandle mit GetWindow( hWnd, GW_HWNDFIRST ) geholt. Die verkettete Liste endet mit hNext ==
NULL.
Beispiel CreateWindow(), DestroyWindow()
Eine Applikation führe z.B. CreateWindow() aus. CreateWindow() erzeugt im Speicher ein Window - Objekt und lieferte ein gültiges Handle.
Nach dem Create... kann das Objekt verwendet werden. Durch DestroyWindow() wird das Objekt vernichtet. Der reservierten Speicher wird frei
gegeben. Das Fenster - Handle wird ungültig und darf nicht mehr verwendet werden.
Die Liste der vorhandenen Fenster-Objekte kann durchlaufen werden. Mit dem erhaltenen Handle können die zugänglichen Fenster-Daten
ausgelesen bzw. vewendet werden. Hie ein Beispiel:
CHAR buf[256]; CHAR pStr[5000]; CHAR * p = pStr;
for ( HWND hNext = GetWindow( hWnd, GW_HWNDFIRST );
hNext != NULL ;
hNext = GetWindow( hNext, GW_HWNDNEXT))
{
if ( GetWindowText( hNext,buf,sizeof(buf)) )
if ( IsWindowVisible( hNext )
&& ( (p-pStr) < sizeof(pStr)-sizeof(buf)))
{
p += wsprintf( p, "%s\n", buf );
} else { p += wsprintf( p,"\t%s\n", buf ); }
} MessageBox( hWnd, pStr, "Alle Fenster:", MB_OK);
Wurde mit WNDCLASS.cbWndExtra=sizeof( void * ) bei Windows für jedes Fenster zusätzlicher Benutzer - Speicher ( 4 Byte ) reserviert, so
kann z.B. mit SetWindowLong() ein Zeiger auf einen vom Benutzer allokierten MYSTRUCT - Heap - Speicher hinterlegt werden.
MYSTRUCT * p = ( MYSTRUCT * ) GetWindowLong( hNext, DWL_USER ) ;
if ( ! IsBadReadPtr( p, sizeof(MYSTRUCT) ) {
... // mit p kann lesend auf MYSTRUCT zugegriffen werden
}
Beim Zugriff auf diesen Speicher kann mit IsBadReadPtr( p, sizeof(MYSTRUCT) geprüft werden, ob dieser Speicher gültig und benutzbar ist.
GDI - Objekte
Die GDI - DLL enthält ( viele ) Funktionen. Hier sollen lediglich einige GDI - Funktionen zum Zeichnen und Schreiben ausgewählt und
behandelt werden. Das Erstellen und Aktualisieren des Bildschirmes erfolgt durch die WM_PAINT - Nachricht.
Device Kontext
Die meisten GDI - Funktionen benutzen globale Daten ( Seiten - Effekt ) aus dem als Device - Kontext. Der Funktions - Parameter ist HDC
hDC. Bei der WM_NCPAINT und WM_NCACTIVATE - Nachrichten - Behandlung wird der Device - Kontext benutzt.
Unter case iMsg = WM_PAINT wird der Device - Kontext z.B. gemäß
case WM_PAINT :
hDC = BeginPaint( hWnd, & ps )
GetClientRect
( hWnd, & rect
DrawText
( hDC, "Hallo,
| DT_VCENTER ) ;
EndPaint
( hWnd, & ps )
break ; //return 0;
;
) ;
Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER
;
benutzt. Die Aktualisierung findet im Client - Bereich statt. Durch GetWindowDC() oder GetDCEx() mit DCX_WINDOW kann der Device Kontext für das gesamte Fenster ( incl. not Client - Bereich mit (0,0) oben links, clipping region ) erhalten werden. Nach der Benutzung ist
dieser Device - Kontext durch ReleaseD() wieder frei zu geben.
Ist der Device - Kontext bekannt, so kann durch hWnd WindowFromDC( HDC hDC ); das Fenster - Handle ermittelt werden.
Funktionen zum Zeichnen MoveToEx(), LineTo(),
Polyline()
Unter WM_PAINT wird mit MoveToEx(), LineTo() eine x - Achse gezeichnet. Die y - Werte von POINT pt [NUM] - Array werden mit den
sin() - Werten gefüllt. Mit Polyline() wird die Folge von Punkten gezeichnet.
#include <math.h>
#define NUM
1000
#define TWOPI (2 * 3.14159)
LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) {
static int cxClient, cyClient ; POINT pt [NUM] ;
switch ( iMsg ) {
case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; break;
case WM_PAINT: {
PAINTSTRUCT ps ; HDC hDC ;
hDC = BeginPaint ( hWnd , &ps ) ;
MoveToEx ( hDC, 0,
cyClient / 2, NULL) ;
LineTo
( hDC, cxClient, cyClient / 2) ;
for ( int i = 0 ; i < NUM ; i++ ) {
pt[i].x = i * cxClient / NUM ;
pt[i].y = ( int ) ( cyClient / 2 * ( 1 - sin( TWOPI * i / NUM ) ) ) ;
}
Polyline ( hDC, pt, NUM ) ;
EndPaint ( hWnd, & ps ) ;
EndPaint();
} return 0 ;
case WM_DESTROY: PostQuitMessage (0) ; return 0 ;
}
return DefWindowProc ( hWnd , iMsg, wParam, lParam ) ;
}
Rectangle(), MoveToEx(), LineTo(), MoveToEx(),
LineTo(), Ellipse(), RoundRect()
In dem folgenden Beispiel wird in WM_SIZE die aktuelle Client - Fenster - Größe in den static - Variablen int cxClient, cyClient hinterlegt.
Unter WM_PAINT werden die Funktionen Rectangle(), MoveToEx(), LineTo(), MoveToEx(), LineTo(), Ellipse(), RoundRect() aufgerufen.
LRESULT CALLBACK WndProc( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) {
static int cxClient, cyClient ; HDC hDC ; PAINTSTRUCT ps ;
switch ( iMsg ) {
case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; break;
case WM_PAINT:
hDC = BeginPaint ( hWnd , & ps ) ;
Rectangle ( hDC,cxClient/8, cyClient/8, 5*cxClient/8, 5*cyClient/8) ;
MoveToEx ( hDC, 0,
0,
NULL ) ;
LineTo
( hDC, cxClient, cyClient ) ;
MoveToEx ( hDC, 0,
cyClient, NULL ) ;
LineTo
( hDC, cxClient, 0 ) ;
Ellipse
( hDC,cxClient/8,cyClient/8,5*cxClient/8,5*cyClient/8) ;
RoundRect (
hDC,cxClient/5,cyClient/5,2*cxClient/5,2*cyClient/5,cxClient/5,cyClient/5 ) ;
EndPaint ( hWnd , & ps ) ;
break; //return 0 ;
case WM_DESTROY: PostQuitMessage (0) ; return 0 ;
}
return DefWindowProc ( hWnd , iMsg, wParam, lParam ) ;
}
Funktionen zum Schreiben TextOut()
Die TextOut() - Funktion wird in der CALLBACK - FUnktion unter iMsg = WM_PAINT etwa in der folgende Art aufgerufen:
case WM_PAINT:
hDC = BeginPaint ( hWnd , & ps ) ;
SelectObject( hDC, GetStockObject( SYSTEM_FONT ) );
//
x
y
012345678901234
TextOut( hDC, 50, 50, "TextOut Example", 15 );
TextOut( hDC, 50, 75, "_______________", 15 );
TextOut( hDC, 50, 100, "1.Zeile",
7 );
TextOut( hDC, 50, 125, "2.Zeile",
7 );
TextOut( hDC, 50, 150, "3.Zeile",
7 );
TextOut( hDC, 50, 175, "4.Zeile",
7 );
TextOut( hDC, 50, 200, "5.Zeile",
7 );
TextOut( hDC, 50, 225, "6.Zeile",
7 );
TextOut( hDC, 50, 250, "7.Zeile",
7 );
TextOut( hDC, 50, 275, "8.Zeile",
7 );
TextOut( hDC, 50, 300, "9.Zeile",
7 );
EndPaint ( hWnd , & ps ) ;
break;
Beispiel: DrawText()
Die DrawText() - Funktion benutzt den Device Kontext hDC, der u.a. den ausgewählten Font, die Text - Farbe und die Text - Hintergrund Farbe enthält.
●
Die DrawText() - Funktion schreibt einen String *lpString in ein umschließendes Rechteck *lpRect.
Falls die Anzahl der auszugebenden Zeichen nCount = -1 ist, so muß *lpRect ein 0 terminierter String sein. Der Text kann gemäß expandierender
Tabs, der Ausrichtung ( Linksbündig, Rechtsbündig, Zentriert ), der Umbrüche am Zeilenrand, usw. justiert werden. Diese Funktion verwendet
intern TextOut(). Die DrawText() gibt die Höhe des Textes zurück.
int DrawText(
HDC hDC,
LPCTSTR lpString,
int nCount,
LPRECT lpRect,
UINT uFormat
);
//
//
//
//
//
handle to device context
pointer to string to draw
string length, in characters
pointer to struct with formatting dimensions
text-drawing flags
Für uFormat können die Konstanten
DT_BOTTOM,
DT_END_ELLIPSIS oder
DT_INTERNAL,
DT_NOPREFIX,
DT_TABSTOP,
DT_WORD_ELLIPSIS
DT_CALCRECT,
DT_PATH_ELLIPSIS,
DT_LEFT,
DT_RIGHT,
DT_TOP,
DT_CENTER,
DT_EXPANDTABS,
DT_MODIFYSTRING,
DT_RTLREADING,
DT_VCENTER,
DT_EDITCONTROL,
DT_EXTERNALLEADING,
DT_NOCLIP,
DT_SINGLELINE,
DT_WORDBREAK,
benutzt werden. Für eine bequemere Benutzung können die benötigten uFormat - FLags unter einer Zahl < -1 angesprochen werden. Die
folgende Funktion int Draw_Text( ) setzt für uFormat = -1, bzw. 0 die gewünschten uFormat - FLags. Falls ( y1 >= y2 ) ist, so wird DrawText()
benutzt, um mit DT_CALCRECT die benötigte Rechteckgröße zu ermitteln.
int Draw_Text (
HDC hDC,
//Handle für den Device Kontext
LPCTSTR lpString , //auszugebender String
int nCount ,
//falls nCount <= 0 ist, so muss ein \0-String vorliegen
und
//es wird dann automatisch strlen ( lpString ) benutzt
LPRECT lpRect ,
//umschließendes Recheck
int uFormat
// Window DrawText-Format, wie z.B.
//
( DT_CENTER / DT_LEFT / DT_RIGHT )
//
( DT_VCENTER / DT_TOP / DT_BOTTOM )
) {
RECT rcText; UINT Fmt ; int dx , dy ; if ( ( lpString == NULL ) || ( hDC ==
NULL ) ) return 0 ;
if ( lpRect != NULL ) { rcText = * lpRect ;
} else { HWND hWnd = WindowFromDC( hDC ); GetClientRect( hWnd , & rcText );
}
if ( uFormat < 0 ) { // DEFAULT
Fmt = DT_EXTERNALLEADING | DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_NOPREFIX
| DT_WORDBREAK ;
} else if ( uFormat == 0 ) {
Fmt = DT_EXTERNALLEADING | DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ;
} else {
Fmt = uFormat ;
}
int x1 = rcText.left ; int y1 = rcText.top ;
int x2 = rcText.right ; int y2 = rcText.bottom ;
if ( y1 >= y2 ) { SetTextAlign ( hDC, TA_NOUPDATECP | TA_LEFT | TA_TOP ) ;
DrawText ( hDC, lpString, nCount, & rcText, Fmt | DT_CALCRECT ) ;
dx = x2 - x1 ; dy = y2 - y1 ;
if ( ( Fmt & DT_CENTER ) || ( Fmt & DT_RIGHT ) ) {
if ( Fmt & DT_CENTER ) dx >>= 1 ;
if ( dx > x1 ) dx = x1 ;
x1 -= dx ; x2 -= dx ;
}
if ( ( Fmt & DT_VCENTER ) || ( Fmt & DT_BOTTOM ) ) {
if ( Fmt & DT_VCENTER ) dy >>= 1 ;
if ( dy > y1 ) dy = y2 ;
y1 -= dy ; y2 -= dy ;
}
SetRect ( & rcText, x1, y1, x2, y2 ) ;
}
return DrawText ( hDC , lpString , nCount , & rcText , Fmt ) ;
}
Resourcen
Um einen ausführbaren, binär - File ( *.EXE ) zu erzeugen, müssen ASCII - Files in Maschinen-Code übersetzt werden:
*.C, *.CPP
*.H, *.RC
*.OBJ, *.DEF
(*.EXE), *.RES
===>
===>
===>
===>
Compiler
Resourcen-Compiler
Linker
Resourcen-Compiler
===>
===>
===>
===>
*.OBJ
*.RES
(*.EXE)
*.EXE
Die *.RC - Resourcen - Files ( ASCII ) enthalten z.B.
●
●
●
Filenamen für Bilder ( Mauszeiger, Rasterbilder, Icons ),
Text - und Hotkey - Tabellen,
Menu - und Dialog - Beschreibungen.
Die *.RC - Resourcen - Files ( ASCII ) können "von Hand" geschrieben werden, aber vielfach ist die "visuelle Erstellung" mit einem Tool ( Resourcen
Workshop ) bequemer. Das Tool benutzt einen binäre Hilfsfiles und generiert automatisch den *.RC - ASCII - File und den zugehörigen *.H-File für die
Identifizierer. Die *.RC - Syntax wird bei der automatsichen Generierung berücksichtigt und braucht nicht gelernt werden. Durch den Resourcen-Compiler wird
der *.RC - File in einen binären *.RES - File übersetzt.
Eine "visuelle Erstellung" ändert, ergänzt und überschreibt den alten *.RC - ASCII - File automatisch. Eine *.RC - Erstellung sollte entweder "von Hand" oder
durchgängig "visuelle" mit einem Tool erstellt werden.
Weil im *.RC - File auch WS_ - , DS_ -, SS_ - Windows - Konstanten benutzt werden, so ist deren Bedeutung bei der Erzeugung von Dialog-Rssourcen ( trotz
Automatik ) zu kennen.
*.RC-Syntax
Die *.RC - ASCII - Datei wird mit dem Resourcen-Compiler in eine *.RES - Binärdatei übersetzt. Der allgemeiner Aufbau einer *.RC Zeile ist:
ID - Identität RC-Typ Speicheroperationen Datenquelle auch BEGIN ... END
Die Speicher - Operationen PRELOAD ( nur Win16: mit *.exe geladen), LOADONCALL ( nur Win16: bei Ausführung geladen), FIXED ( nur Win16:
Resource bleibt an fester Adresse ), MOVEABLE ( nur Win16: Resource kann verschoben werden ), DISCARDABLE ( nur Win16: Resource kann entfernt
werden ).
Im C/C++ - Programm wird mit der ID - Identität ( identifizierende Zahl ) auf die Resource zugegriffen. Die Resourcen entsprechen einer Aufzählung von
benötigten, lesbaren Daten. Deshalb ist im *.RC-File die Reihenfolge der Resourcen nicht wesentlich.
Für Dialoge werden Control Parameter ( wie z.B. PUSHBUTTON or CHECKBOX ) verwendet. Die Breite cx wird in 1/4-character units angegeben. Die
Höhe cy wird in 1/8-character units angegeben. Controls ( innerhalb eines Rssourcen-Templates ) haben die Syntax:
Control-Typ [text,] id,
x, y, cx, cy [, style [, extended-style]]
Diese CONTOLS gehören zu einer ( in Windows enthaltenen ) Klasse, wie z:b: "BUTTON", "EDIT", "LISTBOX", "SCROLLBAR", "COMBOBOX".
Alternativ können Klassen ( mit Prefix: 0xFFFF ) auch identifiziert werden. Zu jeder Klasse ist eine zugehörige CALLBACK-Funktion implizit verfügbar. Mit
Hilfe von GetClassInfoEx() können die Daten in wcx geschrieben werden. Die Dialog-Klasse MAKEINTRESOURCE(0x8002) z.B. durch
GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx). Beispiele:
#define
#define
#define
#define
#define
#define
BUTTON
EDIT
STATIC
LISTBOX
SCROLLBAR
COMBOBOX
0x80
0x81
0x82
0x83
0x84
0x85
WNDCLASSEX wcx = {0};
GetClassInfoEx(GetModuleHandle(0),"EDIT",
&wcx);
GetClassInfoEx(GetModuleHandle(0),"BUTTON", &wcx);
GetClassInfoEx(GetModuleHandle(0),"COMBOBOX",&wcx);
GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx);
Zur Vereinfachung der Ressourcen-Schreinweise enthält Windows die folgenden ( vor - ) definierten Dialog - Elemente ( #define´s ):
Vereinfachung
entspricht dem CONTROL ...
#define LTEXT text, id, x, y, cx, cx, style
CONTROL text, id, "Static", SS_LEFT | WS_GROUP | style, x, y, cx, cy
#define CTEXT text, id, x, y, cx, cx, style
CONTROL text, id, "Static", SS_CENTER | WS_GROUP | style, x, y, cx, cy
#define RTEXT text, id, x, y, cx, cx, style
CONTROL text, id, "Static", SS_RIGHT | WS_GROUP | style, x, y, cx, cy
#define SCOLLBAR text, id, x, y, cx, cx, style CONTROL "", id, "Static", SBS_HORZ | style, x, y, cx, cy
#define ICON text, id, x, y, cx, cx, style
CONTROL text, id, "Static", SS_ICON | style, x, y, cx, cy
#define PUSHBUTTON
text, id, x, y, cx, cx, style
CONTROL text, id, "Button", BS_PUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy
#define DEFPUSHBUTTON
text, id, x, y, cx, cx, style
CONTROL text, id, "Button", BS_DEFPUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy
#define RADIOBUTTON
text, id, x, y, cx, cx, style
CONTROL text, id, "Button", BS_RADIOBUTTON | WS_TABSTOP | style, x, y, cx, cy
#define CHECKBOX text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_CHECKBOX | WS_TABSTOP | style, x, y, cx, cy
#define GROUPBOX text, id, x, y, cx, cx, style CONTROL text, id, "Button", BS_GROUPBOX | WS_TABSTOP | style, x, y, cx, cy
#define COMBOBOX text, id, x, y, cx, cx, style CONTROL text, id, "Combobox", CBS_SIMPLE | WS_TABSTOP | style, x, y, cx, cy
#define EDITTEXT text, id, x, y, cx, cx, style
CONTROL text, id, "Edit", ES_LEFT | WS_BORDER | WS_TABSTOP | style, x, y, cx, cy
Vordefinierte Resourcen - Typen
Für die vordefinierte Resourcen - Typen gibt es die Konstanten:
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
RT_CURSOR
RT_BITMAP
RT_ICON
RT_MENU
RT_DIALOG
RT_STRING
RT_FONTDIR
RT_FONT
RT_ACCELERATOR
RT_RCDATA
RT_MESSAGETABLE
MAKEINTRESOURCE(1)
MAKEINTRESOURCE(2)
MAKEINTRESOURCE(3)
MAKEINTRESOURCE(4)
MAKEINTRESOURCE(5)
MAKEINTRESOURCE(6)
MAKEINTRESOURCE(7)
MAKEINTRESOURCE(8)
MAKEINTRESOURCE(9)
MAKEINTRESOURCE(10)
MAKEINTRESOURCE(11)
//für Mauszeiger
//für Rasterbilder
//Symbol - Rasterbilder
//für Menuleisten
//für Dialogfelder
//für Stringtabellen
//Verzeichnisse der Schriftarten
//für Schriftarten
//für Tastaturkürzel
//für Daten ohne feste Bindung
//für Nachrichten
MAKEINTRESOURCE() - Macro
Der Kern des Betriebssystems vewaltet Atome. Einem String wird ein Hash - Code zugeordnet. Bei Resourcen werden i.a. WORD ID_ ... - Identifizierer
verwendet. Benötigt eine Windows - Funktion den zugeordneten String, so kann das MAKEINTRESOURCE() - Macro verwendet werden. Das
MAKEINTRESOURCE() - Macro ist definiert durch
#define MAKEINTRESOURCE( idRes ) (LPSTR)((DWORD)((WORD)( idRes )))
Resourcen - Itentifizierer
Ressourcen-Tools ( AppWizard zur Erzeugung der *.RC - Quelltexte ) benutzen i.a. typische Präfixe für die Identifizierer ( z.B. #define IDD_DIALOG1 1000:
(I)(D)entifiziere-einen_(D)ialog 1 ). Diese Identifizierer sind WORD - Zahlen und werden oft durch MAKEINTRESOURCE(IDD_DIALOG1) übergeben. In
dem jeweiligen Kontext müssen die Identifizierer so geählt werden, daß diese eindeutig sein. Die MFC - Konvention schlägt die folgenden Präfixe vor.
Prefix
Type of Symbol
Example
Range
IDR_
Identification shared by multiple
resources of different types
IDR_MAINFRAME
1 to 0x6FFF
IDD_
Dialog resource
IDD_SPELL_CHECK
1 to 0x6FFF
HIDD_SPELL_CHECK
0x20001 to 0x26FF
HIDD_ Dialog-resource Help context
IDB_
Bitmap resource
IDB_COMPANY_LOGO
1 to 0x6FFF
IDC_
Cursor resource
IDC_PENCIL
1 to 0x6FFF
IDI_
Icon resource
IDI_NOTEPAD
1 to 0x6FFF
ID_ _
Command from menu item or toolbar ID_TOOLS_SPELLING
0x8000 to 0xDFFF
HID_
Command Help context
HID_TOOLS_SPELLING
0x18000 to 0x1DFFF
IDP_
Message-box prompt
IDP_INVALID_PARTNO
8 to 0xDFFF
Message-box Help context
HIDP_INVALID_PARTNO 0x30008 to 0x3DFFF
IDS_
String resource
IDS_COPYRIGHT
1 to 0x7FFF
IDC_
Control within dialog box
IDC_RECALC
8 to 0xDFFF
HIDP_
Benutzerdefinierte Resourcen - Macros
Damit die unterschiedliche Syntax und Bezeichner im *.RC, *.H und *.CPP Files bei den Übersetzungen unterschieden werden können, gibt es vordefinierte
Konstanten ( z.B. RC_INVODED ). Durch
#ifdef RC_INVODED
#define ID(x) x
#else
#define ID(x) MAKEINTRESOURCE(x)
#endif
wird während der Resourcen - Übersetzung anstelle von ID(x) das Macro MAKEINTRESOURCE(x) verwendet und sonst die Zahl x direkt. Für die Erstellung
eines *.RC - Resourcen - Files ( ASCII ) "von Hand" können die folgenden Macros hilfreich sein. Durch solche Macros kann eine einheitliche, übersichtliche
Gestaltung des *.RC - Files erreicht werden. Im C/C++ - Programm wird eine Resource durch einen Idetifizierer ( idRes = ID_ ... ) angesprochen.
#define ICON_NAME(idRes, pFileName) idRes ICON DISCARDABLE pFileName
#define STR_BEGIN STRINGTABLE DISCARDABLE
BEGIN
#define STR_END
END
#define MENU_BEGIN(idRes) idRes MENU DISCARDABLE BEGIN
#define MENU_END
END
#define MENU_ITEM_BEGIN(text) POPUP text
BEGIN
#define MENU_ITEM_END
END
#define MENU_ITEM(idRes, text, style) MENUITEM text, idRes, style
#define MENU_SEPARATOR
MENUITEM SEPARATOR
#define ACCEL_BEGIN(idRes) \
idRes ACCELERATORS MOVEABLE PURE BEGIN
#define ACCEL_END
END
#define DLG_BEGIN_MODAL( idRes, txt, x,y,dx,dy )
\
idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\
STYLE
DLG_MODAL_STYLE \
FONT
DLG_FONT
\
CAPTION
txt
\
BEGIN
#define DLG_BEGIN( idRes, txt, x,y,dx,dy ) \
idRes DIALOG LOADONCALL MOVEABLE DISCARDABLE x,y,dx,dy\
STYLE
DLG_MODELES_STYLE \
FONT
DLG_FONT
\
CAPTION
txt
\
BEGIN
#define DLG_END
END
#define is_RECT "Static", SS_BLACKRECT
| WS_GROUP//|SS_NOPREFIX
#define is_ICON SS_ICON
#define is_LTEXT "Static", SS_LEFT
| WS_GROUP//|SS_NOPREFIX
#define is_RTEXT "Static", SS_RIGHT
| WS_GROUP//|SS_NOPREFIX
#define is_CTEXT "Static", SS_CENTER
| WS_GROUP//|SS_NOPREFIX
#define is_GROUP "Button", BS_GROUPBOX
| WS_TABSTOP|WS_GROUP
#define is_RADIO "Button", BS_AUTORADIOBUTTON| WS_TABSTOP
#define is_CHECK "Button", BS_AUTOCHECKBOX
| WS_TABSTOP
#define is_PUSH "Button", BS_PUSHBUTTON
| WS_TABSTOP
#define is_PUSHx "Button", BS_DEFPUSHBUTTON | WS_TABSTOP
#define is_PUSH0 "Button", BS_OWNERDRAW
| WS_TABSTOP
#define is_COMBO "ComboBox",CBS_OEMCONVERT|CBS_DROPDOWN\
|CBS_HASSTRINGS|CBS_AUTOHSCROLL|ES_LEFT|ES_NOHIDESEL\
|WS_CHILD|WS_TABSTOP|WS_VSCROLL
#define is_LIST "ListBox",LBS_NOTIFY\
|LBS_USETABSTOPS|LBS_DISABLENOSCROLL|LBS_OWNERDRAWFIXED\
|WS_BORDER|LBS_SORT|LBS_HASSTRINGS|WS_VSCROLL
#define is_VSCROLL "Scrollbar", SBS_VERT|WS_TABSTOP
#define is_HSCROLL "Scrollbar", SBS_HORZ|WS_TABSTOP
#define is_EDIT
"Edit",ES_AUTOHSCROLL|ES_LEFT|WS_BORDER\
|ES_OEMCONVERT|WS_CHILD|WS_TABSTOP|WS_GROUP//|ES_WANTRETURN
#define is_EDIT_X "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\
|ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\
|WS_VISIBLE|WS_HSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP
#define is_EDIT_Y "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\
|ES_AUTOVSCROLL|ES_NOHIDESEL|ES_WANTRETURN|WS_CHILD\
|WS_VISIBLE|WS_VSCROLL|WS_BORDER|WS_TABSTOP|WS_GROUP
#define is_EDIT_XY "Edit",ES_MULTILINE|ES_LEFT|ES_OEMCONVERT\
|ES_AUTOVSCROLL|ES_AUTOHSCROLL|ES_NOHIDESEL\
|ES_WANTRETURN|WS_CHILD\
|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL|WS_BORDER\
|WS_TABSTOP|WS_GROUP
#define DLG_MODELES_STYLE DS_SETFONT|WS_THICKFRAME|WS_MINIMIZEBOX\
|WS_MAXIMIZEBOX|WS_VISIBLE|WS_CAPTION\
|WS_POPUPWINDOW //WS_BORDER|WS_POPUP|WS_SYSMENU
#define DLG_MODAL_STYLE DS_MODALFRAME|DS_SETFONT|WS_POPUP|WS_CAPTION\
|WS_SYSMENU|WS_VISIBLE
#define DLG_FONT 7, "MS Sans Serif" //"Helv"
#define DLG_ITEM(idRes,text,style,x,y,width,height) \
CONTROL text, idRes,style,x,y,width,height
#define DLG_ICON(idRes,text,style,x,y,width,height) \
ICON idRes,-1,x,y,width,height,style
Cursor - Resource
Ein Maus - Cursor wird definiert durch zwei 16x16 Bitmaps und einen kennzeichnenden Punkt ( Hotspot ). Die erste 16x16 Bitmap wird mit dem Hintergrund
AND- und die zweite XOR- verknüpft. Der Hotspot gibt innerhalb der Maske die Pixel - Position an, welche z.B. die Spitze des Pfeils symbolisiert. Die
Erstellung eines Maus - Cursor - Bitmap durch den Benutzer ist nur dann erforderlich, wenn die verfügbaren Maus - Cursor - Bitmaps nicht ausreichen.
Icon - Resource
Ist ein Icon in dem File "c:\\pfad\\...\\myName.ico" enthalten, so kann dieses Icon gemäß
IDI_MYICON ICON DISCARDABLE "c:\\pfad\\...\\myName.ico"
in den *.RC - ASCII - File aufgenommen werden. Im C/C++ - Programm wird dieses Icon z.B. durch
wndclass.hIcon = LoadIcon( GetModuleHandle(0), IDI_MYICON );
geladen.
String - Table - Resource
Tabellen von Strings werden für Fehler - Meldungen, statische Anzeigetexte und Ausgaben benutzt. Das C/C++ - Programm läd bei Bedarf diese Strings. Wird
eine Applikation in eine andere Landes - Sprachen übersetzt, so muß nur die Stringtabellen auswechselt werden. Bei C/C++ wird ein String "..." automatisch mit
einem zusätzlichem \0 - Zeichen abgeschlossen.
●
●
Ein *.RC - String wird nicht automatisch mit einem \0 abgeschlossen.
Sonderzeichen innerhalb eines *.RC - Strings müssen oktal eingegeben werden ( ein "für" wird zu "f\374r" ).
Im *.RC sieht eine STRINGTABLE etwa wie folgt aus:
STRINGTABLE DISCARDABLE BEGIN
IDS_STRING1, "Error in Runtime 1"
....
IDS_STRING16, "Wert = %d"
END
Eine Tabelle sollte maximal 16 Strings enthalten.
Die Strings aus der Resourcen - String - Tabelle werden dann gemäß
CHAR buf[256];
LoadString( GetModuleHandle(0), IDS_STRING1, buf, sizeof(buf) )
geladen. hInstance = GetModuleHandle(0) entspricht der Anfangsadresse des ausgeführten Programmes. Der WinMain( ) - Aufruf übergibt den Parameter
hInstance an das Programm. hInstance wird in unterschiedlichen Funktionen benötigt. Deshable kann hInstance ( anstelle des Aufrufes GetModuleHandle(0) )
auch in einer globale Variablen gespeichert werden.
Alternativ kann hInstance auch beim WM_CREATE - Ereignis ( infolge von CreateWindow ) durch
my_hInstance = ( LPCREATESTRUCT ) lParam -> hInstance erhalten werden.
Eine vereinfachte Funktion Load_String( int idRes ) gibt den Zeiger auf den geladenen String zurück.
LPSTR Load_String( int idRes ) {
static char buf[256];
if ( LoadString( GetModuleHandle(0), idRes, buf, sizeof(buf) ) < 0 )
return NULL;
else
return ( LPSTR ) buf;
}
Sollen drei Resourcen - Strings geladenen, aneinander gefügt und angezeigt werden, so kann dies z.B. gemäß
CHAR buf[1024]; LPSTR pp = &buf[0];
pp += sprintf( pp, Load_String( IDS_STRING1 ) );
pp += sprintf( pp, Load_String( IDS_STRING2 ) );
pp += sprintf( pp, Load_String( IDS_STRING3 ) );
MessageBox( hWnd, buf, "3 Strings", MB_OK );
erfolgen. Sollen drei Strings gleichzeitig, nebeneinander benutzt werden ( nrStr = 0, 1, 2 ), so kann eine erweitert Funktion Load_String_into() geschrieben
werden.
LPSTR Load_String_into( int nrStr, int idRes ) {
static CHAR buf[3][256];
LoadString( GetModuleHandle( NULL ), idRes, buf[nrStr], 256 );
return ( LPSTR ) buf[nrStr];
}
// Die drei static Buffer können mehrfach geladen und
// p0, p1, p2 können unabhängig voneinander benutzt werden.
LPSTR p0 = Load_String_into( 0, IDS_STRING0 );
LPSTR p1 = Load_String_into( 1, IDS_STRING1 );
LPSTR p2 = Load_String_into( 2, IDS_STRING2 );
geladen werden. Mit (NULL!=FindResource(GetModuleHandle(0),MAKEINTRESOURCE((idRes>>4)+1),RT_STRING)) kann geprüft werden, ob die StringRessource im 16-Block existiert.
Menu - Resourcen
Ein *.RC - File kann etwa wie folgt aufgebaut werden:
IDR_MAIN_MENU MENU LOADONCALL MOVEABLE DISCARDABLE {
POPUP "&File" {
MENUITEM "&New", ID_MAIN_NEW, GRAYED
MENUITEM SEPARATOR
MENUITEM "&Exit", ID_MAIN_EXIT
}
POPUP "&Examples" {
MENUITEM "Example&1 F1", ID_MAIN_EXAMPLE_1
MENUITEM "Example&amp2 F2", ID_MAIN_EXAMPLE_2
}
POPUP "&Help" {
MENUITEM "&mp;About", ID_MAIN_ABOUT
}
}
Um das Menu anzuzeigen, wird in RegisterClass()
WNDCLASS wndclass.lpszMenuName = MAKEINTRESOURCE( IDR_MAIN_MENU );
eingetragen. Bei einem Menu - Klick wird die CALLBACK - Funktion mit case iMsg = WM_COMMAND aufgerufen. In LOWORD( wParam ) wird der
Resourcen - Identifizierer ID_... an die CALLBACK - Funktion übergeben.
case WM_COMMAND:
wmId
= LOWORD( wParam );
wmEvent = HIWORD( wParam );
switch ( wmId ) {
case ID_MAIN_EXAMPLE_1:
MessageBox( NULL, "ID_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION | MB_YESNO ) ;
break ;
}
System - Menu
Das Windows - System verwendet ( oben links ) das System - Menu ( Wiederherstellen, Verschieben, Größe ändern, Minimieren, Maximieren, Schließen,
Nächstes ). Das System - Menu kann z.B. in WM_CREATE gemäß
HMENU hSysMenu = GetSystemMenu ( hWnd, FALSE );
if ( hSysMene ) {
InsertMenu ( hSysMenu, SC_RESTORE, MF_STRING, ID_SYSMAIN_HELP, "&Help" );
InsertMenu ( hSysMenu, SC_RESTORE, MF_SEPARATOR, 0, NULL );
}
erweitert werden. Die CALLBACK - Funktion ist dann zu ergänzen.
case WM_SYSCOMMAND:
switch ( LOWORD( wPar ) ) {
case ID_SYSMAIN_HELP:
MessageBox( hWnd, "ID_SYSMAIN_HELP", NULL, MB_OK ) ;
break ;
}
Beschleunigungs - Tasten
Mit Beschleuniguungs - Tasten ( Alt - Hot - Keys ) kann das Menu schneller bedient werden. Hierzu wird im Menu - Text das '&' - Markierungs - Zeichen
verwendet. Es können aber auch andere Tasten einem Menu - Punkt zugeordnet werden. Der bMain.rc - File enthält z.B.
ID_MAIN_ACCEL ACCELERATORS LOADONCALL MOVEABLE
VK_F1, ID_MAIN_EXAMPLE_1, VIRTKEY
VK_F2, ID_MAIN_EXAMPLE_2, VIRTKEY
"?",
ID_...,
ASCII, ALT
}
{
Vor der Haupt - Nachrichten - Schleife wird dieAccelerator - Tabelle geladen.
HACCEL hAccel = LoadAccelerators( GetModuleHandle(0), MAKEINTRESOURCE( ID_MAIN_ACCEL
) );
Die Haupt-Nachrichten-Schleife wird ergänzt.
...
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
if ( ( hAccel != NULL )
&& ( ! TranslateAccelerator ( msg.hwnd, hAccel, & msg ) ) )
{
TranslateMessage( & msg ) ;
DispatchMessage ( & msg ) ;
}
} return msg.wParam ;
Zum Testen des F1-Hot-Keys kann
case WM_SYSCOMMAND:
//case WM_COMMAND:
switch ( LOWORD( wPar ) ) {
case ID_MAIN_EXAMPLE_1:
MessageBox( NULL, "ID_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION | MB_YESNO ) ;
break ;
}
in die WndProc - CALLBACK - Funktion eingefügt werden.
LoadMenuIndirect
Ein Menu kann per Programm im Speicher aufgebaut werden und dann durch LoadMenuIndirect() aufgebaut und mit SetMenu() dem Fenster hinzugefügt
werden. Im Speicher beginnt ein Menu mit dem MENUITEMTEMPLATEHEADER ( meist versionNumber=0; offset=0, falls nachfolgend
MENUITEMTEMPLATE-Struktur kommt ). Dann folgen die MENUITEMTEMPLATE-Einträge.
Header für Menu-Ressourcen
Kopf eines Menu
MENUITEMTEMPLATEHEADER
Jedes Popup/Item
MENUITEMTEMPLATE
typedef struct {
WORD versionNumber; // 0
WORD offset;
// 0
} MENUITEMTEMPLATEHEADER;
typedef struct {
WORD mtOption; // Item-Flag z.B. 0/MF_POPUP/MF_END
WORD mtID;
// ID, fehlt bei Popup-Eintrag
WCHAR mtString[1]; // 00-beendeter Text
} MENUITEMTEMPLATE;
Beispiel für den Menu-Ressourcen-Aufbau ( WORD-aligned )
Beispiel:
0
VersionNumber von MENUITEMTEMPLATEHEADER
0
Offset von MENUITEMTEMPLATEHEADER
MF_POPUP
Kennzeichen für einen Pupup-Eintrag
'Pop1' als Pupup-Text Unicode-Word-Text mit 00-Ende
0
Kennzeichen für einen Item-Eintrag
IDM_100
Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)
'Item 100' als Item-Text Unicode-Word-Text mit 00-Ende
0
Kennzeichen für einen Item-Eintrag
IDM_110
Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)
'Item 110' als Item-Text Unicode-Word-Text mit 00-Ende
MF_END
Kennzeichen für das letzte Item, das zu einem Popup gehören
IDM_120
Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)
'Item 120' als Item-Text Unicode-Word-Text mit 00-Ende
MF_POPUP| MF_END Kennzeichen für den letzten Pupup-Eintrag
'Pop2' als Pupup-Text Unicode-Word-Text mit 00-Ende
0
Kennzeichen für das letzte Item, das zu einem Popup gehören
IDM_200
Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)
'Item 200' als Item-Text Unicode-Word-Text mit 00-Ende
MF_END
Kennzeichen für das letzte Item, das zu einem Popup gehören
IDM_210
Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)
'Item 210' als Item-Text Unicode-Word-Text mit 00-Ende
verwendete User-Struktur
typedef struct _MENU_STRUCT {
WORD
_id; // Menu-Id's, etwa ab 100
LPSTR
_txt; // Menu-Popup/Item-Text
MENUFUNC _fn; // auzurufende Funktion
} MENU_STRUCT;
MENU_STRUCT menu_struct[] =
{
{
0, "Pop1",
0 },
{ 100, "Item 100", ... },
{ 110, "Item 110", ... },
{ 120, "Item 120", ... },
{
0, "Pop2",
0 },
{ 200, "Item 200", ... },
{ 210, "Item 210", ... },
{0,NULL, ... }
}; // <== Endekriterium ist Pflicht!
Alternative mit LoadMenuIndirect()
int
nCopyAnsiToWideChar(LPWORD p,LPSTR pAnsiIn)
{ int nChar = 0;
do { *p++ = (WORD)*pAnsiIn; nChar++; }
while (*pAnsiIn++);
return nChar;
}
HMENU
_set_menu(HWND hwnd,menu_struct * pMenu)
{ int k; if((!hwnd)||(!pMenu))return NULL;
WORD buf[4000]={0};//memset(...)
WORD * p = buf;
*p++ = 0; //(MENUITEMTEMPLATEHEADER);
*p++ = 0; //(MENUITEMTEMPLATEHEADER);
WORD *p1=NULL, *p2=NULL;
for( k=0; pMenu[k]._txt; k++){
if(0 == pMenu[k]._id) { p1 = p;
//CALLBACK-Pseudocode:
if(p2) *p2 = MF_END;
case WM_COMMAND:{if(HIWORD(wParam))break;
*p++ = MF_POPUP;
for( int k=0; (pMenu+k)->_txt; k++) {
p += nCopyAnsiToWideChar(p,
if( LOWORD(wParam) == (pMenu+k)->_id ) {
TEXT(pMenu[k]._txt));
menu_fn_aktiv = (pMenu+k)->_fn;
} else { p2 = p;
if
( menu_fn_aktiv ) {
*p++ = 0;
return menu_fn_aktiv(hwnd);
*p++ = pMenu[k]._id;
}
p += nCopyAnsiToWideChar(p,
}
TEXT(pMenu[k]._txt));
} // for
}
break; } //ende WM_COMMAND
}
if(p1) *p1 = MF_POPUP|MF_END;
if(p2) *p2 = MF_END;
HMENU hMenu = LoadMenuIndirect(buf);
Alternative mit AppendMenu()
SetMenu(hwnd, hMenu);
return hMenu;
HMENU
}
set_menu(HWND hwnd,menu_struct * pMenu)
{ HMENU hMenu=CreateMenu(), hPopup = NULL;
LPSTR pSave=NULL; int j,k=0;
if((!hwnd)||(!pMenu))return NULL;
while(pMenu[k]._txt)
{
hPopup = CreateMenu();
for(j=k+1; pMenu[j]._id; j++){
AppendMenu(hPopup,MF_STRING,
pMenu[j]._id,
pMenu[j]._txt);
}
AppendMenu(hMenu,MF_POPUP,
(UINT_PTR)hPopup,pMenu[k]._txt);
k = j;
}
if(!hMenu)DestroyMenu(hMenu);
SetMenu(hwnd,hMenu);return hMenu;
}
CREATE_DLG_INDIRECT
Ein DLGTEMPLATE kann auch ohne Ressourcen ( ohne *.RC, *.RES ) im C/C++-Programm "bitweise zusammengebastelt" werden und dann durch die
Funktion CreateDialogIndirect() aufgerufen werden. Bei solchen Ressourcen ( im Speicher ) ist das Alignment ( WORD- bzw. DWORD-weise ) wesentlich.
Dies bedeutet z.B., dass ein LPSTR-Strings lpAnsiIn WORDweise in p geschrieben werden muss und das Stringende durch 0x0000 gekennzeichnet ist.
int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn)
{ int nChar = 0;
do {
*p++ = (WORD) *lpAnsiIn;
nChar++;
} while (*lpAnsiIn++);
return nChar;
}
Aufbau der CDLGTEMPLATE-Struktur für CreateDialogIndirect()
[Resource header (type = 5)]
Jedes Control beginnt an DWORD-Grenze
struct DialogBoxHeader {
struct ControlData {
DWORD lStyle;
DWORD lStyle;//WS_CHILD,WS_VISIBLE...
DWORD lExtendedStyle;
DWORD lExtendedStyle;
WORD NumberOfItems;
WORD
x,y,cx,cy;
WORD x,y,cx,cy;
WORD
wId;
[Name or Ordinal] MenuName;
[Name or Ordinal] ClassId;
[Name or Ordinal] ClassName;
[Name or Ordinal] Text;
WCHAR szCaption[];
WORD
nExtraStuff; // soll 0x0000 sein
WORD
wPointSize; //nur bei DS_SETFONT };
WCHAR szFontName[];//nur bei DS_SETFONT
};
Die Bezeichnung [Name or Ordinal] bedeutet, dass hier z.B. für eine für LISTBOX stehen darf: entweder 0xFFFF gefolgt von 0x0083 oder ein String mit 0x0000-
Ende. Intern wird für das Auslesen verwendet
if (*pw == (WORD)-1) pw += 2; else while(*pw++);
Für einen Dialog wird DLG_STRUCT dlg1[] = {... } ( beginnend mit "DIALOG" ) besetzt, bevor dann durch den CREATE_DLG_INDIRECT()-Aufruf der
Dialog erzeugt wird. Als Ctrl-Identifizierer wird der Index i von [i] verwendet. Die 0-enn ( 1. Spalte von DLG_STRUCT ) werden mit dem Ctrl-Handles
dlg1[i].hwnd überschrieben. dlg1[0].hwnd ist das Handle des Dialog-Fensters. Sind die Ctrl-Handles bekannt, so werden keine Identifizierer benötigt.
/////////////////////////////////////////////
// verwendete Struktur zur Ctrl-Beschreibung:
/////////////////////////////////////////////
///////////////////////////////////////////
// Beispiel für Aufruf:
///////////////////////////////////////////
static
typedef struct _DLG_STRUCT {
DLG_STRUCT dlg1[] = {
//
x, y, cx, cy
HWND hwnd;
// wird später eingesetzt
{0,"DIALOG", "dlg-Titel", 50, 50,100,145},//[0]
LPSTR pKlasse;
// z.B. "BUTTON"
{0,"STATIC", "Static-Text",10, 5, 80, 12},//[1]
LPSTR pText; // wird in das Ctrl geschrieben
{0,"LISTBOX", "dlg-List",
10, 20, 80, 40},//[2]
WORD x,y,cx,cy; // Position
{0,"EDIT",
"dlg-Edit",
10, 85, 80, 40},//[3]
} DLG_STRUCT;
{0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4]
{0,"BUTTON", "OK",
10,130, 80, 12},//[5]
{0,"", 0,0,0,0}};//Endekriterium ist Pflicht
CREATE_DLG_INDIRECT(hwnd, dlg1, dlg_callback_func);
// LISTBOX hat [2]
SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"1");
SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"2");
SendMessage(dlg1[2].hwnd,LB_ADDSTRING,0L,(LPARAM)"3");
// COMBOBOX hat [4]
SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"1");
SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"2");
SendMessage(dlg1[4].hwnd,CB_ADDSTRING,0L,(LPARAM)"3");
///////////////////////////////////////////
// class CREATE_DLG_INDIRECT
///////////////////////////////////////////
class CREATE_DLG_INDIRECT
{
int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn)
{ int nChar = 0;
do {
*p++ = (WORD)*lpAnsiIn;
nChar++;
} while (*lpAnsiIn++);
return nChar;
}
#define es_ist(str) (CSTR_EQUAL==CompareString(\
LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,(str),-1,pD->pKlasse,-1))
//////////////////
// so sieht es aus
//////////////////
public:
CREATE_DLG_INDIRECT( HWND hwnd, DLG_STRUCT * pDlg, DLGPROC dlgProc)
{
DWORD lStyle, lExtStyle; DLG_STRUCT * pD;
WORD pDlgStruct[4000] = {0}, *p = pDlgStruct;
int
i, nCtrl=0; // = NumberOfItems !!!
if(!pDlg)return;
while((*pDlg[nCtrl].pKlasse)
&&( pDlg[nCtrl].cx)
&&( pDlg[nCtrl].cy)) nCtrl++;
nCtrl--; // = NumberOfItems !!!
if(nCtrl<1) return;
// Dialog: /////////////////////////////////////////////
pD = pDlg+0; //pD zeigt auf den 0-ten DLG_STRUCT-Eintrag
if(!es_ist("DIALOG"))return;
lStyle = WS_CAPTION|WS_SYSMENU|WS_VISIBLE
| DS_SETFOREGROUND|DS_MODALFRAME|DS_SETFONT;
lExtStyle = WS_EX_DLGMODALFRAME;//WS_EX_CLIENTEDGE;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = nCtrl;
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = 0;
// Menu
*p++ = 0;
// Class
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 7;
// point size; braucht DS_SETFONT
p += nCopyAnsiToWideChar(p,TEXT("Times New Roman"));
for ( i=1; i<=nCtrl; i++){
p = (WORD*)(((DWORD)p + 3) & ~3); // WORD align
pD = pDlg+i; //pD zeigt auf den i-ten DLG_STRUCT-Eintrag
if(es_ist("STATIC")){
lExtStyle = 0;//WS_EX_CLIENTEDGE|WS_EX_STATICEDGE;
lStyle
= WS_VISIBLE|WS_CHILD|SS_NOPREFIX|SS_LEFTNOWORDWRAP;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = 0xffff; //IDOK;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0082;// alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("STATIC"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("BUTTON")){
lExtStyle = 0;//WS_EX_CLIENTEDGE;
lStyle = WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = i; //IDOK;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0080;//alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("BUTTON"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("LISTBOX")){
lExtStyle = WS_EX_CLIENTEDGE;
lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS
|LBS_DISABLENOSCROLL
|LBS_HASSTRINGS|LBS_STANDARD;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = i;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0083;//alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("LISTBOX"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("EDIT")){
lExtStyle = WS_EX_CLIENTEDGE;
lStyle
= WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_CLIPSIBLINGS
|ES_MULTILINE|ES_AUTOVSCROLL ;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = i;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0081;// alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("EDIT"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("COMBOBOX")){
lExtStyle = WS_EX_CLIENTEDGE;
lStyle
= WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS
|CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->cy;
*p++ = i; // ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0085; //alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("COMBOBOX"));
p += nCopyAnsiToWideChar(p,TEXT(""));//pD->pText));
*p++ = 0;
}
} // ende for
HWND hDlg = CreateDialogIndirect(GetModuleHandle(0),
(LPDLGTEMPLATE) pDlgStruct, hwnd, (DLGPROC) dlgProc);
if(!hDlg)return;
////////////////////////////////////////////////////////
// hinterlege die Ctrl-Handles in die Struktur:
pDlg->hwnd = hDlg;
for ( i=1; i<=nCtrl; i++){
pD = pDlg+i; //pD zeigt auf den i-ten Eintrag
pD->hwnd = GetDlgItem( hDlg, i );
if(es_ist("COMBOBOX")){
SetWindowText(pD->hwnd,pD->pText);
} else if(es_ist("LISTBOX")){
SendMessage(pD->hwnd,LB_ADDSTRING,0L,(LPARAM)pD->pText);
}
}
}
#undef es_ist
};
user-typedef's
MENU_STRUCT
WORD
_id; // Menu-Id's,etwa ab 100
LPSTR
_txt;// Menu-Item-Text
MENUFUNC _fn; // auzurufende Funktion
DLG_STRUCT
HWND
LPSTR
LPSTR
WORD
hwnd;
//des Ctrl's
pKlasse;//z.B."EDIT"
pText; //Initialisierung
x,y,cx,cy;//Ctrl-Position
mit typedef
BOOL (* MENUFUNC)(HWND hwnd);
kann WM_COMMAND-Aufruf
'automatisiert' werden
//Beispiel:
BOOL menu_fn100(HWND hwnd)
{ if(hwnd != _hModeless)
MessageBox(hwnd,
"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,
"global _hModeless=%08x",_hModeless);
MessageBox(hwnd,buf,"info",MB_OK);
return TRUE;
}
static // static ist Pflicht!
MENU_STRUCT menu_struct[] = {
{
0, "Test1",
0 },
{ 100, "100",
menu_fn100 },
//{ 120, "120",
menu_fn120 },
//{
0, "Test2",
0 },
//{ 200, "200",
menu_fn100 },
//{ 210, "210",
menu_fn120 },
{0,NULL,0}};//<== Endekrit.ist Pflicht!
//Aufruf falls hwnd existiert:
static DLG_INDIRECT *
pDlg = new DLG_INDIRECT(hwnd);
pDlg -> set_menu(menu_struct);
//Beispiel:
static // static ist Pflicht!
DLG_STRUCT DLG_STRUCT[] = { // x, y, cx, cy
{0,"DIALOG", "dlg1-Titel", 40, 20,100,160},//[0]
{0,"STATIC", "Static-Text",10, 5, 80, 12},//[1]
{0,"LISTBOX", "dlg-List",
10, 20, 80, 40},//[2]
{0,"EDIT",
"dlg-Edit",
10, 85, 80, 40},//[3]
{0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4]
{0,"BUTTON", "OK",
10,130, 80, 12},//[5]
{0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht
//Aufruf mit CALLBAC dlg1_proc:
static DLG_INDIRECT *
pDlg = new DLG_INDIRECT(hwnd);
pDlg -> create_dlg_indirect(DLG_STRUCT, dlg1_proc);
if(!pDlg) error ...
if(!pDlg) error ...
"MDICLIENT"
Dialoge
Eingebaute klassen zur Ereignisbehandlung
Der Entwickler kann eigene Klassen anlegen (RegisterClass) und dort eine CALLBACK-Funktion für die Ereignissteuerung hinterlegen. Es existieren auch bereits verfügbare WindowsKlassen, die der Ereignissteuerung dienen und die bereits eine CALLBACK-Funktion enthalten. Die ersten Windows-Versionen enthielten in User(32).dll und Comctl(32).dll die Klassen:
0x0080 "Button",
0x0081 "Edit",
0x0083 "ListBox",
0x0084 "ScrollBar",
und die Dialog Box Klasse "#32770".
0x0082 "Static",
0x0085 "ComboBox"
Hier eine aktuelle Übersicht (User Interface Element Reference):
Animation control
Calendar control
(ANIMATE_CLASS, "SysAnimate32" in
Commctrl.h)
(MONTHCAL_CLASS, "SysMonthCal32" in
Commctrl.h)
Caret
Pop-up menu ("#32768")
Progress bar control
(PROGRESS_CLASS, "msctls_progress" in
Commctrl.h)
Push button ("BUTTON")
Check box ("BUTTON")
Client object (text, graphics)
Combo box ("COMBOBOX")
Radio button ("BUTTON")
Scroll bar ("SCROLLBAR")
Size grip (special mouse pointer)
IDC_IBEAM "Edit",
IDC_WAIT "Wait",
Cursor IDC_ARROW "Normal",
IDC_CROSS "Graphic",
IDC_UPARROW "Up",
IDC_SIZENWSE "NWSE size",
IDC_SIZENESW "NESW size",
IDC_SIZEWE "Horizontal size",
IDC_SIZENS "Vertical size", IDC_SIZEALL "Move", IDC_NO "Forbidden",
IDC_APPSTARTING "App start",IDC_HELP "Help",
Custom cursor "Unknown"
Slider control
(TRACKBAR_CLASS, "msctls_trackbar" in
Commctrl.h)
Static text ("STATIC")
Status bar control
(STATUSCLASSNAME,
"msctls_statusbar32" in Commctrl.h)
Switch window ("#32771")
Tab control
(WC_TABCONTROL, "SysTabControl" in
Commctrl.h)
Toolbar control
(TOOLBARCLASSNAME,
"ToolbarWindow32" in Commctrl.h)
ToolTip control
(TOOLTIPS_CLASS, "tooltips_class" in
Commctrl.h)
Title bar
Desktop window ("#32769")
Dialog box ("#32770")
Edit control "EDIT", "RichEdit", "RichEdit20A"
Header control
Hot key control
(WC_HEADER, "SysHeader32" in
Commctrl.h)
(HOTKEY_CLASS, "msctls_hotkey32" in
Commctrl.h)
List box ("LISTBOX")
List view control
(WC_LISTVIEW, "SysListView" in
Commctrl.h)
MDI client window ("MDIClient")
Tree view control
(WC_TREEVIEW, "SysTreeView" in
Commctrl.h)
Up-down control
(UPDOWN_CLASS, "msctls_updown32" in
Commctrl.h)
Menu bar
Menu item ( "#32768")
Es gibt zahlreiche Funktionen, die zum Erzeugen und Manipulieren von modalen/modeless Dialogen und deren Unterfenster ( Controls ) dienen:
CreateDialog
CreateDialogParam
DialogBoxIndirect
DialogProc
GetDlgCtrlID
GetDlgItemText
IsDialogMessage
MessageBoxEx
SetDlgItemText
CreateDialogIndirect
DefDlgProc
DialogBoxIndirectParam
EndDialog
GetDlgItem
GetNextDlgGroupItem
MapDialogRect
SendDlgItemMessage
MessageBoxIndirect
CreateDialogIndirectParam
DialogBox
DialogBoxParam
GetDialogBaseUnits
GetDlgItemInt
GetNextDlgTabItem
MessageBox
SetDlgItemInt
Modale Dialoge
Ein modaler Dialog enthält eine eigene Nachrichten-Schleife. Erscheint ein ( Applikations-)modale Dialog - Box auf dem Bildschirm so wird in dieser Nachrichten-Schleife "gewartet", bis
der Benutzer reagieren und den Dialog beendet.
MessageBox()
Eine MessageBox() entspricht einem modalen Dialog. Z.B. wird die Applikation blockiert, bis der Benutzer den "OK" - Button gedrückt hat. Eine MessageBox() erzeugt die Anzeige - Box
für Ausgabe-Text ohne externe Resourcen. Eine eingebaute ( intern verfügbare ) CALLBACK - Funktion behandelt die Nachrichten. Es gibt eine Anzahl von verwendbaren Icons und PushButtons.
int MessageBoxEx(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType,
WORD wLanguageId
);
//
//
//
//
//
handle of owner window
address of text in message box
address of title of message box
style of message box
language identifier
MessageBoxEx() hat gegenüber MessageBox() einen zusätlichen WORD wLanguageId - Parameter. Falls hWnd = NULL verwendet wird, so gehört die Message - Box zu keinem speziellen
Fenster. lpCaption zeigt auf den auszugebenden Text. Für lpszTitle = NULL ist, wird in der Titel - Zeile "Error" angezeigt. Im Fehlerfall gibt die MessageBoxEx() den Wert 0 zurück. Im
Erfolgsfall gibt die MessageBoxEx() eine positiven Wert zurück. Der Rückgabe - Wert entspricht dem gedrückten Button.
IDABORT
IDCANCEL
IDIGNORE
IDNO
IDOK
Abort button was selected.
Cancel button or ESC key was selected.
Ignore button was selected.
No button was selected.
OK button was selected.
IDRETRY
IDYES
Retry button was selected.
Yes button was selected.
Für uType kann verwendet werden:
MB_ABORTRETRYIGNORE three push buttons: Abort, Retry, and Ignore.
MB_OK
one push button:
OK.
This is the default.
MB_OKCANCEL
two push buttons:
OK
and Cancel.
MB_RETRYCANCEL
two push buttons:
Retry and Cancel.
MB_YESNO
two push buttons:
Yes
and No.
MB_YESNOCANCEL
three push buttons: Yes, No, and Cancel.
-------------------------------------------------------------MB_ICONEXCLAMATION, MB_ICONWARNING
icon ( exclamation-point )
MB_ICONINFORMATION, MB_ICONASTERISK
icon ( i in a circle )
MB_ICONQUESTION
icon ( question-mark )
MB_ICONSTOP, MB_ICONERROR, MB_ICONHAND icon ( stop
-sign )
-------------------------------------------------------------MB_DEFBUTTON1 The first button is the default button.
MB_DEFBUTTON2 The second button is the default button.
MB_DEFBUTTON3 The third button is the default button.
MB_DEFBUTTON4 The fourth button is the default button.
-------------------------------------------------------------more:
MB_APPLMODAL, MB_SYSTEMMODAL, MB_TASKMODAL, MB_DEFAULT_DESKTOP_ONLY,
MB_HELP, MB_RIGHT, MB_RTLREADING, MB_SETFOREGROUND, MB_TOPMOST,
MB_SERVICE_NOTIFICATION, MB_SERVICE_NOTIFICATION_NT3X
Beispiele:
MessageBox() als einfacher ( Benachrichtigungs-) Dialog
MessageBox( 0,
"Client-Bereich",
0, MB_OK );
MessageBox( hwnd,
"Client-Bereich",
"Titel",
MB_OK );
MessageBox( hwnd,
"MB_ICONSTOP",
"Titel",
MB_OK|MB_ICONSTOP);
MessageBox(hwnd,
"MB_ICONINFORMATION",
"Titel",
MB_OK|MB_ICONINFORMATION);
MessageBox(hwnd,
"MB_ICONQUESTION",
"Titel",
MB_OK|MB_ICONQUESTION);
int mb_val = MessageBox(hwnd,
"Rückgabewert", Titel",
MB_OKCANCEL|MB_DEFBUTTON2);
mb_val wirdt IDOK oder IDCANCEL
DialogBox()
Der einfache Aufruf einer MessageBox()-Funktion begrenzt die optische Ausgestaltung, die Anzeigeposition und - Form, die enthaltenen Buttons ( Controls ), usw, auf das notwendigste. Eine
erweiternde Gestaltung ist nicht möglich. Eine MessageBox() gehört zu den modalen Dialogen ( Benutzer muß reagieren ). Eine ( allgemeine ) Dialog - Box kann mit der DialogBox()Funktion aufgerufen werden. Die DialogBox()-Funktion braucht eine Dialog-CALLBACK-Funktion und ein Ressourcen-Script ( flexible optische Gestaltung ). Die DialogBox() kann Controls
enthalten, die Informationen angezeigen und Benutzereingaben erlauben ( Texteingaben, Auswahlaktionen, usw. ). Diese Unter - Fenster ( Child - Windows == Controls ) einer DialogBox()
werden Controls genannt. Die "DialogBox() - Funktion" ist ein Macro, das gemäß
#define DialogBoxA(
hInstance, lpTemplate, hWndParent, lpDialogFunc) \
DialogBoxParamA( hInstance, lpTemplate, hWndParent, lpDialogFunc, 0L)
definiert ist. Die Funktion
WINUSERAPI int WINAPI DialogBoxParamA(
HINSTANCE hInstance,
// handle to application instance
LPCTSTR
lpTemplate,
// identifies dialog box template
HWND
hWndParent,
// handle to owner window
DLGPROC
lpDialogFunc // pointer to dialog box procedure
LPARAM
dwInitParam //wird bei WM_INITDIALOG in lParam an CALLBACK
weitergereicht
);
hInstance kann durch GetModuleHandle( NULL) oder unter WM_CREATE durch
static HINSTANCE hInstance = ( LPCREATESTRUCT ) lParam-> hInstance
ermittelt werden.
Beispiel: DialogBox als Hauptprogramm
Existiert eine IDD_DIALOG-Dialog-Ressource und die dlg-CALLBACK-Funktion dlgProc), so kann das Hauptprogramm etwa wie folgt aussehen:
//Hauptprogramm
int APIENTRY WinMain(
HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG),
NULL, (DLGPROC)dlgProc);
}
●
●
●
●
Die DialogBox() - Funktion verwendet intern die CreateWindowEx() - Funktion.
Es wird i.a. eine interne vorhandene ( Dialog - ) Klassen - Registrierung benutzt ( DefDlgProg, default dialog class ).
Für die DialogBox() wird eine eigener, zusätzlicher Nachrichten - Buffer und eine eigene Nachrichten - Loop - Behandlung eingerichtet.
Bevor die Dialog - Box sichtbar wird, sendet DialogBox() die WM_INITDIALOG - Nachricht an die lpDialogFunc - Funktion. In der CALLBACK - Funktion wird
●
●
●
●
WM_INITDIALOG im Normalfall mit return FALSE beendet.
Falls die Dialog - Box den DS_SETFONT - Style hat, so wird die WM_SETFONT - Nachricht an die lpDialogFunc - Funktion gesendet.
Wenn der WS_VISIBLE - Style spezifiziert wurde, so erscheint die Dialog - Box.
Durch EndDialog ( hWnd, wParam ) wird der Dialog beendet, der allokierte Speicher wird freigegeben. DialogBox() gibt wParam zurück.
Eine private Dialog - Klasse muß WNDCLASS - Struktur besetzten ( cbWndExtra = DLGWINDOWEXTRA ) und RegisterClass() aufrufen. Das Dialog - Template muß dann
das CLASS - Statement enthalten.
Gegenüber einer MessageBox() ist der Programmier - Aufwand bei Verwendung von DialogBox() größer.
int DialogBox(
HINSTANCE hInstance,
LPCTSTR
lpTemplate,
HWND
hWndParent,
DLGPROC
lpDialogFunc
);
//
//
//
//
handle to application instance
identifies dialog box template
handle to owner window
pointer to dialog box procedure
DialogBox() erzeugt mit
lpTemplate = MAKEINTRESOURCE( idRes )
aus der *.RC - Template Resource idRes die DialogBox, indem automatisch die Resourcen - Daten in den Speicher geladen werden und die DialogBox angezeigt wird. Durch eine System Klassen - CALLBACK - Funktion werden bestimmte Ereignisse ( Tab, ... ) ( vor - ) behandelt. Ein typischer Aufruf hat die Form:
int rval = DialogBox ( hInstance, MAKEINTRESOURCE( idRes ), hWnd, ( DLGPROC )dlgProc
) ;
Zur Behandlung der Ereignisse muß eine DIALOG - CALLBACK - Funktion geschrieben werden. Diese Funktion wird mit DLGPROC lpDialogFunc an DialogBox() übergeben. Der modale
Dialog wird erst beendet, wenn in der eigenen CALLBACK - Funktion EndDialog() ausgeführt wird. Der Dialog wird meisten unter WM_CLOSE durch EndDialog ( hWnd, rval ) beendet.
Der Rückgabe - Wert von int DialogBox() ist hier rval. Bei einem Fehler wird -1 zurück gegeben.
Steht im *.RC - FIle unter IDD_DIALOG_ABOUT die Resourcen - Beschreibung der Dialog - Box, so wird z.B. in der Fenster - CALLBACK - Funktion WndProc() ( unter dem Menu Punkt ID_MAIN_MENU_1 ) diese modale Dialog - Box erscheinen, wenn
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
case WM_CREATE : ... break ;//return 0;
case WM_PAINT : ... break ; //return 0;
case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0;
case WM_COMMAND:
int wmId
= LOWORD( wParam );
int wmEvent = HIWORD( wParam );
switch ( wmId ) {
case ID_MAIN_MENU_1: //Aufruf der Dialog - Box
Dialog_Box( hWnd, IDD_DIALOG_ABOUT, myDlgBox ) ;
break ;
}
}
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
eingetragen wird. Die Dialog - CALLBACK - Funktion myDlgBox ( muß BOLL zurück geben ) ist zu schreiben. In myDlgBox ( muß BOLL zurück geben ) sind die Buttons, Texteingaben,
Radiobuttons, usw. zu behandeln.
BOOL myDlgBox( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) {
switch ( iMsg ) {
case WM_INITDIALOG :
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case IDOK :
case IDCANCEL :
SendMessage( hWnd , WM_CLOSE, LOWORD( wParam ), 0 );
return TRUE;
}
case WM_CLOSE : EndDialog ( hWnd, wParam ); //beendet den modalen Dialog
break; //return TRUE;
}
return FALSE;
}
Beim Initialisieren des Dialoges ( vor dem Sichtbarwerden ) wird die WM_INITDIALOG - Nachricht gesendet ( sonst WM_CREATE ). Diese Nachricht kommt, bevor das Fenster erscheint.
Unter WM_INITDIALOG können Anpassungen von Controls vorgenommen werden. Soll z.B. der Dialog ( bezüglich des Fensters hWnd ) mittig zentriert erscheinen, so kann unter
WM_INITDIALOG die Position ermittelt und gesetzt werden.
About-Dialog
Die Resourcen werden mit Hilfe eines Identifizierers angesprochen. Für das gesamte About - Template wird Die Konstante IDOK ist verfügbar und wird für den OK-Button verwendet. Das
Icon ist bereits unter IDI_MAIN_ICON vorhanden und kann in das About - Template eingefügt werden. Das MENUITEM "&About", ID_MENUITEM_ABOUT wird für den Aufruf des
About - Dialoges verwendet. Die Konstante IDC_STATIC entspricht der Zahl -1.
*.RC-File-Ausschnitt
Der *.RC-File-Ausschnitt für den About - Dialog und das Menu:
IDI_MAIN_ICON ICON DISCARDABLE "bMain.ico"
IDD_DIALOG_ABOUT DIALOG DISCARDABLE 0, 0, 192, 141
STYLE DS_SYSMODAL | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "About"
FONT 8, "MS Sans Serif"
BEGIN
ICON
IDI_MAIN_ICON,
IDC_STATIC, 30,19, 20,20
LTEXT
"Prof.Dr.W.Bachmann",IDC_STATIC, 87, 5, 68,8
LTEXT
"FH-Giessen",
IDC_STATIC, 87,17, 38,8
LTEXT
"Wiesenstrasse 14", IDC_STATIC, 87,28, 57,8
LTEXT
"(D-35390) GIESSEN", IDC_STATIC, 85,40, 66,8
CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,8,59,175,5
LTEXT
"Bitte beachten Sie:",IDC_STATIC,62,74,61,8
LTEXT
"den Abgabetermin für die Übung",IDC_STATIC,41,84,103,8
LTEXT
"die vollständige Dokumentation incl. aller Quellen",
IDC_STATIC,15,94,155,8
LTEXT
"( *.CPP, *.H, *.RCT, *.RC, *.ICO, usw. )",IDC_STATIC,31,105,123,8
DEFPUSHBUTTON "OK",IDOK,8,120,175,14
END
IDR_MENU_MAIN MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Exit",
ID_MENUITEM_EXIT
END
POPUP "&Examples"
BEGIN
MENUITEM "Example&1", ID_MENUITEM_EXAMPLE1
MENUITEM "Example&2", ID_MENUITEM_EXAMPLE2
MENUITEM "Example&3", ID_MENUITEM_EXAMPLE3
END
POPUP "&Help"
BEGIN
MENUITEM "&About",
ID_MENUITEM_ABOUT
END
END
Aufruf des About-Dialogs:
Der *.CPP - File enthält die
Dialog - CALLBACK - Funktion dlgAboutProc und die
Fenster - CALLBACK - Funktion WndProc, in der der Dialog durch
Dialog_Box( hWnd, IDD_DIALOG_ABOUT, dlgAboutProc ) ; aufgerufen wird.
BOOL CALLBACK dlgAboutProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
case WM_INITDIALOG: ...
break;
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDOK:
case IDCANCEL: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0);
return TRUE;
} break;
case WM_CLOSE: EndDialog ( hWnd, wParam ); DestroyWindow( hWnd );
break;
}
return FALSE;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
case WM_CREATE: ... break ;//return 0;
case WM_PAINT: ... break ; //return 0;
...
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_MENUITEM_ABOUT: //Aufruf der About - Box
Dialog_Box( hWnd, IDD_DIALOG_ABOUT, dlgAboutProc ) ;
break ;
}
case WM_DESTROY: PostQuitMessage(0); break; //return 0;
...
}
return DefWindowProc( hWnd,iMsg,wParam,lParam ) ;
}
Modless Dialoge
Mit der Funktion IsDialogMessage() können Nachrichten der Nachrichten-Schleife an das hDlgModeless-Fenster verteilt werden. Die Modless - Dialog - Nachrichten müssen durch
Erweiterung der Haupt - Nachrichten - Schleife "verschickt" werden. Es können mehrere Modeless - Dialoge gleichzeitig geöffnet sein. Für die Erweiterung der Haupt - Nachrichten - Schleife
kann eine globale Variable HWND hDlgModeless verwendet werden. Ist das globale Handle hDlgModeless != NULL, so ist kein Modless - Fenster "offen". Wird ein Modless - Fenster
aktiviert ( WM_ACTIVATE ), so wird das globale Handle hDlgModeless mit dem Handle des aktiven Fensters überschrieben. Weil nur ein Fenster aktiv ist und den Focus hat, können beliebig
viele Modless - Fenster "gleichzeitig offen" sein.
für Modeless: Haupnachrichten-Schleife
while ( GetMessage( & msg, NULL, 0, 0 ) ) {
if ( NULL == hDlgModeless || ! IsDialogMessage( hDlgModeless, & msg ) ) {
TranslateMessage( & msg );
DispatchMessage ( & msg );
}
}
In der Modeless - Dialog - CALLBACK - Funktion wird die WM_ACTIVATE - Nachricht benutzt, um das globale hDlgModeless - Handle zu setzen. Durch DestroyWindow() wird der
Modeless-Dialog freigegeben.
für Modeless: in der CALLBACK
...
switch ( iMsg ) {
case WM_ACTIVATE: {
if ( 0 == wParam ) hDlgModeless = NULL; // wird inactive
else
hDlgModeless = hWnd; // wird
active
return FALSE;
break; }
case WM_CLOSE: { // ggf. Heap-freigeben
if( hDlgModeless == hWnd )
DestroyWindow( hWnd ) ;
break; }
...
Ein Modless-Dialog wird mit CreateDialog() oder CreateDialogParam() erzeugt. Mit dem Letzten Parameter von CreateDialogParam() kann bereits mit dem CreateDialogParam()-Aufruf von
"aussen" ein 4 Byte-Wert val zur CALLBACK-Funktion ( WM_INITDIALOG ) "durchgereicht" werden.
für Modeless: Aufruf
HWND hDlg = CreateDialogParam(
GetModuleHandle(0),
MAKEINTRESOURCE(idRes),
hParent, dlgProc, val );
if ( hDlg == NULL ) {
... error }
}
Oft sollen Daten zugehörig zum jeweiligen Fenster ( speichern zwischen Fenster-Wechseln ) gespeichert werden. Jedes Fenster hat dann neben den internen Daten auch die benötigten UserDaten. Dies kann Zugeordnet erfolgen, indem durch SetWindowLong( hDlg, GWL_USERDATA, value ) ein 4 Byte-Wert value hinterlegt wird. SetWindowLong() gibt den alten
gespeicherten Wert zurück und hinterlegt den neuen value.
für Modeless: im Fenster hinterlegen
LONG old_value = SetWindowLong( hDlg, DWL_USER,(LONG)value );
}
CreateDialog() - Aufruf
für Modeless:
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
...
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_MENUITEM_MODELESS: //Aufruf der About - Box
Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) ;
break ;
}
}
...
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
Die Funktion Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) benötigt die Resource IDD_DIALOG_MODELESS und die CALLBACK - Funktion
dlgModelessProc().
*.RC enthält
IDD_DIALOG_MODELESS DIALOG DISCARDABLE 0, 0, 186, 129
STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Modeless"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT
"IDC_EDIT0",IDC_STATIC,6,6,38,8
EDITTEXT
IDC_EDIT0,5,17,115,14,ES_AUTOHSCROLL
PUSHBUTTON
"showEB 0",IDC_BUTTON0,129,18,50,14
DEFPUSHBUTTON
"OK",IDOK,130,108,50,14, WS_TABSTOP
END
*.CPP enthält
BOOL CALLBACK dlgModelessProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
static CHAR * pEdit; int len, idx; HWND hCtl0;
switch ( iMsg ) {
case WM_INITDIALOG: // idRes = lParam;
if ( pEdit != NULL ) { DestroyWindow( hWnd ) ; //keine doppelten Dialoge
} else {
pEdit = ( CHAR * ) calloc( 256, sizeof( CHAR ) );
hCtl0 = GetDlgItem( hWnd, IDC_EDIT0 ) ;
Edit_LimitText( hCtl0, 256 ); strcpy( pEdit, "...Text..." );
Edit_SetText ( hCtl0, pEdit );
} break;
case WM_ACTIVATE:
if ( 0 == wParam ) hDlgModeless = NULL; // becoming inactive
else
hDlgModeless = hWnd; // becoming active
return FALSE;
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDC_BUTTON0: len = GetDlgItemText( hWnd, IDC_EDIT0, pEdit, 256 );
MessageBox( hWnd, pEdit, "Eingabe-Feld", MB_OK);
break;
case IDC_BUTTON1: len = GetDlgItemText( hWnd, IDC_COMBO1, p1, 256 ); MessageBox(
hWnd, p1, "Kombinations-Feld", MB_OK);
break;
case IDOK: //fall
case IDCANCEL: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE;
} break;
case WM_CLOSE: free( pEdit ); pEdit = NULL;
EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ) ;
break;
}
return FALSE;
}
Interne Dialog - CALLBACK - Funktion
Alle Dialog - Klassen sind Window - Klassen. Eine Dialog - Box ist ein Window zu einer vorhandenen Klasse. Es wird zusätzlicher Speicher WNDCLASS cbWndExtra =
DLGWINDOWEXTRA benötigt. Für einen DialogBox() - oder CreateDialog() - Aufruf wird i.a. keine eigene Klasse registriert. Anstelle einer eigenen Klassen - CALLBACK - Funktion wird
die eingebaute und bereits unter 0x8002 registrierte USER.EXE - interne IDefDlgProc() - Funktion benutzt.
Durch DialogBox() werden die folgenden Nachrichten versendet.
DM_GETDEFID
WM_CTLCOLORDLG
WM_GETDLGCODE
DM_REPOSITION
WM_CTLCOLORMSGBOX
WM_INITDIALOG
DM_SETDEFID
WM_ENTERIDLE
WM_NEXTDLGCTL
In der internen IDefDlgProc() wird durch result = CallDlgProc( hWnd, iMsg, wParam, lParam)) die eingetragene Benutzer - CALLBACK - Funktion aufgerufen. Der BOOL - Rückgabe Wert entscheidet über die weitere Bearbeitung der Nachrichten. Die CALLBACK - Funktion
●
BOOL myDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
des Benutzers sollte kann z.B. die Nachrichten WM_INITDIALOG, WM_CLOSE, WM_COMMAND ( mit IDOK und IDCANCEL ) bearbeiten. Der BOOL - Rückgabe - Wert entscheidet
über die weitere Bearbeitung der Nachrichten.
Falls in WM_INITDIALOG alles erledigt wurde, so wird der iMsg = WM_INITDIALOG - Case mit return TRUE, sonst return FALSE ( Normalfall ) beendet.
WM_CLOSE soll EndDialog ( hWnd, wParam ) aufrufen. WM_COMMAND mit IDOK und IDCANCEL kann z.B. die Nachricht ( hWnd, WM_CLOSE, wParam, 0L ) senden.
Das folgende Fragment zeigt den Aufruf der eingetragenen Benutzer - CALLBACK - Funktion ( PDLG ) hWnd ) -> lpfnDlg mit Hilfe von CallDlgProc(). Falls keine lpfnDlg - Funktion
eingetragen wurde oder CallDlgProc() FALSE zurück gibt, so erfolgt eine default Behandlung durch Windows.
LRESULT API IDefDlgProc( HWND hWnd, WORD iMsg, WPARAM wParam, LPARAM lParam) {
( ( PDLG ) hWnd ) -> resultWP = 0L; BOOL result = FALSE;
if ( ( ( PDLG ) hWnd ) -> lpfnDlg == NULL
|| ! ( result = CallDlgProc( hWnd, iMsg, wParam, lParam )))
{
if ( ! IsWindow( hWnd ) ) { DebugErr(DBF_ERROR, "..." ); goto ReturnIt; }
switch ( iMsg ) {
case WM_ERASEBKGND:
...
case WM_SHOWWINDOW:
...
case WM_SYSCOMMAND:
...
case WM_ACTIVATE:
...
case WM_SETFOCUS:
...
case WM_CLOSE:
...
case WM_NCDESTROY:
...
case DM_SETDEFID:
...
case DM_GETDEFID:
...
case WM_NEXTDLGCTL:
...//TAB-like operations
case WM_ENTERMENULOOP:...
case WM_LBUTTONDOWN: ...
case WM_NCLBUTTONDOWN:...
case WM_GETFONT:
...
case WM_VKEYTOITEM:
...
case WM_COMPAREITEM: ...
case WM_CHARTOITEM:
...
case WM_INITDIALOG:
...
default: return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
ReturnIt:
if (iMsg == WM_CTLCOLOR
|| iMsg == WM_COMPAREITEM ||
iMsg == WM_VKEYTOITEM
|| iMsg == WM_CHARTOITEM ||
iMsg == WM_QUERYDRAGICON || iMsg == WM_INITDIALOG) {
return( (LRESULT)(DWORD) result );
}
return( ( ( PDLG ) hWnd ) -> resultWP );
}
Standard - Dialoge
CHAR * get_Open_File_Name ( HWND hWnd, CHAR * pNamExt, CHAR * pTitle )
{ OPENFILENAME ofn = { 0 } ;
static char buf[MAX_PATH] ; buf[0] = '\0' ;
if ( pNamExt == NULL ) pNamExt = "All Files\000*.*\000" ;
ofn.lStructSize
= sizeof( OPENFILENAME );
ofn.hwndOwner
= hWnd ;
ofn.hInstance
= GetModuleHandle( NULL );
ofn.lpstrTitle
= pTitle ;
ofn.lpstrFile
= buf ;
ofn.nMaxFile
= sizeof( buf ) ;
ofn.lpstrFilter
= pNamExt ;
ofn.lpstrDefExt
= "*" ;
ofn.nFilterIndex = 1L ;
if ( GetOpenFileName( & ofn ) ) return buf ;
return NULL ;
}
Controls
●
●
●
Ein Dialog enthält untergeordnete Fenster ( Controls ).
Zu einem Control gehört i.a. eine eingebauten Klasse.
Die Klasse enthält eine eingebaute CALLBACK - Funktion, die die Ereignisse behandelt.
Zu einer ein/mehr - zeiligen Texteingabe gehört die Klasse "Edit". Zu einem Button gehört die Klasse "Button". Mit der Kenntnis dieser Control - Ereignisse können die Controls genutzt
werden.
Als Beispiel werden die Combo - Box - Ereignisse angefügt. Die Combo - Box ( Edit - Zeile mit List - Box ) kann die folgenden Nachrichten senden/empfangen/behandeln:
Combo Box Messages
CB_ADDSTRING
CB_FINDSTRING
CB_GETCURSEL
CB_GETDROPPEDWIDTH
CB_GETHORIZONTALEXTENT
CB_GETLBTEXT
CB_GETTOPINDEX
CB_LIMITTEXT
CB_SETCURSEL
CB_SETEXTENDEDUI
CB_SETITEMHEIGHT
CB_SHOWDROPDOWN
CBN_DROPDOWN
CBN_ERRSPACE
CBN_SELENDCANCEL
WM_COMPAREITEM
CB_DELETESTRING
CB_FINDSTRINGEXACT
CB_GETDROPPEDCONTROLRECT
CB_GETEDITSEL
CB_GETITEMDATA
CB_GETLBTEXTLEN
CB_INITSTORAGE
CB_RESETCONTENT
CB_SETDROPPEDWIDTH
CB_SETHORIZONTALEXTENT
CB_SETLOCALE
CBN_CLOSEUP
CBN_EDITCHANGE
CBN_KILLFOCUS
CBN_SELENDOK
WM_DRAWITEM
CB_DIR
CB_GETCOUNT
CB_GETDROPPEDSTATE
CB_GETEXTENDEDUI
CB_GETITEMHEIGHT
CB_GETLOCALE
CB_INSERTSTRING
CB_SELECTSTRING
CB_SETEDITSEL
CB_SETITEMDATA
CB_SETTOPINDEX
CBN_DBLCLK
CBN_EDITUPDATE
CBN_SELCHANGE
CBN_SETFOCUS
WM_MEASUREITEM
Um einem Control eine Nachricht zu schicken wird anstelle von
HWND hCtl = GetDlgItem ( HWND hDlg, int idRes );
LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam);
oft
LONG SendDlgItemMessage ( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam, LPARAM
lParam);
benutzt.
Die folgenden Funktionen werden oft verwendet:
HWND hCtl = GetDlgItem ( HWND hDlg, int idRes );
int idRes = GetDlgCtrlID( HWND hCtl );
BOOL SetDlgItemText
( HWND hDlg, int idRes, LPCSTR lpString);
UINT GetDlgItemText
( HWND hDlg, int idRes, LPSTR lpString, int nMaxCount);
BOOL SetDlgItemInt
( HWND hDlg, int idRes, UINT uValue,
BOOL bSigned);
UINT GetDlgItemInt
( HWND hDlg, int idRes, BOOL *lpTranslated, BOOL bSigned);
BOOL CheckDlgButton
( HWND hDlg, int idRes, UINT uCheck);
BOOL CheckRadioButton
( HWND hDlg, int nIDFirstButton, int nIDLastButton, int
nIDCheckButton);
UINT IsDlgButtonChecked ( HWND hDlg, int idRes);
HWND GetNextDlgGroupItem( HWND hDlg, HWND hCtl, BOOL bPrevious);
HWND GetNextDlgTabItem ( HWND hDlg, HWND hCtl, BOOL bPrevious);
Static Text Control
Static Text Controls
Static
Text
Controls
Static_Enable
(hCtl,
Static_GetIcon
(hCtl,
Static_GetText
(hCtl,
Static_GetTextLength(hCtl)
Static_SetIcon
(hCtl,
Static_SetText
(hCtl,
fEnable)
hIcon)
lpch, cchMax)
hIcon)
lpsz)
Button Control
In windowX.h sind die folgenden Button - Macros definiert:
Button Controls
Button
Controls
Button_Enable
(hCtl,
Button_GetCheck
(hCtl)
Button_GetState
(hCtl)
Button_GetText
(hCtl,
Button_GetTextLength(hCtl)
Button_SetCheck
(hCtl,
Button_SetState
(hCtl,
Button_SetStyle
(hCtl,
Button_SetText
(hCtl,
fEnable)
lpch, cchMax)
check)
state)
style, fRedraw)
lpsz)
Ein Button kann auf drei Arten selektiert werden:
●
●
●
durch Klicken mit der Maus,
durch Auswählen mit der Tab - Taste und dann die Enter - Taste drücken,
durch Auswählen des Group - Rahmens mit der Tab - Taste ( falls der Button den WS_GROUP - Style hat ) und dann kann innerhalb des Group - Rahmens mit den Pfeilchen Tasten der Button selektiert weren.
Die Button - Auswahl bewirkt die folgenden Ereignisse:
●
●
●
●
Button erhält den Keyboard - Focus ( WM_FOCUS ),
Button sendet bei Selektion an das Parent - Window eine Benachrichtigung ( Notification Message ),
das Parent - Window sendet an den Button eine Nachricht zur Zustands - Änderung,
das Parent Window zeichnet den Button neu im Zustand: focus-state / push-state / check-state.
Eine Applikation kann den aktuelle Zustand mit BM_GETCHECK oder BM_GETSTATE abfragen und mit BM_SETCHECK oder BM_SETSTATE setzen.
Der Button sendet Nachrichten an das Parent - Window, wenn sich sein Zustand ändert. Der Button - Identifizierer wird mit wmID, die Notification Messages ( z.B. BN_CLICKED ) wird mit
wmCMD und das Control - Handle mit wmHWND bezeichnet. Wegen der WIN16/WIN32 - Portabilität sind die windoesX.h - Macros sinnvoll:
Nachrichten - Casting
WindosX.h-Macros
#ifdef WIN16
int wmCMD = HIWORD( lParam ) ;
#else
int wmCMD = HIWORD( wParam ) ;
#endif
int wmID = LOWORD( wParam );
HWND wmHWND=(HWND)(UINT)lParam;
int wmCMD = GET_WM_COMMAND_CMD ( wParam, lParam ) ;
int wmID = GET_WM_COMMAND_ID ( wParam, lParam ) ;
HWND wmHWND= GET_WM_COMMAND_HWND( wParam, lParam ) ;
Beim Übergang von WIN16 auf WIN32 hat sich das Nachrichten - Format geändert. Bei WIN16 war wParam ein WORD - Typ, bei WIN32 ist wParam ein LONG - Typ. Bei WIN32 benötigt
ein Handle 32 Bits
Es gibt die folgenden Button - Notification - Messages
ButtonNotificationMessages
Erklärung
BN_CLICKED
Der Benutzer hat den Button geklickt
BN_DBLCLK
Der Benutzer hat den Button doppelt geklickt
BN_DISABLE
Der Button ist gesperrt
BN_PUSHED
Der Benutzer hat den Button gedrückt
BN_KILLFOCUS
Der Button verliert den Keyboard - Focus
BN_PAINT
Der Button sollte gezeichnet werden
BN_SETFOCUS
Der Button erhält den Keyboard - Focus
BN_UNPUSHED
Der Button ist nicht mehr gedrückt
Sendet der Button ID_MY_BUTTON1 z.B. die BN_CLICKED - Notification - Messages an das Parent - Window, so kann diese Nachricht gemäß
int wmCMD = GET_WM_COMMAND_CMD ( wParam, lParam ) ;
int wmID = GET_WM_COMMAND_ID ( wParam, lParam ) ;
switch ( iMsg ) {
...
case WM_COMMAND:
switch ( wmID ) {
case ID_MY_BUTTON1:
HWND hMyButton1 = GET_WM_COMMAND_HWND( wParam, lParam ) ;
if ( wmCMD == BN_CLICKED ) {
...
}
...
}
...
}
in der CALLBACK - Funktion des Parent - Window bearbeitet werden.
Damit die BN_DISABLE, BN_PUSHED, BN_KILLFOCUS, BN_PAINT, BN_SETFOCUS und BN_UNPUSHED Notification - Nachrichten an das Parent - Window gesendet werden, muß
der Button den BS_NOTIFY - Style besitzen.
Ein Owner - Drawn - Button sendet WM_DRAWITEM an das Parent - Window.
Edit Control
Edit Controls
Edit
Controls
Edit_CanUndo
(hCtl)
Edit_EmptyUndoBuffer(hCtl)
Edit_Enable
(hCtl,
Edit_FmtLines
(hCtl,
Edit_GetFirstVisible(hCtl)
Edit_GetHandle
(hCtl)
Edit_GetLine
(hCtl,
Edit_GetLineCount
(hCtl)
Edit_GetModify
(hCtl)
Edit_GetRect
(hCtl,
Edit_GetSel
(hCtl)
Edit_GetText
(hCtl,
Edit_GetTextLength (hCtl)
Edit_LimitText
(hCtl,
Edit_LineFromChar
(hCtl,
Edit_LineIndex
(hCtl,
Edit_LineLength
(hCtl,
fEnable)
fAddEOL)
line, lpch, cchMax)
lprc)
lpch, cchMax)
cchMax)
ich)
line)
line)
Edit_ReplaceSel
(hCtl,
Edit_Scroll
(hCtl,
Edit_SetHandle
(hCtl,
Edit_SetModify
(hCtl,
Edit_SetPasswordChar(hCtl,
Edit_SetRect
(hCtl,
Edit_SetRectNoPaint (hCtl,
Edit_SetSel
(hCtl,
Edit_SetTabStops
(hCtl,
Edit_SetText
(hCtl,
Edit_SetWordBreak
(hCtl,
Edit_Undo(hCtl)
lpszReplace)
dv, dh)
h)
fModified)
ch)
lprc)
lprc)
ichStart, ichEnd)
cTabs, lpTabs)
lpsz)
lpfnWordBreak)
Beispiel
Die folgende Funktion Print_Lines() holt aus einer Multi - Line - Edit - Box alle Zeilen und gibt diese durch PrintInWindow() aus. Print_Lines() wird in unterschiedlicher Schreibweise (
mit/ohne den Edit_GetLineCount-, Edit_GetLine - Macros aus WINDOWS.H ) angegeben.
void Print_Lines( HWND hEdit, WHND hDisplay ) {
int line; int lineLast = (int) SendMessage( hEdit, EM_GETLINECOUNT, 0, 0L );
for ( line = 0; line < lineLast; line ++ ) { int cch; char ach[256];
*( (LPINT) ach ) = sizeof( ach );
cch = (int) SendMessage( hEdit, EM_GETLINE, line, (LONG)(LPSTR) ach );
PrintInWindow( ach, hDisplay);
}
}
In WINDOWS.H ist definiert:
#define Edit_GetLineCount( hEdit ) \
((int)(DWORD)SendMessage((hEdit),\
EM_GETLINECOUNT,0L,0L))
#define Edit_GetLine( hEdit, line, lpch, cchMax) \
((*((int *)(lpch)) = (cchMax)), ((int)(DWORD)\
SendMessage((hEdit),\
EM_GETLINE,(WPARAM)(int)(line),(LPARAM)(LPTSTR)(lpch))))
Bei Verwendung der Edit_GetLineCount-, Edit_GetLine - Macros wird ein mehrfaches Casten vermieden.
void Print_Lines( HWND hEdit, WHND hDisplay ) {
int line; int lineLast = Edit_GetLineCount( hEdit );
for ( line = 0; line < lineLast; line ++ ) { int cch; char ach[256];
cch = Edit_GetLine( hEdit, line, ach, sizeof(ach) );
PrintInWindow( ach, hDisplay );
}
}
List Box Control
List Box Controls
List
Box
Controls
ListBox_AddFile
(hCtl, lpszFilename)
ListBox_AddItemData
(hCtl, data)
ListBox_AddString
(hCtl, lpsz)
ListBox_DeleteString (hCtl, index)
ListBox_Dir
(hCtl, attrs, lpszFileSpec)
ListBox_FindItemData (hCtl, indexStart, data)
ListBox_Enable
(hCtl, fEnable)
ListBox_FindString
(hCtl, indexStart, lpszFind)
ListBox_GetAnchorIndex(hCtl)
ListBox_GetCaretIndex (hCtl)
ListBox_GetCount
(hCtl)
ListBox_GetCurSel
(hCtl)
ListBox_GetHorizontalExtent(hCtl)
ListBox_GetItemData
(hCtl, index)
ListBox_GetItemHeight (hCtl, index) Win32
ListBox_GetItemRect
(hCtl, index, lprc)
ListBox_GetSel
(hCtl, index)
ListBox_GetSelCount
(hCtl)
ListBox_GetText
(hCtl, index, lpszBuffer)
ListBox_GetSelItems
(hCtl, cItems, lpIndices)
ListBox_GetTextLen
(hCtl, index)
ListBox_GetTopIndex
(hCtl)
ListBox_InsertItemData(hCtl, lpsz, index)
ListBox_InsertString (hCtl, lpsz, index)
ListBox_ResetContent (hCtl)
ListBox_SelectItemData(hCtl, indexStart, data)
ListBox_SelectString (hCtl, indexStart, lpszFind)
ListBox_SelItemRange (hCtl, fSelect, first, last)
ListBox_SetAnchorIndex(hCtl, index)
ListBox_SetCaretIndex (hCtl, index)
ListBox_SetColumnWidth(hCtl, cxColumn)
ListBox_SetCurSel
(hCtl, index)
ListBox_SetItemData
(hCtl, index, data)
ListBox_SetHorizontalExtent(hCtl, cxExtent)
ListBox_SetSel
(hCtl, fSelect, index)
ListBox_SetItemHeight (hCtl, index, cy) Win32
ListBox_SetTabStops
(hCtl, cTabs, lpTabs)
ListBox_SetTopIndex
(hCtl, indexTop)
Combo Box Control
Eine Combo - Box besteht aus einer Edit - Zeile und einer zusätzlichen List - Box. Hat eine Combo - Box den Style CBS_DROPDOWN, so kann die Combo - Box aufgeklappt werden. List Zeilen können mit Klick oder Cursor - Tasten in die Edit - Zeile geholt werden.
Combo Box Controls
Combo
Box
Controls
ComboBox_AddItemData
(hCtl, data)
ComboBox_AddString
(hCtl, lpsz)
ComboBox_DeleteString
(hCtl, index)
ComboBox_Dir
(hCtl, attrs, lpszFileSpec)
ComboBox_Enable
(hCtl, fEnable)
ComboBox_FindItemData
(hCtl, indexStart, data)
ComboBox_GetCount
(hCtl)
ComboBox_FindString
(hCtl, indexStart, lpszFind)
ComboBox_GetCurSel
(hCtl)
ComboBox_GetDroppedControlRect(hCtl, lprc) Win32
ComboBox_GetDroppedState (hCtl) Win32
ComboBox_GetEditSel
(hCtl)
ComboBox_GetExtendedUI
(hCtl) Win32
ComboBox_GetItemData
(hCtl, index)
ComboBox_GetItemHeight
(hCtl)
ComboBox_GetLBText
(hCtl, index, lpszBuffer)
ComboBox_GetLBTextLen
(hCtl, index)
ComboBox_GetText
(hCtl, lpch, cchMax)
ComboBox_GetTextLength
(hCtl)
ComboBox_InsertItemData (hCtl, index, data)
ComboBox_InsertString
(hCtl, index, lpsz)
ComboBox_LimitText
(hCtl, cchLimit)
ComboBox_ResetContent
(hCtl)
ComboBox_SelectItemData (hCtl, indexStart, data)
ComboBox_SetCurSel
(hCtl, index)
ComboBox_SelectString
(hCtl, indexStart, lpszSelect)
ComboBox_SetExtendedUI
(hCtl, flags)Win32
ComboBox_SetEditSel
ComboBox_SetItemHeight
ComboBox_SetItemData
ComboBox_SetText
ComboBox_ShowDropdown
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
ichStart, ichEnd)
cyItem)Win32
index, data)
lpsz)
fShow)
Beispiel
Im *.RC - File soll in einer STRINGTABLE ein String IDS_STRING0 abgelegt werden, der zum Füllen einer Combo - Box verwendet werden soll. Die List - Box - Zeilen werden durch \000
beendet. Bei Win16 ist anstelle von Der *.RC - File enthält dann z.B.
STRINGTABLE DISCARDABLE
BEGIN
IDS_STRING0 "(EB_ und 0.LB_Text0\000(1.LB_Text)\000(2.LB_Text)\000"
END
IDD_MYDIALOG DIALOG DISCARDABLE 0, 0, 186, 129
STYLE
DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION ...
FONT
8, "MS Sans Serif"
BEGIN
//
idCombo,
x, y, dx,dy, Combo-Style
COMBOBOX IDC_COMBO1, 5,53, 115,80, CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
END
Die Combo - Box wird mit IDC_COMBO1 identifiziert. Die aufgeklappte Box hat hier eine Höhe von 80 Dialog - Pixeln.
Es wird eine Funktion ComboBox_fillFromResString() angegeben, die idString=IDS_STRING0 holt und in idCombo=IDC_COMBO1 schreibt. Auch die aufgeklappten List - Zeilen
werden eingetragen.
HWND ComboBox_fillFromResString ( HWND hWnd, int idString, int idCombo )
{ int idx = 0 ; char buf[512];
int idxMax = LoadString( GetModuleHandle(NULL), idString, buf, 512 );
HWND hCombo = GetDlgItem( hWnd, idCombo ) ;
if ( ( idxMax <= 0 ) || ( hCombo == NULL ) ) return NULL;
SetWindowRedraw ( hCombo, FALSE );
//CB refresh aus
ComboBox_SetText( hCombo, buf );
//EB
while ( idx < idxMax ) {
//LBs
ComboBox_AddString ( hCombo, & buf[idx] );
idx += strlen( & buf[idx] ) + 1 ;
}
SetWindowRedraw( hCombo, TRUE );
//CB refresh ein
return hCombo;
}
Durch SetWindowRedraw( ) wird eine wiederholte Auffrischung bei jedem Eintrag unterdrück. Dadurch wird das Bildschirm - Flackern reduziert.
In der Dialog - CALLBACK - Funktion werden die Controls meistens unter WM_INITDIALOG initialisiert:
BOOL CALLBACK myDlgProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
case WM_INITDIALOG:
hCombo = ComboBox_fillFromResString ( hWnd, IDS_STRING0, IDC_COMBO1 );
break;
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDOK: ... break;
} break;
case WM_CLOSE: ... break;
...
}
return FALSE;
}
Hex - Calc
IDD_DIALOG_HEXCALC DIALOG DISCARDABLE 5, 10, 188, 135
STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_THICKFRAME
CAPTION "Hex - Calc"
FONT 8, "MS Sans Serif"
BEGIN
COMBOBOX
IDC_COMBO0, 5,5,115,125,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON
"0",48,6,117,14,14,NOT WS_TABSTOP
PUSHBUTTON
"1",49,6,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"2",50,24,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"3",51,42,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"4",52,6,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"5",53,24,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"6",54,42,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"7",55,6,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"8",56,24,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"9",57,42,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"A",65,42,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"B",66,24,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"C",67,6,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"D",68,42,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"E",69,24,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"F",70,6,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"+",43,64,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"-",45,64,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"*",42,82,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
DEFPUSHBUTTON
CONTROL
CONTROL
"/",47,82,99,14,14,NOT WS_TABSTOP
"%",37,64,30,14,14,NOT WS_TABSTOP
"=",61,24,117,31,14,NOT WS_TABSTOP
"&&",38,82,63,14,14,NOT WS_TABSTOP
"|",124,64,63,14,14,NOT WS_TABSTOP
"^",94,64,46,14,14,NOT WS_TABSTOP
"<",60,82,30,14,14,NOT WS_TABSTOP
">",62,82,46,14,14,NOT WS_TABSTOP
"M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP
"M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP
"MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP
"MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP
"BS",8,64,117,31,14,NOT WS_TABSTOP
"AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP
"Schliessen",IDOK,135,117,50,14,NOT WS_TABSTOP
"",IDC_STATIC,"Static", SS_BLACKRECT,126,5,6,125
"",IDC_STATIC,"Static", SS_BLACKRECT,5,21,116,6
END
Die folgenden Programmfragmente zeigen lediglich das Prinzip und können zum Experimentieren dienen.
void hex_show_number ( HWND hWnd, INT idRes, UINT iNum ) {
CHAR buf[256] ; HWND hCtl = GetDlgItem( hWnd, IDC_COMBO0 ) ;
strupr( ltoa( iNum, buf, 16 ));
ComboBox_SetText( hCtl, buf ) ;
if ( idRes == IDC_COMBO0 ) {
if ( ComboBox_GetCount
( hCtl ) >= 15 )
ComboBox_DeleteString( hCtl,
15 ) ;
ComboBox_InsertString
( hCtl, 0, buf );
}
}
DWORD hex_calc_it ( UINT iFirstNum, INT iOperation, UINT iNum ) {
switch ( iOperation ) {
default : return 0 ;
case '=' : return iNum ;
case '+' : return iFirstNum + iNum ;
case '-' : return iFirstNum - iNum ;
case '*' : return iFirstNum * iNum ;
case '&' : return iFirstNum & iNum ;
case '|' : return iFirstNum | iNum ;
case '^' : return iFirstNum ^ iNum ;
case '<' : return iFirstNum << iNum ;
case '>' : return iFirstNum >> iNum ;
case '/' : return iNum ? iFirstNum / iNum : UINT_MAX ;
case '%' : return iNum ? iFirstNum % iNum : UINT_MAX ;
}
}
BOOL CALLBACK dlgHexCalcProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
static BOOL bNewNumber = TRUE ;
static INT
iOperation = '=' ;
static UINT iNumber, iFirstNum ;
static CHAR * pCombo; HWND hCtl;
switch ( iMsg ) {
case WM_INITDIALOG: //keine doppelten Dialoge
if ( pCombo != NULL ) DestroyWindow( hWnd ) ;
pCombo = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); strcpy( pCombo, "0" );
hCtl = GetDlgItem( hWnd, IDC_COMBO0 ) ;
ComboBox_SetText ( hCtl, pCombo );
break;
case WM_COMMAND :
switch ( LOWORD( wParam ) ) {
case IDOK: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE;
case IDC_COMBO0:
case IDC_BUTTON0:
case IDC_BUTTON1:
case IDC_BUTTON2:
case IDC_BUTTON3:
case IDC_BUTTON4:
case IDC_BUTTON5:
break ;
case VK_BACK:
hex_show_number( hWnd, 0, iNumber /= 16 ) ;
break ;
case VK_ESCAPE: hex_show_number( hWnd, 0, iNumber = 0) ;
break ;
default:
if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit
if ( bNewNumber == TRUE ) { iFirstNum = iNumber ; iNumber = 0 ;
}
if ( iNumber <= UINT_MAX >> 4 ) {
iNumber = 16 * iNumber + wParam - ( isdigit( wParam ) ? '0' : 'A' - 10 ) ;
hex_show_number ( hWnd, 0, iNumber ) ;
} else MessageBeep( 0 ) ;
bNewNumber = FALSE ;
} else {
// operation
if ( bNewNumber == FALSE ) {
iNumber = ( UINT ) hex_calc_it ( iFirstNum, iOperation, iNumber ) ;
hex_show_number ( hWnd, IDC_COMBO0, iNumber ) ;
}
iOperation = LOWORD( wParam ) ; bNewNumber = TRUE ;
}
break;
} break;
case WM_CLOSE: free( pCombo ); pCombo = NULL;
EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ) ; break;
}
return FALSE ;
}
Hex-Rechner1 ohne *.rc
Mit Hilfe der CreateWindowEx()-Funktion und den Styles:
Button:
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP
ComboBox: WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN
Edit:
WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN
können Dialogähnliche Controls in ein Fenster auch ohne *.rc-Resourcen gesetzt werden. Allerdings fehlt dann die Dialog-Klasse, die z.B. eine Bedienung der Controls mit der Tab-Taste
ermöglicht. Die Funktionen my_button(), my_combo(), my_edit() vereinfachen die Tipp-Arbeit und die zurück gelieferten
HWND hCombo;
HWND hEdit;
werden direkt verwendet, anstelle von
HWND hCombo = GetDlgItem(hwnd,IDC_COMBO);
HWND hEdit = GetDlgItem(hwnd,IDC_EDIT);
void my_button(HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes)
{
// Bei idRes = 0 wird für idRes der Txt-ASCII-Wert verwendet:
// Beisp.: txt = "A" erzeugt idRes = 65
if(idRes <= 0) idRes = (WORD) *txt;
CreateWindowEx(0,"BUTTON",txt,
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
}
/////////////////////////////////////////////////
HWND my_combo( HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes)
{ HWND
hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN,
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
//RECT rc; // existiert Combo-Liste kann getestet werden mit:
//SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc);
return hCombo;
}
/////////////////////////////////////////////////
HWND my_edit(HWND hwnd, int x,int y, int cx,int cy, char *txt, WORD idRes)
{ HWND
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT
|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN,
x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0);
return hEdit;
}
Hier ein *.cpp-Testprogramm (braucht keinen *.rc):
#include <windows.h>
#include <windowsx.h> #include <limits.h> /////////////////////////////////////////////////
//Hauptprogramm
#define err_if(e,str) \
/////////////////////////////////////////////////
if(e)MessageBox(0,(str),0,MB_OK|MB_ICONSTOP);
int APIENTRY WinMain
/////////////////////////////////////////////////
(HINSTANCE hInst,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
// globales
{
/////////////////////////////////////////////////
// HINSTANCE hInst = GetModuleHandle(0);
const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText()
// Nutze die vorhandene Desktop-Klasse
const UINT MAX_COMBO_CHAR =
8;//ComboBox_LimitText()
// für die Registrierung:
const UINT USE_CE = 1; // Ziel Combo-Edit
WNDCLASSEX wc = { 0 };
const UINT USE_CL = 2; // Ziel Combo-Liste
GetClassInfoEx(hInst,"#32769",&wc);//Desktop-Window
const UINT USE_EM = 4; // Ziel Edit-Multiline
wc.cbSize = sizeof(wc);
wc.lpszClassName = "my_class" ; // eigener Class-Name:
// UINT (M)em(SUM)men-Speicher MSUM
wc.lpfnWndProc = HexCalcProc; // eigene CALLBACK einfügen:
// MSUM hält den Summenwert ('M+','M-')
wc.hIcon = ExtractIcon(hInst,"Shell32.dll",12);
//'MR' für Anzeige, 'MC' setzt MSUM=0
if (!RegisterClassEx(&wc)) err_if(1,"RegisterClassEx()");
UINT MSUM;
// HEX-Rechner als Haupt-Fenster:
// Verwendet werden hCombo, hEdit dadurch entfällt:
int X = 100, Y = 100, DX = 204, DY = 380; HWND hwnd =
// HWND hCombo = GetDlgItem(hwnd,IDC_COMBO);
CreateWindowEx(WS_EX_LEFT,wc.lpszClassName,"HEX-Rechner",
// HWND hEdit = GetDlgItem(hwnd,IDC_EDIT);
WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME,
HWND hCombo; //hCombo anstelle von IDC_COMBO
X,Y,DX,DY,0,0,hInst,0);
HWND hEdit; //hEdit anstelle von IDC_EDIT
// anzeigen:
/////////////////////////////////////////////////
ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);
void my_button
(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
// alle Button's per Programm "createn"
{ if(idRes<=0)idRes=(WORD)*txt;
int cx=24, cy=24, dx=26, dy=26, x,y,
CreateWindowEx(0,"BUTTON",txt,
x0= 4, y0= 5, //für ComboBox
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
x1= 4, y1=40, //1.Button-Spalte
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
x2= 34, y2=40, //2.Button-Spalte
}
x3= 64, y3=40, //3.Button-Spalte
/////////////////////////////////////////////////
x4=100, y4=40, //4.Button-Spalte
HWND my_combo
x5=130, y5=40, //5.Button-Spalte
(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
{ HWND
hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN,
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
//RECT rc;
//SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc);
return hCombo;
}
/////////////////////////////////////////////////
HWND my_edit
(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
{ HWND
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT
|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN,
x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0);
return hEdit;
}
/////////////////////////////////////////////////
// print_append() kann aus den hSrc-Fenster Text holen
// und gemäss "printf-ähnlichem" Formats Text "anhängen"
// und den gesamten Text in das hDst-Fenster schreiben.
// Dadurch entsteht ein "append" von Text
//
// Anstelle der Aufruffolge:
//
print_append(hEdit,hEdit, "\r\n");
//
print_append(hEdit,hEdit, "%u ", u1);
//
print_append(hEdit,hEdit, "%u ", u2);
//
// ist günstiger:
//
print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2);
/////////////////////////////////////////////////
int CDECL print_append
( HWND hDst, HWND hSrc, LPTSTR pFormat, ...)
{ static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048
err_if(!hDst,"print_append(): hDst?");
memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf;
va_list argList;
va_start( argList, pFormat ) ;
if(hSrc) // hole Text aus hSrc
pBuf += GetWindowText(hSrc,Buf,sizeof(Buf));
// bei Speichermangel pBuf auf Buf[0]
if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf;
pBuf += wvsprintf( pBuf, pFormat, argList ) ;
va_end( argList ) ;
// schreibe erweiterten Text in hDest
x6=168, y6=40; //6.Button-Spalte
x=x0; y=y0;
WORD IDC_COMBO = 1000;
hCombo =
my_combo(hwnd,x,y,188,180,"COMBO",IDC_COMBO);
ComboBox_LimitText(hCombo, MAX_COMBO_CHAR);
ComboBox_SetText (hCombo, "0");
// keine Hand-Eingabe, falls
// ComboBox_Enable(hCombo, FALSE);
x=x1; y=y1;
my_button(hwnd,x,y,dx,cy,"F",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"C",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"7",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"4",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"1",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"0",0);
x=x2; y=y2;
my_button(hwnd,x,y,dx,cy,"E",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"B",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"8",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"5",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"2",0);y+=dy;
my_button(hwnd,x,y,2*dx+4,cy,"=",0);
x=x3; y=y3;
my_button(hwnd,x,y,dx,cy,"D",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"A",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"9",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"6",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"3",0);
x=x4; y=y4;
my_button(hwnd,x,y,dx,cy,"%",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"^",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"|",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"+",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"-",0);y+=dy;
my_button(hwnd,x,y,2*dx+4,dy,"BS",1000);
x=x5; y=y5;
my_button(hwnd,x,y,dx,cy,"<",0);y+=dy;
my_button(hwnd,x,y,dx,cy,">",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"&&",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"*",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"/",0);
x=x6; y=y6;
my_button(hwnd,x,y,dx,cy,"M+",1001);y+=dy;
my_button(hwnd,x,y,dx,cy,"M-",1002);y+=dy;
SetWindowText( hDst, Buf );
return (pBuf-Buf);
}
/////////////////////////////////////////////////
// show_hex() schreibt uNum in das ziel.
// Beispiel: show_hex(10,USE_CE);
// Ziel kann sein (USE_CE|USE_CL|USE_EM)
/////////////////////////////////////////////////
void show_hex(UINT uNum, int ziel )
{ char buf[256]; int radix = 16;
//global sind hCombo, hEdit
//schreibe uNum als hex-String (basis 16) in buf
strupr( ltoa(uNum, buf, radix) );
//Ausgabe von buf in ziel
if (USE_CE & ziel) {//in Combo-Liste eintragen:
ComboBox_SetText(hCombo, buf ) ;
}
if (USE_CL & ziel) { //in Combo-Liste eintragen:
if ( ComboBox_GetCount(hCombo) >= 30)
ComboBox_DeleteString(hCombo,30);
ComboBox_InsertString(hCombo, 0, buf );
}
if (USE_EM & ziel) { //in Edit-Journal eintragen:
print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum);
}
}
/////////////////////////////////////////////////
// Beispiel: UINT erg = berechne(6,'+',4);
// Schreibt auch in hEdit
/////////////////////////////////////////////////
UINT berechne(UINT uNum1, char Op, UINT uNum2 )
{ UINT erg;
switch ( Op ) {
default : erg = 0; return erg;
case '=' : erg = uNum2 ; return erg;
case '+' : erg = uNum1 + uNum2 ; break;
case '-' : erg = uNum1 - uNum2 ; break;
case '*' : erg = uNum1 * uNum2 ; break;
case '&' : erg = uNum1 & uNum2 ; break;
case '|' : erg = uNum1 | uNum2 ; break;
case '^' : erg = uNum1 ^ uNum2 ; break;
case '<' : erg = uNum1 << uNum2 ; break;
case '>' : erg = uNum1 >> uNum2 ; break;
case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ;
break;
case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ;
break;
my_button(hwnd,x,y,dx,cy,"MR",1003);y+=dy;
my_button(hwnd,x,y,dx,cy,"MC",1004);y+=dy;
my_button(hwnd,x,y,dx,cy,"AC",1005);y+=dy;
my_button(hwnd,x,y,dx,cy,"EC",1006);y+=dy;
char * pInfo =
"MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n"
"EC löscht diese Anzeige\r\nMR zeigt M an\r\n"
"M+ addiert zu M \r\nM- subtr. von M\r\n";
WORD IDC_EDIT = 2000;
hEdit =
my_edit(hwnd,x0,y+4,188,140,pInfo,IDC_EDIT);
Edit_LimitText(hEdit, MAX_EDIT_CHAR);
// Hauptnachrichtenschleife
BOOL bRet; MSG msg;
while (bRet=GetMessage(&msg, NULL,0,0)){
err_if(-1==bRet,"GetMessage()");
TranslateMessage(&msg);
DispatchMessage (&msg);
} return 0;
}
}
print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n",
uNum1,Op,uNum2,erg);
print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n",
uNum1,Op,uNum2,erg);
return erg;
}
/////////////////////////////////////////////////
// CALLBACK
/////////////////////////////////////////////////
LRESULT CALLBACK HexCalcProc
(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{ static BOOL isNewNum = FALSE ; char buf[1024];
static char Op = '=' ;
static UINT uNum1, uNum2, uNum ; //1.2.-Zahl
switch ( iMsg ) {
case WM_COMMAND : {
WORD hwp = HIWORD(wParam);
if(hwp)//NOTIFY von Combo oder Edit
{
if(hEdit==(HWND)lParam) // EDIT-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify EN_: 0x%",hwp);
}
if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp);
if(CBN_SELCHANGE==HIWORD(wParam))
{ //etwas wird in Comboliste ausgewählt
memset(buf,0,sizeof(buf));
int index = ComboBox_GetCurSel(hCombo);
ComboBox_GetLBText(hCombo,index,buf);
isNewNum = TRUE; char *p = buf;
while(*p) { // Zeichenweise:
WPARAM wp =(WPARAM)(char)*p++;
SendMessage(hwnd,WM_COMMAND,wp,0);
}
}
if(CBN_EDITCHANGE==HIWORD(wParam))
{ // es wurde was in Combo getippt
ComboBox_SetText(hCombo, "0") ;
isNewNum=TRUE; uNum1=uNum2=0;
MessageBox(0,"Bitte keine Tasteneingabe",0,
MB_OK|MB_ICONSTOP);
return 0;
}
} break;
}
/////////////////////////////////////////////////////
switch ( LOWORD( wParam ) ) {
default:{
if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit
if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;}
if (uNum2 <= UINT_MAX >> 4 ) {
uNum2 = 16 * uNum2 + wParam
- (isdigit(wParam)?'0':'A'-10) ;
} else MessageBeep( 0 ) ;
show_hex(uNum2, USE_CE|USE_CL);
isNewNum = FALSE ;
} else {
// operation
if ( isNewNum == FALSE ) {
uNum2 = berechne(uNum1, Op, uNum2) ;
show_hex(uNum2, USE_CE);
} Op = LOWORD(wParam); isNewNum = TRUE ;
}
break;}// Ende von default
case VK_ESCAPE: show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break ;
case 1000:show_hex(uNum2/=16, USE_CE);//"BS";
break;
case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+";
isNewNum = TRUE ;
break;
case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-"
isNewNum = TRUE ;
break;
case 1003://zeige MSUM in Combo an: "MR"
show_hex(uNum2=MSUM, USE_CE|USE_CL);
isNewNum = TRUE ;
print_append(hEdit,hEdit,
"MR=%u MR=0x%X\r\n",MSUM,MSUM);
break;
case 1004: MSUM=0;//Clear MSUM: "MC"
break;
case 1005: // Clear Combo:
"AC"
show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break;
case 1006: // Clear Edit:
"EC"
SetWindowText(hEdit, "");
break;
}
break; }
case WM_DESTROY : PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd,iMsg,wParam,lParam);
}
Scroll Bar Control
Scroll Bar Controls
Scroll
Bar
Controls
ScrollBar_Enable (hCtl,
ScrollBar_GetPos (hCtl)
ScrollBar_GetRange(hCtl,
ScrollBar_SetPos (hCtl,
ScrollBar_SetRange(hCtl,
ScrollBar_Show
(hCtl,
flags)
lpposMin, lpposMax)
pos, fRedraw)
posMin, posMax, fRedraw)
fShow)
Arrow - Keys und Notification Nachrichten
Mit den Funktionen SetScrollInfo(), SetScrollPos(), SetScrollRange(), GetScrollInfo(), GetScrollPos() und GetScrollRange() können Scroll - Bars eingerichtet werden. Scroll - Bars
werden mit der Maus bedient. Das System unterstützt die Maus - Ereignisse. Wenn z.B. bei einer vertikalen Scroll Bar ein Scroll - Ereignies eintritt, so wird die WM_VSCROLL Nachricht an das Fenster gesendet. Die WM_VSCROLL - Nachricht enthält in wParam und lParam die folgenden Anteile.
WM_VSCROLL - Nachricht
●
●
●
nScrollCode = ( int ) LOWORD( wParam ); // scroll bar value
nPos = ( short int ) HIWORD( wParam ); // scroll box position
hwndScrollBar = ( HWND ) lParam; // handle of scroll bar
Der nScrollCode - Parameter kann die Werte
●
●
●
●
●
●
●
●
●
SB_BOTTOM ( Scrolls to the lower right),
SB_ENDSCROLL ( Ends scroll ),
SB_LINEDOWN ( Scrolls one line down ),
SB_LINEUP ( Scrolls one line up ),
SB_PAGEDOWN ( Scrolls one page down ),
SB_PAGEUP ( Scrolls one page up ),
SB_THUMBPOSITION ( der Benutzer hat die scroll box ( Thumb ) gezogen ( dragged ) und losgelassen. Dann gibt nPos ( 16 bits ) die Los-Lass-Position an ),
SB_THUMBTRACK ( der Benutzer ist noch am Ziehen ( dragging ). nPos ist die aktuelle Thumb - Position ),
SB_TOP ( Scrolls to the upper left )
nPos wird nur bei SB_THUMBPOSITION oder SB_THUMBTRACK benutzt. hwndScrollBar ist NULL, wenn die Nachricht nicht von einem Scroll - Bar kommt.
Scroll Bars Nachrichten
●
Die CALLBACK - Funktion sollte 0 zurück geben, wenn die CALLBACK - Funktion die abschließende Bearbeitung übernommen hat.
Keyboard - Interface für Scroll - Bars
Ein Keyboard - Interface für Scroll - Bars ermöglicht die zusätzliche Bedienung mit der Tastatur. Wenn ein Sroll Bar den Keyboard - Focus hat, so werden bei einer Pfeil - Taste ( Arrow Key ) an das Eltern - Fenster die WM_HSCROLL - bzw. WM_VSCROLL - Nachricht gesendet.
Taste
sendet
virtueller
Key-Code
und soll die
Maus-Notification-Nachricht
auslösen ...
DOWN
VK_DOWN
SB_LINEDOWN oder SB_LINERIGHT
UP
VK_UP
SB_LINEUP oder SB_LINELEFT
END
VK_END
SB_BOTTOM
HOME
VK_HOME
SB_TOP
PGDN
VK_NEXT
SB_PAGEDOWN oder SB_PAGERIGHT
PGUP
VK_PRIOR
SB_PAGEUP oder SB_PAGELEFT
LEFT
VK_LEFT
SB_LINEUP oder SB_LINELEFT
RIGHT
VK_RIGHT
SB_LINEDOWN oder SB_LINERIGHT
Ein Inteface soll eine z.B. SB_TOP bzw. SB_BOTTOM Notification - Nachricht senden, wenn VK_HOME bzw. VK_END eintrifft. Diese VK_ - Nachrichten werden unter iMsg ==
WM_KEYDOWN abgehört und die zugeordnete Notification - Nachricht gesendet.
Ein Keyboard - Interface für Scroll - Bars kann dann z.B. gemäß
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
...
case WM_KEYDOWN : { UINT w = -1;
switch ( LOWORD(wParam) ) {
case VK_HOME: w = SB_TOP;
break;
case VK_END:
w = SB_BOTTOM;
break;
case VK_UP:
w = SB_LINEUP;
break;
case VK_DOWN: w = SB_LINEDOWN; break;
case VK_LEFT:
case VK_PRIOR: w = SB_PAGEUP;
break;
case VK_RIGHT:
case VK_NEXT: w = SB_PAGEDOWN; break;
...
}
if ( w != -1 ) SendMessage( hWnd, WM_VSCROLL, MAKELONG(w,0), 0L );
} break;
...
}
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
aufgebaut werden.
Hier wurden nur UINT iMsg und WPARAM wParam verwendet. In LPARAM lParam sind weitere, spezielle Tasten - Scan - Anteile enthalten.
Custom Controls
Eine Applikation kann benutzerdefinierte Controls erstellen, die über die verfügbaren Controls hinaus gehen. Dies kann aus verschiedene Arten erfolgen:
●
●
●
Benutzung von Buttons, Listbox -, Combobox - Nachrichten zum benutzerdefinierten Zeichnen ( owner-drawn ),
Subclassing einer existierenden Control - Klasse,
Vollständige Neugestaltung, Registrierung einer eigenen Window - Klasse.
DLL's
Ein typisches Windows-Programm ( *.exe ) erzeugt Fenster, deren CALLBACK-Funktion die Nachrichten aus dem
Applikations-Buffer geschickt werden. DLL's ( dynamic link libraries, *.dll ) sind i.a. nicht direkt ausführbar, bekommen
keine Nachrichten und enthalten oft System-Funktionen, die von Programmen oder anderen DLL's genutzt werden können (
Export-Table ). Eine DLL braucht ( benutzt ) i.a. Funktionen von anderen DLL's ( Import-Table ). DLL's können wie eine
Sammlung von Funktionen in Maschinen-Code betrachtet werden ( dynamic link libraries ). DLL's können auch Ressourcen
enthalten.
Static-Linking
Mit Hilfe von höhere Programmiersprachen (C, C++, Pascal, FORTRAN, usw. ) und den übersetzenden Werkzeugen können
ausführbare Files ( *.exe ) erstellt werden. Werden die Bibliotek-Object-Files ( Maschinen-Code ) in den ausführbaren File
aufgenommen und zu einem festen Bestandteil des *.exe-Files verbunden ( Linker ), so wird vom permanenten Linken oder
statischem Linken ( static linking ) gesprochen.
Dynamic-Linking
Dynamisches Linken ( dynamic linking ) verknüpft die Bibliotheken zur Laufzeit. DLL's werden nicht in die Applikation
kopiert, sondern haben einen eigenen Adressraum und können von mehreren Anwendungen genutzt werden. Wenn eine DLL
genutzt werden soll, so läd das Operating-System die DLL ( aufgrund des File-Namens ) in en Speicher. Wird eine DLL von
keiner Alpplikation benötigt, so wird die DLL vom Operating-System ( unload ) aus dem Speicher entfernt. Der Lade/EntladeMechanismus kann explizit durch die Applikation oder implizit Operating-System ausgelöst werden.
Unterschiede zwischen Static-DynamicLinking
WDifferences Between Static-Link Libraries and Windows DLLs Windows DLLs differ considerably from static-link
libraries. Basic differences between the two are as follows:
●
●
●
●
●
●
●
●
●
Statische Bibliotheken sind in *.LIB-Files ( object files ) enthalten
Jede Applikation hat eine Kopie der statischen Bibliothek.
Die statische Bibliotek nutzt den Adressraum der Applikation.
Dynamische Bibliotheken sind in ladbaren, auführbaren Files ( *.exe explizit ladbar mit LoadLibrary, *.dll
implizit ladbar ) untergebracht.
Dynamische Bibliotheken können Maschinen-Code, Daten, Ressourcen ( z.B. Bitmaps, Icons, Cursors, usw. )
enthalten.
Beispiele für DLL's sind: A DLL is a Windows dynamic link library residing in a .DLL file. System DLLs may
have .EXE extensions, for example, USER.EXE, GDI.EXE, KRNL286.EXE, KRNL386.EXE, .DRV ( device
driver, wie z.B. MOUSE.DRV, KEYBOARD.DRV ) Nur .DLL-Extension können automatisch durch das
Operating-System geladen werden.
Applikationen enthalten beim dynamischem Linken nur die Namen der benötigten DLL's und implizit
hinzugefügte ( oder explizit angegebene ) Ladeanweisungen.
Eine DLL kann von vielen Applikationen benutzt werden.
Eine DLL hat oft seinen eigenen Daten-Adress-Raum ( shared ), der in den Adress-raum der Applikation
gemappt wird.
What makes a data segment shared?
shared data segment
These three pragma statements override the default data segment behavior and creates
a shared
data segment. See MyClass.cpp in the DLL.
// Aufbau etwa wie folgt:
// Hier stehen globale und
// static Variablen( "nicht shared" )
...
...
// Anfang vom shared data segment
#pragma data_seg("SHARED")
// Definition von einfachen Variablen,
// wie z.B. int, char[] arrays, zeiger
// Keine Klassen verwenden, die einen
// tiefen Copy Constructors brauchen
// Endd des "shared data segment"
// Zurück zum normalen Daten-Segment-Bereich
#pragma data_seg()
// Das folgende Linker-Pragma veranlasst den Linker
// die notwendigen initialisierungen für das
// "shared data segment" zu erzeugen
#pragma comment(linker, "/section:SHARED,RWS")
//////////////////////////////
//////////////////////////////
//////////////////////////////
// Eins dieser pragmas sollte funktionieren:
#pragma comment (linker, "/ENTRY:mainCRTStartup")
#pragma comment (linker, "/ENTRY:wmainCRTStartup")
#pragma comment (linker, "/ENTRY:WinMainCRTStartup")
#pragma comment (linker, "/ENTRY:wWinMainCRTStartup")
// bzw.:
#pragma comment (linker, "/SUBSYSTEM:WINDOWS")
#pragma comment (linker, "/SUBSYSTEM:CONSOLE")
#pragma warning( disable : 4305) //Double-float-Warnung
#pragma comment(lib, "OpenGL32.lib")
//////////////////////////////
Es sind unterschiedliche Methoden zu testen,
die eine Überprüfung des allokierten Heap-Speicher-Bereiches ermöglichen.
void heap_size( void )
{ CHAR Buf [1024]; LPSTR pp = Buf;
OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(!GetVersionEx(&os)) return;
switch(os.dwPlatformId){
case VER_PLATFORM_WIN32s:
pp += wsprintf(pp, "Win32s or Windows 3.1 \tVers:
%ld.%ld",os.dwMajorVersion,os.dwMinorVersion);
break;
case VER_PLATFORM_WIN32_WINDOWS:
if(0 == os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 95");
if(0 < os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 98");
break;
case VER_PLATFORM_WIN32_NT:
pp += wsprintf(pp, "Win32 or NT \tVers:
%ld.%ld",os.dwMajorVersion,os.dwMinorVersion);
break;
default: pp += wsprintf(pp, "unbekannt");
break;
}
pp += wsprintf(pp, " \tServicePack: %s",os.szCSDVersion);
MEMORYSTATUS ms;
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus( &ms ) ;
pp += wsprintf(pp,"\nmemory
in use\t:%12ld %%",ms.dwMemoryLoad);
pp += wsprintf(pp,"\nphys
mem free/total\t:%12ld \t%12ld" ,
ms.dwAvailPhys , ms.dwTotalPhys ) ;
pp += wsprintf(pp,"\npaging file free/total\t:%12ld \t%12ld" ,
ms.dwAvailPageFile , ms.dwTotalPageFile ) ;
pp += wsprintf(pp,"\nuser space free/total\t:%12ld \t%12ld" ,
ms.dwAvailVirtual , ms.dwTotalVirtual ) ;
pp += wsprintf(pp,"\n_______________________________________________" ) ;
MessageBox(auxGetHWND(),Buf,"Heap-Size",MB_OK);
}
=======================================
COM Tutorial Samples
Tutorial Home
Previous Lesson
Lesson List
Next Lesson
DLLSKEL - Win32 DLL Skeleton
SUMMARY
The DLLSKEL sample introduces the basic DLL skeleton that can be used as a point of
departure
for more complex Win32 DLLs (dynamic link libraries). It is used as a base for other
COM Tutorial code samples. In this series of COM Tutorial code samples, DLLSKEL works
with the
DLLUSER code sample to illustrate how DLLSKEL's function services are called by an
EXE consumer.
For functional descriptions and a tutorial code tour of DLLSKEL, see the Code Tour
section in
DLLSKEL.HTM. For details on setting up the programmatic usage of DLLSKEL, see the
Usage section
in DLLSKEL.HTM. To read DLLSKEL.HTM, run TUTORIAL.EXE in the main tutorial directory
and click
the DLLSKEL lesson in the table of lessons. You can also achieve the same thing by
clicking the
DLLSKEL.HTM file after locating the main tutorial directory in the Windows Explorer.
See also
DLLUSER.HTM in the main tutorial directory for more details on the DLLUSER
application and how
it works with DLLSKEL.DLL. You must build DLLSKEL.DLL before building DLLUSER. After
producing
DLLSKEL.DLL and DLLUSER.EXE, the makefile for DLLSKEL copies the necessary
DLLSKEL.H, DLLSKEL.LIB, and DLLSKEL.DLL files to the appropriate sibling directories.
For details on setting up your system to build and test the code samples in this COM
Tutorial
series, see Building the Code Samples. The supplied makefile (MAKEFILE) is Microsoft
NMAKE-compatible. To create a debug build, issue the NMAKE command in the Command
Prompt window.
For convenient use in Microsoft's Visual Studio, a project file is provided for each
sample.
To load the project for the DLLSKEL sample, you can run Visual Studio at the Command
Prompt
in the sample's directory as follows:
MSDEV DLLSKEL.DSP
You can also simply double-click the DLLSKEL.DSP file in the Windows Explorer to load
a sample's
project into Visual Studio. From within Visual Studio you can then browse the C++
classes of
the sample source and generally perform the other edit-compile-debug operations. Note
that,
as part of the Platform SDK, the compilation of these samples from within Visual
Studio
requires the proper setting of directory paths in Visual Studio. For more details,
see Building the Code Samples.
Usage
DLLSKEL is a DLL that you can access from applications by either performing an
explicit
LoadLibrary call or implicitly loading the DLL by linking to its associated .LIB
file.
In either case, you need to include DLLSKEL.H to declare the functions that are
defined
as exported in the DLLSKEL DLL. In the case of this Tutorial lesson, a representative
DLLUSER.EXE application is provided to illustrate the programmatic use of
DLLSKEL.DLL.
DLLUSER is built in the DLLUSER lesson (in sibling directory DLLUSER). See below for
more details.
Run the Sample
The client sample and other related samples must be compiled before you can run the
client.
For more details on building the samples, see Building the Code Samples.
If you have already built the appropriate samples, DLLUSER.EXE is the client
executable to
run for this sample.
CODE TOUR
Files
DLLSKEL.TXT
MAKEFILE
DLLSKEL.H
DLLSKEL.CPP
Description
Short sample description.
The generic makefile for building the DLLSKEL.DLL
code sample of this tutorial lesson.
The include file for declaring as imported or defining as
exported the service functions in DLLSKEL.DLL. Meant for
eventual use by outside users of the DLL.
The main implementation file for DLLSKEL.DLL. Has DllMain
DLLSKELI.H
DLLSKEL.RC
DLLSKEL.ICO
DLLSKEL.DSP
and the two exported service functions.
The include file for the internal class declarations and
the identifier definitions for resources stored inside the
DLLSKEL.DLL.
The DLL resource definition file.
The icon resource.
Microsoft Visual Studio Project file.
In the context of this tutorial, the goal of DLLSKEL is to illustrate a C++ DLL
skeleton that
can serve as a point of departure for making more sophisticated DLLs. The resulting
DLL is
meant to work in conjuntion with DLLUSER.EXE to illustrate how to link to and call
services
in Win32 DLLs. It is the basic DLL framework for subsequent code samples in this
tutorial.
Study the code comments to learn more about this Win32 C++ DLL skeleton.
DLLSKEL makes use of many of the utility classes and services provided by APPUTIL.
For more
details on APPUTIL, study the source code located in the sibling APPUTIL directory
APPUTIL.HTM in the main tutorial directory.
In DLLSKEL.CPP, two exported functions are defined to export representative calls to
outside
consumers: DllHelloBox and DllAboutBox.
After incrementing a shared global counter variable, DllHelloBox uses APPUTIL's
CMsgBox
facility to show a simple information message box. This box says hello and shows the
DLL's
user instance count and a total count of the number of times this Hello function has
been
called by any user. The following DllHelloBox code from DLLSKEL.CPP shows one method
to
protect the incrementation of a global counting variable in a multitasking
environment.
The use of the Win32 InterlockedIncrement function enforces mutual exclusion for the
incrementing operation when multiple processes attempt to increment a shared
variable.
STDENTRY_(BOOL) DllHelloBox(
HWND hWnd)
{
int iHelloCount;
CDllShared* pShared = (CDllShared*) g_pvShared;
// Increment the cummulative global count of all Hellos.
InterlockedIncrement((LONG*) &pShared->iHelloCount);
iHelloCount = pShared->iHelloCount;
// Now show the user a -Notice- message box and load the display strings
// out of this DLL's resources. Use the format string to show the
// user instance count of this loaded DLL and the shared hello count.
g_pDll->pMsgBox->Init(g_pDll->hDllInst, hWnd);
g_pDll->pMsgBox->NoteFmtID(
IDS_HELLOCOUNTFMT,
g_pDll->iUserCount,
iHelloCount);
return TRUE;
}
The global hello count variable is accessed in a shared memory location that is part
of a
section of file-mapped memory. A g_pvShared global variable is used to store a
pointer to
the file-mappped shared memory. This g_pvShared variable is a static global variable
within
the DLL. It is newly created and assigned for each user process that attaches to the
DLL.
In the above fragment, the address of the iHelloCount counter within a shared data
object (
ie, a within CDllShared object) is passed to the InterlockedIncrement function. This
use
of a CDllShared object and the appropriate (CDllShared*) casting shows how to apply
the
object as a template over the file-mapped shared memory image pointed to by
g_pvShared.
See the discussion of DllMain below for more details on how the shared memory object
is
set up as a file mapping.
The DllAboutBox exported function creates an object of the CAboutBox class, as
implemented
in the APPUTIL utility library, to load a dialog box from the DLL's resources and
then display
an About box.
DLLSKEL.CPP defines the DllMain entry function for the entire DLL. To construct a
Win32 DLL,
you must provide the DllMain entry function and handle the following messages sent to
the
DLL via that function: DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, DLL_THREAD_ATTACH,
DLL_THREAD_DETACH.
The following code fragment from DLLSKEL.CPP shows how the DllMain function is
defined and
how the messages are handled. In this sample, no specific actions are taken during
thread
attach and detach.
BOOL WINAPI DllMain(
HINSTANCE hDllInst,
DWORD fdwReason,
LPVOID lpvReserved)
{
BOOL bResult = TRUE;
// Dispatch this call based on the reason it was called.
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// The DLL is being loaded for the first time by a given process.
// Perform per-process initialization here. If the initialization
// is successful, return TRUE; if unsuccessful, return FALSE.
bResult = FALSE;
if (UnicodeOk())
{
// Instantiate a DLL global data encapsulator class.
g_pDll = new CDllData;
if (NULL != g_pDll)
{
// Remember the DLL Instance handle.
g_pDll->hDllInst = hDllInst;
// Create a MsgBox object.
g_pDll->pMsgBox = new CMsgBox;
if (NULL != g_pDll->pMsgBox)
{
BOOL fFirst;
int iSharedSize = sizeof(CDllShared);
// Create a named file mapping object.
g_hMapObj = CreateFileMapping(
(HANDLE) 0xFFFFFFFF, // Use paging file
NULL,
// No security attributes
PAGE_READWRITE,
// Read/Write access
0,
// Mem Size: high 32 bits
iSharedSize,
// Mem Size: low 32 bits
DLLSKELSHARED_STR);
// Name of map object
if (NULL != g_hMapObj)
{
// Determine if this is the first create of the file mapping.
fFirst = (ERROR_ALREADY_EXISTS != GetLastError());
// Now get a pointer to the file-mapped shared memory.
g_pvShared = MapViewOfFile(
g_hMapObj,
// File Map obj to view
FILE_MAP_WRITE,
// Read/Write access
0,
// high: map from beginning
0,
// low:
0);
// default: map entire file
if (NULL != g_pvShared)
{
CDllShared* pShared = (CDllShared*) g_pvShared;
if (fFirst)
{
// If this is the first attaching process, init the
// shared memory.
memset(g_pvShared, 0, iSharedSize);
pShared->iUserCount = 1;
}
else
{
// Increment the cummulative global count of all
// attached processes (ie, the count of DLL users).
InterlockedIncrement((LONG*) &pShared->iUserCount);
}
// Save a local instance copy of this user instance
// count. Each user process has its own g_pDll instance
// data and can thus remember it's user instance count.
g_pDll->iUserCount = pShared->iUserCount;
bResult = TRUE;
}
}
}
}
}
break;
case DLL_PROCESS_DETACH:
// The DLL is being unloaded by a given process. Do any
// per-process clean up here, such as undoing what was done in
// DLL_PROCESS_ATTACH. The return value is ignored.
// Unmap any shared memory from the process's address space.
UnmapViewOfFile(g_pvShared);
// Close the process's handle to the file-mapping object.
CloseHandle(g_hMapObj);
if (NULL != g_pDll)
{
// Delete the message box and global DLL instance data.
DELETE_POINTER(g_pDll->pMsgBox);
DELETE_POINTER(g_pDll);
}
break;
case DLL_THREAD_ATTACH:
// A thread is being created in a process that has already loaded
// this DLL. Perform any per-thread initialization here. The
// return value is ignored.
break;
case DLL_THREAD_DETACH:
// A thread is exiting cleanly in a process that has already
// loaded this DLL. Perform any per-thread clean up here. The
// return value is ignored.
break;
default:
break;
}
return (bResult);
}
When the DLL is attached to a process, DllMain is called with DLL_PROCESS_ATTACH.
During DLL_PROCESS_ATTACH above the UnicodeOk function is called to determine if the
DLL
will run on the platform when compiled for Unicode strings. If the platform doesn't
support
Unicode and yet the DLL is compiled for Unicode, the DllMain function fails, and the
DLL
is unloaded.
The global instance data object is created. This object is pointed to by global
variable,
g_pDLL. This CDllData object encapsulates instance data that is instantiated
separately
for each process that attaches. In this sample, this object contains the DLL's
instance handle,
a place to save the count of the user instance, and a pointer to the Message Box
object.
The Message Box object is created during DLL_PROCESS_ATTACH. After its creation, the
pointer
to it is assigned.
The remainder of the work during DLL_PROCESS_ATTACH sets up the file-mapped memory
section
for a shared CDllShared object. First CreateFileMapping is called to assign a global
handle
to the mapping object, g_hMapObj. The current operating system virtual memory paging
file
is used for the file. No security attributes are needed. Read/Write access is
specified.
A size equal to the size of the shared object is specified. The mapping object is
given
a name so that it can be explicitly shared by instances of this DLL. The
DLLSKELSHARED_STR
macro is used to specify the name string "DLLSkelShared" as ANSI or Unicode depending
on
whether DLLSKEL is being compiled for Unicode or not. This macro is defined
immediately
before DllMain as follows.
#if defined(UNICODE)
#define DLLSKELSHARED_STR L"DLLSkelShared"
#else
#define DLLSKELSHARED_STR "DLLSkelShared"
#endif
The mapping object is then used to map a memory view of the file. This action obtains
a
pointer to the shared memory and assigns it to global variable g_pvShared. If this is
the
first creation (rather than a re-open) of the mapping object, then the shared memory
area
is initialized to zero and the user instance counter is intitialized to 1. If this is
not
the initial creation of the shared object, then the user instance counter is
incremented
to keep a cumulative count of the attaching processes. Since this is globally shared
memory,
the Win32 InterlockedIncrement function is used to ensure mutual exclusion during the
increment
operation. Once this user counter is incremented the new value is saved in a nonshared variable,
g_pDll->iUserCount, that is part of the instance data that is specific to the
attaching process.
When the DLL is detached from the process DllMain is called with DLL_PROCESS_DETACH.
During DLL_PROCESS_DETACH the mapped memory view is unmapped and the mapping object
is closed.
The CMsgBox and CDllData objects are then deleted. To perform the delete, the
DELETE_POINTER macro is used to delete the memory object pointed to by the pointer.
Here is the macro definition from APPUTIL.H:
#define DELETE_POINTER(p){if(NULL != p){delete p; p = NULL;}}
If the original pointer value was not NULL, the macro deletes the memory object that
was
pointed to. By then immediately setting the pointer to NULL, the macro prevents other
threads
from using it.
To build the DLL, you provide specific DLL-related instructions when you compile the
modules
of the DLL and when you link the modules with the Link command. The following
fragment from
the DLLSKEL makefile (file MAKEFILE) shows the compilation rule for the DLLSKEL.CPP
module.
# Compilation/Dependency rules for the .DLL source files.
$(TDIR)\$(DLL).obj: $(DLL).cpp $(DLL).h $(DLL)r.h
$(cc) $(cvarsdll) $(cflags) $(cdebug) -Fo$@ $(DLL).cpp
Note the use of the 'cvarsdll' macro when compiling module components of a DLL. This
is in
contrast to the 'cvars' macro normally used in linking EXE applications. Both of
these macros
are defined in the makefile include file WIN32.MAK. For more details, see WIN32.MAK
in the \MSSDK\INCLUDE directory of the Platform SDK. All of the COM Tutorial code
sample
makefiles include WIN32.MAK.
If there are to be resources in the DLL (as there are in the DLLSKEL DLL), the
appropriate
.RC file is RC-compiled in the normal manner as follows.
# Compile the DLL resources.
$(TDIR)\$(DLL).res: $(DLL).rc $(DLL).ico $(DLL)r.h
rc $(RCFLAGS) -r -fo$@ $(DLL).rc
To link the modules and the resources together to build the DLL binary, you provide a
Link
command like the following from the DLLSKEL makefile:
# Link the object and resource binaries into the target DLL binary.
# Build the import LIB file so apps can link to and use this DLL.
$(DLL).dll: $(DLLOBJS) $(TDIR)\$(DLL).res
$(LINK) @<<
$(LINKFLAGS) $(dlllflags)
-base:0x1C000000
-out:$@
-map:$(TDIR)\$*.map
-implib:$*.lib
$(DLLOBJS)
$(TDIR)\$*.res
$(olelibsdll) $(APPLIBS)
<<
The 'implib:$*.lib' directive to the Linker instructs it to produce the DLLSKEL.LIB
import
library file. This .LIB file is used in turn when the DLL is linked with any
application
that calls the DLL.
Note also that this DLL makes calls to another library, APPUTIL, by statically
linking to it.
The APPLIBS macro reduces to APPUTIL.LIB. In this case, the compiled content of
APPUTIL is
contained entirely in APPUTIL.LIB.
APPUTIL itself could have been a DLL. It is a judgement call as to whether you build
one
library type or another. Usually, if you are exporting C++ class definitions across
the
library boundary, the exported names are decorated in a manner proprietary to the
compiler
vendor. This approach restricts the use of such a DLL to applications that are also
compiled
with the same compiler. If the exported classes are small, it is often more
convenient to put
them into a static .LIB (as is the case with APPUTIL) than to put them into a .DLL.
Because the DLLSKEL DLL has resources and because it is desirable to provide outside
users
of the DLL with an .H file of the same name, a separate DLLSKELI.H is used for
internal
class declarations and resource identifier definitions, while the DLLSKEL.H file is
intended
solely for the DLL's function import declarations and export definitions.
For the consumer application (in this case DLLUSER.EXE) to link to and properly call
the
exported functions in the DLL, it must import them. The following fragment from
DLLSKEL.H
shows how to use the same convenient 'STDENTRY' macros to serve both the consumer
application's import declaration and the provider DLL's export definition needs.
#if !defined(_DLLEXPORT_)
// If _DLLEXPORT_ is not defined then the default is to import.
#if defined(__cplusplus)
#define DLLENTRY extern "C" __declspec(dllimport)
#else
#define DLLENTRY extern __declspec(dllimport)
#endif
#define STDENTRY DLLENTRY HRESULT WINAPI
#define STDENTRY_(type) DLLENTRY type WINAPI
// Here is the list of service APIs offered by the DLL (using the
// appropriate entry API declaration macros just #defined above).
STDENTRY_(BOOL) DllHelloBox (HWND);
STDENTRY_(BOOL) DllAboutBox (HWND);
#else
// _DLLEXPORT_
// Else if _DLLEXPORT_ is defined then we've been told to export.
#if defined(__cplusplus)
#define DLLENTRY extern "C" __declspec(dllexport)
#else
#define DLLENTRY __declspec(dllexport)
#endif
#define STDENTRY DLLENTRY HRESULT WINAPI
#define STDENTRY_(type) DLLENTRY type WINAPI
#endif // _DLLEXPORT_
The DLLENTRY macro allows you more freedom to specify return types and calling
conventions.
The STDENTRY assumes the COM/OLE standard HRESULT return type and the WINAPI calling
conventions
(usually defined as __stdcall). The STDENTRY_ macro makes this same assumption but
does allow
you to specify a return type.
The '__declspec(dllimport)' and '__declspec(dllexport)' directives are one way to
declare
DLL imports and to define DLL exports in Win32 programming. Another way is to Link
the
executable using a module definition (.DEF) file that contains import and export
statements.
This technique was commonly used in Win16 programming but is often not needed in
Win32
programming. Note that the __declspec specifications are Microsoft-specific
techniques in
C++ programs. DLL exports can also be designated using the export switch on the
Linker command
line.
Note the use of extern "C" when compiling under C++ (__cplusplus). This tells the
compiler,
during compilation of both the DLL and the calling code, that the default C++
function name
decoration will not be used. This is usually preferred in generic DLLs, whose
function calls
might be called by applications that could be compiled with a variety of C++
compiler tools,
including straight C compilers.
The default behavior of DLLSKEL.H is to serve calling applications that import the
functions
in the DLL. Such applications simply include DLLSKEL.H during compilation of such a
calling
module. When the DLL itself is compiled, however, this file is included as in the
following
fragment from DLLSKEL.CPP.
#define _DLLEXPORT_
#include "dllskel.h"
When _DLLEXPORT_ is thus defined, the behavior of DLLSKEL.H is to serve the DLL
itself in
defining its exported functions. The following fragment from DLLSKEL.CPP shows such a
function
definiton.
STDENTRY_(BOOL) DllAboutBox(HWND hWnd);
{
...
}
When the DllAboutBox function is defined in DLLSKEL.CPP, the STDENTRY_ macro expands
to yield
the following:
extern "C" __declspec(dllexport) BOOL WINAPI DllAboutBox(HWND hWnd)
{
...
}
Likewise, when the DllAboutBox function is imported in DLLSKEL.H, the declaration is
expanded
to the following import function prototype.
extern "C" __declspec(dllimport) BOOL WINAPI DllAboutBox(HWND hWnd);
The WINAPI macro expands to various things, depending on the build environment, but
generally
stipulates the calling convention (usually __stdcall). See WIN32.MAK and the standard
Windows
include file WINDEF.H for more details on the WINAPI macro.
Back to page top
© 1995-1998 Microsoft Corporation
GLOBALS.C
/******************************************************************************\
*
This is a part of the Microsoft Source Code Samples.
*
Copyright 1993 - 1998 Microsoft Corporation.
*
All rights reserved.
*
This source code is only intended as a supplement to
*
Microsoft Development Tools and/or WinHelp documentation.
*
See these sources for detailed information regarding the
*
Microsoft samples programs.
\******************************************************************************/
/****************************** Module Header *******************************
* Module Name: globals.c
*
* Contains global data for the dialog box editor.
*
****************************************************************************/
#include "dlgedit.h"
#include "dlgextrn.h"
/* Including this verifies they are synched.*/
#include "dlgfuncs.h"
#include "dialogs.h"
#include "dlghelp.h"
HANDLE ghInst;
HMENU ghMenuMain;
PRESLINK gprlHead = NULL;
CURRENTDLG gcd;
HPEN hpenDarkGray;
HANDLE ghAccTable;
INT gMenuSelected = 0;
HBITMAP ghbmDragHandle = NULL;
HBITMAP ghbmDragHandle2 = NULL;
HDC ghDCMem = NULL;
INT gCurTool = W_NOTHING;
PWINDOWCLASSDESC gpwcdCurTool =
BOOL gfToolLocked = FALSE;
PCUSTLINK gpclHead = NULL;
/* Application instance handle.
*/
/* Main menu handle.
*/
/* Head of the linked list of resources.*/
/* Describes the current dialog.
*/
/* A dark gray pen.
*/
/* The accelerator table handle.
*/
/* Currently selected menu item.
*/
/* Handle for the drag handle bitmap.
*/
/* Handle for hollow drag handle bitmap.*/
/* Memory DC for drawing bitmaps.
*/
/* Currently selected tool.
*/
NULL; /* Describes current tool.
*/
/* TRUE if a tool is locked down.
*/
/* Head of custom control linked list. */
/*
* When the dialog editor displays one of its own dialogs, this value
* will contain the resource id of it. It is zero if there is not a
* dialog up.
*/
INT gidCurrentDlg = 0;
/*
* Ordinal for the icon control to display in the dialog.
* initialized to one of the editor's own icons.
*/
ORDINAL gordIcon;
It will be
/*
* Bitmap handles for the up and down W_NOTHING (pointer) tool bitmaps.
*/
HBITMAP ghbmPointerToolUp = NULL;
HBITMAP ghbmPointerToolDown = NULL;
/*-- Initialized "Preferences" Data ------------------------------------*/
/*
* Initialization data structure. This describes each profile entry
* that is contained in the initialization file.
*/
INIENTRY gaie[] = {
{ L"fHexMode",
&gfHexMode,
FALSE,
0 },
{ L"fTranslateMode",&gfTranslateMode,
FALSE,
0 },
{ L"fShowToolbox", &gfShowToolbox,
TRUE,
0 },
{ L"fUseNewKeywords",&gfUseNewKeywords, TRUE,
0 },
{ L"cxGrid",
&gcxGrid,
DEFCXGRID,
0 },
{ L"cyGrid",
&gcyGrid,
DEFCYGRID,
0 },
{ L"xMargin",
&gxMargin,
DEFXMARGIN,
0 },
{ L"yMargin",
&gyMargin,
DEFYMARGIN,
0 },
{ L"xSpace",
&gxSpace,
DEFXSPACE,
0 },
{ L"ySpace",
&gySpace,
DEFYSPACE,
0 },
{ L"xMinPushSpace", &gxMinPushSpace,
DEFXMINPUSHSPACE,
0 },
{ L"xMaxPushSpace", &gxMaxPushSpace,
DEFXMAXPUSHSPACE,
0 },
{ L"yPushSpace",
&gyPushSpace,
DEFYPUSHSPACE,
0 },
{ NULL,
NULL,
0,
0 }
};
BOOL gfHexMode;
BOOL gfTranslateMode;
BOOL gfShowToolbox;
BOOL gfUseNewKeywords;
INT gcxGrid;
INT gcyGrid;
INT gxMargin;
INT gyMargin;
INT gxSpace;
INT gySpace;
INT gxMinPushSpace;
INT gxMaxPushSpace;
INT gyPushSpace;
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
TRUE if in "hex" mode.
TRUE if in "translate" mode.
TRUE if Toolbox is to be shown.
FALSE to only use "CONTROL" keyword.
Current X grid.
Current Y grid.
Top/bottom margin.
Left/right margin.
Horizontal control spacing.
Vertical control spacing.
Minimum horizontal button spacing.
Maximum horizontal button spacing.
Vertical button spacing.
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
TCHAR szAppPos[] = L"AppPos";
/* App window's position keyname.
*/
TCHAR szTBPos[] = L"TBPos";
/* Toolbox window's position keyname.
*/
TCHAR szCustomDLL[] = L"CustomDLL";/* Section name for DLL cust. cntls. */
/*-HWND
HWND
HWND
HWND
HWND
HWND
Sundry Handles.----------------------------------------------------*/
hwndStatus = NULL;
/* Status ribbon window handle.
*/
ghwndToolbox = NULL;
/* Toolbox window handle.
*/
ghwndTestDlg = NULL;
/* Handle of the Test Mode dialog.
*/
ghwndMain = NULL;
/* Main application window.
*/
ghwndSubClient = NULL;
/* The "fake" client area.
*/
ghwndTrackOver = NULL;
/* Window being tracked over.
*/
/*-- Some System constants.---------------------------------------------*/
INT gcxSysChar;
/* Pixel width of system font char box. */
INT gcySysChar;
/* Pixel height of system font char box.*/
INT gcyBorder;
/* System height of a border.
*/
INT gcxPreDragMax;
/* Max X mouse move during pre-drag.
*/
INT gcyPreDragMax;
/* Max Y mouse move during pre-drag.
*/
INT gmsecPreDrag;
/* The milliseconds that pre-drag lasts.*/
INT gcyPixelsPerInch;
/* Vertical pixels/inch of system.
*/
INT gcyStatus;
/* Saves height of the status window.
*/
/*-- Some state variables.----------------------------------------------*/
INT gState = STATE_NORMAL;
/* Has the editor "state" or mode.
*/
BOOL gfResChged = FALSE;
/* Tell if RES has changed
*/
BOOL gfIncChged = FALSE;
/* Tell if include has changed
*/
BOOL gfDlgChanged = FALSE;
/* TRUE if current dialog has changed. */
INT gcSelected = 0;
/* Count of selected windows.
*/
BOOL gfTestMode = FALSE;
/* TRUE if in "test" mode.
*/
BOOL gfDisabled = FALSE;
/* TRUE if editing is disabled for now. */
BOOL gfEditingDlg = FALSE;
/* TRUE means a dlg is picked to edit. */
BOOL gfDlgSelected = FALSE;
/* TRUE if the dialog has the selection.*/
/*
* Contains the window rectangle, in window units, for the "client"
* area for the currently chosen dialog being edited. This rectangle
* is relative to the dialog box window. The xLeft and yBottom fields
* contain the offset from the window origin of the dialog box to the
* origin of the "client" area.
*/
RECT grcDlgClient;
/*
* Contains a rectangle that surrounds all the existing controls. This
* is used during tracking of the dialog to limit the minimum size that
* the dialog can be sized to.
*/
RECT grcMinDialog;
/*
* Contains the offset from the origin of the currently selected
* control to the mouse pointer. This is updated when a control
* is clicked on and is used for dragging calculations.
*/
POINT gptCursorOffset;
/*
* Contains the rectangle that surrounds the selected control(s).
* rectangle is only valid if there are selected controls.
*/
RECT grcSelected;
This
/*
* Contains the rectangle that surrounds the control(s) that are being
* copied. This is also used during a clipboard paste operation. In
* that case, it contains the rectangle that surrounds the control(s)
* as they are defined in the res image.
*/
RECT grcCopy;
/*
* These contain the current location of the tracking rectangle when
* dragging a control. The values for grcTrackDU are in Dialog Units
* (DU's) and the values in grcTrackWin are in window units. The
* grcTrackWin values will only be valid if gfTrackRectShown is TRUE;
*/
RECT grcTrackDU;
/* Track rect in dialog units.
RECT grcTrackWin;
/* Track rect in window units.
BOOL gfTrackRectShown = FALSE; /* TRUE if track rect is visible.
HDC ghDCTrack;
/* Clip DC used when tracking.
/*
* Contains the current drag handle that is being tracked.
* be one of the DRAG_* constants.
*/
INT gHandleHit = DRAG_CENTER;
*/
*/
*/
*/
This will
/*
* Contains the overhang that is allowed during the current tracking
* operation. This is used by various routines during dragging so
* that limiting the tracking to the dialog boundaries works properly.
* In actuality, this is only non-zero when a combo box control is
* being drapped or dragged. It will be the height of the listbox
* portion of the combo. This is how combos are allowed to extend
* below the bottom of the dialog.
*/
INT gnOverHang;
/* Maximum overhang during the drag.
/*
* This pointer is either NULL, or else it points to a dialog resource.
* It is used when copying dialogs/controls, either with the Duplicate
* command or pasting from the clipboard.
*/
*/
PRES gpResCopy;
/* Copy of dialog/controls.
*/
/*-- CTYPE linked lists.------------------------------------------------*/
NPCTYPE npcHead = NULL;
/* Linked List of controls.
*/
INT cWindows = 0;
/* Number of Controls in pctype list.
*/
/*
* Pointer to the CTYPE structure for the currently selected control.
* This will be NULL if there is no control selected.
*/
NPCTYPE gnpcSel = NULL;
/*-- Cursors used by editor.--------------------------------------------*/
HCURSOR hcurArrow = NULL;
/* Normal arrow cursor.
*/
HCURSOR hcurWait = NULL;
/* User Wait cursor, Hourglass.
*/
HCURSOR hcurOutSel = NULL;
/* Outline selection cursor.
*/
HCURSOR hcurMove = NULL;
/* System "Move" cursor.
*/
HCURSOR hcurInsert = NULL;
/* Insert cursor for Order/Group dialog.*/
HCURSOR hcurDropTool = NULL;
/* Cursor for when dropping new ctrls. */
HCURSOR hcurSizeNESW = NULL;
/* System sizing "NESW" cursor.
*/
HCURSOR hcurSizeNS = NULL;
/* System sizing "NS" cursor.
*/
HCURSOR hcurSizeNWSE = NULL;
/* System sizing "NWSE" cursor.
*/
HCURSOR hcurSizeWE = NULL;
/* System sizing "WE" cursor.
*/
HBITMAP hbmTabStop = NULL;
/* Bitmap for showing WS_TABSTOP style. */
HBITMAP hbmTabStopSel = NULL;
/* Selected version of the above.
*/
/*-- Window Class Strings.----------------------------------------------*/
TCHAR szMainClass[] = L"DlgEdit";/* Application window class.
*/
TCHAR szDragClass[] = L"Drag"; /* Class for drag handle windows.
*/
TCHAR szSubClientClass[] =
L"SubClient";
/* Short client area window class.
*/
TCHAR szToolboxClass[] =
L"Toolbox";
/* Toolbox window class.
*/
TCHAR szToolBtnClass[] =
L"ToolBtn";
/* Toolbox button window class.
*/
TCHAR szCustomClass[] =
L"DlgCustom";
/* Our custom emulator class.
*/
/*-- Miscellaneous variables.-------------------------------------------*/
UINT fmtDlg;
/* The Dialog Clipboard format
*/
TCHAR szEmpty[] = L"";
/* An empty string.
*/
HHOOK ghhkMsgFilter;
/* Hook handle for message filter func. */
/*-- Buffers.-----------------------------------------------------------*/
TCHAR szFullResFile[CCHMAXPATH];
/* Full resource file name
*/
LPTSTR pszResFile;
/* Points to resource file name
*/
TCHAR szFullIncludeFile[CCHMAXPATH];/* Full include file name
*/
LPTSTR pszIncludeFile;
/* Points to include file name
*/
TCHAR gszHelpFile[CCHMAXPATH];
/* Path to the help file.
*/
/*
* Write buffer and index into it. This buffer is used by several
* sections to write out the different files. Note that only one
* file can be written out at a time using these globals.
*/
TCHAR gachWriteBuffer[CCHFILEBUFFER];/* Buffer for written file data.
INT cbWritePos;
/* Pointer into gachWriteBuffer.
*/
*/
/*-- Include Data.------------------------------------------------------*/
NPLABEL plInclude = NULL;
/* Pointer to Include data
*/
NPLABEL plDelInclude = NULL;
/* Pointer to deleted includes
*/
/*
* Describes each window class. Indexed by the W_ defined constants.
* The define CCONTROLS needs to be updated if controls are added or
* removed from this array. Note that CCONTROLS does NOT count the
* W_DIALOG type as a control, however.
*/
WINDOWCLASSDESC awcd[] = {
/*
* W_TEXT
*/
{
W_TEXT,
WS_CHILD | WS_GROUP | WS_VISIBLE | SS_LEFT,
WS_DISABLED,
0,
0,
20, 8,
IC_STATIC, NULL,
FALSE, FALSE, TRUE, TRUE, TRUE,
DID_TEXTSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_TEXTSTYLES, IDS_DEFTXTTEXT, NULL, NULL,
IDBM_CTTEXT, NULL, NULL,
IDBM_TUTEXT, NULL, IDBM_TDTEXT, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_EDIT
*/
{
W_EDIT,
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_LEFT |
ES_AUTOHSCROLL,
WS_DISABLED,
0,
0,
32, 12,
IC_EDIT, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_EDITSTYLES, (WNDPROC)EditStylesDlgProc,
HELPID_EDITSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTEDIT, NULL, NULL,
IDBM_TUEDIT, NULL, IDBM_TDEDIT, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_GROUPBOX
*/
{
W_GROUPBOX,
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
WS_DISABLED,
0,
0,
48, 40,
IC_BUTTON, NULL,
FALSE, FALSE, TRUE, TRUE, FALSE,
DID_GROUPBOXSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_GROUPBOXSTYLES, IDS_DEFTXTGROUP, NULL, NULL,
IDBM_CTGROUP, NULL, NULL,
IDBM_TUGROUP, NULL, IDBM_TDGROUP, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_PUSHBUTTON
*/
{
W_PUSHBUTTON,
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
WS_DISABLED,
0,
0,
40, 14,
IC_BUTTON, NULL,
FALSE, FALSE, TRUE, TRUE, TRUE,
DID_PUSHBUTTONSTYLES, (WNDPROC)PushButtonStylesDlgProc,
HELPID_PUSHBUTTONSTYLES, IDS_DEFTXTPUSHBUTTON, NULL, NULL,
IDBM_CTPUSH, NULL, NULL,
IDBM_TUPUSH, NULL, IDBM_TDPUSH, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_CHECKBOX
*/
{
W_CHECKBOX,
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP,
WS_DISABLED,
0,
0,
40, 10,
IC_BUTTON, NULL,
FALSE, FALSE, TRUE, TRUE, TRUE,
DID_CHECKBOXSTYLES, (WNDPROC)CheckBoxStylesDlgProc,
HELPID_CHECKBOXSTYLES, IDS_DEFTXTCHECKBOX, NULL, NULL,
IDBM_CTCHECK, NULL, NULL,
IDBM_TUCHECK, NULL, IDBM_TDCHECK, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_RADIOBUTTON
*/
{
W_RADIOBUTTON,
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
WS_DISABLED,
0,
0,
39, 10,
IC_BUTTON, NULL,
FALSE, FALSE, TRUE, TRUE, TRUE,
DID_RADIOBUTTONSTYLES, (WNDPROC)RadioButtonStylesDlgProc,
HELPID_RADIOBUTTONSTYLES, IDS_DEFTXTRADIOBUTTON, NULL, NULL,
IDBM_CTRADIO, NULL, NULL,
IDBM_TURADIO, NULL, IDBM_TDRADIO, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_COMBOBOX
*/
{
W_COMBOBOX,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWN |
CBS_SORT,
WS_DISABLED | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE |
CBS_HASSTRINGS,
CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE | CBS_HASSTRINGS,
0,
48, 35,
IC_COMBOBOX, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_COMBOBOXSTYLES, (WNDPROC)ComboBoxStylesDlgProc,
HELPID_COMBOBOXSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTCOMBO, NULL, NULL,
IDBM_TUCOMBO, NULL, IDBM_TDCOMBO, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_LISTBOX
*/
{
W_LISTBOX,
WS_CHILD | WS_VISIBLE | LBS_STANDARD | WS_TABSTOP,
WS_DISABLED | LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE |
LBS_HASSTRINGS | LBS_NODATA,
LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
LBS_NODATA,
0,
48, 40,
IC_LISTBOX, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_LISTBOXSTYLES, (WNDPROC)ListBoxStylesDlgProc,
HELPID_LISTBOXSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTLIST, NULL, NULL,
IDBM_TULIST, NULL, IDBM_TDLIST, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_HORZSCROLL
*/
{
W_HORZSCROLL,
WS_CHILD | WS_VISIBLE | SBS_HORZ,
WS_DISABLED,
0,
0,
48, 0,
IC_SCROLLBAR, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_HORZSCROLLSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_HORZSCROLLSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTHSCROL, NULL, NULL,
IDBM_TUHSCROL, NULL, IDBM_TDHSCROL, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_VERTSCROLL
*/
{
W_VERTSCROLL,
WS_CHILD | WS_VISIBLE | SBS_VERT,
WS_DISABLED,
0,
0,
0, 40,
IC_SCROLLBAR, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_VERTSCROLLSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_VERTSCROLLSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTVSCROL, NULL, NULL,
IDBM_TUVSCROL, NULL, IDBM_TDVSCROL, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_FRAME
*/
{
W_FRAME,
WS_CHILD | WS_VISIBLE | SS_BLACKFRAME,
WS_DISABLED,
0,
0,
20, 16,
IC_STATIC, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_FRAMESTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_FRAMESTYLES, IDS_NULL, NULL, NULL,
IDBM_CTFRAME, NULL, NULL,
IDBM_TUFRAME, NULL, IDBM_TDFRAME, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_RECT
*/
{
W_RECT,
WS_CHILD | WS_VISIBLE | SS_BLACKRECT,
WS_DISABLED,
0,
0,
20, 16,
IC_STATIC, NULL,
FALSE, FALSE, FALSE, TRUE, FALSE,
DID_RECTSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_RECTSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTRECT, NULL, NULL,
IDBM_TURECT, NULL, IDBM_TDRECT, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_ICON
*/
{
W_ICON,
WS_CHILD | WS_VISIBLE | SS_ICON,
WS_DISABLED,
0,
0,
0, 0,
IC_STATIC, NULL,
FALSE, FALSE, TRUE, FALSE, FALSE,
DID_ICONSTYLES, (WNDPROC)GenericStylesDlgProc,
HELPID_ICONSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTICON, NULL, NULL,
IDBM_TUICON, NULL, IDBM_TDICON, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_CUSTOM
*
* For Custom controls, we do not allow our emulator control
* to be created with any other styles than the default ones
* (WS_CHILD and WS_VISIBLE), but whatever styles the user
* specifies are written out to the .res and .dlg files,
* of course.
*/
{
W_CUSTOM,
WS_CHILD | WS_VISIBLE,
WS_DISABLED,
0,
0,
40, 14,
IC_CUSTOM, NULL,
TRUE, FALSE, TRUE, TRUE, FALSE,
DID_CUSTOMSTYLES, (WNDPROC)CustomStylesDlgProc,
HELPID_CUSTOMSTYLES, IDS_NULL, NULL, NULL,
IDBM_CTCUSTOM, NULL, NULL,
IDBM_TUCUSTOM, NULL, IDBM_TDCUSTOM, NULL,
NULL, 0, NULL, NULL, NULL, 0
},
/*
* W_DIALOG
*/
{
W_DIALOG,
WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | WS_POPUP |
DS_SETFONT,
WS_DISABLED | DS_SYSMODAL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
WS_CHILD,
DS_SYSMODAL,
0,
160, 100,
IC_DIALOG, NULL,
FALSE, FALSE, TRUE, TRUE, FALSE,
DID_DIALOGSTYLES, (WNDPROC)DialogStylesDlgProc,
HELPID_DIALOGSTYLES, IDS_DEFTXTDIALOG, NULL, NULL,
0, NULL, NULL,
0, NULL, 0, NULL,
NULL, 0, NULL, NULL, NULL, 0
}
};
/*
* This table maps the BS_* style of a button control into its
* appropriate W_* type that is used internally by the editor.
* This table assumes that any value used to index into it is
* masked by BS_ALL.
*/
INT rgmpiClsBtnType[] = {
W_PUSHBUTTON,
/* BS_PUSHBUTTON
W_PUSHBUTTON,
/* BS_DEFPUSHBUTTON
W_CHECKBOX,
/* BS_CHECKBOX
W_CHECKBOX,
/* BS_AUTOCHECKBOX
W_RADIOBUTTON,
/* BS_RADIOBUTTON
W_CHECKBOX,
/* BS_3STATE
W_CHECKBOX,
/* BS_AUTO3STATE
W_GROUPBOX,
/* BS_GROUPBOX
W_PUSHBUTTON,
/* BS_USERBUTTON
W_RADIOBUTTON,
/* BS_AUTORADIOBUTTON
W_PUSHBUTTON,
/* BS_PUSHBOX
W_PUSHBUTTON
/* BS_OWNERDRAW
};
/* Map low word of Static Control Style to static type. */
/*
* This table maps the SS_* style of a static control into its
* appropriate W_* type that is used internally by the editor.
* This table assumes that any value used to index into it is
* masked by SS_ALL.
*/
INT rgmpiClsStcType[] = {
W_TEXT,
/* SS_LEFT
W_TEXT,
/* SS_CENTER
W_TEXT,
/* SS_RIGHT
W_ICON,
/* SS_ICON
W_RECT,
/* SS_BLACKRECT
W_RECT,
/* SS_GREYRECT
W_RECT,
/* SS_WHITERECT
W_FRAME,
/* SS_BLACKFRAME
W_FRAME,
/* SS_GRAYFRAME
W_FRAME,
/* SS_WHITEFRAME
W_TEXT,
/* SS_USERITEM
W_TEXT,
/* SS_SIMPLE
W_TEXT
/* SS_LEFTNOWORDWRAP
};
/*
*
*
*
*
*
*
*
Following are the tables with the predefined RC keywords for each
class (IC_*). These tables describe each keyword other than the
generic "CONTROL" keyword that is possible to use within a dialog
template. The style describes the minimum bits that must be set
to define the keyword. The mask allows a style to be specified
that must have certain bits OFF for a match to occur. The default
styles flag specifies style bits that are implicitly turned on
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
* when this keyword is specified in the dialog template in the .DLG
* file. These bits are checked against the style flag of the control
* that we are trying to match and if any of these default bits are
* NOT set for that control, we need to specify them in the .DLG file
* with a "NOT" in front of them to explicitly turn them off.
*
* The "Has Text" flag is set to FALSE in those cases where the syntax
* for the keyword does NOT include a text field, like "ICON" and
* "LISTBOX".
*/
/*
* Array of the predefined RC keywords for Button styles.
*/
static RCKEYWORD arckwdButton[] = {
/*
* RADIOBUTTON
*/
{
BS_RADIOBUTTON,
BS_ALL,
WS_CHILD | WS_VISIBLE,
IDS_KEYRADIOBUTTON, TRUE
},
/*
* CHECKBOX
*/
{
BS_CHECKBOX,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYCHECKBOX, TRUE
},
/*
* DEFPUSHBUTTON
*/
{
BS_DEFPUSHBUTTON,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYDEFPUSHBUTTON, TRUE
},
/*
* PUSHBUTTON
*/
{
BS_PUSHBUTTON,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYPUSHBUTTON, TRUE
},
/*
* GROUPBOX
*/
{
BS_GROUPBOX,
BS_ALL,
WS_CHILD | WS_VISIBLE,
IDS_KEYGROUPBOX, TRUE
},
/*
* AUTO3STATE
*/
{
BS_AUTO3STATE,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYAUTO3STATE, TRUE
},
/*
* AUTOCHECKBOX
*/
{
BS_AUTOCHECKBOX,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYAUTOCHECKBOX, TRUE
},
/*
* AUTORADIOBUTTON
*/
{
BS_AUTORADIOBUTTON,
BS_ALL,
WS_CHILD | WS_VISIBLE,
IDS_KEYAUTORADIOBUTTON, TRUE
},
/*
* STATE3
*/
{
BS_3STATE,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYSTATE3, TRUE
},
/*
* USERBUTTON
*/
{
BS_USERBUTTON,
BS_ALL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
IDS_KEYUSERBUTTON, TRUE
}
};
/*
* Array of the predefined RC keywords for Edit control styles.
*/
static RCKEYWORD arckwdEdit[] = {
/*
* EDIT
*/
{
0L,
0L,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER,
IDS_KEYEDITTEXT, FALSE
}
};
/*
* Array of the predefined RC keywords for Static styles.
*/
static RCKEYWORD arckwdStatic[] = {
/*
* ICON
*/
{
SS_ICON,
SS_ALL,
WS_CHILD | WS_VISIBLE,
IDS_KEYICON, TRUE
},
/*
* RTEXT
*/
{
SS_RIGHT,
SS_ALL,
WS_CHILD | WS_GROUP | WS_VISIBLE,
IDS_KEYRTEXT, TRUE
},
/*
* CTEXT
*/
{
SS_CENTER,
SS_ALL,
WS_CHILD | WS_GROUP | WS_VISIBLE,
IDS_KEYCTEXT, TRUE
},
/*
* LTEXT
*/
{
SS_LEFT,
SS_ALL,
WS_CHILD | WS_GROUP | WS_VISIBLE,
IDS_KEYLTEXT, TRUE
}
};
/*
* Array of the predefined RC keywords for ListBox styles.
*/
static RCKEYWORD arckwdLB[] = {
/*
* LISTBOX
*/
{
0L,
0L,
WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_NOTIFY,
IDS_KEYLISTBOX, FALSE
}
};
/*
* Array of the predefined RC keywords for ComboBox styles.
*/
static RCKEYWORD arckwdComboBox[] = {
/*
* COMBOBOX
*/
{
0L,
0L,
WS_CHILD | WS_VISIBLE,
IDS_KEYCOMBOBOX, FALSE
}
};
/*
* Array of the predefined RC keywords for ScrollBar styles.
*/
static RCKEYWORD arckwdScrollBar[] = {
/*
* SCROLLBAR
*/
{
0L,
0L,
WS_CHILD | WS_VISIBLE,
IDS_KEYSCROLLBAR, FALSE
}
};
/*
* Following are the Class Styles structures. These tables define the
* styles for the different window classes (IC_*). The first element
* is the style flag, followed by an optional style mask. If the style
* mask is zero, the style flag becomes the mask also. This is often good
* enough, but there are cases where the style depends on certain bits
* being off, as well as certain bits being on, to definitively identify
* a certain style. An extreme example of this is the BS_PUSHBUTTON
* style, which is actually zero (no bits are on). The mask for this
* style had to be set to include all four of the lower bits, or all
* buttons would be incorrectly figured to have the BS_PUSHBUTTON style.
* With the proper mask, only styles that have all four lower bits
* OFF will be considered to have the BS_PUSHBUTTON style.
*/
/*
* Button styles.
*/
static CLASSSTYLE acsButton[] = {
{BS_PUSHBUTTON,
{BS_DEFPUSHBUTTON,
{BS_CHECKBOX,
BS_ALL,
BS_ALL,
BS_ALL,
DID_BS_PUSHBUTTON
DID_BS_DEFPUSHBUTTON
0
},
},
},
{BS_AUTOCHECKBOX,
{BS_RADIOBUTTON,
{BS_3STATE,
{BS_AUTO3STATE,
{BS_GROUPBOX,
{BS_USERBUTTON,
{BS_AUTORADIOBUTTON,
{BS_PUSHBOX,
{BS_OWNERDRAW,
{BS_LEFTTEXT,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
BS_ALL,
0,
0
0
0
0
0
0
0
0
DID_BS_OWNERDRAW
DID_BS_LEFTTEXT
},
},
},
},
},
},
},
},
},
}
0
0
0
0
0
0
0
0
0
},
},
},
},
},
},
},
},
}
DID_ES_LEFT
DID_ES_CENTER
DID_ES_RIGHT
DID_ES_MULTILINE
DID_ES_UPPERCASE
DID_ES_LOWERCASE
DID_ES_PASSWORD
DID_ES_AUTOVSCROLL
DID_ES_AUTOHSCROLL
DID_ES_NOHIDESEL
DID_ES_OEMCONVERT
DID_ES_READONLY
},
},
},
},
},
},
},
},
},
},
},
}
DID_SS_LEFT
DID_SS_CENTER
DID_SS_RIGHT
0
DID_SS_BLACKRECT
DID_SS_GRAYRECT
DID_SS_WHITERECT
DID_SS_BLACKFRAME
DID_SS_GRAYFRAME
},
},
},
},
},
},
},
},
},
};
/*
* Scroll bar styles.
*/
static CLASSSTYLE acsSB[] = {
{SBS_HORZ,
SBS_ALL,
{SBS_VERT,
SBS_ALL,
{SBS_TOPALIGN,
0,
{SBS_LEFTALIGN,
0,
{SBS_BOTTOMALIGN,
0,
{SBS_RIGHTALIGN,
0,
{SBS_SIZEBOXTOPLEFTALIGN, 0,
{SBS_SIZEBOXBOTTOMRIGHTALIGN, 0,
{SBS_SIZEBOX,
0,
};
/*
* Entry field styles.
*/
static CLASSSTYLE acsEdit[]
{ES_LEFT,
{ES_CENTER,
{ES_RIGHT,
{ES_MULTILINE,
{ES_UPPERCASE,
{ES_LOWERCASE,
{ES_PASSWORD,
{ES_AUTOVSCROLL,
{ES_AUTOHSCROLL,
{ES_NOHIDESEL,
{ES_OEMCONVERT,
{ES_READONLY,
};
= {
ES_ALIGN,
ES_ALIGN,
ES_ALIGN,
0,
0,
0,
0,
0,
0,
0,
0,
0,
/*
* Static styles.
*/
static CLASSSTYLE acsStatic[] = {
{SS_LEFT,
SS_ALL,
{SS_CENTER,
SS_ALL,
{SS_RIGHT,
SS_ALL,
{SS_ICON,
SS_ALL,
{SS_BLACKRECT,
SS_ALL,
{SS_GRAYRECT,
SS_ALL,
{SS_WHITERECT,
SS_ALL,
{SS_BLACKFRAME,
SS_ALL,
{SS_GRAYFRAME,
SS_ALL,
{SS_WHITEFRAME,
{SS_USERITEM,
{SS_SIMPLE,
{SS_LEFTNOWORDWRAP,
{SS_NOPREFIX,
SS_ALL,
SS_ALL,
SS_ALL,
SS_ALL,
0,
DID_SS_WHITEFRAME
DID_SS_USERITEM
DID_SS_SIMPLE
DID_SS_LEFTNOWORDWRAP
DID_SS_NOPREFIX
},
},
},
},
}
{
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
DID_LBS_NOTIFY
DID_LBS_SORT
DID_LBS_NOREDRAW
DID_LBS_MULTIPLESEL
DID_LBS_OWNERDRAWFIXED
DID_LBS_OWNERDRAWVARIABLE
DID_LBS_HASSTRINGS
DID_LBS_USETABSTOPS
DID_LBS_NOINTEGRALHEIGHT
DID_LBS_MULTICOLUMN
DID_LBS_WANTKEYBOARDINPUT
DID_LBS_EXTENDEDSEL
DID_LBS_DISABLENOSCROLL
DID_LBS_NODATA
},
},
},
},
},
},
},
},
},
},
},
},
},
}
DID_CBS_SIMPLE
DID_CBS_DROPDOWN
DID_CBS_DROPDOWNLIST
DID_CBS_OWNERDRAWFIXED
DID_CBS_OWNERDRAWVARIABLE
DID_CBS_AUTOHSCROLL
DID_CBS_OEMCONVERT
DID_CBS_SORT
DID_CBS_HASSTRINGS
DID_CBS_NOINTEGRALHEIGHT
DID_CBS_DISABLENOSCROLL
},
},
},
},
},
},
},
},
},
},
}
/*
* Dialog styles.
*/
static CLASSSTYLE acsDialog[] = {
{DS_ABSALIGN,
0,
DID_DS_ABSALIGN
{DS_SYSMODAL,
0,
DID_DS_SYSMODAL
{DS_LOCALEDIT,
0,
DID_DS_LOCALEDIT
{DS_SETFONT,
0,
0
{DS_MODALFRAME,
0,
DID_DS_MODALFRAME
{DS_NOIDLEMSG,
0,
DID_DS_NOIDLEMSG
/*
* The following two styles are the same bits as WS_GROUP and
* WS_TABSTOP, so they must be in this table and there has
* to be special case code for writing the appropriate string
},
},
},
},
},
},
};
/*
* List box styles.
*/
static CLASSSTYLE acsLB[] =
{LBS_NOTIFY,
{LBS_SORT,
{LBS_NOREDRAW,
{LBS_MULTIPLESEL,
{LBS_OWNERDRAWFIXED,
{LBS_OWNERDRAWVARIABLE,
{LBS_HASSTRINGS,
{LBS_USETABSTOPS,
{LBS_NOINTEGRALHEIGHT,
{LBS_MULTICOLUMN,
{LBS_WANTKEYBOARDINPUT,
{LBS_EXTENDEDSEL,
{LBS_DISABLENOSCROLL,
{LBS_NODATA,
};
/*
* Combo Box styles.
*/
static CLASSSTYLE acsComboBox[] = {
{CBS_SIMPLE,
CBS_ALL,
{CBS_DROPDOWN,
CBS_ALL,
{CBS_DROPDOWNLIST,
CBS_ALL,
{CBS_OWNERDRAWFIXED,
0,
{CBS_OWNERDRAWVARIABLE, 0,
{CBS_AUTOHSCROLL,
0,
{CBS_OEMCONVERT,
0,
{CBS_SORT,
0,
{CBS_HASSTRINGS,
0,
{CBS_NOINTEGRALHEIGHT, 0,
{CBS_DISABLENOSCROLL,
0,
};
* out when writing dialog styles.
*/
{WS_MINIMIZEBOX,
0,
{WS_MAXIMIZEBOX,
0,
DID_WS_MINIMIZEBOX
DID_WS_MAXIMIZEBOX
},
}
};
/*
* Window styles.
*/
static CLASSSTYLE acsWindow[] = {
{WS_POPUP,
0,
DID_WS_POPUP
{WS_CHILD,
0,
DID_WS_CHILD
{WS_MINIMIZE,
0,
DID_WS_MINIMIZE
{WS_VISIBLE,
0,
DID_WS_VISIBLE
{WS_DISABLED,
0,
DID_WS_DISABLED
{WS_CLIPSIBLINGS,
0,
DID_WS_CLIPSIBLINGS
{WS_CLIPCHILDREN,
0,
DID_WS_CLIPCHILDREN
{WS_MAXIMIZE,
0,
DID_WS_MAXIMIZE
{WS_CAPTION,
WS_CAPTIONALL, DID_WS_CAPTION
{WS_BORDER,
WS_CAPTIONALL, DID_WS_BORDER
{WS_DLGFRAME,
WS_CAPTIONALL, DID_WS_DLGFRAME
{WS_VSCROLL,
0,
DID_WS_VSCROLL
{WS_HSCROLL,
0,
DID_WS_HSCROLL
{WS_SYSMENU,
0,
DID_WS_SYSMENU
{WS_THICKFRAME,
0,
DID_WS_THICKFRAME
{WS_GROUP,
0,
DID_WS_GROUP
{WS_TABSTOP,
0,
DID_WS_TABSTOP
};
/*
* Resource Flags styles.
*/
static CLASSSTYLE acsResFlags[] = {
{MMF_MOVEABLE,
0,
{MMF_PURE,
0,
{MMF_PRELOAD,
0,
{MMF_DISCARDABLE,
0,
};
/*
* Extended Styles.
*/
static CLASSSTYLE acsExStyle[] = {
{WS_EX_DLGMODALFRAME,
0,
{0x0002 /*WS_EX_DRAGOBJECT*/, 0,
{WS_EX_NOPARENTNOTIFY, 0,
{WS_EX_TOPMOST,
0,
{WS_EX_ACCEPTFILES,
0,
{WS_EX_TRANSPARENT,
0,
};
/*
*
*
*
*
*
*
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
}
DID_MMF_MOVEABLE
DID_MMF_PURE
DID_MMF_PRELOAD
DID_MMF_DISCARDABLE
},
},
},
}
0
0
0
0
0
0
},
},
},
},
},
}
Array of class style description structures. These are indexed by
the IC_* constants and describe each class. They contain pointers
to both the class styles array and the predefined keywords array
for each class.
The last few entries are included in the table for convenience,
* and are used to describe things like the various window (WS_*, WS_EX_*)
* and resource memory flags (MMF_*) styles, although they don't exactly
* map to an IC_* style that a control will have.
*/
CLASSSTYLEDESC acsd[] = {
/*
* IC_BUTTON
*/
{
IDS_WCBUTTON,
acsButton, sizeof(acsButton) / sizeof(CLASSSTYLE), IDS_IC_BUTTON,
arckwdButton, sizeof(arckwdButton) / sizeof(RCKEYWORD),
ORDID_BUTTONCLASS
},
/*
* IC_SCROLLBAR
*/
{
IDS_WCSCROLLBAR,
acsSB, sizeof(acsSB) / sizeof(CLASSSTYLE), IDS_IC_SCROLLBAR,
arckwdScrollBar, sizeof(arckwdScrollBar) / sizeof(RCKEYWORD),
ORDID_SCROLLBARCLASS
},
/*
* IC_EDIT
*/
{
IDS_WCEDIT,
acsEdit, sizeof(acsEdit) / sizeof(CLASSSTYLE), IDS_IC_EDIT,
arckwdEdit, sizeof(arckwdEdit) / sizeof(RCKEYWORD),
ORDID_EDITCLASS
},
/*
* IC_STATIC
*/
{
IDS_WCSTATIC,
acsStatic, sizeof(acsStatic) / sizeof(CLASSSTYLE), IDS_IC_STATIC,
arckwdStatic, sizeof(arckwdStatic) / sizeof(RCKEYWORD),
ORDID_STATICCLASS
},
/*
* IC_LISTBOX
*/
{
IDS_WCLISTBOX,
acsLB, sizeof(acsLB) / sizeof(CLASSSTYLE), IDS_IC_LISTBOX,
arckwdLB, sizeof(arckwdLB) / sizeof(RCKEYWORD),
ORDID_LISTBOXCLASS
},
/*
* IC_COMBOBOX
*/
{
IDS_WCCOMBOBOX,
acsComboBox, sizeof(acsComboBox) / sizeof(CLASSSTYLE), IDS_IC_COMBOBOX,
arckwdComboBox, sizeof(arckwdComboBox) / sizeof(RCKEYWORD),
ORDID_COMBOBOXCLASS
},
/*
* IC_CUSTOM
*/
{
IDS_WCCUSTOM,
NULL, 0, 0,
NULL, 0,
0
},
/*
* IC_DIALOG
*/
{
IDS_WCDIALOG,
acsDialog, sizeof(acsDialog) / sizeof(CLASSSTYLE), IDS_IC_DIALOG,
NULL, 0,
0
},
/*
* IC_WINDOW
*/
{
IDS_NULL,
acsWindow, sizeof(acsWindow) / sizeof(CLASSSTYLE), IDS_IC_WINDOW,
NULL, 0,
0
},
/*
* IC_RESFLAGS
*/
{
IDS_NULL,
acsResFlags, sizeof(acsResFlags) / sizeof(CLASSSTYLE), 0,
NULL, 0,
0
},
/*
* IC_EXSTYLE
*/
{
IDS_NULL,
acsExStyle, sizeof(acsExStyle) / sizeof(CLASSSTYLE), IDS_IC_EXSTYLE,
NULL, 0,
0
}
};
/*
* Message box messages, for the Message() function.
*/
MESSAGEDATA gamdMessages[] = {
{ IDS_DELETEDIALOG,
MB_YESNO | MB_ICONEXCLAMATION
{ IDS_OUTOFMEMORY,
MB_OK | MB_ICONHAND
{ IDS_CANTCREATE,
MB_OK | MB_ICONEXCLAMATION
{ IDS_SYMNOCHANGE,
MB_OK | MB_ICONEXCLAMATION
{ IDS_IDSYMMISMATCH,
MB_OK | MB_ICONEXCLAMATION
{ IDS_CLOSING,
MB_YESNOCANCEL | MB_ICONEXCLAMATION
},
},
},
},
},
},
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
{
IDS_BADRESFILE,
MB_OK | MB_ICONEXCLAMATION
IDS_INCLCLOSING,
MB_YESNOCANCEL | MB_ICONEXCLAMATION
IDS_SYMEXISTS,
MB_OK | MB_ICONEXCLAMATION
IDS_BADSYMBOLID,
MB_OK | MB_ICONEXCLAMATION
IDS_LABELDUPID,
MB_OK | MB_ICONEXCLAMATION
IDS_SELECTFIRST,
MB_OK | MB_ICONEXCLAMATION
IDS_CTRLDUPID,
MB_OK | MB_ICONEXCLAMATION
IDS_BADCUSTDLL,
MB_OK | MB_ICONEXCLAMATION
IDS_NOCLIP,
MB_OK | MB_ICONEXCLAMATION
IDS_INTERNAL,
MB_OK | MB_ICONEXCLAMATION
IDS_NOMOUSE,
MB_OK | MB_ICONEXCLAMATION
IDS_NOINIT,
MB_OK | MB_ICONEXCLAMATION
IDS_GTZERO,
MB_OK | MB_ICONEXCLAMATION
IDS_ICONNAMEHASBLANKS,MB_OK | MB_ICONEXCLAMATION
IDS_IDUPIDS,
MB_OK | MB_ICONEXCLAMATION
IDS_CREATECTRLERROR, MB_OK | MB_ICONEXCLAMATION
IDS_CANTOPENRES,
MB_OK | MB_ICONEXCLAMATION
IDS_CONFIRMDISCARD,
MB_YESNO | MB_ICONEXCLAMATION
IDS_SYMNOTFOUND,
MB_OK | MB_ICONEXCLAMATION
IDS_NOCLASS,
MB_OK | MB_ICONEXCLAMATION
IDS_POSITIVENUM,
MB_OK | MB_ICONEXCLAMATION
IDS_MEMERROR,
MB_OK | MB_ICONHAND
IDS_DLGNAMEHASBLANKS, MB_OK | MB_ICONEXCLAMATION
IDS_NODLGNAME,
MB_OK | MB_ICONEXCLAMATION
IDS_CANTINITDLL,
MB_OK | MB_ICONEXCLAMATION
IDS_NOICONNAME,
MB_OK | MB_ICONEXCLAMATION
IDS_RESTOREDIALOG,
MB_YESNO | MB_ICONEXCLAMATION
IDS_ZEROPOINTSIZE,
MB_OK | MB_ICONEXCLAMATION
IDS_MINGTMAXSPACE,
MB_OK | MB_ICONEXCLAMATION
IDS_CUSTCNTLINUSE,
MB_OK | MB_ICONEXCLAMATION
IDS_CUSTALREADYLOADED,MB_OK | MB_ICONEXCLAMATION
IDS_CANTLOADDLL,
MB_OK | MB_ICONEXCLAMATION
IDS_DLLBADEXPORTS,
MB_OK | MB_ICONEXCLAMATION
IDS_DLLBADCOUNT,
MB_OK | MB_ICONEXCLAMATION
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
}
};
/*
* Table that maps menu items to help context id's for them.
*/
HELPMAP gahmapMenu[] = {
{MENU_NEWRES,
HELPID_FILE_NEWRES
{MENU_OPEN,
HELPID_FILE_OPEN
{MENU_SAVE,
HELPID_FILE_SAVE
{MENU_SAVEAS,
HELPID_FILE_SAVEAS
{MENU_SETINCLUDE,
HELPID_FILE_SETINCLUDE
{MENU_NEWCUST,
HELPID_FILE_NEWCUST
{MENU_OPENCUST,
HELPID_FILE_OPENCUST
{MENU_REMCUST,
HELPID_FILE_REMCUST
{MENU_EXIT,
HELPID_FILE_EXIT
{MENU_RESTOREDIALOG,
{MENU_CUT,
{MENU_COPY,
{MENU_PASTE,
{MENU_DELETE,
{MENU_DUPLICATE,
{MENU_SYMBOLS,
{MENU_STYLES,
HELPID_EDIT_RESTOREDIALOG
HELPID_EDIT_CUT
HELPID_EDIT_COPY
HELPID_EDIT_PASTE
HELPID_EDIT_DELETE
HELPID_EDIT_DUPLICATE
HELPID_EDIT_SYMBOLS
HELPID_EDIT_STYLES
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
{MENU_SIZETOTEXT,
{MENU_NEWDIALOG,
{MENU_SELECTDIALOG,
HELPID_EDIT_SIZETOTEXT
HELPID_EDIT_NEWDIALOG
HELPID_EDIT_SELECTDIALOG
},
},
},
{MENU_ALIGNLEFT,
{MENU_ALIGNVERT,
{MENU_ALIGNRIGHT,
{MENU_ALIGNTOP,
{MENU_ALIGNHORZ,
{MENU_ALIGNBOTTOM,
{MENU_SPACEHORZ,
{MENU_SPACEVERT,
{MENU_ARRSIZEWIDTH,
{MENU_ARRSIZEHEIGHT,
{MENU_ARRPUSHBOTTOM,
{MENU_ARRPUSHRIGHT,
{MENU_ORDERGROUP,
{MENU_ARRSETTINGS,
HELPID_ARRANGE_ALIGNLEFT
HELPID_ARRANGE_ALIGNVERT
HELPID_ARRANGE_ALIGNRIGHT
HELPID_ARRANGE_ALIGNTOP
HELPID_ARRANGE_ALIGNHORZ
HELPID_ARRANGE_ALIGNBOTTOM
HELPID_ARRANGE_SPACEHORZ
HELPID_ARRANGE_SPACEVERT
HELPID_ARRANGE_ARRSIZEWIDTH
HELPID_ARRANGE_ARRSIZEHEIGHT
HELPID_ARRANGE_ARRPUSHBOTTOM
HELPID_ARRANGE_ARRPUSHRIGHT
HELPID_ARRANGE_ORDERGROUP
HELPID_ARRANGE_ARRSETTINGS
},
},
},
},
},
},
},
},
},
},
},
},
},
},
{MENU_TESTMODE,
{MENU_HEXMODE,
{MENU_TRANSLATE,
{MENU_USENEWKEYWORDS,
{MENU_SHOWTOOLBOX,
HELPID_OPTIONS_TESTMODE
HELPID_OPTIONS_HEXMODE
HELPID_OPTIONS_TRANSLATE
HELPID_OPTIONS_USENEWKEYWORDS
HELPID_OPTIONS_SHOWTOOLBOX
},
},
},
},
},
{MENU_CONTENTS,
HELPID_HELP_CONTENTS
{MENU_SEARCH,
HELPID_HELP_SEARCH
// No help for the About menu command.
},
},
{0,
}
0
};
/*
* Table that maps dialog ids to help context id's for them.
*/
HELPMAP gahmapDialog[] = {
// No help for the About dialog.
{DID_ARRSETTINGS,
HELPID_ARRSETTINGS
{DID_CHECKBOXSTYLES,
HELPID_CHECKBOXSTYLES
{DID_COMBOBOXSTYLES,
HELPID_COMBOBOXSTYLES
{DID_CUSTOMSTYLES,
HELPID_CUSTOMSTYLES
{DID_DIALOGSTYLES,
HELPID_DIALOGSTYLES
{DID_EDITSTYLES,
HELPID_EDITSTYLES
{DID_FRAMESTYLES,
HELPID_FRAMESTYLES
{DID_GROUPBOXSTYLES,
HELPID_GROUPBOXSTYLES
{DID_ORDERGROUP,
HELPID_ORDERGROUP
{DID_HORZSCROLLSTYLES,
HELPID_HORZSCROLLSTYLES
{DID_ICONSTYLES,
HELPID_ICONSTYLES
{DID_LISTBOXSTYLES,
HELPID_LISTBOXSTYLES
{DID_NEWCUST,
HELPID_NEWCUST
{DID_PUSHBUTTONSTYLES,
HELPID_PUSHBUTTONSTYLES
{DID_RADIOBUTTONSTYLES,
HELPID_RADIOBUTTONSTYLES
{DID_RECTSTYLES,
HELPID_RECTSTYLES
{DID_REMCUST,
HELPID_REMCUST
{DID_SELECTDIALOG,
HELPID_SELECTDIALOG
{DID_SYMBOLS,
HELPID_SYMBOLS
{DID_TEXTSTYLES,
HELPID_TEXTSTYLES
{DID_VERTSCROLLSTYLES,
HELPID_VERTSCROLLSTYLES
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
{DID_COMMONFILEOPENINCLUDE,
{DID_COMMONFILEOPENRES,
{DID_COMMONFILESAVEINCLUDE,
{DID_COMMONFILESAVERES,
{DID_COMMONFILEOPENDLL,
HELPID_COMMONFILEOPENINCLUDE
HELPID_COMMONFILEOPENRES
HELPID_COMMONFILESAVEINCLUDE
HELPID_COMMONFILESAVERES
HELPID_COMMONFILEOPENDLL
},
},
},
},
},
{DID_TOOLBOX,
{DID_STATUS,
HELPID_TOOLBOX
HELPID_PROPERTIESBAR
},
},
{0,
0
}
};
/*
* Language and Sub Language tables.
*/
static SUBLANGTABLE aslNeutral[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
{ SUBLANG_DEFAULT,
IDS_SUBLANG_DEFAULT,
};
IDS_SL_NEUTRAL
IDS_SL_DEFAULT
static SUBLANGTABLE aslChinese[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
{ SUBLANG_CHINESE_SIMPLIFIED, IDS_SUBLANG_CHINESE_SIMPLIFIED,
IDS_SL_CHINESE_SIMPLIFIED
},
{ SUBLANG_CHINESE_TRADITIONAL, IDS_SUBLANG_CHINESE_TRADITIONAL,
IDS_SL_CHINESE_TRADITIONAL }
};
},
}
},
static SUBLANGTABLE aslDutch[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
{ SUBLANG_DUTCH,
IDS_SUBLANG_DUTCH,
{ SUBLANG_DUTCH_BELGIAN,IDS_SUBLANG_DUTCH_BELGIAN,
};
IDS_SL_NEUTRAL
},
IDS_SL_DUTCH
},
IDS_SL_DUTCH_BELGIAN}
static SUBLANGTABLE aslEnglish[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
{ SUBLANG_ENGLISH_US,
IDS_SUBLANG_ENGLISH_US,
{ SUBLANG_ENGLISH_UK,
IDS_SUBLANG_ENGLISH_UK,
{ SUBLANG_ENGLISH_AUS, IDS_SUBLANG_ENGLISH_AUS,
{ SUBLANG_ENGLISH_CAN, IDS_SUBLANG_ENGLISH_CAN,
};
IDS_SL_NEUTRAL
IDS_SL_ENGLISH_US
IDS_SL_ENGLISH_UK
IDS_SL_ENGLISH_AUS
IDS_SL_ENGLISH_CAN
},
},
},
},
}
static SUBLANGTABLE aslFrench[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
},
{ SUBLANG_FRENCH,
IDS_SUBLANG_FRENCH,
IDS_SL_FRENCH
},
{ SUBLANG_FRENCH_BELGIAN, IDS_SUBLANG_FRENCH_BELGIAN, IDS_SL_FRENCH_BELGIAN },
{ SUBLANG_FRENCH_CANADIAN, IDS_SUBLANG_FRENCH_CANADIAN, IDS_SL_FRENCH_CANADIAN },
{ SUBLANG_FRENCH_SWISS, IDS_SUBLANG_FRENCH_SWISS,
IDS_SL_FRENCH_SWISS }
};
static SUBLANGTABLE aslGerman[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
{ SUBLANG_GERMAN,
IDS_SUBLANG_GERMAN,
{ SUBLANG_GERMAN_SWISS, IDS_SUBLANG_GERMAN_SWISS,
};
static SUBLANGTABLE aslItalian[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
},
IDS_SL_GERMAN
},
IDS_SL_GERMAN_SWISS }
IDS_SL_NEUTRAL
},
{ SUBLANG_ITALIAN,
IDS_SUBLANG_ITALIAN,
IDS_SL_ITALIAN
},
{ SUBLANG_ITALIAN_SWISS, IDS_SUBLANG_ITALIAN_SWISS, IDS_SL_ITALIAN_SWISS }
};
static SUBLANGTABLE aslNorwegian[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
},
{ SUBLANG_NORWEGIAN_BOKMAL, IDS_SUBLANG_NORWEGIAN_BOKMAL, IDS_SL_NORWEGIAN_BOKMAL
},
{ SUBLANG_NORWEGIAN_NYNORSK, IDS_SUBLANG_NORWEGIAN_NYNORSK,
IDS_SL_NORWEGIAN_NYNORSK }
};
static SUBLANGTABLE aslPortuguese[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
{ SUBLANG_PORTUGUESE,
IDS_SUBLANG_PORTUGUESE,
IDS_SL_PORTUGUESE
{ SUBLANG_PORTUGUESE_BRAZILIAN, IDS_SUBLANG_PORTUGUESE_BRAZILIAN,
IDS_SL_PORTUGUESE_BRAZILIAN }
};
},
},
static SUBLANGTABLE aslSpanish[] = {
{ SUBLANG_NEUTRAL,
IDS_SUBLANG_NEUTRAL,
IDS_SL_NEUTRAL
},
{ SUBLANG_SPANISH,
IDS_SUBLANG_SPANISH,
IDS_SL_SPANISH
},
{ SUBLANG_SPANISH_MEXICAN, IDS_SUBLANG_SPANISH_MEXICAN, IDS_SL_SPANISH_MEXICAN },
{ SUBLANG_SPANISH_MODERN, IDS_SUBLANG_SPANISH_MODERN, IDS_SL_SPANISH_MODERN }
};
LANGTABLE gaLangTable[] = {
{ LANG_NEUTRAL,
IDS_LANG_NEUTRAL,
IDS_L_NEUTRAL,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_CHINESE,
IDS_LANG_CHINESE,
IDS_L_CHINESE,
sizeof(aslChinese) / sizeof(SUBLANGTABLE), aslChinese },
{ LANG_CZECH,
IDS_LANG_CZECH,
IDS_L_CZECH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_DANISH,
IDS_LANG_DANISH,
IDS_L_DANISH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_DUTCH,
IDS_LANG_DUTCH,
IDS_L_DUTCH,
sizeof(aslDutch) / sizeof(SUBLANGTABLE), aslDutch },
{ LANG_ENGLISH,
IDS_LANG_ENGLISH,
IDS_L_ENGLISH,
sizeof(aslEnglish) / sizeof(SUBLANGTABLE), aslEnglish },
{ LANG_FINNISH,
IDS_LANG_FINNISH,
IDS_L_FINNISH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_FRENCH,
IDS_LANG_FRENCH,
IDS_L_FRENCH,
sizeof(aslFrench) / sizeof(SUBLANGTABLE), aslFrench },
{ LANG_GERMAN,
IDS_LANG_GERMAN,
IDS_L_GERMAN,
sizeof(aslGerman) / sizeof(SUBLANGTABLE), aslGerman },
{ LANG_GREEK,
IDS_LANG_GREEK,
IDS_L_GREEK,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_HUNGARIAN,
IDS_LANG_HUNGARIAN,
IDS_L_HUNGARIAN,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_ICELANDIC,
IDS_LANG_ICELANDIC,
IDS_L_ICELANDIC,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_ITALIAN,
IDS_LANG_ITALIAN,
IDS_L_ITALIAN,
sizeof(aslItalian) / sizeof(SUBLANGTABLE), aslItalian },
{ LANG_JAPANESE,
IDS_LANG_JAPANESE,
IDS_L_JAPANESE,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_KOREAN,
IDS_LANG_KOREAN,
IDS_L_KOREAN,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_NORWEGIAN,
IDS_LANG_NORWEGIAN,
IDS_L_NORWEGIAN,
sizeof(aslNorwegian) / sizeof(SUBLANGTABLE), aslNorwegian },
{ LANG_POLISH,
IDS_LANG_POLISH,
IDS_L_POLISH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_PORTUGUESE,
IDS_LANG_PORTUGUESE,
IDS_L_PORTUGUESE,
sizeof(aslPortuguese) / sizeof(SUBLANGTABLE), aslPortuguese },
{ LANG_RUSSIAN,
IDS_LANG_RUSSIAN,
IDS_L_RUSSIAN,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_SLOVAK,
IDS_LANG_SLOVAK,
IDS_L_SLOVAK,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_SPANISH,
IDS_LANG_SPANISH,
IDS_L_SPANISH,
sizeof(aslSpanish) / sizeof(SUBLANGTABLE), aslSpanish },
{ LANG_SWEDISH,
IDS_LANG_SWEDISH,
IDS_L_SWEDISH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
{ LANG_TURKISH,
IDS_LANG_TURKISH,
IDS_L_TURKISH,
sizeof(aslNeutral) / sizeof(SUBLANGTABLE), aslNeutral },
};
INT gcLanguages = sizeof(gaLangTable) / sizeof(LANGTABLE);
===============================
////////////////////////////////////
//-----------------------------------------------------------//
// Netstatp
//
// Copyright (C) 1998 Mark Russinovich
// Systems Internals
// http://www.sysinternals.com
//
// This program implements a subset of the Netstat program's
// functionality. Specifically, it enumerates and displays
// information about all UDP and TCP endpoints.
//
//-----------------------------------------------------------#include "windows.h"
#include "stdio.h"
#include "snmp.h"
#include "winsock.h"
#define HOSTNAMELEN 256
#define PORTNAMELEN 256
#define ADDRESSLEN HOSTNAMELEN+PORTNAMELEN
typedef struct _tcpinfo {
struct _tcpinfo
struct _tcpinfo
UINT
UINT
UINT
UINT
UINT
} TCPINFO, *PTCPINFO;
*prev;
*next;
state;
localip;
localport;
remoteip;
remoteport;
BOOL (__stdcall *SnmpExtensionInit)(
IN DWORD
dwTimeZeroReference,
OUT HANDLE
*hPollForTrapEvent,
OUT AsnObjectIdentifier *supportedView);
BOOL (__stdcall *SnmpExtensionQuery)(
IN BYTE
requestType,
IN OUT RFC1157VarBindList *variableBindings,
OUT AsnInteger
*errorStatus,
OUT AsnInteger
*errorIndex);
//
// Possible TCP endpoint states
//
static char TcpState[][32] = {
"???",
"CLOSED",
"LISTENING",
"SYN_SENT",
"SEN_RECEIVED",
"ESTABLISHED",
"FIN_WAIT",
"FIN_WAIT2",
"CLOSE_WAIT",
"CLOSING",
"LAST_ACK",
"TIME_WAIT"
};
//
// Lists of endpoints
//
TCPINFO
TcpInfoTable;
TCPINFO
UdpInfoTable;
//-----------------------------------------------------------//
// GetPortName
//
// Translate port numbers into their text equivalent if
// there is one
//
//-----------------------------------------------------------char *GetPortName( UINT port, char *proto, char *name, int namelen )
{
struct servent *psrvent;
if( psrvent = getservbyport( htons( (USHORT) port ), proto )) {
strcpy( name, psrvent->s_name );
} else {
sprintf(name, "%d", port);
}
return name;
}
//-----------------------------------------------------------//
// GetIpHostName
//
// Translate IP addresses into their name-resolved form
// if possible.
//
//-----------------------------------------------------------char *GetIpHostName( BOOL local, UINT ipaddr, char *name, int namelen )
{
struct hostent
*phostent;
UINT
nipaddr;
nipaddr = htonl( ipaddr );
if( !ipaddr ) {
if( !local ) {
sprintf( name, "%d.%d.%d.%d",
(nipaddr >> 24) & 0xFF,
(nipaddr >> 16) & 0xFF,
(nipaddr >> 8) & 0xFF,
(nipaddr) & 0xFF);
} else {
gethostname(name, namelen);
}
} else if( ipaddr == 0x0100007f ) {
if( local ) {
gethostname(name, namelen);
} else {
strcpy( name, "localhost" );
}
} else if( phostent = gethostbyaddr( (char *) &ipaddr,
sizeof( nipaddr ), PF_INET )) {
strcpy( name, phostent->h_name );
} else {
sprintf( name, "%d.%d.%d.%d",
(nipaddr >> 24) & 0xFF,
(nipaddr >> 16) & 0xFF,
(nipaddr >> 8) & 0xFF,
(nipaddr) & 0xFF);
}
return name;
}
//-----------------------------------------------------------//
// LoadInetMibEntryPoints
//
// Load the TCP/IP SNMP extension DLL and locate the entry
// points we will use.
//
//------------------------------------------------------------
BOOLEAN LoadInetMibEntryPoints()
{
HINSTANCE
hInetLib;
if( !(hInetLib = LoadLibrary( "inetmib1.dll" ))) {
return FALSE;
}
if( !(SnmpExtensionInit = (void *) GetProcAddress( hInetLib,
"SnmpExtensionInit" )) ) {
return FALSE;
}
if( !(SnmpExtensionQuery = (void *) GetProcAddress( hInetLib,
"SnmpExtensionQuery" )) ) {
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------//
// Main
//
// Do it all. Load and initialize the SNMP extension DLL and
// then build a table of TCP endpoints and UDP endpoints. After
// each table is built resolve addresses to names and print
// out the information
//
//-----------------------------------------------------------int main( int argc, char *argv[] )
{
HANDLE
hTrapEvent;
AsnObjectIdentifier
hIdentifier;
RFC1157VarBindList
bindList;
RFC1157VarBind
bindEntry;
UINT
tcpidentifiers[] = {
1,3,6,1,2,1,6,13,1,1};
UINT
udpidentifiers[] = { 1,3,6,1,2,1,7,
5,1,1};
AsnInteger
errorStatus, errorIndex;
TCPINFO
*currentEntry, *newEntry;
UINT
currentIndex;
WORD
wVersionRequested;
WSADATA
wsaData;
char
localname[HOSTNAMELEN],
remotename[HOSTNAMELEN];
char
remoteport[PORTNAMELEN],
localport[PORTNAMELEN];
char
localaddr[ADDRESSLEN],
remoteaddr[ADDRESSLEN];
//
// Initialize winsock
//
wVersionRequested = MAKEWORD( 1, 1 );
if( WSAStartup( wVersionRequested, &wsaData ) ) {
printf("Could not initialize Winsock.\n");
return 1;
}
//
// Locate and initialize INETMIB1
//
if( !LoadInetMibEntryPoints()) {
printf("Could not load extension DLL.\n");
return 1;
}
if( !SnmpExtensionInit( GetCurrentTime(), &hTrapEvent, &hIdentifier )) {
printf("Could not initialize extension DLL.\n");
return 1;
}
//
// Initialize the query structure once
//
bindEntry.name.idLength = 0xA;
bindEntry.name.ids = tcpidentifiers;
bindList.list = &bindEntry;
bindList.len = 1;
TcpInfoTable.prev = &TcpInfoTable;
TcpInfoTable.next = &TcpInfoTable;
//
// Roll through TCP connections
//
currentIndex = 1;
currentEntry = &TcpInfoTable;
while(1) {
if( !SnmpExtensionQuery( ASN_RFC1157_GETNEXTREQUEST,
&bindList, &errorStatus, &errorIndex )) {
return 1;
}
//
// Terminate when we're no longer seeing TCP information
//
if( bindEntry.name.idLength < 0xA ) break;
//
// Go back to start of table if we're reading info
// about the next byte
//
if( currentIndex != bindEntry.name.ids[9] ) {
currentEntry = TcpInfoTable.next;
currentIndex = bindEntry.name.ids[9];
}
//
// Build our TCP information table
//
switch( bindEntry.name.ids[9] ) {
case 1:
//
// Always allocate a new structure
//
newEntry = (TCPINFO *) malloc( sizeof(TCPINFO ));
newEntry->prev = currentEntry;
newEntry->next = &TcpInfoTable;
currentEntry->next = newEntry;
currentEntry = newEntry;
currentEntry->state = bindEntry.value.asnValue.number;
break;
case 2:
currentEntry->localip =
*(UINT *) bindEntry.value.asnValue.address.stream;
currentEntry = currentEntry->next;
break;
case 3:
currentEntry->localport =
bindEntry.value.asnValue.number;
currentEntry = currentEntry->next;
break;
case 4:
currentEntry->remoteip =
*(UINT *) bindEntry.value.asnValue.address.stream;
currentEntry = currentEntry->next;
break;
case 5:
currentEntry->remoteport =
bindEntry.value.asnValue.number;
currentEntry = currentEntry->next;
break;
}
}
//
// Now print the connection information
//
printf("%7s %-30s %-30s %s\n", "Proto", "Local", "Remote", "State" );
currentEntry = TcpInfoTable.next;
while( currentEntry != &TcpInfoTable ) {
sprintf( localaddr, "%s:%s",
GetIpHostName( TRUE, currentEntry->localip, localname,
HOSTNAMELEN),
GetPortName( currentEntry->localport, "tcp", localport,
PORTNAMELEN ));
sprintf( remoteaddr, "%s:%s",
GetIpHostName( FALSE, currentEntry->remoteip, remotename,
HOSTNAMELEN),
currentEntry->remoteip ?
GetPortName( currentEntry->remoteport, "tcp",
remoteport, PORTNAMELEN ):
"0" );
printf("%7s %-30s %-30s %s\n", "TCP",
localaddr, remoteaddr,
TcpState[currentEntry->state]);
currentEntry = currentEntry->next;
}
printf("\n");
//
// Initialize the query structure once
//
bindEntry.name.idLength = 0xA;
bindEntry.name.ids = udpidentifiers;
bindList.list = &bindEntry;
bindList.len = 1;
UdpInfoTable.prev = &UdpInfoTable;
UdpInfoTable.next = &UdpInfoTable;
//
// Roll through UDP endpoints
//
currentIndex = 1;
currentEntry = &UdpInfoTable;
while(1) {
if( !SnmpExtensionQuery( ASN_RFC1157_GETNEXTREQUEST,
&bindList, &errorStatus, &errorIndex )) {
return 1;
}
//
// Terminate when we're no longer seeing TCP information
//
if( bindEntry.name.idLength < 0xA ) break;
//
// Go back to start of table if we're reading info
// about the next byte
//
if( currentIndex != bindEntry.name.ids[9] ) {
currentEntry = UdpInfoTable.next;
currentIndex = bindEntry.name.ids[9];
}
//
// Build our TCP information table
//
switch( bindEntry.name.ids[9] ) {
case 1:
//
// Always allocate a new structure
//
newEntry = (TCPINFO *) malloc( sizeof(TCPINFO ));
newEntry->prev = currentEntry;
newEntry->next = &UdpInfoTable;
currentEntry->next = newEntry;
currentEntry = newEntry;
currentEntry->localip =
*(UINT *) bindEntry.value.asnValue.address.stream;
break;
case 2:
currentEntry->localport =
bindEntry.value.asnValue.number;
currentEntry = currentEntry->next;
break;
}
}
//
// Now print the connection information
//
currentEntry = UdpInfoTable.next;
while( currentEntry != &UdpInfoTable ) {
printf("%7s %s:%s\n", "UDP",
GetIpHostName( TRUE, currentEntry->localip,
localname, HOSTNAMELEN),
GetPortName( currentEntry->localport, "udp",
localport, PORTNAMELEN ) );
currentEntry = currentEntry->next;
}
printf("\n");
}
/////////////////////////////
#if defined(__cplusplus) && !defined(CINTERFACE)
//#define interface
struct FAR
#define interface struct
#define STDMETHOD(method)
virtual HRESULT __stdcall method
#define STDMETHOD_(type,method)
virtual type
__stdcall method
#define PURE
= 0
#define THIS_
#define THIS
void
#define DECLARE_INTERFACE(iface) interface iface
#define DECLARE_INTERFACE_(iface, baseiface)\
interface iface:public baseiface
#else
#define interface
struct
#define STDMETHOD(method)
HRESULT (__stdcall * method)
#define STDMETHOD_(type,method) type (__stdcall * method)
#ifdef __cplusplus
extern "C" {
#endif
...
...
#ifdef __cplusplus
}
#endif
// Common Library header for DLL and application-- lib1.h
#ifdef MAKE_A_DLL
#define LINKDLL __declspec( dllexport)
#else
#define LINKDLL __declspec( dllimport)
#endif
LINKDLL int libglobal;
LINKDLL void libfuncA(char * buffer);
LINKDLL int libfuncB(int const * mainint);
Was erfolgt beim Laden einer DLL?
Das Operating System führt die folgenden Schritte aus:
Suche der ( zu ladenden ) DLL auf Platte.
Im Adressraum der Applikation wird die Liste
der bereits geladenen DLL's durchsucht,
ob ein Laden erforderlich ist.
Falls erfordelich, wird Speicher für die zu ladende DLL allokiert
( section object ).
Die notwendigen vorbereitende Initialisierungen werden durchgeführt
( Adressanpassungen von static-Variablen, fix-up, imports, exports ).
================
TN038: MFC/OLE IUnknown Implementation
At the heart of OLE 2 is the "OLE Component Object Model", or COM. COM defines a
standard for
how cooperating objects communicate to one another. This includes the details of what
an
"object" looks like, including how methods are dispatched on an object. COM also
defines a
base class, from which all COM compatible classes are derived. This base class is
IUnknown.
Although the IUnknown interface is referred to as a C++ class, COM is not specific to
any one
language — it can be implemented in C, PASCAL, or any other language which can
support the
binary layout of a COM object.
OLE refers to all classes derived from IUnknown as "interfaces." This is an important
distinction, since an "interface" such as IUnknown carries with it no implementation.
It simply defines the protocol by which objects communicate, not the specifics of
what those
implementations do. This is reasonable for a system which allows for maximum
flexibility.
It is MFC's job to implement a default behavior for MFC/C++ programs.
To understand MFC's implementation of IUnknown you must first understand what this
interface is.
A simplified version of IUnknown is defined below:
class IUnknown
{
public:
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
Note
Certain necessary calling convention details, such as __stdcall are left out
for this
illustration.
The AddRef and Release member functions control memory management of the object. COM
uses a
reference counting scheme to keep track of objects. An object is never referenced
directly
as you would in C++. Instead, COM objects are always referenced through a pointer.
To release the object when the owner is done using it, the object's Release member is
called
(as opposed to using operator delete, as would be done for a traditional C++ object).
The reference counting mechanism allows for multiple references to a single object to
be
managed. An implementation of AddRef and Release maintains a reference count on the
object — the object is not deleted until its reference count reaches zero.
AddRef and Release are fairly straightforward from an implementation standpoint.
Here is a trivial implementation:
ULONG CMyObj::AddRef()
{
return ++m_dwRef;
}
ULONG CMyObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
The QueryInterface member function is a little more interesting. As you can imagine,
it isn't
very interesting to have an object whose only member functions are AddRef and Release
—
it would be nice to tell the object to do more things than IUnknown provides.
This is where QueryInterface is useful. It allows you to obtain a different
"interface"
on the same object. These interfaces are usually derived from IUnknown and add
additional
functionality by adding new member functions. COM interfaces never have member
variables
declared in the interface, and all member functions are declared as pure-virtual.
For example,
class IPrintInterface : public IUnknown
{
public:
virtual void PrintObject() = 0;
};
To get an IPrintInterface if you only have an IUnknown, call IUnknown::QueryInterface
using
the IID of the IPrintInterface. An IID is a 128-bit number that uniquely identifies
the
interface. There is an IID for each interface that either you or OLE define.
If pUnk is a pointer to an IUnknown object, the code to retrieve an IPrintInterface
from
it might be:
IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface,
(void**)&pPrint) == NOERROR)
{
pPrint->PrintObject();
pPrint->Release();
// release pointer obtained via QueryInterface
}
That seems fairly easy, but how would you implement an object supporting both the
IPrintInterface and IUnknown interface? In this case it is simple since the
IPrintInterface
is derived directly from IUnknown — by implementing IPrintInterface, IUnknown is
automatically
supported. For example:
class CPrintObj : public CPrintInterface
{
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
virtual void PrintObject();
};
The implementations of AddRef and Release would be exactly the same as those
implemented above.
CPrintObj::QueryInterface would look something like this:
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
As you can see, if the interface identifier (IID) is recognized, a pointer is
returned to your
object; otherwise an error occurs. Also note that a successful QueryInterface results
in an
implied AddRef. Of course, you'd also have to implement CEditObj::Print.
That is simple because the IPrintInterface was directly derived from the IUnknown
interface.
However if you wanted to support two different interfaces, both derived from
IUnknown,
consider the following:
class IEditInterface : public IUnkown
{
public:
virtual void EditObject() = 0;
};
Although there are a number of different ways to implement a class supporting both
IEditInterface and IPrintInterface, including using C++ multiple inheritance,
this note will concentrate on the use of nested classes to implement this
functionality.
class CEditPrintObj
{
public:
CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD m_dwRef;
class CPrintObj : public IPrintInterface
{
public:
CEditPrintObj* m_pParent;
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_printObj;
class CEditObj : public IEditInterface
{
public:
CEditPrintObj* m_pParent;
virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_editObj;
};
The entire implementation is included below:
CEditPrintObj::CEditPrintObj()
{
m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef()
{
return ++m_dwRef;
}
CEditPrintObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = &m_printObj;
AddRef();
return NOERROR;
}
else if (iid == IID_IEditInterface)
{
*ppvObj = &m_editObj;
AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
ULONG CEditPrintObj::CEditObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CEditObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
ULONG CEditPrintObj::CPrintObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CPrintObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CPrintObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
Notice that most of the IUnknown implementation is placed into the CEditPrintObj
class rather
than duplicating the code in CEditPrintObj::CEditObj and CEditPrintObj::CPrintObj.
This reduces the amount of code and avoids bugs. The key point here is that from the
IUnknown interface it is possible to call QueryInterface to retrieve any interface
the
object might support, and from each of those interfaces it is possible to do the
same.
This means that all QueryInterface functions available from each interface must
behave
exactly the same way. In order for these embedded objects to call the implementation
in the "outer object", a back-pointer is used (m_pParent). The m_pParent pointer is
initialized during the CEditPrintObj constructor. Then you would implement
CEditPrintObj::CPrintObj::PrintObject and CEditPrintObj::CEditObj::EditObject as
well.
Quite a bit of code was added to add one feature — the ability to edit the object.
Fortunately, it is quite uncommon for interfaces to have only a single member
function
(although it does happen) and in this case, EditObject and PrintObject would usually
be
combined into a single interface.
That's a lot of explanation and a lot of code for such a simple scenario. The MFC/OLE
classes
provide a simpler alternative. The MFC implementation uses a technique similar to the
way
Windows messages are wrapped with Message Maps. This facility is called Interface
Maps and
is discussed in the next section.
MFC Interface Maps
MFC/OLE includes an implementation of "Interface Maps" similar to MFC's
"Message Maps" and "Dispatch Maps" in concept and execution.
The core features of MFC's Interface Maps are as follows:
A standard implementation of IUnknown, built into the CCmdTarget class.
Maintenance of the reference count, modified by AddRef and Release
Data driven implementation of QueryInterface
In addition, interface maps support the following advanced features:
Support for creating aggregatable COM objects
Support for using aggregate objects in the implementation of a COM object
The implementation is hookable and extensible
For more information on aggregation, see the OLE Programmer's Reference.
MFC's interface map support is rooted in the CCmdTarget class. CCmdTarget "has-a"
reference
count as well as all the member functions associated with the IUnknown implementation
(the reference count for example is in CCmdTarget). To create a class that supports
OLE COM, you derive a class from CCmdTarget and use various macros as well as member
functions of CCmdTarget to implement the desired interfaces. MFC's implementation
uses
nested classes to define each interface implementation much like the example above.
This is made easier with a standard implementation of IUnknown as well as a number
of macros that eliminate some of the repetitive code.
Interface Map Basics
To implement a class using MFC's interface maps follow these steps:
Derive a class either directly or indirectly from CCmdTarget.
Use the DECLARE_INTERFACE_MAP function in the derived class definition.
For each interface you wish to support, use the BEGIN_INTERFACE_PART and
END_INTERFACE_PART
macros in the class definition.
In the implementation file, use the BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros
to define
the class's interface map.
For each IID supported, use the INTERFACE_PART macro between the
BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros to map that IID to a specific "part"
of your
class.
Implement each of the nested classes that represent the interfaces you support.
Use the METHOD_PROLOGUE macro to access the parent, CCmdTarget-derived object.
AddRef, Release, and QueryInterface can delegate to the CCmdTarget implementation of
these
functions (ExternalAddRef, ExternalRelease, and ExternalQueryInterface).
The CPrintEditObj example above could be implemented as follows:
class CPrintEditObj : public CCmdTarget
{
public:
// member data and member functions for CPrintEditObj go here
// Interface Maps
protected:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(EditObj, IEditInterface)
STDMETHOD_(void, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART(PrintObj, IPrintInterface)
STDMETHOD_(void, PrintObject)();
END_INTERFACE_PART(PrintObj)
};
The above declaration creates a class derived from CCmdTarget. The
DECLARE_INTERFACE_MAP macro
tells the framework that this class will have a custom interface map. In addition,
the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros define nested classes, in this
case
with names CEditObj and CPrintObj (the X is used only to differentiate the nested
classes
from global classes which start with "C" and interface classes which start with "I").
Two nested members of these classes are created: m_CEditObj, and m_CPrintObj,
respectively.
The macros automatically declare the AddRef, Release, and QueryInterface functions;
therefore you only declare the functions specific to this interface: EditObject and
PrintObject
(the OLE macro STDMETHOD is used such so that _stdcall and virtual keywords are
provided
as appropriate for the target platform).
To implement the interface map for this class:
BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
This connects the IID_IPrintInterface IID with m_CPrintObj and IID_IEditInterface
with
m_CEditObj respectively. The CCmdTarget implementation of QueryInterface
(CCmdTarget::ExternalQueryInterface) uses this map to return pointers to m_CPrintObj
and m_CEditObj when requested. It is not necessary to include an entry for
IID_IUnknown;
the framework will use the first interface in the map (in this case, m_CPrintObj)
when
IID_IUnknown is requested.
Even though the BEGIN_INTERFACE_PART macro automatically declared the AddRef, Release
and QueryInterface functions for you, you still need to implement them:
ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
// code to "Edit" the object, whatever that means...
}
The implementation for CEditPrintObj::CPrintObj, would be similar to the above
definitions
for CEditPrintObj::CEditObj. Although it would be possible to create a macro that
could be
used to automatically generate these functions (as a matter of fact, earlier in the
MFC/OLE
development this was the case), it becomes difficult to set break points when a macro
generates
more than one line of code. For this reason, this code is expanded manually.
By using the framework implementation of message maps there are a number of things
that weren't
necessary to do:
Implement QueryInterface
Implement AddRef and Release
Declare either of these built-in methods on both of your interfaces
In addition, the framework uses message maps internally. This allows you to derive
from a
framework class, say COleServerDoc, that already supports certain interfaces and
provides
either replacements or additions to the interfaces provided by the framework. This is
enabled
by the fact that the framework fully supports inheriting an interface map from a base
class —
that is the reason why BEGIN_INTERFACE_MAP takes as its second parameter the name of
the base
class.
Note
It is generally not possible to reuse the implementation of MFC's built-in
implementations of the OLE interfaces by inheriting the embedded specialization of
that
interface from the MFC version. This is not possible because the use of the
METHOD_PROLOGUE
macro to get access to the containing CCmdTarget-derived object implies a fixed
offset of the
embedded object from the CCmdTarget-derived object. This means, for example, you
cannot derive
an embedded XMyAdviseSink from MFC's implementation in COleClientItem::XAdviseSink,
because XAdviseSink relies on being at a specific offset from the top of the
COleClientItem
object.
You can, however, delegate to the MFC implementation for all of the functions that
you want
MFC's default behavior. This is done in the MFC implementation of IOleInPlaceFrame
(XOleInPlaceFrame) in the COleFrameHook class (it delegates to m_xOleInPlaceUIWindow
for many
functions). This design was chosen to reduce the runtime size of objects which
implement
many interfaces; it eliminates the need for a back-pointer (such as the way m_pParent
was
used in the previous section).
Aggregation and Interface Maps
In addition to supporting stand-alone COM objects, MFC also supports aggregation.
Aggregation itself is too complex a topic to discuss here; refer to the OLE
Programmer's
Reference for more information on aggregation. This note will simply describe the
support
for aggregation built into the framework and interface maps.
There are two ways to use aggregation: (1) using a COM object that supports
aggregation,
and (2) implementing an object that can be aggregated by another. These capabilities
can
be referred to as "using an aggregate object" and "making an object aggregatable".
MFC supports both.
Using an Aggregate Object
To use an aggregate object, there needs to be some way to tie the aggregate into the
QueryInterface mechanism. In other words, the aggregate object must behave as though
it
is a native part of your object. So how does this tie into MFC's interface map
mechanism?
In addition to the INTERFACE_PART macro, where a nested object is mapped to an IID,
you
can also declare an aggregate object as part of your CCmdTarget derived class. To do
so,
the INTERFACE_AGGREGATE macro is used. This allows you to specify a member variable
(which must be a pointer to an IUnknown or derived class), which is to be integrated
into the interface map mechanism. If the pointer is not NULL when
CCmdTarget::ExternalQueryInterface is called, the framework will automatically call
the aggregate object's QueryInterface member function, if the IID requested is not
one of the native IIDs supported by the CCmdTarget object itself.
To use the INTERFACE_AGGREGATE macro, follow these steps:
Declare a member variable (an IUnknown*) which will contain a pointer to the
aggregate object.
Include an INTERFACE_AGGREGATE macro in your interface map, which refers to the
member variable
by name.
At some point (usually during CCmdTarget::OnCreateAggregates), initialize the member
variable
to something other than NULL.
For example,
class CAggrExample : public CCmdTarget
{
public:
CAggrExample();
protected:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
// "native" interface part macros may be used here
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
// wire up aggregate with correct controlling unknown
m_lpAggrInner = CoCreateInstance(CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID*)&m_lpAggrInner);
if (m_lpAggrInner == NULL)
return FALSE;
// optionally, create other aggregate objects here
return TRUE;
}
BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
// native "INTERFACE_PART" entries go here
INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
The m_lpAggrInner is initialized in the constructor to NULL. The framework will
ignore a NULL
member variable in the default implementation of QueryInterface. OnCreateAggregates
is a good
place to actually create your aggregate objects. You'll have to call it explicitly if
you are
creating the object outside of the MFC implementation of COleObjectFactory. The
reason for
creating aggregates in CCmdTarget::OnCreateAggregates as well as the usage of
CCmdTarget::GetControllingUnknown will become apparent when creating aggregatable
objects is
discussed.
This technique will give your object all of the interfaces that the aggregate object
supports
plus its native interfaces. If you only want a subset of the interfaces that the
aggregate
supports, you can override CCmdTarget::GetInterfaceHook. This allows you very low
level
hookability, similar to QueryInterface. Usually, you want all the interfaces that the
aggregate supports.
Making an Object Implementation Aggregatable
For an object to be aggregatable, the implementation of AddRef, Release, and
QueryInterface
must delegate to a "controlling unknown." In other words, for it to be part of the
object,
it must delegate AddRef, Release, and QueryInterface to a different object, also
derived
from IUnknown. This "controlling unknown" is provided to the object when it is
created,
that is, it is provided to the implementation of COleObjectFactory. Implementing this
carries
a small amount of overhead, and in some cases is not desirable, so MFC makes this
optional.
To enable an object to be aggregatable, you call CCmdTarget::EnableAggregation from
the
object's constructor.
If the object also uses aggregates, you must also be sure to pass the correct
"controlling unknown" to the aggregate objects. Usually this IUnknown pointer is
passed to the
object when the aggregate is created. For example, the pUnkOuter parameter is the
"controlling
unknown" for objects created with CoCreateInstance. The correct "controlling unknown"
pointer
can be retrieved by calling CCmdTarget::GetControllingUnknown. The value returned
from that
function, however, is not valid during the constructor. For this reason, it is
suggested that
you create your aggregates only in an override of CCmdTarget::OnCreateAggregates,
where the
return value from GetControllingUnknown is reliable, even if created from the
COleObjectFactory
implementation.
It is also important
adding or
releasing artificial
ExternalAddRef
and ExternalRelease
call InternalRelease
that the object manipulate the correct reference count when
reference counts. To ensure this is the case, always call
instead of InternalRelease and InternalAddRef. It is rare to
or InternalAddRef on a class that supports aggregation.
Reference Material
Advanced usage of OLE, such as defining your own interfaces or overriding the
framework's
implementation of the OLE interfaces requires the use of the underlying interface map
mechanism.
This section discusses each macro and the APIs which is used to implement these
advanced
features.
CCmdTarget::EnableAggregation — Function Description
void EnableAggregation();
Note
Call this function in the constructor of the derived class if you wish to
support OLE
aggregation for objects of this type. This prepares a special IUnknown implementation
that is
required for aggregatable objects.
CCmdTarget::ExternalQueryInterface — Function Description
DWORD ExternalQueryInterface(const void FAR* lpIID, LPVOID FAR* ppvObj);
lpIID
A far pointer to an IID (the first argument to QueryInterface)
ppvObj
A pointer to an IUnknown* (second argument to QueryInterface)
Note
Call this function in your implementation of IUnknown for each interface your
class
implements. This function provides the standard data-driven implementation of
QueryInterface
based on your object's interface map. It is necessary to cast the return value to an
HRESULT.
If the object is aggregated, this function will call the "controlling IUnknown"
instead of
using the local interface map.
CCmdTarget::ExternalAddRef — Function Description
DWORD ExternalAddRef();
Note
Call this function in your implementation of IUnknown::AddRef for each
interface your
class implements. The return value is the new reference count on the CCmdTarget
object.
If the object is aggregated, this function will call the "controlling IUnknown"
instead of
manipulating the local reference count.
CCmdTarget::ExternalRelease — Function Description
DWORD ExternalRelease();
Note
Call this function in your implementation of IUnknown::Release for each
interface
your class implements. The return value indicates the new reference count on the
object.
If the object is aggregated, this function will call the "controlling IUnknown"
instead
of manipulating the local reference count.
DECLARE_INTERFACE_MAP — Macro Description
DECLARE_INTERFACE_MAP
Note
Use this macro in any class derived from CCmdTarget that will have an
interface map.
Used in much the same way as DECLARE_MESSAGE_MAP. This macro invocation should be
placed in
the class definition, usually in a header (.H) file. A class with
DECLARE_INTERFACE_MAP must
define the interface map in the implementation file (.CPP) with the
BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros.
BEGIN_INTERFACE_PART and END_INTERFACE_PART — Macro Descriptions
BEGIN_INTERFACE_PART(localClass, iface);
END_INTERFACE_PART(localClass)
localClass
The name of the class that implements the interface
iface
The name of the interface that this class implements
Note
For each interface that your class will implement, you need to have a
BEGIN_INTERFACE_PART and END_INTERFACE_PART pair. These macros define a local class
derived
from the OLE interface that you define as well as an embedded member variable of
that class.
The AddRef, Release, and QueryInterface members are declared automatically. You must
include
the declarations for the other member functions that are part of the interface
being implemented (those declarations are placed between the
BEGIN_INTERFACE_PART and END_INTERFACE_PART macros).
The iface argument is the OLE interface that you wish to implement, such as
IAdviseSink,
or IPersistStorage (or your own custom interface).
The localClass argument is
will
automatically be prepended
collisions
with global classes of the
the same as the localClass
the name of the local class that will be defined. An 'X'
to the name. This naming convention is used to avoid
same name. In addition, the name of the embedded member,
name except it is prefixed by 'm_x'.
For example:
BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange)(DWORD, LONG);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
would define a local class called XMyAdviseSink derived from IAdviseSink, and a
member of the
class in which it is declared called m_xMyAdviseSink.Note:
Note
The lines beginning with STDMETHOD_ are essentially copied from OLE2.H and
modified
slightly. Copying them from OLE2.H can reduce errors that are hard to resolve.
BEGIN_INTERFACE_MAP and END_INTERFACE_MAP — Macro Descriptions
BEGIN_INTERFACE_MAP(theClass, baseClass)
END_INTERFACE_MAP
theClass
The class in which the interface map is to be defined
baseClass
The class from which theClass derives from.
Remarks: The BEGIN_INTERFACE_MAP and END_INTERFACE_MAP macros are used in the
implementation
file to actually define the interface map. For each interface that is implemented
there is one
or more INTERFACE_PART macro invocations. For each aggregate that the class uses,
there is one
INTERFACE_AGGREGATE macro invocation.
INTERFACE_PART — Macro Description
INTERFACE_PART(theClass, iid, localClass)
theClass
The name of the class which contains the interface map.
iid
The IID which is to be mapped to the embedded class.
localClass
The name of the local class (less the 'X')
Note
This macro is used between the BEGIN_INTERFACE_MAP macro and the
END_INTERFACE_MAP macro for each interface your object will support.
It allows you to map an IID to a member of the class indicated by theClass and
localClass.
The 'm_x' will be added to the localClass automatically. Note that more than one IID
may be
associated with a single member. This is very useful when you are implementing only a
"most
derived" interface and wish to provide all intermediate interfaces as well. A good
example
of this is the IOleInPlaceFrameWindow interface. Its hierarchy looks like this:
IUnknown
IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
If an object implements IOleInPlaceFrameWindow, a client may QueryInterface on any of
these
interfaces: IOleUIWindow, IOleWindow, or IUnknown, besides the "most derived"
interface
IOleInPlaceFrameWindow (the one you are actually implementing). To handle this you
can use
more than one INTERFACE_PART macro to map each and every base interface to the
IOleInPlaceFrameWindow interface:
in the class definition file:
BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)
in the class implementation file:
BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
The framework takes care of IUnknown since it is always required.
INTERFACE_PART — Macro Description
INTERFACE_AGGREGATE(theClass, theAggr)
theClass
The name of the class which contains the interface map,
theAggr
The name of the member variable which is to be aggregated.
Note
This macro is used to tell the framework that the class is using an aggregate
object.
It must appear between the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros. An
aggregate
object is a separate object, derived from IUnknown. By using an aggregate and the
INTERFACE_AGGREGATE macro, you can make all the interfaces that the aggregate
supports appear
to be directly supported by the object. The theAggr argument is simply the name of a
member
variable of your class which is derived from IUnknown (either directly or
indirectly).
All INTERFACE_AGGREGATE macros must follow the INTERFACE_PART macros when placed in
an
interface map.
Technical Notes by Number | Technical Notes by Category
//////////////////////////////////////////
/****** Interface Declaration ***********************************************/
/*
*
*
*
These are macros for declaring interfaces. They exist so that
a single definition of the interface is simulataneously a proper
declaration of the interface structures (C++ abstract classes)
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
for both C and C++.
DECLARE_INTERFACE(iface) is used to declare an interface that does
not derive from a base interface.
DECLARE_INTERFACE_(iface, baseiface) is used to declare an interface
that does derive from a base interface.
By default if the source file has a .c extension the C version of
the interface declaratations will be expanded; if it has a .cpp
extension the C++ version will be expanded. if you want to force
the C version expansion even though the source file has a .cpp
extension, then define the macro "CINTERFACE".
eg.
cl -DCINTERFACE file.cpp
Example Interface declaration:
#undef INTERFACE
#define INTERFACE
IClassFactory
DECLARE_INTERFACE_(IClassFactory, IUnknown)
{
// *** IUnknown methods ***
STDMETHOD(QueryInterface) (THIS_
REFIID riid,
LPVOID FAR* ppvObj) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// *** IClassFactory methods ***
STDMETHOD(CreateInstance) (THIS_
LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID FAR* ppvObject) PURE;
};
Example C++ expansion:
struct FAR IClassFactory : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
IID FAR& riid,
LPVOID FAR* ppvObj) = 0;
virtual HRESULT STDMETHODCALLTYPE AddRef(void) = 0;
virtual HRESULT STDMETHODCALLTYPE Release(void) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateInstance(
LPUNKNOWN pUnkOuter,
IID FAR& riid,
LPVOID FAR* ppvObject) = 0;
};
NOTE: Our documentation says '#define interface class' but we use
'struct' instead of 'class' to keep a lot of 'public:' lines
out of the interfaces. The 'FAR' forces the 'this' pointers to
be far, which is what we need.
Example C expansion:
typedef struct IClassFactory
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
{
const struct IClassFactoryVtbl FAR* lpVtbl;
} IClassFactory;
typedef struct IClassFactoryVtbl IClassFactoryVtbl;
struct IClassFactoryVtbl
{
HRESULT (STDMETHODCALLTYPE * QueryInterface) (
IClassFactory FAR* This,
IID FAR* riid,
LPVOID FAR* ppvObj) ;
HRESULT (STDMETHODCALLTYPE * AddRef) (IClassFactory FAR* This) ;
HRESULT (STDMETHODCALLTYPE * Release) (IClassFactory FAR* This) ;
HRESULT (STDMETHODCALLTYPE * CreateInstance) (
IClassFactory FAR* This,
LPUNKNOWN pUnkOuter,
IID FAR* riid,
LPVOID FAR* ppvObject);
HRESULT (STDMETHODCALLTYPE * LockServer) (
IClassFactory FAR* This,
BOOL fLock);
};
MFC
MFC ist eine Abkürzung für Microsoft Foundation Class Library. MFC kapselt mit C++ einen Teil der umfangreiche Windows API-Schnittstelle, die in C
programmiert wurde. MFC-Klassen-Bibliothek ist eine ( "dünne" ) Software-Schicht über der API-Schnittstelle ( WOSA: Windows Open Services Architecture APIs )
und unterstützt z.B. die ( Framework- ) Programmierung von Windows-Applikationen mit Dialog boxes, Device Contexts, Common GDI Objekte.
Das Arbeiten mit dem Gerüst der Die Microsoft Foundation Class Library (MFC) basiert auf einigen Hauptklassen ( CObject, CWnd, ... ). Die Klassen kapseln einen
großen Teil des Application Programming Interface (Win32-APIs). Anstelle von HINSTANCE hInst = GetModuleHandle(0) wird nun z.B. HINSTANCE hInst =
AfxGetInstanceHandle() verwendet. Anstelle von RegisterClass() wird nun AfxRegisterWndClass (UINT nClassStyle,HCURSOR hCursor,HBRUSH hbrBackground,
HICON hIcon) verwendet. Anstelle von WM_CREATE-Einträgen in der CALLBACK-Funktion wird ( automatisch ) PreCreateWindow(CREATESTRUCT& cs)
aufgerufen.
Andere Klassen kapseln Anwendungskonzepte wie Dokumente, Ansichten und die Anwendung, sowie OLE-Funktionen und ODBC- und DAO-Datenzugriffe. Das
Win32-Konzept eines Fensters wird z. B. durch die MFC-Klasse CWnd eingekapselt.
●
●
●
●
Die CWnd-Klasse kapselt die internen Win32-API-Daten,
-Funktionen für ein Windows-Fenster.
Die CDialog-Klasse kapselt die Win32-Dialogfelder.
Die Member-Funktionen der Klasse haben meistens ähnliche
( denselben ) Namen wie die Win32-Funktion.
Beispiel: LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle,
HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 );
Wegen der Ausführungsgeschwindigkeit werden zahlreiche Macros benutzt
( z.B. afx.h: DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC, DECLARE_SERIAL, IMPLEMENT_SERIAL, usw. )
Für die Entwicklung der Klassen-Bibliothek gab es die folgenden Richtlinien:
●
Ausführungsgeschwindigkeit höchstens 5% geringer als bei C-Language Win-API
●
Entwickler können Win-API-Functionen ( an bel. Stelle ) direkter aufrufen ( global scoping operator ::, wie z.B. ::GetSystemMetrics )
●
Geringer Nativ-Code-Overhead
●
Einfache Konvertierung von existierenden C-Programmen nach C++/MFC
●
Quelltext-Generatoren mit Kommentaren für Constructors, Attributes, Operations, Overridables, Implementation. Die //{{...//}} Klammerung dient als
Positionsangabe zum Einfügen/Entfernen von Mapping-Makros ( z.B. ON_WM_SETFOCUS() ) durch den Klassen-Assistenten
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_SETFOCUS()
//}}AFX_MSG_MAP
●
Vereinfachung der Windows-Programmierung, geringe Einarbeitungszeit
( Achtung! Trotz vieler on-line-Hilfen, Class Library Reference, MFC Technical Notes, MFC-specific articles, Visual C++ Programmer’s Guide, MFC Samples and Tutorials, , Quelltext-Generatoren, Werzeugen, usw.
darf die Einarbeitungszeit nicht unterschätzt werden )
MFC hat wenige abstrakte Basis-Klassen ( CObject, CCmdTarget ). MFC benutz 2 klassen-Typen: "value"-Klassen ( kapseln eine Struktur, wie z.B. Strings oder
Koordinaten, CPoint vereinfacht die Benutzung der vorhandenen API-Funktionalität ) "framework"-Klassen ( abgeleitet von CObject, z.T. "dünne" Kapselung der
Windows-Funktionalität ).
Value- gegenüber Framework-Klassen
Characteristics
Value Framework
Hat eine
virtual Funktion?
Nein
Ja
Ist eine Basis-Klasse?
Nein
CObject derived
Kann direkt benutzt werden?
Ja
Maybe
Kann abgeleitet werden?
Nein
Ja
Hat einen "="-Operator?
meist
Nein
Hat einen Copy-Konstruktor?
meist
Nein
Wirkt wie ein eingebauter Type? meist
Nein
Vergleich möglich?
Usually Nein
Vergleichsreferenz möglich?
Nein
Ja (Addresse ist identisch)
MFC-Schreibweise
MFC verwendet eine General Prefix Naming Conventions ( vereinfacht ungarische Notation ). Die Klassen enthalten als Member-Variable u.a. Daten vom Typ
HWND. CWnd::m_hWnd, and an accessor function, CWnd::GetSafeHwnd. Static member Variablen ( Klassen-Variablen ) haben einen "global class namespace" und
werden ohne Prefix verwendet.
Prefix
Prefix: C
Type: Class or structure
Example: CDocument, CPrintInfo
Prefix: m_
Type: Member variable
Example: m_pDoc, m_nCustomers
Gegenüberstellung
Value-Objekte
Value-Übergabe
void Do(CMyValue val);
( wenige Bytes )
Framework-Objekte
Referenz-Übergabe
void Do( const CMyValue& val );
( umfangreiche Size )
Value-Objekte
Framework-Objekten
benutzen void GetSomething( CMyValue* pval );
benutzen void Do( const CMyView* pob );
non-const Zeiger
const Zeiger-Übergabe
return-Werte eines
CMyValue GetCurrentValue();
Value-Objektes
return-Werte eines
CMyView* GetCurrentView();
Framework-Objektes
Hinweise zur Programmierung
Overloading-Operatoren und Copy-Konstructoren sollten vermieden werden ( insbesondere bei Framework-Klassen ). Falls dennoch erforderlich, so sollte der CopyKonstructor vom Argument "const classname&" sein.
Beispiel für CWND_Member-Funktion
Die internen Fensterdaten werden bei der Klasse CWnd mit der API-Funktion CreateEx() angelegt. Die Klasse CWnd entspricht eine "Wrapper"-Funktion Create bzw.
CreateEx ( wincore.cpp ):
BOOL CWnd::
CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */)
{
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}
// überladen:
BOOL CWnd::
CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.style
= dwStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.x = x; cs.cx = nWidth;
cs.y = y; cs.cy = nHeight; cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs)){PostNcDestroy();return FALSE;}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
#ifdef _DEBUG
if (hWnd==NULL){
TRACE1("Warning: creation failed:GetLastError 0x%8.8X\n",GetLastError());
}
#endif
if (!AfxUnhookWindowCreate())PostNcDestroy();
if (hWnd == NULL)return FALSE;
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
return TRUE;
}
// auch:
BOOL CWnd::
Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
// can't use for desktop or pop-up windows(use CreateEx instead)
ASSERT(pParentWnd != NULL);
ASSERT((dwStyle & WS_POPUP) == 0);
return CreateEx(0, lpszClassName, lpszWindowName,
dwStyle | WS_CHILD,
rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext);
}
Anstelle von HINSTANCE hInst = GetModuleHandle(0) wird nun HINSTANCE hInst = AfxGetInstanceHandle() verwendet. Anstelle von RegisterClass() wird nun
AfxRegisterWndClass (UINT nClassStyle,HCURSOR hCursor,HBRUSH hbrBackground, HICON hIcon) verwendet. Anstelle von WM_CREATE-Einträgen wird
PreCreateWindow(CREATESTRUCT& cs) Die folgende, überladene CreateEx-Funktion zeigt, wie sog. "Hooks" eingebaut werden:
CArray-Beispiel
// Fehlerhaft ist:
CArray myarray1;
CArray myarray2; ... (insertion of data)
myarray1 = myarray2;
// erlaubt ist
CArray myarray1;
CArray myarray2; ... (insertion of data)
myarray2.RemoveAll();
myarray2.Append(myarray1);
Handles und MFC
*
Die meisten OLE-Daten-Typen sind als COle-Variant class "gewrapped".
Andere MFC Klassen benutzen COleVariant
( COleDateTime, COleDateTimeSpan, COleCurrency ).
1 GDI-Objekte werden meist als lokale Variablen
auf dem Stack-Frame angelegt ( z.B. CPen pen; ).
2 Controls werden meist zusammen mit dem Parent-Window
angelegt. Enthält z.B. ein CDialog ein CButton-Object,
so wird ides als CButton m_button; deklariert.
Abhängigkeiten zwischen MFC- und Windows Handles, Controls, Strukturen
Windows
Type
Example
Variable
MFC Class
Example
Object
HWND hWnd;
CWnd*
pWnd;
HDLG hDlg;
CDialog*
pDlg;
CDC*
pDC;
CGdiObject*
pGdiObj;
CPen*
pPen;1
HBRUSH hBrush;
CBrush*
pBrush;1
HFONT hFont;
CFont*
pFont;1
HBITMAP hBitmap;
CBitmap*
pBitmap;1
HPALETTE hPalette;
CPalette*
pPalette;1
CRgn*
pRgn;1
HMENU hMenu;
CMenu*
pMenu;1
HWND hCtl;
CStatic*
pStatic;2
HWND hCtl;
CButton*
pBtn;2
HWND hCtl;
CEdit*
pEdit;2
HWND hCtl;
CListBox*
pListBox;2
HWND hCtl;
CComboBox*
pComboBox;2
HWND hCtl;
CScrollBar*
pScrollbar;2
CString
pStr;2
CPoint
pt;
HDC hDC;
HGDIOBJ hGdiObj;
HPEN hPen;
HRGN hRgn;
HSZ hszStr;
POINT pt;
SIZE size;
CSize
size;
RECT rect;
CRect
rect;
MFC-Klassenhirachie
Die MFC-Klassen-Deklarationen sind in stdafx.h enthalten. stdafx.h verwendet als MFC-Kern- und -Standardkomponenten afxwin.h. In afxwin.h sind die folgenden
Klassen deklariert:
class CSize;
class CPoint;
class CRect;
class CGdiObject;
class CPen;
class CBrush;
class CFont;
class CBitmap;
class CPalette;
class CRgn;
//
//
//
//
//
//
//
CDC drawing tool
a pen / HPEN wrapper
a brush / HBRUSH wrapper
a font / HFONT wrapper
a bitmap / HBITMAP wrapper
a palette / HPALLETE wrapper
a region / HRGN wrapper
class CDC;
class CClientDC;
class CWindowDC;
class CPaintDC;
//
//
//
//
a Display Context / HDC wrapper
CDC for client of window
CDC for entire window
embeddable BeginPaint struct helper
class CMenu;
// a menu / HMENU wrapper
class CCmdTarget;
// a target for user commands
class CWnd;
class CDialog;
// a window / HWND wrapper
// a dialog
// standard windows controls
class CStatic;
// Static control
class CButton;
// Button control
class CListBox;
// ListBox control
class CCheckListBox; // special listbox with checks
class CComboBox;
// ComboBox control
class CEdit;
// Edit control
class CScrollBar;
// ScrollBar control
// frame windows
class CFrameWnd;
class CMDIFrameWnd;
class CMDIChildWnd;
class CMiniFrameWnd;
//
//
//
//
// views on a document
class CView;
class CScrollView;
// a view on a document
// a scrolling view
class CWinThread;
class CWinApp;
standard SDI frame
standard MDI frame
standard MDI child
half-height caption frame wnd
// thread base class
// application base class
class CDocTemplate;
// template for document creation
class CSingleDocTemplate;// SDI support
class CMultiDocTemplate; // MDI support
class CDocument;
// main document abstraction
//CObject
//CException
//CSimpleException
class CResourceException;// Win resource failure exception
class CUserException;
// Message Box alert and stop operation
// Helper classes:
class CCmdUI;
// Menu/button enabling
class CDataExchange;
// Data exchange and validation context
class CCommandLineInfo; // CommandLine parsing helper
class CDocManager;
// CDocTemplate manager object
Nachrichten und MFC
MFC verwendet Tabellen, um die Funktionszeiger von auszuführenden Funktionen zu hinterlegen. Ein Tabelleneintrag enthält die Nachricht ( z.B. WM_...) und die
auszuführenden Funktionen.
Mit
struct AFX_MSGMAP_ENTRY
{ UINT nMessage;
// windows message
UINT nCode;
// control code or WM_NOTIFY code
UINT nID;
// control ID (or 0 for windows messages)
UINT nLastID;
// used for entries specifying a range of control id's
UINT nSig;
// signature type (action) or pointer to message #
AFX_PMSG pfn;
// routine to call (or special value)
};
wird BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) aufgelöst gemäss:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_SETFOCUS(),
ON_WM_....
END_MESSAGE_MAP()
//
AFX_MSGMAP_ENTRY CMainFrame::_messageEntries[] =
{{WM_SETFOCUS,0,0,0,AfxSig_vW,(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL
CWnd::*)(CWnd*))&OnSetFocus },
...
//END_MESSAGE_MAP() wird aufgelöst in:
{0,0,0,0, AfxSig_end, (AFX_PMSG)0 }};
Eine separate CALLBACK-Funktion ist nicht nötig, weil zum Verteilen der Nachrichten die Klasse CWnd verwendet wird. Die Funktion nWndMsg() ruft z.B. bei
WM_COMMAND OnCommand(wParam, lParam)) auf.
BOOL CWnd::OnWndMsg
(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LRESULT lResult = 0;
if (message == WM_COMMAND){
if (OnCommand(wParam, lParam)){
lResult = 1; goto LReturnTrue;
} return FALSE;
}
if (message == WM_NOTIFY){
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL
&& OnNotify(wParam, lParam, &lResult)) goto LReturnTrue;
return FALSE;
}
if (message == WM_ACTIVATE)
_AfxHandleActivate(this,wParam, CWnd::FromHandle((HWND)lParam));
if (message == WM_SETCURSOR &&
_AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam))){
lResult = 1;goto LReturnTrue;
}
const AFX_MSGMAP* pMessageMap = GetMessageMap();
UINT iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax-1);
AfxLockGlobals(CRIT_WINMSGCACHE);
AFX_MSG_CACHE* pMsgCache = &_afxMsgCache[iHash];...
AfxUnlockGlobals(CRIT_WINMSGCACHE);
for (pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
{
// Note: catch not so common but fatal mistake!!
//
BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)
// registered windows message
lpEntry = pMessageMap->lpEntries;
while ((lpEntry = AfxFindMessageEntry(lpEntry,0xC000,0,0)) != NULL){
UINT* pnID = (UINT*)(lpEntry->nSig);
...
lpEntry++;
} return FALSE;
LDispatch: union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn;
switch (nSig){
// lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
case AfxSig_vw: (this->*mmf.pfn_vw)(wParam);break;
case AfxSig_bb: ... case AfxSig_bD: ... case AfxSig_bWww: ...
case AfxSig_bWCDS: .case AfxSig_bHELPINFO: ...
case AfxSig_hDWw:
case AfxSig_hDw:
case AfxSig_iwWw: ...
case AfxSig_iww:
case AfxSig_iWww:
case AfxSig_is: ...
case AfxSig_lwl:
case AfxSig_lwwM:
case AfxSig_vv:...
case AfxSig_vww:
case AfxSig_vvii:
case AfxSig_vwww:
case AfxSig_vwii:
case AfxSig_vwl:
case AfxSig_vbWW:
case AfxSig_vD:
case AfxSig_vM:
case AfxSig_vMwb:
case AfxSig_vW:
case AfxSig_vW2:
case AfxSig_vWww:
case AfxSig_vWp:
case AfxSig_vWh:
case AfxSig_vwW:
case AfxSig_vwWb:
case AfxSig_vwwW:
case AfxSig_vwwx:
case AfxSig_vs:
case AfxSig_vws:
case AfxSig_vOWNER:
case AfxSig_iis:
case AfxSig_wp:
case AfxSig_wv:
case AfxSig_vCALC: case AfxSig_vPOS:
case AfxSig_vwwh:
case AfxSig_vwp:
case AfxSig_vwSIZING:case AfxSig_bwsp:
default:break;
}
goto LReturnTrue;
LDispatchRegistered:
// for registered windows messages
ASSERT(message >= 0xC000);
mmf.pfn = lpEntry->pfn;
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
LReturnTrue:
if (pResult != NULL)*pResult = lResult;
return TRUE;
}
Die DefWindowProc() der Klasse CWnd kann auch Super- und Subclassing von CALLBACK-Funktionen handhaben:
LRESULT CWnd::
DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
if (m_pfnSuper != NULL)
return ::CallWindowProc(m_pfnSuper,m_hWnd,nMsg,wParam,lParam);
WNDPROC pfnWndProc;
if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
return ::DefWindowProc(m_hWnd,nMsg,wParam,lParam);
else
return ::CallWindowProc(pfnWndProc,m_hWnd,nMsg,wParam,lParam);
}
Hinweise zum Übersezungsvorgang
Die folgende Tabelle gibt Konfigurationsmakros ( Linker ) an:
Konfigurationsmakros ( Linker )
_AFXDLL
Stand-alone dynamic-link library (DLL) version
_DEBUG
Debug version including diagnostics
_MBCS
Compilation for multi-byte character sets
Macro-Name Macro-Typ
_UNICODE Enables Unicode in an application
AFXAPI
Function provided by MFC
WINAPI
Function provided by Windows
CALLBACK Function called back via pointer
Der Linker kann unterschiedliche Bibliotheken ( z.B. Static- Library, Versionen ) binden.
NAFXCWD.LIB ist eine Debug version: MFC Static Link Library
UAFXCWD.LIB ist eine Debug version: MFC Static Link Library with Unicode support
NAFXCW.LIB ist eine Release version: MFC Static Link Library
UAFXCW.LIB ist eine Release version: MFC Static Link Library with Unicode support Mit der #pragma comment(lib, "...") -Präprozessor-Direktive kann der
Übersetzungsvorgang gesteuert werden:
#ifndef _UNICODE
#ifdef _DEBUG
#pragma comment(lib,
#else
#pragma comment(lib,
#endif
#else
#ifdef _DEBUG
#pragma comment(lib,
#else
#pragma comment(lib,
#endif
#endif
"nafxcwd.lib")
"nafxcw.lib")
"uafxcwd.lib")
"uafxcw.lib")
1. Praktikum
Diese Aufgabe besteht aus den folgenden Teilen.
1. Es ist eine einfache Console-Applikation zu erstellen, mit der einige Tests durchzuführen sind.
2. Die Definition von Windows-Datentypen ist mit Hilfe einer Console-Applikation und freopen() zu untersuchen
3. Es sind die unten angegebenen Tests durchzuführen und die Macros, Datentypen, Zeiger zu verstehen:
❍ windows.h definiert zahlreiche Typen ( siehe z.B. windef.h ). Welche typedef's sind richtig?
typedef
typedef
typedef
typedef
typedef
typedef
typedef
char *LPSTR;
unsigned int *PUINT;
long BOOL;
unsigned char BYTE;
unsigned long DWORD;
unsigned short WORD;
unsigned int UINT;
4. Wieviele Byte belegen im Win32-Programmiermodell die Datentypen long, unsigned long, float, double, signed short,
unsigned short, char, signed char, bool?
Erklären sie dies bitte im Zusammenhang mit der Hardware-Archtektur von Dadatypen.
5. Welche Änderungen ergeben sich mit #define UNICODE für String und Char?
6. Das Windows-System ist im Überblick zu quantifizieren ( *.exe, *.dll-Files, *.dll-Funktionen )
❍ In welchem absoluten Pfad befinden sich *.dll-Files des Betriebssystems?
❍ Wieviele *.exe-Files gehören etwa zu dem benutzten Windows-System?
❍ Wieviele *.dll-Files gehören etwa zu dem benutzten Windows-System?
❍ Wieviele Funktionen enthält eine *.dll im Mittel?
❍ Für die C,C++-Programmentwicklung werden *.h-Files benötigt.
In welchem Verzeichnis befinden sich die *.h-Files?
❍ Wieviele *.h-Files gehören zu der verwendeten C++-Entwicklungsumgebung?
Hinweise
Hinweise zum MS-Studio-Bedienung
1. Studie-Menu:
Datei Neu Projekt Win32ConsoleAnwendung
Projetname: myauf01
Pfad
: d:\temp\my...
(x) Neuen Arbeitsbereich erstellen
2. Studie-Menu:
Datei Neu Dateien C++-Quellcodedatei
[x] dem Projekt hinzufügen
Dateiname: myauf01
Pfad
: d:\temp\my...
Mit der
rechten Maustaste auf dem
grauen Fenster-Rand
können die benötigten Hilfsfenster
aktiviert werden:
Ausgabe-Fenster
( für die Übersetzungsfehler )
Minileiste-Erstellen
( zum Compilieren, Linken, Starten )
Arbeitsbereich
( für Klassen und Dateien )
Console-Applikation
Zum Ausführen von Tests ist eine Console-Applikation zu erstellen.
#include <stdio.h>
#include <windows.h>
void main()
{
printf("sizeof(PSZ)
}
=%d\n", sizeof(PSZ));
Tests zu Macros,Datentypen, Zeigern
Macros können z.B. definiert werden gemäss:
#define my_tolower(_c)
( (_c)-'A'+'a' )
#define my_toupper(_c)
( (_c)-'a'+'A' )
#define my_isascii(_c)
( (unsigned)(_c) < 0x80 )
#define my_toascii(_c)
( (_c) & 0x7f )
#define my_isspace(_c)
(_c==' ' || _c=='\t' || _c=='\n')
#define my_seterror( api, retstring )
\
sprintf(retstring,"%s: Error %d from %s on line %d\n",\
__FILE__, GetLastError(), api, __LINE__);
Das folgende User-Macro stdout_to(f)
#define stdout_to(f) if((freopen(f,"at",stdout)) == NULL) \
{fprintf(stderr,"\nredir-err\n");exit(-1);}
kann definiert und für die Umleitung der Ausgabe auf die Console oder die Umleitung der Ausgabe in den Quelltext-File verwendet
werden:
Macro-Aufrufe z.B.
stdout_to("CON");
stdout_to(__FILE__);
In windows.h, windef.h sind zahlreiche Macros definiert. Testen Sie die folgenden Macros:
#define MAKELONG(a, b)
#define LOWORD(l)
#define HIWORD(l)
#define LOBYTE(w)
#define HIBYTE(w)
Welche Werte ( Bitmuster ) gehören zu:
LOWORD (0x123456789),
HIWORD(0x123456789),
MAKELONG(0xBCDEF,0x56789A) ?
Es sei char a=(char)0xff; LPSTR p="ABC"; Welche Werte haben die BOOLschen Ausdrücke:
FALSE
TRUE
(
a <
*p )
( (BYTE) a < (BYTE) *p )
*(p+3)
hat
hat
hat
hat
hat
den
den
den
den
den
Wert
Wert
Wert
Wert
Wert
...
...
...
...
...
Welche Änderungen ergeben sich, wenn
#define UNICODE
#include <windows.h>
TCHAR a=(char)0xff;
LPSTR p="ABC";
LPTSTR pt=...
verwendet wird?
Etwas Wiederholung:
// Gegeben:
int x[] = { 8, 1, 7, 2, 6, 3, 5, 4, 0, -1, 1, -2, 2, -3 };
int k = 2, *z = &x[5];
// Gesucht: Welche Werte haben damit die folgenden Ausdrücke:
1
*z+k
ergibt ..... 2
*(z+k)
ergibt .....
3
z-x
ergibt ..... 4
*(z-k)
ergibt .....
5
x[2]-*(z+2)
ergibt ..... 6
x[2]-(*z+2)
ergibt .....
7
x[k+1] << *z ergibt ..... 8
x[*z+k]
ergibt .....
9
x[k**z]
11 x[x[k]]
ergibt ..... 10 x[k**z+3]**z+3 ergibt .....
ergibt ..... 12 x[x[k]]
ergibt .....
Machen sie sich bitte mit dem folgenden Programm das Prinzip von CALLBACK-Funktionen klar. Welchen Typ haben die meisten
Windows-CALLBACK-Funktionen?
#include <stdio.h>
#include <conio.h>
void system_func( int (*user_func)(int) ) {
static int first=0; char ch=' ';
while ((ch=getch()) != 27) user_func (++first);
return;
}
int myfunction(int wert) {
printf("... myfunction: system_call_wert =%d\n", wert);
return (wert);
}
int main () {
system_func(myfunction);
return 0 ;
}
Testen Sie das eigene Macro ACHAR2WCHAR mit ihren Initialen. Welche Bytefolge steht im w-Speicher?
#define ACHAR2WCHAR(pa,buf,cb) MultiByteToWideChar(CP_ACP,0,pa,-1,buf,cb)
CHAR a[3]="BW";
WCHAR w[3];
ACHAR2WCHAR(a,w,sizeof(w));
Der Aufbau von Windows-Header-Files ist zu untersuchen ( windows.h )
●
Warum beginnt windows.h mit
#ifndef _WINDOWS_
#define _WINDOWS_
//und endet mit
#endif / * _WINDOWS_ */
●
*.h-Files ( z.B. windef.h ) enthalten oft die Klammerungen
#ifdef __cplusplus
extern "C" {
......
}
#endif
Wozu dient diese Klammerung? Betrachten Sie bitte den Windows.h-File. Welche Nachrichten können nicht
verwendet werden, wenn in einem C-Quelltext-File steht:
#define NOWINOFFSETS
#include <windows.h>
Windows definiert zahlreiche Macros ( siehe z.B. windoswx.h ). Welche Werte liefert z.B.
LOWORD (0x123456789)
HIWORD(0x123456789)
MAKELONG(0xBCDEF,0x56789A)
Der System-Begriff ist zu verstehen ( siehe Script ).
Hier einige Fragen:
1. Warum werden soviele neue Typen (z.B. typedef unsigned short WORD;) gebraucht?
2. Wieviele Byte hat ein double und wie ist eine double-Zahl intern aufgebaut?
3. Wieviele Byte hat ein UNICODE-Char und mit wievielen 0-Bytes wird ein UNICODE-String beendet?
4. Was enthält ein dll-File?
5. Worin unterscheiden sich Console-Applikation/Win32-Applikation/AFC-Applikation?
6. Wozu dienen die folgenden Zeilen?
#include #define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
wchar_t *pwsz = __WFILE__;
7. Welches (Entwicklungs-Übersetzungs-) Programm verwendet *.h/*.lib/*.res?
8. Überlegen Sie, welchen Wert der Ausdruck (bei 1, 2, ...., 12) hat:
int x[] = { 8, 1, 7, 2, 6, 3, 5, 4, 0, -1, 1, -2, 2, -3 };
int k = 2, *z = &x[5];Ausgabe:
========
1: *z+k
=....| 2: *(z+k)
=....3: z-x
=....| 4: *(z-k)
=....5: x[2]-*(z+2) =....| 6: x[2]-(*z+2)
=....7: x[k+1] <<*z =....| 8: x[*z+k]
=....9: x[k**z]
=....| 10: x[k**z+3]**z+3 =....11: x[x[k]]
=....| 12:
x[x[k]]
=....
IA-32 architecture datatypes
integer datatype formats
signed
byte
signed
word
signed
dword
7
6..0
S
integer
15
14..0
S
integer
31
30..0
S
integer
7..0
unsigned
byte
integer
15..0
unsigned
word
integer
31..0
unsigned
dword
integer
63..0
unsigned
qword
integer
BCD
packed
BCD
7..4
3..0
res.
BCD
7..4
3..0
BCD
BCD
pointer datatype formats
31..0
near
pointer
offset or virtual address
far
pointer
47..32
31..0
segment or selector
offset
FP datatype formats
single
real
double
real
extended 79
real S
31
30..23
22..0
S
exp.
fraction
63
62..52
51..0
S
exp.
fraction
78..64
63
62..0
exp.
I
fraction
word
integer
short
integer
long
integer
packed 79
BCD S
res.
14..0
S
integer
31
30..0
S
integer
63
62..0
S
integer
78..72
15
71..0
D17 D16 D15 D14 D13 D12 D11 D10 D9
D8
D7
D6
D5
D4
D3
D2
D1
D0
MMX datatype formats
63..56 55..48 47..40 39..32 31..24 23..16 15..8
packed
byte
byte
packed
word
byte
byte
byte
byte
byte
byte
7..0
byte
63..48
47..32
31..16
15..0
word
word
word
word
packed
dword
63..32
31..0
dword
dword
63..0
qword
qword
packed 127..120 119..112 111..104 103..96 95..88 87..80 79..72 71..64 63..56 55..48 47..40 39..32 31..24 23..16 15..8 7..0
byte byte
byte
byte
byte byte byte byte byte byte byte byte byte byte byte byte byte
packed
word
packed
dword
127..112
111..96
95..80
79..64
63..48
47..32
31..16
15..0
word
word
word
word
word
word
word
word
127..96
95..64
63..32
31..0
dword
dword
dword
dword
packed
qword
127..64
63..0
qword
qword
SSE datatype format
scalar
single
FP
packed
single
FP
127..96
95..64
63..32
31..0
reserved
reserved
reserved
single FP
127..96
95..64
63..32
31..0
single FP
single FP
single FP
single FP
SSE2 datatype format
scalar
double
FP
packed
double
FP
127..64
63..0
reserved
double FP
127..64
63..0
double FP
double FP
2.Praktikum
Diese Aufgabe besteht aus den Teilen 1, 2, 3, ..., usw. Es soll ein erste "Hallo Welt"-Windows-Applikation geschrieben
werden. Zur Reduzierung der Tipp-Tätigkeit soll das unten angegebene Rahmen-Programm benutzt werden. Das
Rahmen-Programm ist zu erweitern. Zum besseren Verstehen sind einige Tests durchzuführen, wie z.B. aktuelle
Maus-Position in der Titelzeile ausgeben, eine MessageBox() angezeigen, die verwendeten Windows-Datenstrukturen
mit dem Debugger schrittweise anschauen, die Nachrichten mit dem Spy-Werkzeug ( Spy ) verfolgen ( MausNachrichten, Tasten-Nachrichten, Fenstervergrößerung, usw. ).
1. Mit WinMain() ist eine Windows-Applikation zu schreiben. Ein Programm "Hallo Welt" ist mit
WinMain() und WndProc() zu erstellen.
2. Der Text in der Titelzeile ist bei WM_RBUTTONDOWN zu ändern
3. Die Maus-Position ( bei Klick mit der linke Maus-Taste ) ist in die in Titelzeile zu schreiben.
4. Bei Klick mit der rechten Maus-Taste soll eine MessageBox() angezeigt werden.
5. Mit einer Windows-Applikation ist die MessageBox()-Funktion zu untersuchen
6. Es ist eine einfache Grafik zu erstellen, die die Funktionen MoveToEx(), LineTo(), Ellipse(), Rectangle(),
RoundRect(), Polyline(), PolyPolyline() verwendet.
7. Das "Hallo Welt"-Beispiel ist zu debuggen.
8. Die Nachrichten sind mit einem geeigneten Werkzeug ( Spy ) zu verfolgen.
Hallo Welt
Es ist ein einfaches, kleines Beispiel mit WinMain() und einer WndProc() - CALLBACK - Funktion sorgfältig zu
durchdenken. In ein Hauptfenster soll ( testweise ) Text zentriert hinein geschrieben und die Funktionen
MoveToEx(), LineTo(), Ellipse(), Rectangle(), RoundRect(), Polyline(), PolyPolyline() verwendet werden.
GetClientRect( hwnd, & rect ) ;
DrawText
( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER |
DT_VCENTER ) ;
Mit dem Debugger ist das Programm schrittweise durchzugehen. Die Window-Daten-Strukturen sind zu entnehmen
und am Programm-Anfang als Kommentar in den Quelltext einzufügen.
#include <windows.h>
//=======================
LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg,
WPARAM wParam, LPARAM lParam ) {
//=======================
switch ( iMsg ) {
case WM_CREATE : break ;//return 0;
case WM_PAINT : {
RECT rect ; PAINTSTRUCT ps ;
HDC hDC = BeginPaint( hwnd, & ps ) ;
// hier Zeichen-Func einfügen
EndPaint
( hwnd, & ps ) ;
} break ; //return 0;
case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0;
}
return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wndclass = { 0 } ;
wndclass.cbSize
wndclass.style
wndclass.lpfnWndProc
wndclass.cbClsExtra
wndclass.cbWndExtra
wndclass.hInstance
wndclass.hIcon
wndclass.hCursor
wndclass.hbrBackground
wndclass.lpszMenuName
wndclass.lpszClassName
wndclass.hIconSm
=
=
=
=
=
=
=
=
=
=
=
=
sizeof( WNDCLASSEX ) ;
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
WndProc ;
0 ;
0 ;
hInstance ;
LoadIcon
( NULL, IDI_APPLICATION ) ;
LoadCursor ( NULL, IDC_ARROW
) ;
( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
NULL ;
"my_class" ;
LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wndclass ) ) return -1 ;
HWND hwndMain = CreateWindowEx( WS_EX_LEFT,
"my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow
( hwndMain, iShowMain ) ;
UpdateWindow ( hwndMain ) ;
MSG msg ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return msg.wParam ;
}
Das "Hallo Welt"-Beispiel ist zu debuggen und zu kommentieren. Die verwendeten Windows-Datenstrukturen sind
einzufügen.
Text in Titelzeile
Ändern Sie das Programm so, dass das Windows-Programm die eigene hg-Nummer in der Titelzeile beim
WM_RBUTTONDOWN-Ereignis anzeigt. Verwenden Sie
SetWindowText (hwnd, szText);
Der Text in der Titelzeile ist bei WM_RBUTTONDOWN zu ändern.
Maus-Pos in Titelzeile
Die Position ( xPos, yPos ) der Maus soll bei einem Klick in der Titelzeile erscheinen. Verwenden Sie in der
CALLBACK-Funktion Maus-Nachrichten, wie z.B.
case
case
case
case
case
case
case
case
case
case
WM_LBUTTONUP:
WM_RBUTTONUP:
WM_MBUTTONUP:
WM_LBUTTONDOWN:
WM_RBUTTONDOWN:
WM_MBUTTONDOWN:
WM_LBUTTONDBLCLK:
WM_MBUTTONDBLCLK:
WM_RBUTTONDBLCLK:
WM_MOUSEMOVE:
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
char MouseMsgStrings[][20] = {
"
",
"WM_LBUTTONUP
",
"WM_RBUTTONUP
",
"WM_MBUTTONUP
",
"WM_LBUTTONDOWN
",
"WM_RBUTTONDOWN
",
"WM_MBUTTONDOWN
",
"WM_LBUTTONDBLCLK
",
"WM_MBUTTONDBLCLK
",
"WM_RBUTTONDBLCLK
",
};
In lParam ist die Maus-Position enthalten. Hinweis:
char szBuffer[???]; char * p=szBuffer;
p += wsprintf ( p, "...wie printf: x=%04d", xPos );
SetWindowText ( hwnd, szBuffer );
MessageBox()
Die MessageBox() ist zu testen, indem bei einem Tasten-Anschlag ( siehe WM_CHAR ) eine "Hallo-Welt"MessageBox() angezeigt wird.
case WM_CHAR : {
switch ( LOWORD(wParam) ) {
case ‘\b’ : Rücktaste; break;
case ‘\t’ : Tabulatortaste; break;
case ‘\n’ : LF-Taste; break;
default : //normales Zeichen bearbeiten
}
}
Für die MessageBox() testen Sie bitte
a )die Flags
MB_OK
MB_OKCANCEL
MB_YESNO
MB_DEFBUTTON2
MB_ICONHAND
MB_ICONERROR
MB_ICONASTERISK
MB_ICONWARNING
MB_ABORTRETRYIGNORE
MB_RETRYCANCEL
MB_YESNOCANCEL
MB_DEFBUTTON3
MB_ICONSTOP
MB_ICONQUESTION
MB_ICONEXCLAMATION
MB_ICONINFORMATION
b ) Bitte beachten Sie den Rückgabewert von MessageBox() c ) Ändern Sie bitte den Default-Button der MessageBox()
d ) Verwenden Sie bitte verschiedene Icons
MB_ICONHAND
MB_ICONERROR
MB_ICONASTERISK
MB_ICONWARNING
MB_ICONSTOP
MB_ICONQUESTION
MB_ICONEXCLAMATION
MB_ICONINFORMATION
e ) Erstellen Sie eine MessageBox(), die den eigenen Quelltext-Aufruf ( mit den \"-Zeichen ) im Client-Bereich anzeigt
Hier einige Fragen:
1. Was bedeutet CALLBACK? Was bedeutet typedef __int32 LRESULT; ?
2. Welche Bedeutung haben die WindowProc()-Parameter HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam?
Welche übergebene Nachricht kündigt das Schließen des Fensters an?
3. Was hat BeginPaint() mit sizing, moving, creating, scrolling und der Clipping-Region zu tun?
Welche Nachrichten sendet BeginPaint()?
4. Wozu dient der Device-Context? Welche Funktionen benutzen den Device-Context?
5. Wozu dient WNDCLASSEX wc = { 0 }; ?
6. Wozu braucht ein mit CreateWindowEx() erstelltes Fenster
eine Fensterklasse, die mit RegisterClassEx() erstellt wurde?
7. Wodurch werden die folgenden Nachrichten ausgelöst?
a) WM_LBUTTONDOWN,
b) WM_CHAR,
c) WM_PAINT,
d) WM_DESTROY
#include <windows.h>
//=======================
LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg,
WPARAM wParam, LPARAM lParam ) {
//=======================
switch ( iMsg ) {
case WM_PAINT : { PAINTSTRUCT ps ;
HDC hDC = BeginPaint( hwnd, & ps );
//...
EndPaint( hwnd, & ps ) ;
} break;
case WM_DESTROY : PostQuitMessage( 0 ) ; break;
} return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow
( hwndMain, iShowMain ) ;
UpdateWindow ( hwndMain ) ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return msg.wParam ;
}
3.Praktikum
Diese Aufgabe besteht darin, das "Hallo Welt" - Windows - Programm schrittweise zu erweitern und das Programm sicher zu
beenden, einfache Menu-Möglichkeiten ( ohne externe Ressource ) in das das Window-Gerüst zu integrieren. Die verwendeten
Windows-Datenstrukturen sind sorgfältig mit dem Debugger zu betrachten. Die Nachrichten sind mit einem geeigneten Werkzeug (
Spy++ ) zu verfolgen ( Fenstervergrößerung, Maus-Nachrichten, Tasten-Nachrichten, usw. ).
1. Mit einer MessageBox() ist vor dem Beenden des Programmes eine Sicherheits - Rückfrage
( "Do you want to Exit?" ) auszulösen
2. Es ist ein System - Menu - Erweiterung durchzuführen, um eine
MessageBox(hwnd,"Dies war ein System-Menu-Klick","Test",MB_...) anzuzeigen
3. Für die rechte Maus-Taste ist ein Popup - Menu zu programmieren und zu testen. Ein Menu-Auswahl-Klick ruft dann
die CALLBACK-Funktion mit WM_COMMAND auf.
4. Es ist ein Menu mit LoadMenuIndirect() zu programmieren (siehe menu.cpp).
5. Mit Hilfe von i=0... können das i-te Icon aus Shell32.dll geholt und angezeigt werden:
HICON hIcon = ExtractIcon(GetModuleHandle(0),"Shell32.dll",i);
if(!hIcon) break;
DrawIcon(hDC, x, y, hIcon);
DestroyIcon(hIcon);
Stellen Sie alle Icons dar, indem sie die Funktion
BOOL draw_icons(HWND hwnd,
int idx_start, /*Start-Index des Icons*/
int anz )
/*Anzahl der anzuzeigenden Icons*/
schreiben und testen.
WM_CLOSE
Beim Schliessen des Fensters wird in der CALLBACK-Funktion durch einen x-Mausklick auf
die iMsg = WM_CLOSE - Nachricht und damit der Aufruf von
LRESULT CALLBACK WndProc
( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam )
ausgelöst, Beim Schliessen des Fensters ist unter WM_CLOSE mit
char buf[256]; GetWindowText( hwnd, buf, 256 );
der Text der Titelzeile in char buf[256] zu kopieren. Dann ist mit
MessageBox ( hwnd, "Do you want to Exit?", buf, ??? | MB_YESNO) eine MessageBox anzuzeigen. Ist der Rückgabewert der
MessageBox IDYES, so darf nicht DefWindowProc() aufgerufen werden, denn dann würde nach der WM_CLOSE-Nachricht
durch Windows die WM_DESTROY-Nachricht gesendet. Ist der Rückgabewert der MessageBox IDYES, so kann z.B. mit
DestroyWindow( hwnd ) die WM_DESTROY-Nachricht gesendet werden.
System - Menu
Das System-Menu soll erweitert werden. Dazu wird zunächst z.B. in WM_CREATE eingefügt:
HMENU hSysMenu = GetSystemMenu( hwnd, FALSE );
if ( hSysMenu ) {
InsertMenu ( hSysMenu, SC_RESTORE, MF_STRING, IDM_SYS_MENU_HELP, "&Help"
);
InsertMenu ( hSysMenu, SC_RESTORE, MF_SEPARATOR, 0, NULL );
}
Dann wird vor der CALLBACK-Funktion ein User-define ergänzt, wie z.B.
#define IDM_SYS_MENU_HELP 4711
case WM_SYSCOMMAND:
switch ( LOWORD(wParam ) ) {
case IDM_SYS_MENU_HELP:
MessageBox(hwnd, "IDM_SYS_MENU_HELP",NULL, MB_OK ) ; break ; }
}
break;
Popup-Menu
Ein PopupMenu soll bei einem Klick mit der rechten Maustaste an der Mausposition erscheinen. Was ist zu tun, wenn das KontextMenü ( nicht mit Resourcen, sondern ) per Programm "zusammen-gebastelt" werden soll?
Unter WM_CREATE: //( PopupMenu wird unsichtbar erstellt )
soll per Programm ein Menu hMenu zusammengestellt werden, das Einzelpunkte ( Menu-Items, hPopup ) enthält:
hMenu = CreateMenu ();
hPopup = CreateMenu ();
AppendMenu ( hPopup, MF_STRING, IDM_STATE0, "Menu-Text0" );
AppendMenu ( hPopup, MF_STRING, IDM_STATE1, "Menu-Text1" );
...
// Menu-Items zusammenfügen:
AppendMenu ( hMenu, MF_POPUP, (???)hPopup, "Popup-Menu");
// und falls error DestroyMenu( hMenu );
IDM_... sind eindeutige WORD-Identifizierer z.B. zwischen 1000-5000.
Unter WM_RBUTTONUP: //PopupMenu wird sichtbar u. benutzbar
POINT mouse; GetCursorPos ( & mouse );
TrackPopupMenu ( hPopup, ???, mouse.x, mouse.y, 0, hwnd, NULL);
Achtung! hMenu, hPopup wird in mehreren cases der CALLBACK-Funktion verwendet ... Bitte nicht vergessen, unter
WM_DESTROY : den Windowinternen Speicher frei zu geben durch DestroyMenu( hMenu );
Unter WM_COMMAND: soll LOWORD( wParam ) in der Titelzeile angezeigt werden.
Hallo Welt
GetClientRect( hwnd, & rect ) ;
DrawText
( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER |
DT_VCENTER ) ;
Mit dem Debugger ist das Programm schrittweise durchzugehen. Die Window-Daten-Strukturen sind zu entnehmen und am
Programm-Anfang als Kommentar in den Quelltext einzufügen.
#include <windows.h>
//=======================
LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg,
WPARAM wParam, LPARAM lParam ) {
//=======================
PAINTSTRUCT ps ; HDC hDC ; RECT rect ;
switch ( iMsg ) {
case WM_CREATE : break ;//return 0;
case WM_PAINT : hDC = BeginPaint( hwnd, & ps ) ;
//hier einfügen
EndPaint
( hwnd, & ps ) ;
break ; //return 0;
case WM_DESTROY : PostQuitMessage( 0 ) ; break ; //return 0;
}
return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wndclass = { 0 } ; HWND hwndMain ; MSG msg ;
wndclass.cbSize
wndclass.style
wndclass.lpfnWndProc
wndclass.cbClsExtra
wndclass.cbWndExtra
wndclass.hInstance
wndclass.hIcon
wndclass.hCursor
wndclass.hbrBackground
wndclass.lpszMenuName
wndclass.lpszClassName
wndclass.hIconSm
=
=
=
=
=
=
=
=
=
=
=
=
sizeof( WNDCLASSEX ) ;
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
WndProc ;
0 ;
0 ;
hInstance ;
LoadIcon
( NULL, IDI_APPLICATION ) ;
LoadCursor ( NULL, IDC_ARROW
) ;
( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
NULL ;
"my_class" ;
LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wndclass ) ) return -1 ;
hwndMain = CreateWindowEx( WS_EX_LEFT, "my_class", "Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow
( hwndMain, iShowMain ) ;
UpdateWindow ( hwndMain ) ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return msg.wParam ;
}
Menu mit LoadMenuIndirect()
Normalerweise werden Ressourcen mit dem Ressourcen-Work-Shop erstellt. Hier soll nun mit Hilfe von HMENU hMenu =
LoadMenuIndirect(buf); das Menue zusammen gebaut werden. Weil die Bit-Operationen zunächst recht unverständlich sind,
verwenden sie bitte das Programm menu.cpp, dessen Aufbau etwa folgender Idee folgt:
Der User schreibt Funktionen, wie z.B.
BOOL menu_1(HWND hwnd) {
...
return TRUE;
}
und legt eine Tabelle menu_struct mit Menu-Item-Text und auszuführende Funktion menu_1 an. Der Aufruf von
MENU_CLASS(hwndMain, menu_struct) aktiviert das Menue und vergibt (duch hochzählen) automatisch die MENUE-ID's:
MENU_STRUCT menu_struct[] = {
//-------------------------------------------------// Menutext
Funktion
//-------------------------------------------------{L"Einstelungen",
0 },/////////////////
{L"menu_1",
menu_1
},
{L"menu_2",
menu_2
},
{L"beenden",
menu_ende
},
{L"Zeichnen",
0 },/////////////////
{L"Icons aus Shell32.dll
0.. 99", menu_4
},
{L"Icons aus Shell32.dll 100..199", menu_5
},
{L"Icons aus Shell32.dll 200..299", menu_6
},
{L"\0\0",0}}; // <== Endekriterium ist Pflicht!
MENU_CLASS(hwndMain, menu_struct);
Fügen Sie bitte einen Punkt L"beenden" hinzu.
Bemerkung: Durch ein Sub-Classing wird CALLBACK new_wnd_proc() automatisch VOR der WndProc() ausgeführt und dort
werden automatisch die WM_COMMAND-Nachrichten ausgeführt.
Icons anzeigen
Die folgenden Icons können Shell32.dll entnommen und verwendet werden. Schreiben Sie die Funktion BOOL draw_icons(HWND
hwnd, int idx_start, /*Start-Index des Icons*/ int anz ) /*Anzahl der anzuzeigenden Icons*/
Shell32.dll
0.. 99
Shell32.dll
100..199
Shell32.dll
200..299
Fragen
1.
2.
3.
4.
5.
Wozu dient der Rückgabewert von MessageBox()?
Enthält eine MessageBox() eine eigene Hauptnachrichtenschleife?
Was bedeutet modal?
Was enthält wParam bei einem Aufruf der CALLBACK-Funktion infolge eines Menu-Item-Klick?
Was würden Sie anstelle von GetClientRect() verwende, wenn die äußeren Abmessungen des Fensters gebraucht
werden?
6. Wieviele Pixel enthält ein Icon?
#include <windows.h>
//=======================
LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg,
WPARAM wParam, LPARAM lParam ) {
//=======================
switch ( iMsg ) {
case WM_PAINT : { PAINTSTRUCT ps ;
HDC hDC = BeginPaint( hwnd, & ps );
//...
EndPaint( hwnd, & ps ) ;
} break;
case WM_DESTROY : PostQuitMessage( 0 ) ; break;
} return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow
( hwndMain, iShowMain ) ;
UpdateWindow ( hwndMain ) ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
return msg.wParam ;
}
///////////////////////////////////////////////
// Menue mit LoadMenuIndirect()
///////////////////////////////////////////////
#include <windows.h>
#define err_if(e,errStr) if(e) MessageBox(NULL,(errStr),0,\
MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
typedef BOOL (* DRAWPROC)(HWND);
typedef struct _MENU_STRUCT {
//für das Menue
WCHAR * pMenu; union { DRAWPROC drawProc; int length; }; WORD id;
} MENU_STRUCT;
MENU_STRUCT * pMenuStruc;
//für das Menue
void MENU_CLASS(HWND hwnd_main, MENU_STRUCT pMenuStruct[]);
WNDPROC
old_wnd_proc;
//für das Menue
///////////////////////////////////////////////
// Funktionen, die beiMenue-Klick ausgeführt werden
///////////////////////////////////////////////
BOOL menu_1(HWND hwnd) {
MessageBox(0,"Hallo1","Titel1",MB_OK);
return TRUE;
}
BOOL menu_2(HWND hwnd) {
MessageBox(hwnd,"Hallo2","Titel2",MB_OK);
return TRUE;
}
BOOL menu_3(HWND hwnd)
{
RECT rect ;
GetClientRect( hwnd, & rect ) ;
HDC
hDC = GetDC(hwnd);
DrawText( hDC, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
ReleaseDC(hwnd, hDC);
return TRUE;
}
BOOL draw_icons(HWND hwnd,
int idx_start, //Start-Index des Icons
int anz
//Anzahl der anzuzeigenden Icons
)
{
...
...
...
return TRUE;
}
BOOL menu_4(HWND hwnd) {
return draw_icons(hwnd, 0, 100);
}
BOOL menu_5(HWND hwnd) {
return draw_icons(hwnd, 100,100);
}
BOOL menu_6(HWND hwnd) {
return draw_icons(hwnd, 200,100);
}
///////////////////////////////////////////////
// Normale (nachgeschaltete CALLBACK-Funktion)
///////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hwnd , UINT uMsg,
WPARAM wParam, LPARAM lParam ) {
switch ( uMsg ) {
case WM_COMMAND:
//MessageBox(0,"WM_COMMAND","WM_COMMAND",MB_OK);
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hDC = BeginPaint( hwnd, & ps );
//...
EndPaint( hwnd, & ps );
} break;
case WM_DESTROY: PostQuitMessage( 0 );
return 0;
} return DefWindowProc( hwnd, uMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wc = { 0 } ; MSG msg ; HWND hwndMain;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "my_class" ;
//wc.hIconSm
= LoadIcon( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
hwndMain = CreateWindowEx( WS_EX_LEFT,"my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
20,20,420,320,
// x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
ShowWindow
( hwndMain, iShowMain ) ;
UpdateWindow ( hwndMain ) ;
MENU_STRUCT menu_struct[] = {
//-------------------------------------------------// Menutext
Funktion
//-------------------------------------------------{L"Einstelungen",
0 }, // 0 für Popup
{L"menu_1",
menu_1
},
{L"menu_2",
menu_2
},
{L"Zeichnen",
0 }, // 0 für Popup
{L"Icons aus Shell32.dll
0.. 99", menu_4
},
{L"Icons aus Shell32.dll 100..199", menu_5
},
{L"Icons aus Shell32.dll 200..299", menu_6
},
{L"\0\0",0}}; // <== Endekriterium ist Pflicht!
MENU_CLASS(hwndMain, menu_struct);
while ( GetMessage ( & msg, NULL, 0, 0 ) ) {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
} return 0;
}
///////////////////////////////////////////////
// ACHTUNG!
HIER BITTE NICHTS ÄNDERN!!!
///////////////////////////////////////////////
LRESULT CALLBACK new_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{ err_if((old_wnd_proc==NULL),"ERR:new_wnd_proc");
if(iMsg==WM_COMMAND) if(!(HIWORD(wParam)))
{ WORD id = LOWORD(wParam);
WORD n = pMenuStruc[0].length;
for(WORD k=0;k<n;k++){
if(id==pMenuStruc[k].id) {
if(pMenuStruc[k].drawProc) { BOOL
ok = pMenuStruc[k].drawProc(hwnd);
if(!ok){
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
}}}}}
if(old_wnd_proc)return CallWindowProc( old_wnd_proc,hwnd,iMsg,wParam,lParam);
else
return DefWindowProc(
hwnd,iMsg,wParam,lParam ) ;
};
///////////////////////////////////////////////
// ACHTUNG!
HIER BITTE NICHTS ÄNDERN!!!
///////////////////////////////////////////////
size_t AddMenuItem( // Bitweise die Menue-Resource zusammenbauen
LPVOID MenuTemplate,
WCHAR* MenuString, WORD MenuID,
BOOL IsPopup, BOOL LastItem)
{ MENUITEMTEMPLATE* pItem = (MENUITEMTEMPLATE*) MenuTemplate;
size_t bytes_used = 0;
if (IsPopup) {
// for popup menu
if (LastItem)
pItem->mtOption = MF_POPUP | MF_END;
else
pItem->mtOption = MF_POPUP;
bytes_used
+= sizeof (pItem->mtOption);
pItem = (MENUITEMTEMPLATE*) ((BYTE*) MenuTemplate + bytes_used);
// a popup doesn't have mtID!!!
wcscpy((WCHAR*) pItem, MenuString);
bytes_used += sizeof (WCHAR) * (wcslen(MenuString) + 1); // include '\0'
} else {
// for command item
pItem->mtOption = LastItem ? MF_END : 0;
pItem->mtID
= MenuID;
wcscpy(pItem->mtString, MenuString);
bytes_used += sizeof (pItem->mtOption )
+ sizeof (pItem->mtID)
+ sizeof (WCHAR) * (wcslen(MenuString) + 1); // include '\0'
} return bytes_used;
}
///////////////////////////////////////////////
// ACHTUNG!
HIER BITTE NICHTS ÄNDERN!!!
///////////////////////////////////////////////
void OnCreate_SetCallBackFunc(HWND hwnd, MENU_STRUCT pMenuStruct[])
{ BYTE buf[4000]; memset(buf, 0, 4000); int k,j=0,m = -1, id=9100;
BOOL letzteSpalte = TRUE, IsPopup[256], LastItem[256];
size_t bytes_used
= sizeof(MENUITEMTEMPLATEHEADER);
MENUITEMTEMPLATEHEADER* p = (MENUITEMTEMPLATEHEADER*) buf;
p->versionNumber = 0; //WORD
p->offset = 0;
//WORD
pMenuStruc = pMenuStruct; //global
while (*pMenuStruct[++m].pMenu){
if( pMenuStruc[m].drawProc==NULL ) {
pMenuStruct[m].id = 0;
} else { id++; pMenuStruct[m].id = id; }
} err_if((m<1),"kein Menue");
pMenuStruct[0].length = m;
for(k=0;k<m;k++) {
IsPopup[k]=FALSE; LastItem[k]=FALSE;
if(pMenuStruct[k].id == 0) {
j = k; IsPopup[k]=TRUE; if(k>0)LastItem[k-1]=TRUE;
}
} LastItem[j]=TRUE; LastItem[m-1]=TRUE;
for(k=0;k<m;k++) { // baue Ressource zusammen
bytes_used += AddMenuItem(buf + bytes_used,
pMenuStruct[k].pMenu,
pMenuStruct[k].id,
IsPopup[k],
LastItem[k]);
}
HMENU hMenu = LoadMenuIndirect(buf); err_if(!hMenu,"LoadMenuIndirect");
HMENU hMenuOld = GetMenu(hwnd); SetMenu(hwnd, NULL); DestroyMenu(hMenuOld);
BOOL ok = SetMenu(hwnd, hMenu); err_if(!ok,"SetMenu");
HICON hIcon = ExtractIcon(GetModuleHandle(0),"Shell32.dll",43);
SetClassLong(hwnd, GCL_HICON, (LONG)hIcon );
DestroyIcon(hIcon);
}
///////////////////////////////////////////////
// ACHTUNG!
HIER BITTE NICHTS ÄNDERN!!!
///////////////////////////////////////////////
void MENU_CLASS(HWND hwnd_main, MENU_STRUCT pMenuStruct[]){ //Konstruktor
OnCreate_SetCallBackFunc(hwnd_main, pMenuStruct);
old_wnd_proc =(WNDPROC)SetWindowLong(hwnd_main,GWL_WNDPROC,(long)new_wnd_proc);
err_if(!old_wnd_proc,"OnCreate_SetCallBackFunc:old_wnd_proc");
}
///////////////////////////////////////////////
// ACHTUNG!
HIER BITTE NICHTS ÄNDERN!!!
///////////////////////////////////////////////
4.Praktikum
Diese Aufgabe besteht darin, das "Hallo Welt" - Windows - Programm zu erweitern und Ressourcen zu benutzen. Zunächst sollen
einfache Ressource von Hand (resource.rc) erstellt und in dem Window-Gerüst genutzt werden.
Später werden wir (gewöhnlich immer) den Ressourcen-Workshop für die Erstellung eines Ressourcenskript verwenden.
Durch die Verwendung des Ressourcen-Compilers kann dann auf das bitweise Zusammenbasteln der Ressourcen im C++Programm (wie im früheren Quelltext menu.cpp, der LoadMenuIndirect() verwendete) verzichtet werden.
1) Die Ressourcen-Erstellung von Hand besteht im folgenden:
●
●
●
Von Hand ist eine ( User - ) Menu - Ressource ( als ASCII-File resource.rc ) zu erstellen und im Window - Projekt zu
nutzen. resource.h soll die IDM_-Konstanten enthalten. resource.h soll in die Files *.cpp und resource.rc includiert
werden. In resource.rc soll eine einfache ( User-) Menue - Ressource erstellt und mit dem *.cpp getestet werden
Verwenden Sie für das Menu Beschleuniguungs-Tasten ( Alt-Hot-Keys ). Es sind Beschleunigungs - Tasten ( HotKeys )
zu verwenden.
In resource.rc soll eine einfache ( User-) Ressourcen - String - Table angelegt und Strings geladen werden. Legen Sie
eine String-Tabelle an. Die Strings sind nach dem Laden anzuzeigen. Verwenden Sie diese Texte z.B. für die FensterTitelzeile.
2) Die Ressourcen-Erstellung mit dem Ressourcen-Workshop besteht im folgenden:
●
Wiederholen Sie den Teil 1 der Übung in einem neuen Projekt, indem NUN der Ressourcen-Workshop verwendet
wird.
3) Es ist eine kleiner "HTML-Code-Generierer" zu schreiben, der folgendes leisten soll:
●
●
●
Erweitern Sie das Menu, indem Edit-Fenster sichtbar/unsichtbar gemacht werden können. Eine Anleitung ist unten.
Jedes Edit-Fenster soll bereits ein HTML-Struktur-Element enthalten.
In ein "Haupt"-Text-Fenster soll eine HTML-Page "halb-automatisch" zusammengestellt werden, indem das jeweilige
HTML-Element aus dem vorbelegten Fenstern geholt und in das "Haupt"-Text-Ergebnis-Fenster eingefügt wird.
1. Menu-Resource von Hand
Für Anfänger ist wohl günstig, ein neues Win32-Projekt anzulegen.
Diese Aufgabe besteht darin, eine "Resource von Hand" zu erstellen und zu testen. Gehen Sie bitte von dem Grundgerüst aus. Fügen
Sie dem Projekt ASCII-Files hinzu ( mit dem Dev-Studio-Menu: Neu - Textdatei und mit dem Namen resource.h und resource.rc )
a) In der Entwicklungsumgebung (im Projekt-Fenster auf Header-Files) kann ein neuer File resource.h -File leer hin-zu-zu-fügt
werden (rechte Maustaste im Projekt-Fenster auf Header-Dateien, Element hinzufügen). In resource.h sind die RessourcenIDentifizierer einzufügen:
#define
#define
#define
#define
#define
IDM_MAIN_MENU
IDM_MAIN_EXIT
IDM_MAIN_NEW
IDM_MAIN_EXAMPLE_1
IDM_MAIN_EXAMPLE_2
101
4001
4002
4003
4004
#define IDM_MAIN_ABOUT
4005
b) In der Entwicklungsumgebung (im Projekt-Fenster auf Ressourcen-Dateien, rechte Maustaste im Projekt-Fenster, Element
hinzufügen) kann ein neuer resource.rc - File hinzugefügt werden. resource.rc - File ist mit dem Ascii-Quellcode-Editor und alles
(automatisch beim Erstellen bereits eingetragene) zu löschen (außer #include "resource.h"). Dort hinein wird der folgende rcQuelltext kopiert. Dann soll diese Ressource (für sich allein) kopiliert werden.
#include "???.h"
IDM_MAIN_MENU MENU DISCARDABLE {
POPUP "&File" {
MENUITEM "&New", IDM_MAIN_NEW, GRAYED
MENUITEM SEPARATOR
MENUITEM "&Exit", IDM_MAIN_EXIT
}
POPUP "&Examples" {
MENUITEM "Example&1 F1", IDM_MAIN_EXAMPLE_1
MENUITEM "Example&2 F2", IDM_MAIN_EXAMPLE_2
}
POPUP "&Help" {
MENUITEM "&About", IDM_MAIN_ABOUT
}
}
c) Um das Menu anzuzeigen, wird in der WinMain()-Funktion die RegisterClass()-Struktur ergänzt durch den Eintrag:
WNDCLASS wc.lpszMenuName = MAKEINTRESOURCE( IDM_MAIN_MENU );
d) Nun sollte das Projekt komplett neu erstelle (build) werden und das Menu im Hauptfenster sichtbar sein. Ein Mausklick auf einen
Menu-Item hat keine Wirkung.
d) Menu-Ereignisse rufen die CALLBACK-Funktion mit der WM_COMMAND-Nachricht auf und übergeben in wParam den
Menu-Ressourcen-IDentifizierer (genauer: LOWORD(wParam) enthält den IDentifizierer).
Um die Ausführung nach Menu-Klick zu testen muss die WndProc-CALLBACK-Funktion (bei WM_COMMAND) ergänzt
werden. Tragen Sie bitte in die CALLBACK-Funktion WndProc ein:
case WM_COMMAND:
switch ( LOWORD(wParam) ) {
case IDM_MAIN_EXAMPLE_1: {
MessageBox( NULL, "IDM_MAIN_EXAMPLE_1", NULL, MB_ICONQUESTION |
MB_YESNO ) ;
} break ;
case IDM_MAIN_EXAMPLE_2: {
// ...
} break ;
} break; // Ende von WM_COMMAND
e) Ein Menu kann dynamisch geladen und gewechselt werden. Legen Sie bitte im resource.rc - File durch Kopieren des 1.MenuEintrages eine 2.Menu-Ressource an, die auch einen Eintrag "BITTE 2. MENU LADEN" enthalten soll und fügen Sie im
WM_COMMAND-Switch das Laden des 2.Menu ein (case IDM_...???:) ein etwa gemäss:
HMENU hMenu = LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE( IDM_??? ));
SetMenu( hwnd, h??? );
Das 1. Menu und 2. Menu sollen gewechselt werden können.
Beschleunigungs-Tasten
f) Mit Beschleuniguungs - Tasten ( Alt - Hot - Keys ) kann das Menu schneller bedient werden. Hierzu wird im Menu - Text das '&' Markierungs - Zeichen verwendet. Es können aber auch andere Tasten einem Menu - Punkt zugeordnet werden. Dem resource.rc File kann z.B. von Hand hinzugefügt werden:
ID_MAIN_ACCEL ACCELERATORS LOADONCALL MOVEABLE
VK_F1, IDM_MAIN_EXAMPLE_1, VIRTKEY
VK_F2, IDM_MAIN_EXAMPLE_2, VIRTKEY
"?",
IDM_...,
ASCII, ALT
}
{
Vor der Haupt - Nachrichten - Schleife wird dieAccelerator - Tabelle mit LoadAccelerators(...) geladen.
HACCEL hAccel = LoadAccelerators ( hInstance, MAKEINTRESOURCE( ID_MAIN_ACCEL )
);
hAccel == NULL signalisiert einen Ladungsfehler, d.h. meist ist ID_MAIN_ACCEL falsch. In der Haupt-Nachrichten-Schleife
wird unmittelbar nach while zuerst geprüft, ob eine Beschleunigungstaste gedrückt wurde:
if ( ( hAccel != NULL )
&& ( ! TranslateAccelerator ( msg.hwnd, hAccel, & msg ) ) ) {
...
String-Table
g) Im *.cpp soll ein Text - Hinweis mit LoadString() aus *.rc ( IDS_MAIN_STRING1 ) geladen werden und als MessageBox(
GetFocus(), "...", "...", MB_OK) vor dem Main - Window angezeigt werden. Die in *.rc mit dem Resourcen - Werkzeug erstellte
STRINGTABLE sieht etwa wie folgt aus:
STRINGTABLE DISCARDABLE BEGIN
IDS_MAIN_STRING1, "Copyright - MessageBox"
IDS_MAIN_STRING2, "Error in Runtime 1"
....
IDS_MAIN_STRING16, "Wert = %d"
END
Es ist eine Resourcen - String - Table und LoadString() zu verwenden.
Der LoadString( hInstance, IDS_..., buf, sizeof(buf) ) - Rueckgabe - Wert muss > 0 sein.
2. Menu-Resource mit Ressourcen-Workshop
Für Anfänger ist wohl günstig, ein NEUES Win32-Projekt anzulegen. Die obige Aufgabe soll nun mit dem Ressourcen-Workshop
erstellt werden. Wenn Sie die Identifizierer von vorher verwenden, so braucht das C++-Programm kaum geändert werden.
3. "Quellcode-Generierung"
a) Es sollen nun MEHRER Fenster verwendet werden, deren Handle im globalen Array HWND ghwnd[] gespeichert werden. Die
Fenster werden NICHT zerstört, sondern lediglich sichtbar bzw. unsichtbar gemacht. Dadurch "behält sich" Windows auch die zu
einem Fenster gehörenden Daten auch dann, wenn das Fenster nicht sichtbar ist. Alle Fenster verwenden die CALLCACK-Funktion
WndProc().
Um ein Fenster sichtbar zu machen kann verwendet werden:
void show_window(HWND hwnd)
{
SetForegroundWindow( hwnd );
ShowWindow
( hwnd, SW_RESTORE);
UpdateWindow
( hwnd ) ;
}
Beim Klick auf (X) der Titelzeile wird ein WM-CLOSE gesendet. Dann soll das Fenster unsichtbar werden, aber nur dann, wenn es
nicht das Haupt-Fenster ghwnd[0] ist. Ergänzen Sie bei WM_CLOSE:
for(int i=1;i<sizeof(ghwnd)/sizeof(ghwnd[0]);i++) {
if(hwnd == ghwnd[i]) {
ShowWindow ( hwnd, SW_HIDE);
UpdateWindow( hwnd ); return 0;
}
} break;
Die folgende Funktion create_edit_window(hwndMain, lpWindowName,x,y,cx,cy) erstellt eine Klasse lpWindowName und
hinterlegt immer die CALLBACK-Funktion WndProc. Dann wird ein Parent-Fenster erzeugt, in das ein "EDIT" (bereits verfügbar)
"eingehängt" wird. Schauen Sie sich create_edit_window() bitte einmal sorgfältig an!
Unmittelbar vor WinMain() sollt hinkopiert werden:
HWND create_edit_window(HWND hwndMain, LPCTSTR lpWindowName,
int x,int y,int cx,int cy)
{ // create (m)odeless_(w)indow
HINSTANCE hInst = GetModuleHandle(0);
WNDCLASSEX wc = { 0 } ;
if (cx<=0) cx = CW_USEDEFAULT;
if (cy<=0) cy = CW_USEDEFAULT;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.lpfnWndProc
= WndProc ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.hInstance
= hInst;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = lpWindowName;
if (!RegisterClassEx(&wc)) return 0 ;
HWND hwndParent = CreateWindowEx(WS_EX_TOOLWINDOW,
wc.lpszClassName, lpWindowName,
WS_POPUPWINDOW | WS_CHILD | WS_CAPTION,
x,y,cx,cy,hwndMain,0,hInst,0);
// zusätzlich ein Editchild ins obige hwndParent
WNDCLASS wcMS ={0}; GetClassInfo(hInst, "EDIT", &wcMS);
RECT rc; GetClientRect( hwndParent, & rc ) ;
int ID_EDIT = (int) hwndParent;
HWND hwndEdit = CreateWindowEx( WS_EX_CLIENTEDGE,
wcMS.lpszClassName, 0,
WS_CHILD | WS_VISIBLE | WS_VSCROLL //| WS_BORDER
| ES_MULTILINE | ES_AUTOVSCROLL | ES_OEMCONVERT,
rc.left,rc.top,rc.right,rc.bottom,
hwndParent, (HMENU)ID_EDIT, hInst,0);
return hwndParent;
}
In WinMain() hinein und dort vor die Hauptnachrichtenschleife soll hin:
// ghwnd[0] vom Haupt-Fenster
ghwnd[1] = create_edit_window(ghwnd[0], "[1] mein Edit 1",
0,300, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 );
ghwnd[2] = create_edit_window(ghwnd[0], "[2] mein Edit 2",
20,320, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 );
ghwnd[3] = create_edit_window(ghwnd[0], "[3] mein Edit 3",
40,340, GetSystemMetrics(SM_CXFULLSCREEN)-40,300 );
show_window(ghwnd[0]);
show_window(ghwnd[1]);
show_window(ghwnd[2]);
show_window(ghwnd[3]);
Nun sollten die Fenster erscheinen und sichtbar sein. Die Edit-Fenster haben ein Kontext-Menue.
In ein Edit[i]-Fenster kann Text auch per Programm geschrieben werden, etwa gemäss:
HWND hEdit = GetTopWindow(ghwnd[i]); // i > 0
SetWindowText(hEdit,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"
"\r\n<html><head>\r\n <title>...</title>\r\n</head><body>\r\n"
"\r\n<h1>...</h1>\r\n<p>\r\n...\r\n</p>\r\n\r\n</body></head>");
Mit SetWindowText() kann Text in ein Fenster geschrieben werden.
Mit GetWindowText() kann Text aus einem Fenster geholt werden. Für umfangreichen Text ist der Virtual-Mem-Speicher geeignet:
// Virtual-Mem-Speicher auch für SEHR umfangreichen Text:
HWND hSrc = GetTopWindow(ghwnd[i]);
// i > 0
int anz = GetWindowTextLength(hSrc); // hSrc ist Quelle
anz += 1000; //zusätzlicher Bedarf 1000 Byte
PSTR p = (PSTR) VirtualAlloc((LPVOID)NULL,
(DWORD)(anz+1),MEM_COMMIT,PAGE_READWRITE);
int n = GetWindowText(hSrc, p, anz+1); // p zeigt auf Heap-Text
// Verarbeite den Text ...
wsprintf(p+n,"\r\nGEHOLT\r\nUND\r\nGESCHRIEBEN");
SetWindowText(hDst, p); //hDst ist Ziel
VirtualFree(p,0,MEM_RELEASE);
Holen Sie den aktuellen Text aus dem einen Edit-Fenster und schreiben Sie diesen in ein anderes Edit-Fenster.
Es ist eine kleiner "HTML-Code-Generierer" zu schreiben, der folgendes leistet: Jedes Edit-Fenster soll bereits ein HTML-StrukturElement enthalten. In ein "Haupt"-Text-Fenster soll eine HTML-Page "halb-automatisch" zusammengestellt werden, indem das
jeweilige HTML-Element aus dem vorbelegten Fenstern geholt und in das "Haupt"-Text-Ergebnis-Fenster eingefügt wird.
Window Sub-Classing
Um alle Nachrichten einer vorhandenen MS-Edit-CALLBACK-Funktion zu erhalten, wird das Sub-Classing-Verfahren verwendet.
Damit können Nachrichten umgeleitet werden.
Beim Sub-Classing einer MS-Edit-CALLBACK-Funktion wird eine eigene EditProc vor die MS-Edit-CALLBACK-Funktion
"gehängt". Die eigene EdtProc erhält dann erst die Nachrichten und muss am Ende die alte MS-Edit-CALLBACK-Funktion
aufrufen.
///////////////////////////////////////////////
// SUB-CLASSING
// OldEdtProc ist die Orginal-"EDIT"-CALLBACK-Funktion,
// die nach dem Erzeugen von
// HWND hEdit = CreateWindowEx( WS_EX_CLIENTEDGE, ...
// durch
// WNDPROC OldEdtProc = (WNDPROC)SetWindowLong(hEdit,GWL_WNDPROC,(DWORD)NewEdtProc);
//
// zurück-gegeben wurde. Mit
//
//
SetWindowLong(hEdit,GWL_USERDATA,(DWORD)OldEdtProc);
//
// wird in den Windows-GWL_USERDATA-Fenster OldEdtProc aufgehoben
// und kann in der CALLBACK NewEdtProc( HWND hwnd,... durch
//
//
WNDPROC OldEdtProc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA);
//
if(!OldEdtProc) return DefWindowProc(hwnd,uMsg,wParam,lParam);
//
// geholt werden. Am Ende von CALLBACK NewEdtProc( HWND hwnd,...
// wird dann die alte MS-OldEdtProc aufgerufen durch
//
//
return CallWindowProc(OldEdtProc,hwnd,uMsg,wParam,lParam);
///////////////////////////////////////////////
LRESULT CALLBACK NewEdtProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
WNDPROC OldEdtProc=(WNDPROC)GetWindowLong(hwnd,GWL_USERDATA);
if(!OldEdtProc) return DefWindowProc(hwnd,uMsg,wParam,lParam);
switch ( uMsg ) {
case WM_CONTEXTMENU: {//1. rM-Taste, Menu will aufgehen
if(0xffffffff==(DWORD)lParam) break;//Orginal-Kontex-Menu
gpMenuStruc = (MENU_STRUCT
*)GetWindowLong(GetParent(hwnd),GWL_USERDATA);
if(!gpMenuStruc) break;
err_if(!gpMenuStruc,"kein hPopupmenu");
if(gpMenuStruc){
HMENU hKM = gpMenuStruc[0].hMenu;
err_if(!hKM,"kein hPopupmenu");
if (hKM) { POINT m; GetCursorPos( & m );
TrackPopupMenu(hKM, TPM_LEFTALIGN,
m.x,m.y,0,GetParent(hwnd),0);
return 0; }}
break; }
case WM_KEYUP:
case WM_LBUTTONUP: {
// Edit sendet bei jeder WM_KEYUP oder
// WM_LBUTTONUP-Nachricht an Parent
// die folgende Notify-Nachricht:
SendMessage(GetParent(hwnd),WM_COMMAND,
(WPARAM)MAKELONG(wParam,0xFFFF),(LPARAM)hwnd);
break; }
} return CallWindowProc(OldEdtProc,hwnd,uMsg,wParam,lParam);
}
Und (z.B.) die WndProc empfängt die die Notify-Nachricht:
// Dies ist die Parent-CALLBACK-Funktion, die
// die Notify-Nachricht erhält und verarbeitet.
case WM_COMMAND: {
if(HIWORD(wParam)) {//==0xffff user-notify
HWND hEdit = (HWND)lParam;
edit_caret_teste_pos_anzeige(hEdit);
}
break; }
Die folgende Test-Funktion edit_caret_teste_pos_anzeige() zeigt lediglich, wie mit der "EDIT"-Klasse gearbeitet wird (Betrachten
Sie das Fenster [5] des *.exe bei Caret-Bewegungen):
void edit_caret_teste_pos_anzeige(HWND hEdit) {
DWORD iLineBeg, iLineEnd, iLineLen;
DWORD iSelBeg, iSelEnd;
DWORD cxPos,
cyPos;
//30000 = SendMessage(hEdit,EM_GETLIMITTEXT,0,0);
DWORD iAnz = GetWindowTextLength(hEdit);
//aktuelle Selektierung geht von [iSelBeg] bis [iSelEnd]
SendMessage(hEdit,EM_GETSEL,(WPARAM)&iSelBeg,(LPARAM)&iSelEnd);
//aktuelle Zeile geht von [iLineBeg] bis [iLineEnd]
iLineBeg = SendMessage(hEdit, EM_LINEINDEX,-1,0);
iLineLen = SendMessage(hEdit,EM_LINELENGTH,iLineBeg,0);
iLineEnd = iLineBeg + iLineLen;
cyPos = iSelBeg - iLineBeg;
cxPos = SendMessage(hEdit, EM_LINEFROMCHAR,-1,0);
char buf[512],*p=buf;
p+=wsprintf(p,"iSel:(%02d,%02d)", iSelBeg, iSelEnd);
p+=wsprintf(p,"xyCar:(%02d,%02d)", cxPos,cyPos);
p+=wsprintf(p,"iLine:(%02d,%02d)",iLineBeg, iLineEnd);
p+=wsprintf(p,"iAnz:(%02d)",iAnz);
p+=wsprintf(p,"\r\n");
//SetWindowText(ghwnd[5], buf);
SetWindowText(GetTopWindow(ghwnd[5]), buf);
}
Fragen
1.
2.
3.
4.
5.
6.
7.
8.
9.
Wann wird in der CALLBACK-Funktion return 0; verwendet?
Warum wird ein DestroyWindow(ghwnd[0]) aber kein DestroyWindow(ghwnd[1]) benötigt?
Welche Prä-Zeichen (??_...) verwendet die "EDIT"-Klasse für Edit-Nachrichten?
Anstelle von
❍ HWND hEdit = GetTopWindow(ghwnd[1]);
kann auch verwendet werden:
❍ HWND hEdit = GetDlgItem(ghwnd[1],(int)ghwnd[1]);
Warum "funktioniert die Dlg-Funktion GetDlgItem()?
Welche alternativen Möglichkeiten gibt es anstelle der Verwendung von Virtual-Mem-Speicher?
Wozu dient LoadAccelerators()?
Wodurch wird ein WS_CHILD-Fenster zerstört?
Wie kann CreateWindowEx() eine vorhandene Klasse von MS verwenden?
Was bedeutet Window Sub-Classing?
#include <windows.h>
HWND ghwnd[20]; // globale Handle für die Fenster
void show_window(HWND hwnd) {
SetForegroundWindow( hwnd );
ShowWindow
( hwnd, SW_RESTORE);
UpdateWindow
( hwnd ) ;
}
//=======================
LRESULT CALLBACK WndProc( HWND hwnd , UINT iMsg,
WPARAM wParam, LPARAM lParam ) {
//=======================
switch ( iMsg ) {
//////////////////////////////////////////////////////
case WM_COMMAND: {
} break; // Ende von WM_COMMAND
//////////////////////////////////////////////////////
case WM_PAINT : { PAINTSTRUCT ps ;
HDC hDC = BeginPaint( hwnd, & ps );
EndPaint( hwnd, & ps ) ;
} break;
case WM_CLOSE : {
} break;
case WM_DESTROY : PostQuitMessage( 0 ) ; return 0;
} return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain ) {
//===================
WNDCLASSEX wc = { 0 } ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = 0; //MAKEINTRESOURCE( IDM_MAIN_MENU );
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
ghwnd[0] = CreateWindowEx( WS_EX_LEFT, "my_class",
"Main-Titel-Zeile",
WS_OVERLAPPEDWINDOW, // window style
0,0,GetSystemMetrics(SM_CXFULLSCREEN),300,//x,y,dx,dy
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL ) ;
// creation parameters
show_window(ghwnd[0]);
show_window(ghwnd[1]);
show_window(ghwnd[2]);
show_window(ghwnd[3]);
MSG msg ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
DestroyWindow(ghwnd[0]);
return msg.wParam ;
}
//////////////////////////////////////////////
// File: menu.cpp
// Einfaches Menu
//////////////////////////////////////////////
#ifndef _MYMENU_
#define _MYMENU_
//////////////////////////////////////////////
#include <windows.h> // wird immer gebraucht
#include <wchar.h>
// für das Menu
#define err(errStr) MessageBox(0,(errStr),0,MB_OK)
//////////////////////////////////////////////
// global verfügbar
//////////////////////////////////////////////
typedef BOOL (* DRAWPROC)(void);
typedef struct _MENU_STRUCT {
WORD
_id; // Menu-Identifizierer
WCHAR * _txt; // Menu-Item-Text
DRAWPROC _fn; // auzurufende Funktion
//union { DRAWPROC _fn; int _length; };
} MENU_STRUCT;
static WNDPROC g_wnd_proc_old;//EINE alte
//////////////////////////////////////////////
class MENU_CLASS {
//////////////////////////////////////////////
static LRESULT CALLBACK wnd_proc_new
( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam )
{ int k;
static HWND
g_hwnd_main; //EIN aktiv
static DRAWPROC
g_fn_aktiv; //EINE fn aktiv
static MENU_STRUCT * g_menu_struc;//WM_ACTIVATE
switch ( iMsg ) {
case WM_COMMAND: { if(HIWORD(wParam)) break;
// alle Menu-Tabellen-Einträge durchgehen:
for( k=0; g_menu_struc[k]._txt; k++) {
if( LOWORD(wParam) == g_menu_struc[k]._id ) {
//Menu-ausgewählte Funktion aufrufen:
g_fn_aktiv = g_menu_struc[k]._fn;
if ( g_fn_aktiv )
g_fn_aktiv();
//SetFocus(hwnd);
//InvalidateRect(hwnd,NULL,TRUE);
//UpdateWindow(hwnd);
}
} // for
} break; //ende WM_COMMAND
case WM_ACTIVATE: {
if(0==wParam) { g_hwnd_main = 0;
} else { g_menu_struc = (MENU_STRUCT *)
::GetWindowLong(hwnd,GWL_USERDATA);
if(!g_menu_struc) err("g_menu_struc");
g_hwnd_main = hwnd;
g_hwnd_main = (HWND)g_menu_struc[0]._fn;
}
} break;
case WM_CLOSE: { if(IDNO==MessageBox(hwnd,"Exit?",
"Programm",MB_ICONQUESTION|MB_YESNO)) return 0;
} break;
case WM_DESTROY: { PostQuitMessage(0);
} break;
} //ende switch ( iMsg )
if(g_wnd_proc_old) {
return
CallWindowProc((WNDPROC)g_wnd_proc_old,hwnd,iMsg,wParam,lParam);
} else { return err("ERR:g_wnd_proc_old"); }
};
//////////////////////////////////////////////
UINT AddMenuItem(LPVOID pBuf, MENU_STRUCT *pMenu,
BOOL IsPopup, BOOL LastItem)
{ WORD
MenuID
= pMenu->_id;
WCHAR * MenuString = pMenu->_txt;
MENUITEMTEMPLATE* pM = (MENUITEMTEMPLATE*) pBuf;
UINT cb = 0;
if (IsPopup) { // for popup menu
if (LastItem) pM->mtOption = MF_POPUP | MF_END;
else
pM->mtOption = MF_POPUP;
cb += sizeof (pM->mtOption);
pM = (MENUITEMTEMPLATE*) ((BYTE*)pBuf + cb);
wcscpy((WCHAR*) pM, MenuString);
cb += sizeof(WCHAR)*(wcslen(MenuString)+1);
} else {
// for command item
pM->mtOption = LastItem ? MF_END : 0;
pM->mtID
= MenuID;
wcscpy(pM->mtString, MenuString);
cb += sizeof(pM->mtOption)
+ sizeof(pM->mtID)
+ sizeof(WCHAR)*(wcslen(MenuString)+1);
} return cb;
}
//////////////////////////////////////////////
void BAUE_DAS_MENU_ZUSAMMEN( HWND hwnd,
MENU_STRUCT * pMenu )
{ BYTE buf[4000]={0};// memset(buf, 0, 4000);
BYTE * p = buf; p += sizeof(MENUITEMTEMPLATEHEADER);
HMENU hMenu=NULL; int i,k,j,m=-1;
BOOL letzteSpalte=TRUE,IsPopup[100],LastItem[100];
while (*pMenu[++m]._txt){ i=pMenu[m]._id;
if( i == 0 ) pMenu[m]._id = 0;
}
for(k=0;k<m;k++) { IsPopup[k]=FALSE; LastItem[k]=FALSE; }
for(k=0;k<m;k++) {
if(pMenu[k]._id==0){
IsPopup[k]=TRUE; j=k-1;
IsPopup[j]=FALSE; LastItem[j]=TRUE; j=k;
}
} LastItem[j]=TRUE; LastItem[m-1]=TRUE;
for(k=0;k<m;k++) { MENU_STRUCT mmm = pMenu[k];
p += AddMenuItem(p,&mmm,IsPopup[k],LastItem[k]);
}
hMenu = LoadMenuIndirect(buf);if(!hMenu) err("createEdit");
SetMenu(hwnd, hMenu);
}
//////////////////////////////////////////////
public: //Konstruktor
MENU_CLASS(HWND hwnd, MENU_STRUCT * pMenu)
{
pMenu[0]._fn = (DRAWPROC)hwnd;
::SetWindowLong(hwnd,GWL_USERDATA,(LONG)pMenu);
g_wnd_proc_old = (WNDPROC)::SetWindowLong(hwnd,
GWL_WNDPROC,(LONG)wnd_proc_new);
if(!g_wnd_proc_old) err("g_wnd_proc_old");
BAUE_DAS_MENU_ZUSAMMEN(hwnd, pMenu);
}
}; // Ende MENU_CLASS
//////////////////////////////////////////////
#endif _MYMENU_
//////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////
// File: main.cpp
// Hauptprogramm für GDI-Tests
////////////////////////////////////////////////////
#include <windows.h>
??? // #include "menu.cpp"
HWND g_hwnd_main;
////////////////////////////////////////////////////
// GDI-Vereinfachungen
////////////////////////////////////////////////////
class GDI_OBJ { //global: HWND g_hwnd_main;
HWND
_hwnd;
HDC _hdc;
HPEN
_hPenOld,
_hPenNew;
HBRUSH
_hBrushOld, _hBrushNew;
COLORREF _text_color, _bktext_color;
public: //////////////////////////////////////////////
GDI_OBJ(void){ //Konstruktor
if(!g_hwnd_main) err("g_hwnd_main==0");
_hwnd = g_hwnd_main;
_hdc = GetDC(_hwnd);
} ////////////////////////////////////////////////////
~GDI_OBJ(void){ //Destruktor
ReleaseDC(_hwnd, _hdc);
} ////////////////////////////////////////////////////
void begin_pen(int fnPenStyle,int nWidth,COLORREF crColor) {
_hPenNew = (HPEN) CreatePen(fnPenStyle,nWidth,crColor);
_hPenOld = (HPEN) SelectObject(_hdc, _hPenNew );
} ////////////////////////////////////////////////////
void end_pen(void) {
SelectObject( _hdc, _hPenOld );
DeleteObject( _hPenNew );
} ////////////////////////////////////////////////////
void begin_textcolor( COLORREF color, COLORREF bkcolor ){
_text_color = SetTextColor(_hdc,
color);
_bktext_color = SetBkColor (_hdc, bkcolor);
} ////////////////////////////////////////////////////
void end_textcolor( void ){
SetBkColor(_hdc,_bktext_color);
SetTextColor(_hdc, _text_color);
} ////////////////////////////////////////////////////
void begin_brush( COLORREF color ){
//LOGBRUSH * pLB HBRUSH _hbrush = (HBRUSH) GetCurrentObject(_hdc, OBJ_BRUSH);
_hBrushNew = (HBRUSH) CreateSolidBrush( color );
if(!_hBrushNew){err("!_hBrushNew");exit(-1);}
_hBrushOld = (HBRUSH) SelectObject(_hdc, _hBrushNew );
} ////////////////////////////////////////////////////
void end_brush( void ){
SelectObject( _hdc, _hBrushOld );
DeleteObject(
_hBrushNew );
} ////////////////////////////////////////////////////
void draw_rect( int xLeft,int yTop,int xRight,int yBottom ){
Rectangle(_hdc, xLeft,yTop,xRight,yBottom );
} ////////////////////////////////////////////////////
void draw_polyline( CONST POINT *pt, int cPoints ) {
Polyline( _hdc, pt, cPoints );
} ////////////////////////////////////////////////////
void draw_text( int x, int y, char * str ){
TextOut( _hdc, x, y, str, lstrlen(str));
} ////////////////////////////////////////////////////
void erase(){
SendMessage(_hwnd,WM_ERASEBKGND,(UINT)_hdc,0);
}
};
////////////////////////////////////////////////////
////////////////////////////////////////////////////
// Lösche den Viewport
////////////////////////////////////////////////////
BOOL loesche()
{ GDI_OBJ g = GDI_OBJ();
g.erase();
return FALSE;
}
////////////////////////////////////////////////////
// Schreibe Text an Position
////////////////////////////////////////////////////
BOOL draw_test1()
{ GDI_OBJ g = GDI_OBJ();
g.begin_textcolor( RGB(0,0,255), RGB(255,255,0) );
g.draw_text( 180,140, "Hallo");
g.end_textcolor();
return FALSE;
}
////////////////////////////////////////////////////
// Zeichne Rechteck mit pen: draw_rect
////////////////////////////////////////////////////
BOOL draw_test2()
{ GDI_OBJ g = GDI_OBJ();
// PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT
g.begin_pen(PS_SOLID,3,RGB(0,0,0));
g.draw_rect(50,10, 300,250);
g.end_pen();
return FALSE;
}
////////////////////////////////////////////////////
// Zeichne Rechteck mit pen: draw_polyline
////////////////////////////////////////////////////
BOOL draw_test3()
{ POINT Points[] = {
{ 200,100}
,{ 250,150}
,{ 200,200}
,{ 150,150}
,{ 200,100}
};
int cPoints = sizeof(Points)/sizeof(Points[0]);
GDI_OBJ g = GDI_OBJ();
////////////////////////////////////////////////////
// fnPenStyle: PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT
// crColor
: RGB(00, 00, 0xff)
////////////////////////////////////////////////////
g.begin_pen(PS_SOLID,13, RGB(255,0,0));
g.draw_polyline( Points, cPoints );
g.end_pen();
return FALSE;
}
////////////////////////////////////////////////////
// Zeichne Rechteck mit brush: BS_SOLID
////////////////////////////////////////////////////
BOOL draw_test4()
{
GDI_OBJ g = GDI_OBJ();
g.begin_brush( RGB(0,0,255) );
g.draw_rect(80,80, 120,120);
g.end_brush( );
return FALSE;
}
////////////////////////////////////////////////////
// Zeichne Rechteck mit brush: BS_HATCHED
////////////////////////////////////////////////////
BOOL draw_test5()
{
GDI_OBJ g = GDI_OBJ();
g.begin_brush( RGB(0,255,0) );
g.draw_rect(80,140, 120,180);
g.end_brush( );
return FALSE;
}
////////////////////////////////////////////////////
// Gib Info mit MessageBox aus
////////////////////////////////////////////////////
BOOL show_msg()
{
MessageBox( g_hwnd_main,
"Hallo", "Hallo", MB_OK);
return FALSE;
}
//=========================================================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain )
{ WNDCLASSEX wc = { 0 } ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= DefWindowProc; //WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance ;
wc.hIcon
= LoadIcon
( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon ( NULL, IDI_APPLICATION ) ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
g_hwnd_main = CreateWindowEx( WS_EX_LEFT,"my_class",
"Main-Titel-Zeile", WS_OVERLAPPEDWINDOW,
20,20,420,320, NULL,NULL,hInstance, NULL );
MENU_STRUCT menu_struct[] = {
{
0, L"allgemein",
{ 100, L"loesche",
{ 120, L"MessageBox()",
0
loesche
show_msg
},
},
},
{
0, L"einige Tests",
0
},
{ 220, L"draw test1",
draw_test1 },
{ 230, L"pen test rect2",
draw_test2 },
{ 235, L"pen test polyline",
draw_test3 },
{ 240, L"brush test1",
draw_test4 },
{ 250, L"brush test2",
draw_test5 },
{0,L"\0\0",0}}; // <== Endekriterium ist Pflicht!
MENU_CLASS mc = MENU_CLASS(g_hwnd_main, menu_struct);
ShowWindow (g_hwnd_main,iShowMain) ;
UpdateWindow(g_hwnd_main) ;
MSG msg;
while ( GetMessage(&msg,NULL,0,0 ) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam ;
}
5.Praktikum
Diese Aufgabe besteht darin, mit einer modalen DialogBox das Hauptprogramm zu gestalten und weitere DialogBoxen zu erstellen und die
zugehörigen CALLBACK-Funktionen zu schreiben.
1. DialogBox() soll in WinMain() benutzt werden.
2. Diese DialogBox soll ein Menu erhalten.
3. Es ist eine Dialog-CALLBACK-Funktion zu schreiben,
die die Klick-Nachricht eines OK-Button bearbeitet.
4. Es sind Button's einzufügen, die den Notepad starten.
5. Per Button-Klick sind *.exe-Programme zu starten.
6. Es ist eine Prototyp füer einen Hex-Taschenrechner zu programmieren.
Es sind Verbesserungen und Erweiterungen ( ComboBox, Edit ) vorzunehmen.
7. Mit einem neuen Projekt ( für But.cpp ) ist der Taschenrechner ohne Ressourcen-Script zu schreiben.
WinMain-DialogBox
Es ist in einem neuen ( leeren ) Projekt ein einfacher Dialog zu erstellen ( z.B. 2 Buttons, Eingabe-Zeile, Menu, Icon ). Ist die IDD_DIALOGDialog-Resource ( resource.rc ) verfügbar, so kann mit der dlgProc-CALLBACK-Funktion ein Dialog gemaess
int ret = DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE( IDD_DIALOG), hwnd,
(DLGPROC)dlgProc);
erzeugt werden. Das Windows-Hauptprogramm enthält DialogBox() und in dieser ist die Nachrichten-Schleife. Die DialogBox() erzeugt implizit
die while-Schleife des Hauptprogrammes. Die Dialog-Resource ( resource.rc ) soll den Identifizierer IDD_DIALOG haben. Ein IDD_DIALOGDialog und die dlg-CALLBACK-Funktion dlgProc) sollen mit dem Ressourcen-Workshop erstellt werden.
//Hauptprogramm
int APIENTRY WinMain(
HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG),
NULL, (DLGPROC)dlgProc);
}
dlgProc-CALLABCK
Bekanntlich senden MenuItem-Klicks und Button-Klicks Nachrichten
iMsg=WM_COMMAND mit LOWORD(wParam) = IDB_... , IDM_, usw. ...
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDB_...: break;
case IDM_...: break;
} break;
an die CALLBACK-Funktion: dlgProc, die etwa folgenden Aufbau hat:
//dlgProc-CALLBACK-Funktion
#include <windows.h>
#include "resource.h"
BOOL CALLBACK dlgProc(
HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
case WM_INITDIALOG : {
// statt WM_CREATE
break; }
case WM_CLOSE : {
char buf[256]; int ret;
GetWindowText( hwnd, buf, sizeof(buf) ) ;
ret = MessageBox( hwnd,"Exit?","Exit?",MB_ICONQUESTION|MB_YESNO);
if ( IDNO == ret ) return TRUE;
EndDialog( hwnd, ret );
//wParam=IDNO wird der ret-Value von DialogBox()
break; }
/* spaeter:
case WM_COMMAND: {
switch ( LOWORD(wParam) )
{ //MenuItems, Buttons
case IDB_...: break;
case IDM_...:
MessageBox( hwnd, "Hallo","ID...",MB_OK);
break;
case IDOK : //(OK)-Button zum beenden
SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), lParam );
return TRUE;
}
} break; //Ende von WM_COMMAND
*/
} //Ende von switch(iMsg)
return FALSE;
}
Menu für DialogBox
Die Main-DialogBox soll ein Menu IDM_MENU erhalten. Das Ressourcen-Script soll mit dem Resourcen-Workshop erstellt werden. Der
Resourcen-Workshop kann unmittelbar das Menu einfügen. Alternativ kann z.B. das Menu IDM_MENU ( zur Laufzeit ) unter case
WM_INITDIALOG mit SetMenu() geladen und angezeigt werden.
SetMenu(hwnd, LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDM_MENU)));
DialogBox mit Button's
Die DialogBox von Main soll einen Button IDB_... erhalten. Die Button-Beschriftung soll starte IDD_DIALOG1 sein. Ein Button-Klick von
IDB_... soll einen weiteren Dialog IDD_DIALOG1 anzeigen.
Starten von *.exe-Programmen
Als Beispiel wird beschrieben, wie das Notepad.exe-Programm gestartet werden kann. Am einfachsten ist die alte WinExec().Funktion.
UINT ui = WinExec("Notepad", SW_SHOW);
if(ui > 31) ...
Experimentieren und untersuchen Sie nützliche Anwendungen von
UINT ui = WinExec("cmd /K dir \r\n", SW_SHOW);
WinExec() wurde zu CreateProcess() erweitert, ist aufwendiger und wird empfohlen. Create.. braucht eine "saubere" Freigabe! Hier ein Muster,
wenn "BuildLog.htm" im gleichen Verzeichnis ist, wie unser entwickelter sp2aufxx.exe-File. Grob ausgedrückt entspricht dies etwa dem Aufruf
von
WinExec("Notepad.exe FULLPATH\\BuildLog.htm", SW_SHOW)).
CHAR * programm = "Notepad.exe";
CHAR * filename = "BuildLog.htm";
CHAR drive[256]; CHAR dir[256]; CHAR fname[256];
CHAR ext[256]; CHAR path[512]; CHAR aufruf[512];
STARTUPINFO si; ZeroMemory(&si,sizeof(si));
GetStartupInfo(&si);
_splitpath(si.lpTitle, drive, dir, fname, ext);
_makepath(path, drive, dir,"","");
wsprintf(aufruf,"%s %s%s",programm,path,filename);
PROCESS_INFORMATION pi; ZeroMemory(&pi,sizeof(pi));
BOOL ok = CreateProcess (0,aufruf,
0,0,0,NORMAL_PRIORITY_CLASS,0,0,&si,&pi);
if(!ok){ //Process konnte nicht gestartet werden
err_if(!ok,"KEIN PROCESS");
} else {
//befreie, falls nicht mehr benötigt
CloseHandle(pi.hThread);
// WaitForSingleObject(pi.hProcess, INFINITE);
// der Process terminierte
DWORD dwExitCode; // wie wurde er beendet?
GetExitCodeProcess(pi.hProcess, &dwExitCode);
//befreie, falls nicht mehr benötigt:
CloseHandle(pipi.hProcess);
}
Wozu kann GetFullPathName(filename,sizeof(path),path,?); nützlich sein?
Taschenrechner mit Ressourcenscript
Es ist ein Prototyp für einen Hex-Taschenrechner zu gestalten ( mit Verbesserungen und Erweiterungen ). Um einem Control eine Nachricht zu
schicken kann anstelle von
HWND hCtl = GetDlgItem ( HWND hDlg, int idRes );
LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam);
kürzer auch verwendet werden:
LONG SendDlgItemMessage( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam,
LPARAM lParam);
Für das Edit- und ComboBox-Control sollen die Macros ( wie z.B. Edit_SetText() ) aus WindosX.h verwendet werden.
Bei der Erstellung des Ressourcen-Scripts kann zunächst ein "leeres grosses Dialog-Rechteck" angelegt werden und in diesen rcQuelltext wird der untere rc-Quelltext hinein kopiert ( ID-Konstanten beachten ).
BEGIN //RESOURCE
COMBOBOX
IDC_COMBO1,5,5,115,125,CBS_DROPDOWN
| WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "0",48, 6,117,14,14,NOT WS_TABSTOP
PUSHBUTTON "1",49, 6, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "2",50,24, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "3",51,42, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "4",52, 6, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "5",53,24, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "6",54,42, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "7",55, 6, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "8",56,24, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "9",57,42, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "A",65,42, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "B",66,24, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "C",67, 6, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "D",68,42, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "E",69,24, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "F",70, 6, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "+",43,64, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "-",45,64, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "*",42,82, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "/",47,82, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "%",37,64, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "=",61,24,117,31,14,NOT WS_TABSTOP
PUSHBUTTON "&&",38,82, 63,14,14,NOT WS_TABSTOP
PUSHBUTTON "|",124,64, 63,14,14,NOT WS_TABSTOP
PUSHBUTTON "^",94,64, 46,14,14,NOT WS_TABSTOP
PUSHBUTTON "<",60,82, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON ">",62,82, 46,14,14,NOT WS_TABSTOP
PUSHBUTTON "M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP
PUSHBUTTON "M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP
PUSHBUTTON "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP
PUSHBUTTON "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP
PUSHBUTTON "BS",8,64,117,31,14,NOT WS_TABSTOP
PUSHBUTTON "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP
CONTROL
"",IDC_STATIC,"Static",SS_BLACKRECT,98,30,6,101
CONTROL
"",IDC_STATIC,"Static",SS_BLACKRECT,5,21,116,6
CONTROL
"",IDC_STATIC,"Static",SS_BLACKRECT,58,29,6,101
CONTROL
"",IDC_STATIC,"Static",SS_BLACKRECT,7,132,116,6
EDITTEXT
IDC_EDIT1,7,141,113,45,ES_MULTILINE
|WS_TABSTOP|ES_WANTRETURN|WS_VSCROLL|WS_HSCROLL
DEFPUSHBUTTON "Schliessen",IDOK,37,193,50,14,NOT WS_TABSTOP
END
Achtung! Es ist sinnvoll,
die folgenden KonstantenBezeichner zu verwenden:
IDC_COMBO1
IDC_EDIT1
IDC_BUTTON0
IDC_BUTTON1
IDC_BUTTON2
IDC_BUTTON3
IDC_BUTTON4
IDC_BUTTON5
Windows kenn bereits:
IDC_STATIC
IDOK
Hier ein Anfang für die CALLBACK dlgHexCalcProc() und hex_show_number() zum Anzeigen von iNum in IDC_COMBO1 und der Funktion
hex_calc_it(), die abhängig von dem geklickten Button ( siehe default: iAsc = LOWORD( wParam ); ... ) auf die alte Zahl iFirstNum die aktuelle
iNum "drauf-rechnet" und das Ergebnis zurück gibt.
//C-Quelltext
#include <limits.h>
void hex_show_number ( HWND hwnd, INT idRes, UINT iNum ) {
CHAR buf[256] ; HWND hCombo1 = GetDlgItem( hwnd, IDC_COMBO1 ) ;
strupr( ltoa( iNum, buf, 16 ));
ComboBox_SetText( hCombo1, buf ) ;
if ( idRes == IDC_COMBO1 ) {
if ( ComboBox_GetCount
( hCombo1 ) >= 15 )
ComboBox_DeleteString( hCombo1,
15 ) ;
ComboBox_InsertString
( hCombo1, 0, buf );
}
}
DWORD hex_calc_it ( UINT iFirstNum, INT iOperation, UINT iNum ) {
switch ( iOperation ) {
default : return 0 ;
case '=' : return iNum ;
case '+' : return iFirstNum + iNum ;
case '-' : return iFirstNum - iNum ;
case '*' : return iFirstNum * iNum ;
case '&' : return iFirstNum & iNum ;
case '|' : return iFirstNum | iNum ;
case
case
case
case
case
}
'^'
'<'
'>'
'/'
'%'
:
:
:
:
:
return
return
return
return
return
iFirstNum ^ iNum ;
iFirstNum << iNum ;
iFirstNum >> iNum ;
iNum ? iFirstNum / iNum : UINT_MAX ;
iNum ? iFirstNum % iNum : UINT_MAX ;
}
BOOL CALLBACK dlgHexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
static BOOL
bNewNumber = TRUE ;
static INT
iOperation = '=' ;
static UINT
iAsc,iNumber, iFirstNum ;
static CHAR * pCombo1;
static HWND
hCombo1;
switch ( iMsg ) {
case WM_INITDIALOG:
if ( pCombo1 != NULL ) { free( pCombo1 ); pCombo1 = NULL; }
pCombo1 = ( CHAR * ) calloc( 256, sizeof( CHAR ) );
strcpy( pCombo1, "0" );
hCombo1 = GetDlgItem( hwnd, IDC_COMBO1 ) ;
ComboBox_SetText ( hCombo1, pCombo1 );
break;
case WM_COMMAND :
if(HIWORD(wParam)) break; //Notifications
switch ( LOWORD( wParam ) ) {
case IDOK: SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE;
case IDC_BUTTON0://M+
case IDC_BUTTON1://Mcase IDC_BUTTON2://MR
case IDC_BUTTON3://MC
case IDC_BUTTON4://AC
case IDC_BUTTON5://BS
break ;
default:
iAsc = LOWORD( wParam );
if ( isxdigit( iAsc ) ) {
// hex digit
if ( bNewNumber == TRUE ) {
iFirstNum = iNumber ;
iNumber = 0;
}
if ( iNumber <= (UINT_MAX >> 4) ) {
iNumber = 16 * iNumber + iAsc
- ( isdigit( iAsc ) ? '0' : 'A' - 10 ) ;
hex_show_number ( hwnd, 0, iNumber ) ;
} else {
MessageBeep( 0 ) ; // MessageBeep(MB_ICONHAND);
} bNewNumber = FALSE ;
} else {
// operation
if ( bNewNumber == FALSE ) {
iNumber = ( UINT ) hex_calc_it ( iFirstNum, iOperation, iNumber ) ;
hex_show_number ( hwnd, IDC_COMBO1, iNumber ) ;
}
iOperation = iAsc ;
bNewNumber = TRUE ;
} break; // ende von switch ( LOWORD( wParam )
} break; // ende von WM_COMMAND
case WM_CLOSE:
if(pCombo1) free( pCombo1 ); pCombo1 = NULL;
EndDialog ( hwnd, wParam );
// DestroyWindow( hwnd ); ... ist bei modal unnötig
break;
}
return FALSE ;
}
Taschenrechner Ohne Ressourcen-Script
Empfehlung: Neues Projekt anlegen. Durch den Aufruf von CreateWindowEx() kann ein Button mit der Klasse "BUTTON" erzeugt werden. Der
Identifizierer (HMENU)idRes wird bei HMENU hMenu ( mit geeignetem Casten ) eingetragen. Der Style sollte auch WS_CHILD enthalten,
damit eine automatische Freigabe beim Schliessen des Parent-Fensters erfolgt.
_hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON",
pText,WS_VISIBLE | WS_CHILD, x,y,dx,dy,
hParent,(HMENU)idRes,GetModuleHandle(0),0);
Als ein Anfang kann die class my_button { ... } verwendet werden, die CreateWindowEx() mit der Window-Fenster-Klasse "BUTTON" und den
Identifizierer idRes nutzt. Die Klasse my_button { ... } ist in dem Rahmenprogramm But.cpp enthalten. Ein Aufruf erfolgt etwa gemäss:
// mit
static my_button * pButtton[256]; //max 256 Button's
// können Child-Button ( Zeichen entspricht
// dem Identifizierer ) in das Haupt-Fenster
// platziert werden, etwa gemäss:
WM_CREATE : ... pButton[255] = new my_button(hwnd,255,"255", 200,100,80,80);
WM_DESTROY: ... if(pButton[255]) delete pButton[255];
Fragen
1.
2.
3.
4.
5.
6.
Enthält die Funktion DialogBox() eine Hauptnachrichtenschleife?
Nennen Sie unterschiedliche Möglichkeiten, wie DialogBox() mit einem Menu versehen werden kann.
Wozu dient der ret-Parameter bei EndDialog(hwnd,ret)?
Welche Nachricht wird durch einen Button-Klick ausgelöst?
Wie heißt die Klasse, die Button's erstellt und die MS-CALLBACK-Funktion enthält?
Was ist zu tun, wenn alle Nachrichten ZUERST an eine eigene CALLBACK-Funktion geschickt werden sollen und erst danach an
die "vorhandene, unsichtbare" MS-CALLBACK-Funktion weiter gereicht werden sollen?
7. Was bewirkt der Aufruf: ShellExecute(hwnd,"explore",0,0,0,SW_SHOWNORMAL)?
Fragen
1. Welches Programm übersetzt einen *.rc-File in einen *.res-File?
2. Welches Programm bindet *.res-Files in das *.exe-File ein?
3. Welche CALLBACK-Funktion gehört zu der eingebauten Klasse "#32770" und
welche Nachrichten (Beispiele angeben) verarbeitet dies CALLBACK-Funktion?
4. Wozu dienen die Aufrufe: WNDCLASSEX wc = { 0 }; GetClassInfoEx(hInst,"#32770",&wc);?
5. Eine CALLBACK-Funktion soll unter WM_COMMAND nur Menu und Button-Nachrichten verarbeiten, aber keine NotifyNachrichten von Controls. Wie würden Sie (unmittelbat nach WM_COMMAND) die Notify-Nachrichten "abblocken"? Lösung
durch:
case WM_COMMAND: if(HIWORD(wParam)) ....;
6. Eine modless Dialog liefere mit CreateDialog() das HWND hDlg zurück. Der Dialog enthalte eine ComboBox.
Wie kann mit Hilfe von hDlg das Handle hCombo erhalten werden, wenn ID_COMBO der Identifizierer für die ComboBox ist?
7. Eine modale DialogBox() liefert kein HWND zurück. Der Dialog enthalte eine ComboBox.
Wie wird per Programm in die Edit-Eingabezeile der ComboBox ein Text geschrieben?
Wie werden in die List-Zeile der ComboBox Texte geschrieben?
8. CreateWindowEx() gehört zu einer der folgenden Klassen.
a) "EDIT"
b) "BUTTON"
c) "COMBOBOX"
Wie würden Sie die folgenden Styles 1), 2), 3) zu a), b), c) zuordnen?
1) WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP
2) WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN
3) WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN
#include <windows.h>
#include <windowsx.h>
#include <limits.h>
#define err_if(e,str) \
if(e)MessageBox(0,(str),0,MB_OK|MB_ICONSTOP);
/////////////////////////////////////////////////
// ... NOTIFY-TEST ...
// Ausgabe von Hilfetext als Notify-Hinweis:
// if(CBN_EDITCHANGE==HIWORD(wParam)) ...
/////////////////////////////////////////////////
char * helpCBN_EDITCHANGE =
"\r\nWenn Sie die Texteingabe in die Combo-Edit-Zeile"
"\r\nProgrammieren möchten, so können die"
"\r\nCombobox-Notify-Nachrichten CBN_ ..."
"\r\nverwendet werden, die kommen unter:"
"\r\n\r\nWM_COMMAND:"
"\r\n if(HIWORD(wParam))"
"\r\n if(hCombo==(HWND)lParam)"
"\r\n if(CBN_EDITCHANGE==HIWORD(wParam))"
"\r\n { // es wurde was in Combo getippt"
"\r\n\tmemset(buf,0,sizeof(buf));"
"\r\n\tGetWindowText(hCombo,buf,sizeof(buf));"
"\r\n\tchar *p = buf; UINT uNum=0;"
"\r\n\twhile(*p)"
"\r\n\t\{ // Zahl zeichenweise:"
"\r\n\t\tchar asc = *p; p++;"
"\r\n\t\terr_if(!isxdigit(asc),\"Bitte nur Hex-Digit!\")"
"\r\n\t\tuNum = 16 * uNum + asc - (isdigit(asc)?\'0\':\'A\'-10) ;"
"\r\n\t} uNum2 = ...; isNewNum = ... ; \r\n}";
// err_if(1,helpCBN_EDITCHANGE);
/////////////////////////////////////////////////
// globales
/////////////////////////////////////////////////
const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText()
const UINT MAX_COMBO_CHAR =
8;//ComboBox_LimitText()
const UINT USE_CE = 1; // Ziel Combo-Edit
const UINT USE_CL = 2; // Ziel Combo-Liste
const UINT USE_EM = 4; // Ziel Edit-Multiline
// UINT (M)em(SUM)men-Speicher MSUM
// MSUM hält den Summenwert ('M+','M-')
//'MR' für Anzeige, 'MC' setzt MSUM=0
UINT MSUM;
// Verwendet werden hCombo, hEdit dadurch entfällt:
// HWND hCombo = GetDlgItem(hwnd,IDC_COMBO);
// HWND hEdit = GetDlgItem(hwnd,IDC_EDIT);
HWND hCombo; //hCombo anstelle von IDC_COMBO
HWND hEdit; //hEdit anstelle von IDC_EDIT
/////////////////////////////////////////////////
// print_append() kann aus den hSrc-Fenster Text holen
// und gemäss "printf-ähnlichem" Formats Text "anhängen"
// und den gesamten Text in das hDst-Fenster schreiben.
// Dadurch entsteht ein "append" von Text
//
// Anstelle der Aufruffolge:
//
print_append(hEdit,hEdit, "\r\n");
//
print_append(hEdit,hEdit, "%u ", u1);
//
print_append(hEdit,hEdit, "%u ", u2);
//
// ist günstiger:
//
print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2);
/////////////////////////////////////////////////
int CDECL print_append(HWND hDst, HWND hSrc, LPTSTR pFormat, ...)
{ static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048
err_if(!hDst,"print_append(): hDst?");
memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf;
va_list argList;
va_start( argList, pFormat ) ;
if(hSrc) // hole Text aus hSrc
pBuf += GetWindowText(hSrc,Buf,sizeof(Buf));
// bei Speichermangel pBuf auf Buf[0]
if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf;
pBuf += wvsprintf( pBuf, pFormat, argList ) ;
va_end( argList ) ;
// schreibe erweiterten Text in hDest
SetWindowText( hDst, Buf );
return (pBuf-Buf);
}
/////////////////////////////////////////////////
// show_hex() schreibt uNum in das ziel.
// Beispiel: show_hex(10,USE_CE);
// Ziel kann sein (USE_CE|USE_CL|USE_EM)
/////////////////////////////////////////////////
void show_hex(UINT uNum, int ziel )
{ char buf[256]; int radix = 16;
//global sind hCombo, hEdit
//schreibe uNum als hex-String (basis 16) in buf
strupr( ltoa(uNum, buf, radix) );
//Ausgabe von buf in ziel
if (USE_CE & ziel) {//in Combo-Liste eintragen:
ComboBox_SetText(hCombo, buf ) ;
}
if (USE_CL & ziel) { //in Combo-Liste eintragen:
if ( ComboBox_GetCount(hCombo) >= 30)
ComboBox_DeleteString(hCombo,30);
ComboBox_InsertString(hCombo, 0, buf );
}
if (USE_EM & ziel) { //in Edit-Journal eintragen:
print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum);
}
}
/////////////////////////////////////////////////
// Beispiel: UINT erg = berechne(6,'+',4);
// Schreibt auch in hEdit
/////////////////////////////////////////////////
UINT berechne(UINT uNum1, char Op, UINT uNum2 )
{ UINT erg;
switch ( Op ) {
default : erg = 0; return erg;
case '=' : erg = uNum2 ; return erg;
case '+' : erg = uNum1 + uNum2 ; break;
case '-' : erg = uNum1 - uNum2 ; break;
case '*' : erg = uNum1 * uNum2 ; break;
case '&' : erg = uNum1 & uNum2 ; break;
case '|' : erg = uNum1 | uNum2 ; break;
case '^' : erg = uNum1 ^ uNum2 ; break;
case '<' : erg = uNum1 << uNum2 ; break;
case '>' : erg = uNum1 >> uNum2 ; break;
case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ;
break;
case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ;
break;
}
print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n",
uNum1,Op,uNum2,erg);
print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n",
uNum1,Op,uNum2,erg);
return erg;
}
/////////////////////////////////////////////////
// CALLBACK
/////////////////////////////////////////////////
LRESULT CALLBACK HexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{ static BOOL isNewNum = FALSE ; char buf[1024];
static char Op = '=' ;
static UINT uNum1, uNum2, uNum ; //1.2.-Zahl
switch ( iMsg ) {
case WM_COMMAND : {
WORD hwp = HIWORD(wParam);
if(hwp)//NOTIFY von Combo oder Edit
{
if(hEdit==(HWND)lParam) // EDIT-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify EN_: 0x%",hwp);
}
if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp);
if(CBN_SELCHANGE==HIWORD(wParam))
{ //etwas wird in Comboliste ausgewählt
memset(buf,0,sizeof(buf));
int index = ComboBox_GetCurSel(hCombo);
ComboBox_GetLBText(hCombo,index,buf);
isNewNum = TRUE; char *p = buf;
while(*p) { // Zeichenweise:
WPARAM wp =(WPARAM)(char)*p++;
SendMessage(hwnd,WM_COMMAND,wp,0);
}
}
if(CBN_EDITCHANGE==HIWORD(wParam))
{ // es wurde was in Combo getippt
ComboBox_SetText(hCombo, "0") ;
isNewNum=TRUE; uNum1=uNum2=0;
err_if(1,helpCBN_EDITCHANGE);
return 0;
}
} break;
}
/////////////////////////////////////////////////////
switch ( LOWORD( wParam ) ) {
default:{
if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit
if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;}
if (uNum2 <= UINT_MAX >> 4 ) {
uNum2 = 16 * uNum2 + wParam
- (isdigit(wParam)?'0':'A'-10) ;
} else MessageBeep( 0 ) ;
show_hex(uNum2, USE_CE|USE_CL);
isNewNum = FALSE ;
} else {
// operation
if ( isNewNum == FALSE ) {
uNum2 = berechne(uNum1, Op, uNum2) ;
show_hex(uNum2, USE_CE);
} Op = LOWORD(wParam); isNewNum = TRUE ;
}
break;}// Ende von default
case VK_ESCAPE: show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break ;
case 1000:show_hex(uNum2/=16, USE_CE);//"BS";
break;
case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+";
isNewNum = TRUE ;
break;
case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-"
isNewNum = TRUE ;
break;
case 1003://zeige MSUM in Combo an: "MR"
show_hex(uNum2=MSUM, USE_CE|USE_CL);
isNewNum = TRUE ;
print_append(hEdit,hEdit,
"MR=%u MR=0x%X\r\n",MSUM,MSUM);
break;
case 1004: MSUM=0;//Clear MSUM: "MC"
break;
case 1005: // Clear Combo:
"AC"
show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break;
case 1006: // Clear Edit:
"EC"
SetWindowText(hEdit, "");
break;
}
break; }
case WM_DESTROY : PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd,iMsg,wParam,lParam);
}
/////////////////////////////////////////////////
void my_button(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
{ if(idRes<=0)idRes=(WORD)*txt;
CreateWindowEx(0,"BUTTON",txt,
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
}
/////////////////////////////////////////////////
HWND my_combo(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
{ HWND
hCombo = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWN,
x,y,cx,cy,hwnd,(HMENU)idRes,GetModuleHandle(0),0);
//RECT rc;
//SendMessage(hCombo,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rc);
return hCombo;
}
/////////////////////////////////////////////////
HWND my_edit(HWND hwnd,int x,int y,int cx,int cy,char *txt,WORD idRes)
{ HWND
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT",txt,
WS_CHILD|WS_VISIBLE|WS_VSCROLL|SS_LEFT
|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN,
x,y,cx,cy,hwnd,(HMENU)(void*)idRes,GetModuleHandle(0),0);
return hEdit;
}
/////////////////////////////////////////////////
//Hauptprogramm
/////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
{
// HINSTANCE hInst = GetModuleHandle(0);
// Nutze die vorhandene Desktop-Klasse
// für die Registrierung:
WNDCLASSEX wc = { 0 };
GetClassInfoEx(hInst,"#32769",&wc);//Desktop-Window
wc.cbSize = sizeof(wc);
wc.lpszClassName = "my_class" ; // eigener Class-Name:
wc.lpfnWndProc = HexCalcProc; // eigene CALLBACK einfügen:
wc.hIcon = ExtractIcon(hInst,"Shell32.dll",12);
if (!RegisterClassEx(&wc)) err_if(1,"RegisterClassEx()");
// HEX-Rechner als Haupt-Fenster:
int X = 100, Y = 100, DX = 204, DY = 380; HWND hwnd =
CreateWindowEx(WS_EX_LEFT,wc.lpszClassName,"HEX-Rechner",
WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME,
X,Y,DX,DY,0,0,hInst,0);
// anzeigen:
ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);
// alle Button's per Programm "createn"
int cx=24, cy=24, dx=26, dy=26, x,y,
x0= 4, y0= 5, //für ComboBox
x1= 4, y1=40, //1.Button-Spalte
x2= 34, y2=40, //2.Button-Spalte
x3= 64, y3=40, //3.Button-Spalte
x4=100, y4=40, //4.Button-Spalte
x5=130, y5=40, //5.Button-Spalte
x6=168, y6=40; //6.Button-Spalte
x=x0; y=y0;
WORD IDC_COMBO = 1000;
hCombo =
my_combo(hwnd,x,y,188,180,"COMBO",IDC_COMBO);
ComboBox_LimitText(hCombo, MAX_COMBO_CHAR);
ComboBox_SetText (hCombo, "0");
// keine Hand-Eingabe, falls
// ComboBox_Enable(hCombo, FALSE);
x=x1; y=y1;
my_button(hwnd,x,y,dx,cy,"F",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"C",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"7",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"4",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"1",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"0",0);
x=x2; y=y2;
my_button(hwnd,x,y,dx,cy,"E",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"B",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"8",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"5",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"2",0);y+=dy;
my_button(hwnd,x,y,2*dx+4,cy,"=",0);
x=x3; y=y3;
my_button(hwnd,x,y,dx,cy,"D",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"A",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"9",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"6",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"3",0);
x=x4; y=y4;
my_button(hwnd,x,y,dx,cy,"%",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"^",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"|",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"+",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"-",0);y+=dy;
my_button(hwnd,x,y,2*dx+4,dy,"BS",1000);
x=x5; y=y5;
my_button(hwnd,x,y,dx,cy,"<",0);y+=dy;
my_button(hwnd,x,y,dx,cy,">",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"&&",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"*",0);y+=dy;
my_button(hwnd,x,y,dx,cy,"/",0);
x=x6; y=y6;
my_button(hwnd,x,y,dx,cy,"M+",1001);y+=dy;
my_button(hwnd,x,y,dx,cy,"M-",1002);y+=dy;
my_button(hwnd,x,y,dx,cy,"MR",1003);y+=dy;
my_button(hwnd,x,y,dx,cy,"MC",1004);y+=dy;
my_button(hwnd,x,y,dx,cy,"AC",1005);y+=dy;
my_button(hwnd,x,y,dx,cy,"EC",1006);y+=dy;
char * pInfo =
"MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n"
"EC löscht diese Anzeige\r\nMR zeigt M an\r\n"
"M+ addiert zu M \r\nM- subtr. von M\r\n";
WORD IDC_EDIT = 2000;
hEdit =
my_edit(hwnd,x0,y+4,188,140,pInfo,IDC_EDIT);
Edit_LimitText(hEdit, MAX_EDIT_CHAR);
// Hauptnachrichtenschleife
BOOL bRet; MSG msg;
while (bRet=GetMessage(&msg, NULL,0,0)){
err_if(-1==bRet,"GetMessage()");
TranslateMessage(&msg);
DispatchMessage (&msg);
} return 0;
}
#include <windows.h>
#include <windowsx.h>
#include <limits.h>
Unten ist bei ??? ein Programmierfehler ...
///////////////////////////////////////////////////////////////////////////
// Globales:
///////////////////////////////////////////////////////////////////////////
typedef struct _DLG_STRUCT {//für das DlgTemplate
WORD buf[2048]; // Speicher für das DlgTemplate-Aufbau
int
idxBuf; // idx, wo weiter geschrieben wird
DLGPROC dlgProc;// Dialog CALLBACK-Funktion !!!
} DLG_STRUCT;
HWND ghwnd[10]; // [0]=aktuelles Window, [1]=Main-Window
WORD IDC_COMBO = 1000;
WORD IDC_EDIT = 2000;
///////////////////////////////////////////////////////////////////////////
// Prototypen:
///////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK wnd_default_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
BOOL
CALLBACK dlg_default_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
#define err_if(e,errStr) if(e) MessageBox(0,(errStr),0,\
MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
///////////////////////////////////////////////////////////////////////////
// dlg_...- Funktionen für "RAM-Dlg-Templates"
///////////////////////////////////////////////////////////////////////////
int nCopyAnsiToWideChar (LPWORD lpWCStr, LPSTR lpAnsiIn)
{ // lediglich eine Hilfsfunktionen:
return MultiByteToWideChar(CP_ACP,0,lpAnsiIn,-1,lpWCStr,256);
}
BOOL dlg_init(DLG_STRUCT *dlgStruct,
WORD x,WORD y,WORD cx,WORD cy,char * szTitelStr)
{
PWORD p = dlgStruct->buf; memset(p,0,sizeof(dlgStruct->buf));
char * font= "Times New Roman"; WORD FontSize = 9;
DWORD lStyle = WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
| DS_MODALFRAME | DS_SETFONT;
DWORD lExStyle = WS_EX_DLGMODALFRAME;
*p++ = 1;
// DlgVer
*p++ = 0xFFFF; // Signature
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = 0; // NumberOfItems, buf[8]=3;
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = 0;
// Menu
*p++ = 0;
// Class
p += nCopyAnsiToWideChar (p,szTitelStr);
if(FontSize < 6) FontSize = 9;
*p++ = FontSize; //z.B. 9
*p++ = FW_DONTCARE;
// Weight
*p++ = MAKEWORD(FALSE,DEFAULT_CHARSET );// italic flag and charset.
if(font)p+=nCopyAnsiToWideChar(p,font);// Face name
else
p+=nCopyAnsiToWideChar(p,"Courier New");
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
///////////////////////////////////////////////////////////////////////////
BOOL dlg_editM(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy,
char * szInitStr, WORD idRes)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | SS_LEFT
| ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_WANTRETURN;
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"EDIT");
if(szInitStr)p += nCopyAnsiToWideChar(p,szInitStr);
else
p += nCopyAnsiToWideChar(p,"");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
///////////////////////////////////////////////////////////////////////////
int dlg_button(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy,
char * szStr, WORD idRes)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle = WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP;
DWORD lExStyle = 0;//WS_EX_CLIENTEDGE;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"BUTTON");
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,"?");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
///////////////////////////////////////////////////////////////////////////
BOOL dlg_combo(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, WORD idRes)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_GROUP|WS_VSCROLL
|CBS_SORT|CBS_AUTOHSCROLL|CBS_DROPDOWN;
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p, "COMBOBOX");
p += nCopyAnsiToWideChar(p,"");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
/*
///////////////////////////////////////////////////////////////////////////
int dlg_but_check(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy,
char * szStr, WORD idRes)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
//DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP| WS_GROUP | BS_AUTORADIOBUTTON ;
DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP | BS_AUTOCHECKBOX;
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"BUTTON");
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,"?");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
*/
///////////////////////////////////////////////////////////////////////////
/*
BOOL dlg_edit(DLG_STRUCT *dlgStruct,
WORD x,WORD y,WORD cx,WORD cy,char * szInitStr,WORD idRes)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle
= WS_VISIBLE|WS_CHILD|WS_TABSTOP|SS_LEFT|ES_AUTOHSCROLL;
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"EDIT");
if(szInitStr)p +=nCopyAnsiToWideChar(p,szInitStr);
else
p +=nCopyAnsiToWideChar(p,"");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
///////////////////////////////////////////////////////////////////////////
int dlg_static(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy, char * szStr)
{
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle = WS_CHILD | WS_VISIBLE | SS_LEFT;
DWORD lExStyle = 0;//WS_EX_CLIENTEDGE;
WORD idRes = 0xffff;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"STATIC");
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,"");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
///////////////////////////////////////////////////////////////////////////
int dlg_black(DLG_STRUCT *dlgStruct, WORD x, WORD y, WORD cx, WORD cy)
{// schwarzes Rechteck
PWORD p = &dlgStruct->buf[dlgStruct->idxBuf]; dlgStruct->buf[8]++;
DWORD lStyle = WS_CHILD | WS_VISIBLE |SS_BLACKRECT| SS_LEFT;
DWORD lExStyle = WS_EX_CLIENTEDGE;
WORD idRes = 0xffff;
*p++ = 0; *p++ = 0; // LO-HIWORD (lHelpID)
*p++ = LOWORD(lExStyle);*p++ = HIWORD(lExStyle);
*p++ = LOWORD(lStyle); *p++ = HIWORD(lStyle);
*p++ = x; *p++ = y; *p++ = cx; *p++ = cy;
*p++ = idRes; // LOWORD (Control ID)
*p++ = 0;
// HOWORD (Control ID)
p += nCopyAnsiToWideChar(p,"STATIC");
p += nCopyAnsiToWideChar(p,"");
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
dlgStruct->idxBuf = p-dlgStruct->buf; return TRUE;
}
*/
/////////////////////////////////////////////////
// Hex-Rechner: globales
/////////////////////////////////////////////////
const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText()
const UINT MAX_COMBO_CHAR =
8;//ComboBox_LimitText()
const UINT USE_CE = 1; // Ziel Combo-Edit
const UINT USE_CL = 2; // Ziel Combo-Liste
const UINT USE_EM = 4; // Ziel Edit-Multiline
// UINT (M)em(SUM)men-Speicher MSUM
// MSUM hält den Summenwert ('M+','M-')
//'MR' für Anzeige, 'MC' setzt MSUM=0
UINT MSUM;
// Verwendet werden hCombo, hEdit dadurch entfällt:
// HWND hCombo = GetDlgItem(hwnd,IDC_COMBO);
// HWND hEdit = GetDlgItem(hwnd,IDC_EDIT);
HWND hCombo; //hCombo anstelle von IDC_COMBO
HWND hEdit; //hEdit anstelle von IDC_EDIT
/////////////////////////////////////////////////
// print_append() kann aus den hSrc-Fenster Text holen
// und gemäss "printf-ähnlichem" Formats Text "anhängen"
// und den gesamten Text in das hDst-Fenster schreiben.
// Dadurch entsteht ein "append" von Text
//
// Anstelle der Aufruffolge:
//
print_append(hEdit,hEdit, "\r\n");
//
print_append(hEdit,hEdit, "%u ", u1);
//
print_append(hEdit,hEdit, "%u ", u2);
//
// ist günstiger:
//
print_append(hEdit,hEdit,"\r\n%u %u ",u1,u2);
/////////////////////////////////////////////////
int CDECL print_append(HWND hDst, HWND hSrc, LPTSTR pFormat, ...)
{ static TCHAR Buf[MAX_EDIT_CHAR]; //MAX_EDIT_CHAR etwa 2048
err_if(!hDst,"print_append(): hDst?");
memset(Buf,0,sizeof(Buf)); TCHAR *pBuf = Buf;
va_list argList;
va_start( argList, pFormat ) ;
if(hSrc) // hole Text aus hSrc
pBuf += GetWindowText(hSrc,Buf,sizeof(Buf));
// bei Speichermangel pBuf auf Buf[0]
if(sizeof(Buf)-(pBuf-Buf)<128) pBuf = Buf;
pBuf += wvsprintf( pBuf, pFormat, argList ) ;
va_end( argList ) ;
// schreibe erweiterten Text in hDest
SetWindowText( hDst, Buf );
return (pBuf-Buf);
}
/////////////////////////////////////////////////
// show_hex() schreibt uNum in das ziel.
// Beispiel: show_hex(10,USE_CE);
// Ziel kann sein (USE_CE|USE_CL|USE_EM)
/////////////////////////////////////////////////
void show_hex(UINT uNum, int ziel )
{ char buf[256]; int radix = 16;
//global sind hCombo, hEdit
//schreibe uNum als hex-String (basis 16) in buf
strupr( ltoa(uNum, buf, radix) );
//Ausgabe von buf in ziel
if (USE_CE & ziel) {//in Combo-Liste eintragen:
ComboBox_SetText(hCombo, buf ) ;
}
if (USE_CL & ziel) { //in Combo-Liste eintragen:
if ( ComboBox_GetCount(hCombo) >= 30)
ComboBox_DeleteString(hCombo,30);
ComboBox_InsertString(hCombo, 0, buf );
}
if (USE_EM & ziel) { //in Edit-Journal eintragen:
print_append(hEdit,hEdit,"hex=0x%08x\r\n",uNum);
}
}
/////////////////////////////////////////////////
// Beispiel: UINT erg = berechne(6,'+',4);
// Schreibt auch in hEdit
/////////////////////////////////////////////////
UINT berechne(UINT uNum1, char Op, UINT uNum2 )
{ UINT erg;
switch ( Op ) {
default : erg = 0; return erg;
case '=' : erg = uNum2 ; return erg;
case '+' : erg = uNum1 + uNum2 ; break;
case '-' : erg = uNum1 - uNum2 ; break;
case '*' : erg = uNum1 * uNum2 ; break;
case '&' : erg = uNum1 & uNum2 ; break;
case '|' : erg = uNum1 | uNum2 ; break;
case '^' : erg = uNum1 ^ uNum2 ; break;
case '<' : erg = uNum1 << uNum2 ; break;
case '>' : erg = uNum1 >> uNum2 ; break;
case '/' : erg = uNum2?uNum1/uNum2:UINT_MAX ;
break;
case '%' : erg = uNum2?uNum1%uNum2:UINT_MAX ;
break;
}
print_append(hEdit,hEdit,"(%u %c %u )= %u\r\n",
uNum1,Op,uNum2,erg);
print_append(hEdit,hEdit,"(0x%X %c 0x%X )= 0x%X\r\n",
uNum1,Op,uNum2,erg);
return erg;
}
/////////////////////////////////////////////////
// CALLBACK
/////////////////////////////////////////////////
BOOL CALLBACK HexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{ static BOOL isNewNum = FALSE ; char buf[1024];
static char Op = '=' ;
static UINT uNum1, uNum2, uNum ; //1.2.-Zahl
switch ( iMsg ) {
case WM_INITDIALOG: {
if(!hCombo) hCombo = GetDlgItem(hwnd,IDC_COMBO);
if(!hEdit) hEdit
= GetDlgItem(hwnd,IDC_EDIT);
ComboBox_LimitText(hCombo,MAX_COMBO_CHAR);// 8
ComboBox_SetText (hCombo, "0");
char * pInfoText =
"MC löscht M Speicher\r\nAC löscht Combo-Anzeige\r\n"
"EC löscht diese Anzeige\r\nMR zeigt M an\r\n"
"M+ addiert zu M \r\nM- subtr. von M\r\n";
Edit_LimitText(hEdit,MAX_EDIT_CHAR);//=2048
Edit_SetText(hEdit, pInfoText );
break; }
case WM_COMMAND : {
WORD hwp = HIWORD(wParam);
if(hwp)//NOTIFY von Combo oder Edit
{
if(hEdit==(HWND)lParam) // EDIT-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify EN_: 0x%",hwp);
}
if(hCombo==(HWND)lParam) // COMBOBOX-NOTIFY
{ //nur für Notify-Tests (Titelzeile):
print_append(hwnd,0,"Notify CBN_: 0x%04x",hwp);
if(CBN_SELCHANGE==HIWORD(wParam))
{ //etwas wird in Comboliste ausgewählt
memset(buf,0,sizeof(buf));
int index = ComboBox_GetCurSel(hCombo);
ComboBox_GetLBText(hCombo,index,buf);
isNewNum = TRUE; char *p = buf;
while(*p) { // Zeichenweise:
WPARAM wp =(WPARAM)(char)*p++;
SendMessage(hwnd,WM_COMMAND,wp,0);
}
}
if(CBN_EDITCHANGE==HIWORD(wParam))
{ // es wurde was in Combo getippt
ComboBox_SetText(hCombo, "0") ;
isNewNum=TRUE; uNum1=uNum2=0;
char * helpCBN_EDITCHANGE =
"\r\nWenn Sie die Texteingabe in die Combo-Edit-Zeile"
"\r\nProgrammieren möchten, so können die"
"\r\nCombobox-Notify-Nachrichten CBN_ ..."
"\r\nverwendet werden, die kommen unter:"
"\r\n\r\nWM_COMMAND:"
"\r\n if(HIWORD(wParam))"
"\r\n if(hCombo==(HWND)lParam)"
"\r\n if(CBN_EDITCHANGE==HIWORD(wParam))"
"\r\n { // es wurde was in Combo getippt"
"\r\n\tmemset(buf,0,sizeof(buf));"
"\r\n\tGetWindowText(hCombo,buf,sizeof(buf));"
"\r\n\tchar *p = buf; UINT uNum=0;"
"\r\n\twhile(*p)"
"\r\n\t\{ // Zahl zeichenweise:"
"\r\n\t\tchar asc = *p; p++;"
"\r\n\t\terr_if(!isxdigit(asc),\"Bitte nur Hex-Digit!\")"
"\r\n\t\tuNum = 16 * uNum + asc - (isdigit(asc)?\'0\':\'A\'-10) ;"
"\r\n\t} uNum2 = ...; isNewNum = ... ; \r\n}";
MessageBox(0,helpCBN_EDITCHANGE,0,MB_OK|MB_ICONSTOP);
return TRUE;
}
} break;
} // Ende von if(hwp)
/////////////////////////////////////////////////////
switch ( LOWORD( wParam ) ) {
default:{
if ( isxdigit( LOWORD ( wParam ) ) ) { // hex digit
if (isNewNum==TRUE) {uNum1=uNum2; uNum2=0;}
if (uNum2 <= UINT_MAX >> 4 ) {
uNum2 = 16 * uNum2 + wParam
- (isdigit(wParam)?'0':'A'-10) ;
} else MessageBeep( 0 ) ;
show_hex(uNum2, USE_CE|USE_CL);
isNewNum = FALSE ;
} else {
// operation
if ( isNewNum == FALSE ) {
uNum2 = berechne(uNum1, Op, uNum2) ;
show_hex(uNum2, USE_CE);
} Op = LOWORD(wParam); isNewNum = TRUE ;
}
break;}// Ende von default
case IDOK: SendMessage(hwnd,WM_CLOSE,0,0);return TRUE;
case IDHELP:
MessageBox(hwnd,
"Quelltext-Beschreibung ist im Skript"
"\r\nim Kapitel über Dialoge ...",
"Hilfetext",MB_OK);
break ;
case VK_ESCAPE: show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break ;
case 1000:show_hex(uNum2/=16, USE_CE);//"BS";
break;
case 1001:MSUM=berechne(MSUM,'+',uNum2);//"M+";
isNewNum = TRUE ;
break;
case 1002:MSUM=berechne(MSUM,'-',uNum2);//"M-"
isNewNum = TRUE ;
break;
case 1003://zeige MSUM in Combo an: "MR"
show_hex(uNum2=MSUM, USE_CE|USE_CL);
isNewNum = TRUE ;
print_append(hEdit,hEdit,
"MR=%u MR=0x%X\r\n",MSUM,MSUM);
break;
case 1004: MSUM=0;//Clear MSUM: "MC"
break;
case 1005: // Clear Combo:
"AC"
show_hex(uNum2=0, USE_CE);
isNewNum = TRUE ;
break;
case 1006: // Clear Edit:
"EC"
SetWindowText(hEdit, "");
break;
}
break; }
case WM_ACTIVATE:
if ( WA_INACTIVE == LOWORD(wParam) ) {
ghwnd[0] = NULL;//becoming inactive
} else {ghwnd[0] = hwnd; }//becoming active
break;
case WM_CLOSE: PostQuitMessage(0); //beende modeless
break;
} return FALSE;
}
void hex_rechner_indirect() {
HWND ghwnd =0; // keins bekannt
// Ressource für CreateDialogIndirect()
// des HEX-Rechners zusammenbauen:
int X = 100, Y = 100, DX = 100, DY = 200;
// alle Button's per Programm "createn"
int cx=12, cy=12, dx=13, dy=13, x,y,
x0= 2, y0= 4, //für ComboBox
x1= 2, y1=20, //1.Button-Spalte
x2= 17, y2=20, //2.Button-Spalte
x3= 32, y3=20, //3.Button-Spalte
x4= 50, y4=20, //4.Button-Spalte
x5= 65, y5=20, //5.Button-Spalte
x6= 84, y6=20; //6.Button-Spalte
//////////////////
DLG_STRUCT ds; ds.dlgProc = HexCalcProc;
///////////////////
// in ds werden die Controls zusammengebaut
x=x0; y=y0;
dlg_init (&ds,X,Y,DX,DY, "HEX_RECHNER");
dlg_combo (&ds, x,y,94,90,IDC_COMBO);
x=x1; y=y1;
dlg_button(&ds,x,y,dx,cy,"F",'F');y+=dy;
dlg_button(&ds,x,y,dx,cy,"C",'C');y+=dy;
dlg_button(&ds,x,y,dx,cy,"7",'7');y+=dy;
dlg_button(&ds,x,y,dx,cy,"4",'4');y+=dy;
dlg_button(&ds,x,y,dx,cy,"1",'1');y+=dy;
dlg_button(&ds,x,y,dx,cy,"0",'0');
x=x2; y=y2;
dlg_button(&ds,x,y,dx,cy,"E",'E');y+=dy;
dlg_button(&ds,x,y,dx,cy,"B",'B');y+=dy;
dlg_button(&ds,x,y,dx,cy,"8",'8');y+=dy;
dlg_button(&ds,x,y,dx,cy,"5",'5');y+=dy;
dlg_button(&ds,x,y,dx,cy,"2",'2');y+=dy;
dlg_button(&ds,x,y,2*dx+2,cy,"=",'=');
x=x3; y=y3;
dlg_button(&ds,x,y,dx,cy,"D",'D');y+=dy;
dlg_button(&ds,x,y,dx,cy,"A",'A');y+=dy;
dlg_button(&ds,x,y,dx,cy,"9",'9');y+=dy;
dlg_button(&ds,x,y,dx,cy,"6",'6');y+=dy;
dlg_button(&ds,x,y,dx,cy,"3",'3');
x=x4; y=y4;
dlg_button(&ds,x,y,dx,cy,"%",'%');y+=dy;
dlg_button(&ds,x,y,dx,cy,"^",'^');y+=dy;
dlg_button(&ds,x,y,dx,cy,"|",'|');y+=dy;
dlg_button(&ds,x,y,dx,cy,"+",'+');y+=dy;
dlg_button(&ds,x,y,dx,cy,"-",'-');y+=dy;
dlg_button(&ds,x,y,2*dx+2,cy,"BS",1000);
x=x5; y=y5;
dlg_button(&ds,x,y,dx,cy,"<",'<');y+=dy;
dlg_button(&ds,x,y,dx,cy,">",'>');y+=dy;
dlg_button(&ds,x,y,dx,cy,"&&",'&&');y+=dy;
???
Hier ist ein Programmierfehler! Bei "&&",'&&' ist
"&&" richtig aber das nochfolgende '&&' falsch. Warum?
dlg_button(&ds,x,y,dx,cy,"*",'*');y+=dy;
dlg_button(&ds,x,y,dx,cy,"/",'/');
x=x6; y=y6;
dlg_button(&ds,x,y,dx,cy,"M+",1001);y+=dy;
dlg_button(&ds,x,y,dx,cy,"M-",1002);y+=dy;
dlg_button(&ds,x,y,dx,cy,"MR",1003);y+=dy;
dlg_button(&ds,x,y,dx,cy,"MC",1004);y+=dy;
dlg_button(&ds,x,y,dx,cy,"AC",1005);y+=dy;
dlg_button(&ds,x,y,dx,cy,"EC",1006);y+=dy;
dlg_editM(&ds,x0,y+4,95,70,
"",
IDC_EDIT);
dlg_button(&ds, x0,DY-27,43,dy," Beenden ",IDOK);
dlg_button(&ds,DX/2,DY-27,43,dy,"Quelltext",IDHELP);
/////////////////////////////////////////////////
// jetzt kommt der spannende Create-Moment ...
DialogBoxIndirect(GetModuleHandle(0),
(LPDLGTEMPLATE)ds.buf,ghwnd,(DLGPROC)ds.dlgProc);
}
//Hauptprogramm
int APIENTRY WinMain
(HINSTANCE hInst,HINSTANCE hiPr,PSTR pCmd,int iShow)
{ hex_rechner_indirect(); return 0;
}
#include <windows.h>
#include <windowsx.h>
///////////////////////////////////////////////////////////
// class my_button zum
// Erzeugen von Buttons
///////////////////////////////////////////////////////////
class my_button { HWND _hBut,_hParent;
public:
my_button(HWND hParent,WORD idRes,LPSTR pText,
int x,int y,int dx,int dy)
{
_hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON",
pText,WS_VISIBLE | WS_CHILD, x,y,dx,dy,
hParent,(HMENU)idRes,GetModuleHandle(0),0);
_hParent = hParent;
}
my_button(HWND hParent, char ch,
int x,int y,int dx,int dy)
{ char txt[2]; txt[1]='\0'; txt[0] = ch;
WORD idRes = MAKEWORD(txt[0],txt[1]);
_hBut = CreateWindowEx(WS_EX_LEFT, "BUTTON",
txt,WS_VISIBLE | WS_CHILD, x,y,dx,dy,
hParent,(HMENU)idRes,GetModuleHandle(0),0);
_hParent = hParent;
}
~my_button(void){ DestroyWindow(_hBut); }
};
///////////////////////////////////////////////////////////
// class my_edit zum
// Erzeugen von Edit-Fenstern
///////////////////////////////////////////////////////////
class my_edit { HWND _hEdt,_hParent;
public:
my_edit(HWND hParent,WORD idRes,LPSTR pText,
int x,int y,int dx,int dy)
{
_hEdt = CreateWindowEx( WS_EX_CLIENTEDGE,
"EDIT",pText, WS_VISIBLE | WS_CHILD, x,y,dx,dy,
hParent, (HMENU)idRes, GetModuleHandle(0),0);
_hParent = hParent;
}
my_edit(HWND hParent,WORD idRes,LPSTR pText,
int x,int y,int dx,int dy,BOOL multiline)
{ if(multiline){
_hEdt = CreateWindowEx( WS_EX_CLIENTEDGE,
"EDIT", pText,
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL
| ES_MULTILINE | ES_AUTOVSCROLL | ES_OEMCONVERT,
x,y,dx,dy,hParent,(HMENU)idRes,GetModuleHandle(0),0);
_hParent = hParent;
} else my_edit(hParent, idRes,pText,x,y,dx,dy);
}
HWND get_hwnd(void) { return _hEdt; }
~my_edit(void){ DestroyWindow(_hEdt); }
};
///////////////////////////////////////////////////////////
// class my_combo zum
// Erzeugen von ComboBox-Controls
///////////////////////////////////////////////////////////
class my_combo { HWND _hCombo,_hParent;
public:
my_combo(HWND hParent,WORD idRes,int x,int y,int dx,int dy)
{
_hCombo = CreateWindowEx( WS_EX_CLIENTEDGE,"COMBOBOX","",
WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_BORDER
|CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS
,x,y,dx,dy,hParent,(HMENU)idRes,GetModuleHandle(0),0);
//EnableWindow(_hCombo,TRUE);
_hParent = hParent;
}
HWND get_hwnd(void) { return _hCombo; }
BOOL set_text( LPSTR lpsz ) {
return SetWindowText(_hCombo,lpsz);
}
BOOL get_text( LPSTR Buf, int sizBuf ) {
return GetWindowText(_hCombo,Buf,sizBuf);
}
int add_text( LPSTR lpsz ) {
return ((int)(DWORD)SendMessage(
_hCombo,CB_ADDSTRING,0L,(LPARAM)(LPCTSTR)(lpsz)));
}
int get_text(int idx, LPSTR Buf, int sizBuf ) {
return ((int)(DWORD)SendMessage(
_hCombo,CB_GETLBTEXT,(WPARAM)idx,(LPARAM)(LPCTSTR)Buf));
}
~my_combo(void){ DestroyWindow(_hCombo); }
};
////////////////////////////////////////////////////////
#define IDC_EDIT0 1000
#define IDC_EDIT1 1001
////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc( HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam )
{ int i;
static my_button * pBut[256];
static my_edit
* pEdt[2];
static my_combo * pCombo[1];
switch ( iMsg ) {
case WM_CREATE : {
int x,y, dx=19, dy=19;
x=2; y=10;
pEdt[0]
= new my_edit(hwnd,IDC_EDIT0,"0",x,y,100,dy);
pEdt[1]
= new my_edit(hwnd,IDC_EDIT1,"Append:",x,y+150,100,100,TRUE);
pCombo[0] = new my_combo(hwnd,4711,x,300,100,100);
pCombo[0]->add_text("2");
pCombo[0]->add_text("1");
pCombo[0]->add_text("3");
pCombo[0]->set_text("Hallo ComboBox");
x=2; y=30;
pBut['F'] = new my_button(hwnd,'F', x,y,dx,dy);y+=20;
pBut['C'] = new my_button(hwnd,'C', x,y,dx,dy);y+=20;
pBut['7'] = new my_button(hwnd,'7', x,y,dx,dy);y+=20;
pBut['4'] = new my_button(hwnd,'4', x,y,dx,dy);y+=20;
pBut['1'] = new my_button(hwnd,'1', x,y,dx,dy);y+=20;
pBut['0'] = new my_button(hwnd,'0', x,y,dx,dy);y+=20;
x=32; y=30;
pBut['E'] = new my_button(hwnd,'E', x,y,dx,dy);y+=20;
pBut['B'] = new my_button(hwnd,'B', x,y,dx,dy);y+=20;
pBut['8'] = new my_button(hwnd,'8', x,y,dx,dy);y+=20;
pBut['5'] = new my_button(hwnd,'5', x,y,dx,dy);y+=20;
pBut['2'] = new my_button(hwnd,'2', x,y,dx,dy);y+=20;
pBut['='] = new my_button(hwnd,'=', x,y,dx+dx+1,dy);
x=52; y=30;
pBut['D'] = new my_button(hwnd,'D', x,y,dx,dy);y+=20;
pBut['A'] = new my_button(hwnd,'A', x,y,dx,dy);y+=20;
pBut['9'] = new my_button(hwnd,'9', x,y,dx,dy);y+=20;
pBut['6'] = new my_button(hwnd,'6', x,y,dx,dy);y+=20;
pBut['3'] = new my_button(hwnd,'3', x,y,dx,dy);y+=20;
// ...
x=72; y=30;
pBut['?'] = new my_button(hwnd,'?', x,y,dx,dy);y+=20;
break ; }
case WM_COMMAND: { // keine Notify-Nachrichten:
if(HIWORD(wParam)) break;
// aber Button- und Menu-Nachrichten in LOWORD(wParam):
int idButton = LOWORD(wParam);
////////////////////////////////////////////////////
// hier sind die Klick-Nachrichten zu verarbeiten
////////////////////////////////////////////////////
// obere einzeilige hEdt0
char buf[256];
HWND hEdt0 = pEdt[0]->get_hwnd();
// schreibe formatiert in buf:
int len0 = wsprintf(buf,"Button:%i",idButton);
// gib buf in hEdt0 aus
Edit_SetText( hEdt0, buf);
//////////////////////////////////////////
// untere mehrzeilige hEdt1
int cBuf = 4000; char pBuf [ 4000 ];
HWND hEdt1 = pEdt[1]->get_hwnd();
// tue Text aus hEdt1 in pBuf
Edit_GetText( hEdt1, pBuf, cBuf );
int len1 = Edit_GetTextLength(hEdt1);
if( cBuf > len0 + len1 ) {
strcat( pBuf, "\r\n");
strcat( pBuf, buf);
} else { // bei Überlauf
strcpy( pBuf, buf);
} Edit_SetText( hEdt1, pBuf);
Edit_Scroll(hEdt1, cBuf,0);
break; }
case WM_DESTROY : {
int anz = sizeof(pBut)/sizeof(pBut[0]);
for( i=0; i<anz; i++)
if(pBut[i]) delete pBut[i];
PostQuitMessage( 0 ) ;
break; }
} // ende von switch ( iMsg )
return DefWindowProc( hwnd, iMsg, wParam, lParam ) ;
}
BOOL myDlgBox( HWND hWnd , UINT iMsg, WPARAM wParam, LPARAM lParam ) {
switch ( iMsg ) {
case WM_INITDIALOG :
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case IDOK :
case IDCANCEL :
SendMessage( hWnd , WM_CLOSE, LOWORD( wParam ), 0 );
return TRUE;
}
case WM_CLOSE : EndDialog ( hWnd, wParam ); //beendet den modalen Dialog
break; //return TRUE;
}
return FALSE;
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int iShowMain )
{ WNDCLASSEX wc = { 0 } ; HWND hwndMain ; MSG msg ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.hInstance
= GetModuleHandle(0);
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "my_dlgclass" ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
hwndMain = CreateWindowEx(WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE,
"my_dlgclass", "Hex-Taschenrechner",
WS_CAPTION|WS_VISIBLE|WS_SYSMENU,
120,120,120,420, 0,0,GetModuleHandle(0),0);
ShowWindow ( hwndMain, iShowMain ) ;
UpdateWindow( hwndMain ) ;
while ( GetMessage ( &msg,NULL,0,0)){
TranslateMessage( &msg );
DispatchMessage ( &msg );
} return msg.wParam ;
}
6.Praktikum
1. Eine Win 32 - Applikation ist als neues Projekt zu schreiben. Die Anwendung soll als "Taskbar-Icon" starten.
Hierzu wird
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
verwendet ( NIM_... Nachrichten ). Das beigelegte Programm soll auf "richtige" Ressourcen Icon, Menu und ein
weiterer Dialog umgestellt werden. Erstellen Sie mit dem Resourcen-Workshop-Tool ein eigenes Icon IDI_ICON
und ein Menu IDR_TRAYMENU und ändern Sie das Rahmenprogramm an den passenden Stellen.
2. Es ist ein Standard-File-Open-Dialog mit GetOpenFileName(&ofn)) zu verwenden. Das angefuegte Muster hat
"Schwachstellen" ( auch logische! ). Diese sind zu beseitigen. Es ist eine "bessere" Routine zu schreiben.
3. Aus der eigenen Applikation sind *.exe-Programme ( wie z.B. notepad.exe ) zu starten.
4. Mit dem Resourcen-Workshop-Tool sind aus einem *.exe-File die Resourcen zu extrahieren und anzusehen (
verwenden Sie z.B. notepad.exe, comdlg32.dll, shell32.dll )
5. Bei modalen Dialogen soll je Dialog bei Windows ein 4 Byte Wert ( Zeiger auf Instanz ) hinterlegt werden. Hierzu
dienen die ...param()-Funktionen. Bitte testen.
6. Im Client-Bereich des Hauptfenster ist ein anderes Icon anzuzeigen und mit der Maus zu bewegen. Um mehrere
Icons mit der Maus zu steuern, soll eine Klasse bIcon geschrieben werden.
7. OPTIONAL:
Es ist mit der Windows-Klasse "BUTTON" eine C++-Klasse zu erstellen, die einen Button erzeugt und zu
verschieben gestattet.
8. OPTIONAL:
Das Icon soll in der Titelzeile Hauptfenster angezeigt werden. Im *cpp-Quelltext wird die String-Resource mit
WNDCLASS wndclass.hIcon = LoadIcon ( hInstance,MAKEINTRESOURCE(IDI_MAIN));
geladen. Achten Sie bitte darauf, dass auch das "kleine" Icon in WNDCLASS gesetzt wird.
StandardFile-Open-Dialog
Es ist ein File-Open-Dialog gemaess dem angefuegten Muster eines Standard-Dialoges zu verwenden.
#include <commdlg.h>
// includes common dialog functionality
char * get_Open_File_Name ( HWND hwnd, CHAR * pFilt, CHAR * pTitle ) {
??? char buf[MAX_PATH] ; buf[0] = '\0' ;
OPENFILENAME ofn = { 0 } ; //ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize
= sizeof( OPENFILENAME );
ofn.hwndOwner
= hwnd ;
ofn.hInstance
= GetModuleHandle( NULL );
ofn.lpstrTitle
= pTitle ;
ofn.lpstrFile
= buf ;
ofn.nMaxFile
= sizeof( buf ) ;
ofn.lpstrFilter
= (pFilt) ? pFilt : "Alle Files (*.*)\000*.*\000" ;
ofn.lpstrDefExt
= "*" ;
ofn.nFilterIndex = 1L ;
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn)) return buf;//(char*)ofn.lpstrFile;
else return NULL ;
}
Achtung! Der String pFilt enthält Stringpaare mit \000 als Trennzeichen. Im Speicher ist pFilt durch \000\000 beendet. Der
Aufruf von get_Open_File_Name() liefert den ausgewählten File-Namen.
char * pFilNam = get_Open_File_Name( hwnd,
"C-Dateien (*.c;*.cpp;)\000*.c;*.cpp;\000"
"H-Dateien (*.h;*.hpp;)\000*.h;*.hpp;\000"
"Text-Dateien (*.txt)\000*.txt\000"
"Alle Files (*.*)\000*.*\000",
"Titel von get_Open_File_Name" );
Programme starten
Um z.B. notepad.exe mit dem ausgewählten File zu starten kann
//Hinweis:
case IDC_...: //Edit-Button
strcpy( buf, "notepad " ) ;
strcat( buf, pPfad ) ;
WinExec( buf, SW_SHOW ) ;
break ;
..param()-Funktionen
Bei modalen Dialogen soll ( bei Windows ) je Dialog ein 4 Byte Wert ( Zeiger auf Instanz ) hinterlegt werden.
LONG set_user_long (HWND hwnd, LPARAM val) {
return SetWindowLong(hwnd,GWL_USERDATA,(LONG)val);
}
LONG get_user_long (HWND hwnd) {
return GetWindowLong(hwnd,GWL_USERDATA);
}
Wird zum Aufruf des modalen Dialoges
ret = DialogBoxParam( GetModuleHandle(NULL),
MAKEINTRESOURCE(idDlg),hwnd,
(DLGPROC) dlgProc, (LPARAM) this);
}
( nicht DialogBox() ) verwendet, so wird der this-Zeiger bei case WM_INITDIALOG an die CALLBACK-Funktion
durchgereicht und kann mit set_user_long() bei Windows hinterlegt werden.
Hierdurch können Dialog-Daten zwischen CALLBACK-Funktion und Aufruf-Ebene übergeben werden. Dies ist zu testen
//ACHTUNG! NICHT GESTESTET
class bDLG { public:
bDLG (HWND hwnd, int
bDLG (HWND hwnd, int
HWND _hwnd; CREATESTRUCT
void * _buf;
void * _bufOld;
int
_bufSize;
int _idDlg, _ret;
} ;
...
idDlg, DLGPROC dlgProc);
idDlg, DLGPROC dlgProc, void * buf, int sizebuf);
_cs;
bDLG::bDLG(HWND hwnd, int idDlg, DLGPROC dlgProc){
_bufSize = 0;
_buf
= NULL;
_idDlg
= idDlg;
_hwnd
= hwnd;
_ret
= DialogBoxParam( GetModuleHandle(NULL),
MAKEINTRESOURCE(idDlg),hwnd,
(DLGPROC) dlgProc, (LPARAM) this);
}
bDLG::bDLG(HWND hwnd, int idDlg, DLGPROC dlgProc, void * buf, int sizebuf){
_bufSize = sizebuf;
_buf
= buf;
_idDlg
= idDlg;
_hwnd
= hwnd;
_ret
= DialogBoxParam( GetModuleHandle(NULL),
MAKEINTRESOURCE(idDlg),hwnd,
(DLGPROC) dlgProc, (LPARAM) this);
}
optional: Button ( dynamisch)
Es ist mit der Windows-Klasse "BUTTON" eine C++-Klasse class bBUTTON { ...} mit Hilfe von CreateWindow() zu erstellen,
die einen Button erzeugt und mit SetWindowPos() positioniert. Dieser Button soll mit der Maus verschiebbar sein.
optional: C++-bBUTTON-Klasse
//Aufruf
:bBUTTON pB = new bBUTTON(hwnd,"Hallo",100,10,80,20);
//Zeichnen :
pB->drawButton(LOWORD(lParam),HIWORD(lParam));
//Freigeben:delete pB;
#include <windows.h>
class bBUTTON { public:
bBUTTON(HWND hParent, LPSTR pText, int x, int y, int dx, int dy );
//??virtual void setPos( x, y);
virtual void drawButton( void);
int _x, _y, _dx, _dy; HWND _hButton, _hParent; LPSTR _pText;
};
bBUTTON::bBUTTON(HWND hParent, LPSTR pText, int x, int y, int dx, int dy ){
_hParent = hParent; _pText = pText;
_x = x; _y = y;
_dx = dx; _dy = dy;
_hButton = CreateWindow( "BUTTON",_pText,WS_VISIBLE | WS_CHILD,
_x,_y,_dx,_dy,hParent,NULL,GetModuleHandle(NULL),NULL);
}
void bBUTTON::drawButton( void ){
SetWindowPos(_hButton,HWND_TOP,_x,_y,_dx,_dy,SWP_SHOWWINDOW);
}
optional: Icon
Einem neuen Projekt ( "Hallo Welt" ) wird nun ein Resourcenskript hinzugefügt. Die resource.rc - Erstellung mit dem
Resourcen-Workshop-Tool ( hier Icon ) hat etwa folgende Schritte:
Datei
Neu
Resourcenskript
auf resource.rc rechte Maustaste und
einfügen...
Icon neu
Das Icon soll den Identifizierer IDI_MAIN erhalten ( Doppelklick und Eigenschaften ).
resource.h und resource.rc sind dem Projekt hinzuzufügen.
Zum Laden von Resourcen werden im *.cpp-File sogenannte Load-Funktionen benötigt. Load-Funktionen haben einen
hInstance-Parameter.
HINSTANCE hInstance = GetModuleHandle( NULL );
//oder durch
//HINSTANCE hInstance = (HINSTANCE) GetWindowLong( hwnd, GWL_HINSTANCE );
//statisch in Windows-Klasse eintragen z.B. durch
WNDCLASS wndclass.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN) );
//dynamisch in Windows-Fenster-Klasse eintragen z.B. durch
HICON hIconOld = (HICON)SetClassLong(hwnd,GCL_HICONSM,
(LONG)LoadIcon(NULL,IDI_HAND));
optional: Icon (dynamisch)
Um mehrere Icons mit der Maus zu steuern, soll eine Klasse bIcon geschrieben werden:
●
●
●
●
●
●
Der Konstruktor z.B. bIcon * pIcon = new bIcon(10,20,IDI_MAIN);
❍ erzeugt die Instanz
❍ läd das IDI_MAIN - Icon
❍ speichert die x,y - Positionswerte
Um auch verfügbares Icons des Systems ( z.B. IDI_ASTERISK ) verwenden zu können ist
LoadIcon(NULL,MAKEINTRESOURCE(idIcon)) zu verwenden. Der Konstruktor kann gemäß bIcon(int x, int y,
LPCTSTR idIcon ) überladen werden.
pIcon->drawIcon(hDC) zeichnet das Icon, wenn durch pIcon->setOn() das Zeichenflag gesetzt ist.
pIcon->setOn() bzw. pIcon->setOff() setzen die Zeichenflags auf TRUE bzw. FALSE.
Durch delete pIcon; wird die Klasse freigegeben
Um bei WM_PAINT einen eingeschränktes Rechteck neu zu zeichnen kann
x1=x; x=dx=LOWORD(lParam); x0=x1+x; if(x < x1)dx=x1;
y1=y; y=dy=HIWORD(lParam); y0=y1+y; if(y < y1)dy=y1;
SetRect( & rc, x0-dx,y0-dy, dx+32,dy+32 );
InvalidateRect(hwnd, & rc, TRUE);
durchdacht und berücksichtigt werden
optional: C++-bIcon-Klasse
//bIcon pI = new bIcon(10,10,IDI_MAIN); pIcon->setOn();
//
pI->setOn(); pI->setOff();
//
pI->setPos(LOWORD(lParam),HIWORD(lParam));
//
pI->drawIcon(hDC);
//delete pI;
//InvalidateRect(hwnd,NULL,TRUE);
#include <windows.h>
class bIcon { public:
bIcon(int x, int y, WORD idIcon );
virtual void drawIcon(HDC hDC );
virtual void setPos( int x, int y);
virtual void setOn(void);
virtual void setOff(void);
HICON hIcon;
int
_x, _y;
BOOL fDraw;
};
bIcon::bIcon(int x, int y, WORD idIcon){ //User
hIcon=LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(idIcon));
setPos ( x, y ); setOn();
}
void bIcon::setOn (void){ fDraw=TRUE;
}
void bIcon::setOff(void){ fDraw=FALSE;
}
void bIcon::setPos ( int x, int y ){ _x=x; _y=y;
}
void bIcon::drawIcon(HDC hDC ){
if(fDraw)
DrawIconEx(hDC,_x,_y,hIcon,32,32,0,NULL,DI_NORMAL);
}
Die mittige Zentrierung etwa wie folgt:
RECT rc ;
GetWindowRect ( hwnd , & rc ) ;
rc.left = ( GetSystemMetrics ( SM_CXSCREEN ) - rc.right + rc.left ) / 2 ;
rc.top = ( GetSystemMetrics ( SM_CYSCREEN ) - rc.bottom + rc.top ) / 2 ;
SetWindowPos ( hwnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER ) ;
#include <windows.h>
typedef BOOL (* MENUFUNC)(HWND hwnd);
//////////////////////////////////////////////////
// Prototypen
//////////////////////////////////////////////////
BOOL fn_tray_create
(HWND hwnd);
BOOL fn_tray_destroy
(HWND hwnd);
BOOL fn_tray_notifcation(HWND hwnd);
BOOL fn_tray_hide
(HWND hwnd);
BOOL fn_tray_show
(HWND hwnd);
BOOL fn_tray_about
(HWND hwnd);
//////////////////////////////////////////////////
// von Hand erstelltes Menu
//////////////////////////////////////////////////
typedef struct _MENU_STRUCT {
WORD
_id; // Menu-Id's, etwa ab 100
LPSTR
_txt; // Menu-Popup/Item-Text
MENUFUNC _fn; // auzurufende Funktion
} MENU_STRUCT;
HMENU my_set_menu(HWND hwnd, MENU_STRUCT * pMenu)
{ HMENU hMenu=CreateMenu(), hPopup = NULL;
LPSTR pSave=NULL; int j,k=0;
if((!hwnd)||(!pMenu))return NULL;
while(pMenu[k]._txt){
hPopup = CreateMenu();
for(j=k+1; pMenu[j]._id; j++){
AppendMenu(hPopup,MF_STRING,pMenu[j]._id,pMenu[j]._txt);
} AppendMenu(hMenu, MF_POPUP,(UINT_PTR)hPopup,pMenu[k]._txt);
k = j;
} //if(!hMenu)DestroyMenu(hMenu);
SetMenu(hwnd,hMenu);
return hMenu;
}
//////////////////////////////////////////////////
// Shell_NotifyIcon() bringts ...
//////////////////////////////////////////////////
BOOL my_tray_message(HWND hwnd, DWORD iMsg, HICON hIcon, PSTR pszTip){
NOTIFYICONDATA tnd
= {0};
tnd.cbSize
= sizeof(NOTIFYICONDATA);
tnd.hWnd
= hwnd;
tnd.uID
= ID_TRAYICON;
tnd.uFlags
= NIF_MESSAGE|NIF_ICON|NIF_TIP;
tnd.uCallbackMessage = WM_TRAY_NOTIFICATION;
tnd.hIcon
= hIcon;
lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip));
BOOL res = Shell_NotifyIcon(iMsg, &tnd);
if (hIcon) DestroyIcon(hIcon);
return res;
}
//////////////////////////////////////////////////
// Menu-Aufrufe ...
//////////////////////////////////////////////////
BOOL fn_tray_hide(HWND hwnd){ ShowWindow(hwnd, SW_HIDE);return TRUE;}
BOOL fn_tray_show(HWND hwnd){ ShowWindow(hwnd, SW_SHOW);return TRUE;}
BOOL fn_tray_about(HWND hwnd)
{
MessageBox(hwnd,"","Tray-Icon",MB_OK|MB_ICONINFORMATION);
return TRUE;
}
HMENU my_menu1(HWND hwnd)
{
// alternativ mit Ressourcen:
// HMENU hMenu = LoadMenu(GetModuleHandle(0),MAKEINTRESOURCE(IDR_TRAYMENU)),0);
// SetMenu(hwnd,hMenu);
MENU_STRUCT menu_struct[] = {
{
0, "Tray-App", 0 },
{ 110, "anzeigen", fn_tray_show },
{ 120, "verstecken",fn_tray_hide },
{ 130, "Info",
fn_tray_about },
{ 140, "beenden",
fn_tray_destroy },
{
0, "Pop2",
0 },
{ 4718, "Item 4718", 0 },
{0,NULL,0}};// <== Endekriterium ist Pflicht!
HMENU hMenu = my_set_menu(hwnd, menu_struct);
return hMenu;
}
BOOL fn_tray_create(HWND hwnd)
{
HICON hIcon = LoadIcon(NULL, IDI_APPLICATION);
HMENU hMenu = my_menu1(hwnd);
SetMenu(hwnd,hMenu);
my_tray_message(hwnd, NIM_ADD,
NULL,
NULL);
my_tray_message(hwnd, NIM_MODIFY, hIcon, "Kurzinfo");
return TRUE;
}
BOOL fn_tray_destroy(HWND hwnd)
{
my_tray_message(hwnd, NIM_DELETE, NULL, NULL);
PostQuitMessage( 0 );
return TRUE;
}
BOOL fn_tray_notifcation(HWND hwnd)
{
HMENU hMenu = my_menu1(hwnd);
POINT mouse; GetCursorPos(&mouse);
HMENU hMenuSub = GetSubMenu(hMenu,0);
TrackPopupMenu(hMenuSub,0,mouse.x,mouse.y,0,hwnd,NULL);
return TRUE;
}
//////////////////////////////////////////////////
// CALLBACK-Funktion
//////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch( iMsg ) {
case WM_TRAY_NOTIFICATION:
switch (lParam ){
case WM_RBUTTONUP:
fn_tray_notifcation(hwnd); break;
case WM_LBUTTONDBLCLK: break; //hat Klasse Doppeklicks?
} // ende switch (lParam )
break;
case WM_CREATE: {
//hIcon =
(HICON)LoadImage(GetModuleHandle(0),MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,0);
HICON hIcon = LoadIcon(NULL, IDI_APPLICATION);
my_tray_message(hwnd, NIM_ADD,
NULL,
NULL);
my_tray_message(hwnd, NIM_MODIFY, hIcon, "Kurzinfo");
break;}
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case 110: fn_tray_show(hwnd);
break;//{ 110, "anzeigen", fn_tray_show },
case 120: fn_tray_hide(hwnd);
break;//{ 120, "verstecken",fn_tray_hide },
case 130: fn_tray_about(hwnd);
break;//{ 130, "Info",
fn_tray_about },
case 140: fn_tray_destroy(hwnd); break;//{ 140, "beenden",
fn_tray_destroy },
//case xxx:
//
DialogBox(GetModuleHandle(0),MAKEINTRESOURCE(IDD_ABOUT),
//
hwnd,(DLGPROC)DlgProc); break;
}
// ende switch(LOWORD(wParam))
break; } // ende von WM_COMMAND
case WM_DESTROY:
fn_tray_destroy(hwnd); break;
} // ende von switch( iMsg )
return DefWindowProc( hwnd, iMsg, wParam, lParam );
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR
lpCmdLine,
int
nCmdShow )
{
WNDCLASSEX wc;
wc.cbSize
= sizeof(WNDCLASSEX);
wc.style
= CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra
= 0;
wc.cbWndExtra
= 0;
wc.hInstance
= hInstance;
wc.hIcon
= LoadIcon(NULL, IDI_APPLICATION);
//alternativ
LoadIcon(hInstance, (LPCTSTR)IDI_ICON);
wc.hIconSm
= LoadIcon(NULL, IDI_APPLICATION);
//alternativ
LoadIcon(wc.hInstance, (LPCTSTR)IDI_ICON);
wc.hCursor
= LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground= (HBRUSH) (COLOR_WINDOW);
wc.lpszMenuName = 0;//alternativ (LPTSTR) IDR_WINMENU;
wc.lpszClassName= "my_class";
RegisterClassEx(&wc);
HWND hwnd = CreateWindow("my_class",
"TrayIcon Beispiel", WS_OVERLAPPEDWINDOW,
50,50,200,60,
NULL,NULL,hInstance,NULL);
if( !hwnd ) return FALSE;
HMENU hMenu = my_menu1(hwnd);
ShowWindow( hwnd, SW_HIDE );
UpdateWindow( hwnd );
MSG msg;
while( GetMessage(&msg,NULL,0,0)) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
7. Praktikum
Diese Aufgabe besteht im darin, mit Modeless-Dialogen zu arbeiten.
●
Zum Üben und besseren Verstehen beginnen Sie bitte mit einem "Hallo Welt"-Programm und fügen ein Menü ( für
Dialog-Aufrufe ) ein, erstellen 2 einfache Dialog-Rssourcen, wie z.B.
und die Callback-Funktion mit Dialog-Aufrufen ( zunächst für modale Dialoge )
unter WM_COMMAND, switch (LOWORD(wParam)),
case IDM_...: DialogBox(hwnd, IDD_..., (DLGPROC)myDlgProc)
unter WM_CLOSE: EndDialog(hwnd, bel_return_zahl);
unter WM_DESTROY: PostQuitMessage(0);
BOOL CALLBACK my_dlgProc //Muster
( HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam){
switch ( iMsg ) {
case WM_INITDIALOG: ... break;
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDM_...:{
break; }
case IDM_...:{
break; }
} break; }
case WM_CLOSE:
EndDialog(hwnd,...);
// DestroyWindow(hwnd);
break;
}
return FALSE;
}
●
Unter WM_INITDIALOG werden nun die benötigten Control-Handles hCtrl... in static-Variablen geholt ( ggf. können
die hCtrl... auch ohne static benutzt werden, müssen dann aber jeweils bei Bedarf vor der Verwendung neu geholt werden
).
HWND hCtl... = GetDlgItem(hwnd, ID_CTRL...);
//int idCtrl = GetDlgCtrlID(hCtl...);
Mit diesen hCtl... können nun Nachrichten an die "EDIT"-, COMBOBOX"-, usw. CALLBACK-Funktionen der Controls
geschickt werden.
SendMessage(hCtl,iMsg,wParam,lParam);
günstiger sind oft die "gecasteten SendMessage-Macros" aus "windowsx.h", wie z.B.
Edit_SetText(hCtl..., "mein Text" );
Initialisieren Sie bitte unter WM_INITDIALOG die Controls wie gewünscht.
●
●
●
Lesen Sie z.B. per Butten-Klick aus einem Control einen Text aus und schreiben diesen in ein anderes Control.
Wenn dies funktioniert, stellen Sie bitte auf Modeless-Dialoge um, indem static HWND hDlg; CALLBACK-intern
angelegt wird und
unter WM_CLOSE: EndDialog() durch DestroyWindow() ersetzt wird und
unter WM_COMMAND, switch (LOWORD(wParam)) bei
case IDM_...: anstelle DialogBox() nun
hDlg = CreateDialog(GetModuleHandle(0),MAKEINTRESOURCE(IDD_...), hwnd,(DLGPROC)myDlgProc); verwendet
wird.
Wenn dies funktioniert, ersetzen Sie bitte CreateDialog() durch CreateDialogParam() und beobachten mit dem Debugger
das "Reinkommen" des Parameters bei WM_INITDIALOG.
●
Überlegen Sie, wie Sie es erreicht können, dass z.B. bei den sichtbaren Dialogen 1,2,3 der Modeless Dialog 1 nicht
zusätzlich ( unnötig ) geöffnet werden kann.
●
Nun wrd das globale HWND hDlgModeless für den einen, aktiven Modeless-Dialog angelegt.
●
Nun wird für Modeless-Dialoge die Haupnachrichten-Schleife ergänzt:
while ( GetMessage( & msg, NULL, 0, 0 ) ) {
if ( NULL == hDlgModeless || ! IsDialogMessage( hDlgModeless, & msg ) ) {
TranslateMessage( & msg );
DispatchMessage ( & msg );
}
}
●
In jeder Modeless-Dialog-CALLBACK-Funktion wird die WM_ACTIVATE-Nachricht zum Umschalten des
hDlgModeless benutzt.
...
switch ( iMsg ) {
case WM_ACTIVATE: {
if ( 0 == wParam ) hDlgModeless = NULL; // wird inactive
else
hDlgModeless = hWnd; // wird
active
return FALSE;
break; }
case WM_CLOSE: { // ggf. Heap-freigeben
if( hDlgModeless == hWnd )
DestroyWindow( hWnd ) ;
break; }
...
●
Erstellen Sie einen zusätzlichen Edit-Dialog möglichst nach den folgenden Vorgaben:
... mit Resourcen-Workshop erstellen:
IDC_COMBO_FIND
IDC_BUTTON_FIND
IDC_COMBO_REPL
IDC_BUTTON_REPL
Dialog
Edit-Control
Allgemein:
Allgemein:
ID: IDC_EDIT
ID: IDD_ ...
[x] Sichtbar
Titel: ...
[x] Tabstop
Formate:
Formate:
Stil: Kontextmenü
Text ausrichten: links
Rand: Größe ändern
[x] Mehrzeilig
[x] Titelleiste
[x] Auto Hor. Bildlauf
[x] Systemmenü
[x] Auto Vert. Bildlauf
[x] Minimieren Schaltfläche
[x] Return möglich
[x] Maximieren Schaltfläche
[x] Rand
Weitere Formate:
Weitere Formate:
[x] Sichtbar
[x] Sichtbar
[x] Vordergrund setzen
[x] Vordergrund setzen
[x] Zentriert
[x] Zentriert
Schreiben Sie eine CALLBACK-Funktionen dlg_edit() für diesen Dialog ( siehe mitgelieferte Quelltexte )
Betrachten Sie den mitgelieferten Quelltext, der ohne externe Ressourcen auskommt.
●
●
Nun soll in einen Dialog ein bmp-Bild eigefügt werden. Ein Bild kann eingefügt werden etwa durch:
case WM_INITDIALOG :
{
HBITMAP bild =
LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP1));
HWND hbmp = CreateWindowEx( WS_EX_LEFT, "static", NULL, WS_CHILD |
SS_BITMAP,
0,0,GetSystemMetrics(SM_CXMAXIMIZED),GetSystemMetrics(SM_CYMAXIMIZED),
hwnd, (HMENU)NULL, GetModuleHandle(NULL), NULL);
SendMessage(hbmp,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)bild);
SetWindowPos( hbmp, HWND_BOTTOM,
0,0,GetSystemMetrics(SM_CXMAXIMIZED),GetSystemMetrics(SM_CYMAXIMIZED),
SWP_SHOWWINDOW );//oder ShowWindow(hbmp,SW_SHOWNORMAL ) ;
} break;
●
Nun ist eine Kofigurationsdatei zu verwenden. Windows-Applikationen benutzen *.INI - Files, in die zahlreiche
Informationen ( Start-Parameter, Treiber-Programme, usw. ) fuer die Applikation eingetragen werden können. Die
Profile-Funktionen sind auf die Benutzung der INI-Files ( Kofigurationsdatei wie z.B. my App.ini ) abgestimmt. Die
folgenden Anweisungen zeigen die Nutzung:
#define err(errStr) if(MessageBox(0,(errStr),0, \
MB_OKCANCEL)-1){*((void **)0)=0;}
------------------------- dies kann eine init-Func fuer *.ini werden:
// hole Pfad-fileNamen.EXE der Applikation
char fileName[MAX_PATH]; HANDLE hFile;
DWORD n2,n1 = GetModulefileName(GetModuleHandle(0),fileName,sizeof(fileName));
// ersetze EXE durch INI
lstrcpy(fileName+lstrlen(fileName)-3, "ini");
// prüfe, ob dieser INI-File bereits existiert:
hFile = CreateFile(fileName,GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
// falls der INI-File noch nicht existiert, erstelle diesen INI-File:
if (GetLastError()!=0) {// s. WINERROR.H
hFile = CreateFile(fileName,GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
if (GetLastError()!=0) err("CreateFile");
char * pInitStr = "[TOOLDIR]\r\n"
"BcLib=d:\\bc\\BC45\\LIB\r\n"
"BcInclude=d:\\bc\\BC45\\INCLUDE\r\n\r\n"
"[IDE]\r\n"
"DefaultDesktopDir=d:\\bc\\BC45\\BIN\r\n"
"HelpDir=d:\\bc\\BC45\\BIN\r\n"
"[START]\r\n"
"Status=TRUE\r\n"
"Links=4\r\n"
"Rechts=2\r\n"
"Breite=-550\r\n"
"Höhe=608\r\n";
n1 = lstrlen(pInitStr);
// schreibe die pInitStr-Initialisierung in den INI-File
if(!WriteFile(hFile,pInitStr,n1,&n2,NULL))if(n1!=n2)err("diskFull");
} CloseHandle(hFile);
----------------------------------------------Beispiele fuer das Arbeiten mit ProfileString's:
// hole HelpDir aus INI, schreibe nach buf
char buf[512];
GetPrivateProfileString("IDE","HelpDir","?", buf,sizeof(buf),fileName);
// hinterlege einen Text in INI
WritePrivateProfileString("START","Status","FALSE",fileName ) ;
// hinterlege eine int-Zahl in INI
int breite=+1234; wsprintf(buf, "%d", val ) ;
WritePrivateProfileString("START","Breite", buf,fileName ) ;
// hole eine int-Zahl aus INI
GetPrivateProfileString("START","Breite","0", buf,sizeof(buf),fileName);
breite = atoi(buf) ;
Schreiben Sie einfach zu benutzende Profile-Funktionen, die das Arbeiten mit solchen privaten Profile Strings erleichtern.
Wie können Einträge gelöscht werden?
//Modeless-Dialoge
#include <windows.h>
#include "resource.h"
HINSTANCE hInst;
HWND
hDlgModeless;
HWND
h_ML[10]; //Handles auf ModlessDlg's
BOOL CALLBACK my_dlgProc1 //Muster
( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam){
switch ( iMsg ) {
case WM_INITDIALOG:{ }break;
case WM_CLOSE:{ }break;
case WM_ACTIVATE:
if ( WA_INACTIVE == LOWORD(wParam) ) {
_hModeless = NULL;//becoming inactive
} else {
_hModeless = hwnd;//becoming active
} return FALSE;
} return FALSE;
}
//...BOOL CALLBACK my_dlgProc2 ... wie oben
//...BOOL CALLBACK my_dlgProc3 ... wie oben
LRESULT CALLBACK WndProc //Muster
( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam){
switch ( iMsg ) {
case WM_CREATE: break;
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case ID_DLG1: ShowWindow( h_ML[1],SW_SHOW);break;
case ID_DLG2: ShowWindow( h_ML[2],SW_SHOW);break;
case ID_HIDE1:ShowWindow( h_ML[1],SW_HIDE);break;
case ID_HIDE2:ShowWindow( h_ML[2],SW_HIDE);break;
} break; }
case WM_CLOSE: { char buf[256]; int ret;
GetWindowText(hwnd,buf,sizeof(buf) ) ;
ret=MessageBox(hwnd,"Exit?","Exit?",MB_ICONQUESTION|MB_YESNO);
if ( IDNO == ret ) return TRUE;
DestroyWindow(hwnd);
} break;
case WM_DESTROY: PostQuitMessage(0); break;
}
return DefWindowProc(hwnd,iMsg,wParam,lParam);
}
int APIENTRY WinMain(
HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
{ hInst = hInstance; //=GetModuleHandle(0);
WNDCLASSEX wc = { 0 } ; MSG msg ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInst ;
wc.hIcon
= LoadIcon ( NULL, IDI_APPLICATION ) ;
wc.hCursor
= LoadCursor( NULL, IDC_ARROW
) ;
wc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH ) ;
wc.lpszMenuName = (LPSTR) IDR_MENU1 ;
wc.lpszClassName = "my_class" ;
wc.hIconSm
= LoadIcon(NULL, IDI_APPLICATION );
//auch bei:
//WM_CREATE, WM_INITDIALOG:
//HMENU hMenu = LoadMenu(hInst,(LPSTR)ID_..);
//
SetMenu(hwnd,hMenu);
//HICON hIcon = ExtractIcon(hInst,"Shell32.dll",41);
//SetClassLong(hwnd,GCL_HICON,(long)hIcon);
if ( ! RegisterClassEx( & wc ) ) return -1 ;
h_ML[0]= CreateWindowEx(WS_EX_LEFT,"my_class",
"Hauptfenster-Titel",
WS_OVERLAPPEDWINDOW,//window style
20,20,420,240,
//x,y,dx,dy
NULL, NULL,hInst,NULL);
//WM_NCCREATE,WM_NCCALCSIZE,WM_CREATE
ShowWindow (h_ML[0], SW_SHOW) ;
UpdateWindow(h_ML[0]) ;
h_ML[1]=
CreateDialog(hInst,(LPSTR)IDD_DLG1,h_ML[0],my_dlgProc1);
h_ML[2]=
CreateDialog(hInst,(LPSTR)IDD_DLG2,h_ML[0],my_dlgProc2);
while ( GetMessage( & msg, NULL,0,0)) {
if ( NULL == hDlgModeless
|| ! IsDialogMessage(hDlgModeless,&msg))
{
TranslateMessage( & msg );
DispatchMessage ( & msg );
}
}
DestroyWindow(h_ML[0]);
DestroyWindow(h_ML[1]);
DestroyWindow(h_ML[2]);
return 0;
}
/////////////////////////////////////////////////////
// dlg_modeless.cpp
/////////////////////////////////////////////////////
#ifndef _MYMODELESS_
#define _MYMODELESS_
#include <windows.h> // wird immer gebraucht
#include <windowsx.h>
#include <wchar.h>
// für das Menu
#define err(errStr) MessageBox(0,(errStr),0,MB_OK)
#define err_if(p,errStr) if(p)MessageBox(0,(errStr),0,MB_OK)
#define get_pDlg(hwnd) (DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA);
//////////////////////////////////////////////
// global verfügbar
//////////////////////////////////////////////
typedef BOOL (* MENUFUNC)(HWND hwnd);
static HWND
_hModeless; //global
static HINSTANCE _hInst;
//global
static MENUFUNC _mfunc;//EINE fn aktiv
typedef struct _MENU_STRUCT {
WORD
_id; // Menu-Identifizierer, etwa ab 100
LPSTR
_txt; // Menu-Item-Text
MENUFUNC _fn; // auzurufende Funktion
} MENU_STRUCT;
typedef struct _DLG_STRUCT {
HWND hwnd;
LPSTR pKlasse;
LPSTR pText;
WORD x,y,cx,cy;
} DLG_STRUCT;
///////////////////////////////////////////
// class CREATE_DLG_INDIRECT
///////////////////////////////////////////
class DLG_INDIRECT {
MENU_STRUCT *_pMenu; //_pMenu muss immer zuerst sein
int
_nCtrl;
HWND
_hParent;
DLG_STRUCT *_pFirst, *_pLast;
int nCopyAnsiToWideChar (LPWORD p, LPSTR lpAnsiIn)
{ int nChar = 0;
do { *p++ = (WORD)*lpAnsiIn; nChar++; } while (*lpAnsiIn++);
return nChar;
}
public:
~DLG_INDIRECT()
{
HWND hWnd
= this->get_hwnd();
if(hWnd) {
HMENU hMenu = GetMenu(hWnd);
if(hMenu)DestroyMenu(GetMenu(hWnd));
DestroyWindow(hWnd);
}
}
DLG_INDIRECT(HWND hParent, DLG_STRUCT * pDlg, DLGPROC dlgProc)
{ _nCtrl = 0;
_pMenu = NULL;
_pFirst = _pLast = NULL;
_hParent= hParent;
HWND hDlg = create_dlg_indirect(pDlg,dlgProc);
if(!hDlg||(hDlg!=this->get_hwnd())) err("ERR: pDlg??, dlgProc??");
}
MENU_STRUCT * get_pMenu() { return _pMenu; }
DLG_STRUCT * get_pFirst() { return _pFirst;}
DLG_STRUCT * get_pLast() { return _pLast; }
int get_nCtrl() { return _nCtrl; }
HWND get_parent() { return _hParent; }
HWND get_hwnd()
{
if(!_pFirst)return NULL;
return _pFirst->hwnd;
}
HWND get_hwnd(int i) {
if(i>get_nCtrl())return NULL;
return (_pFirst+i)->hwnd;
}
HWND set_hwnd(HWND hwnd) { if(!_pFirst) return NULL;
HWND hwnd_old = _pFirst->hwnd;
_pFirst->hwnd = hwnd; return hwnd_old;
}
HMENU create_menu(MENU_STRUCT * pMenu)
{ HMENU hMenu = CreateMenu(), hPopup = NULL;
int j,k=0; if(!pMenu)return NULL;
LPSTR pSave=NULL;
while(pMenu[k]._txt) {
hPopup = CreateMenu();
for(j=k+1; pMenu[j]._id; j++){
AppendMenu(hPopup,MF_STRING,
pMenu[j]._id,
pMenu[j]._txt);
}
AppendMenu(hMenu,MF_POPUP,
(UINT_PTR)hPopup,pMenu[k]._txt);
k = j;
} return hMenu;
}
BOOL set_menu(MENU_STRUCT * pMenu)
{
HWND hwnd = get_hwnd();
if(!hwnd) return FALSE;
HMENU hMenu = create_menu(pMenu); if(!hMenu)return FALSE;
DestroyMenu(GetMenu(hwnd));
if(!SetMenu(hwnd,hMenu)) return FALSE;
_pMenu = pMenu; return TRUE;
}
BOOL do_wm_command_func(DLG_INDIRECT *pDlg,WPARAM wParam )
{ if(!pDlg) return FALSE;
MENU_STRUCT *p = pDlg->_pMenu; if(!p) return FALSE;
HWND
hwnd = get_hwnd();
if(!hwnd ) return FALSE;
while ( p->_txt ) {
if ( p->_id == LOWORD(wParam) ) {
if( p->_fn ) return p->_fn(hwnd);
} p++;
} return FALSE;
}
HWND create_dlg_indirect( DLG_STRUCT * pDlg, DLGPROC dlgProc)
{
#define es_ist(str) (CSTR_EQUAL==CompareString(\
LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,(str),-1,pD->pKlasse,-1))
DWORD lStyle, lExtStyle; DLG_STRUCT * pD;
WORD pDlgStruct[8000] = {0}, *p = pDlgStruct;
int
i;
_nCtrl=0; if(!pDlg)return NULL;
while((pDlg+_nCtrl)->pKlasse)
_nCtrl++;
_pFirst = pDlg;
_pLast = pDlg + _nCtrl;
_nCtrl--;
// Dialog: /////////////////////////////////////////////
pD = _pFirst; //pD zeigt auf den 0-ten DLG_STRUCT-Eintrag
if(!es_ist("DIALOG"))return NULL;
lStyle = WS_OVERLAPPEDWINDOW|DS_MODALFRAME|DS_SETFOREGROUND|DS_SETFONT;
//|WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
//WS_VISIBLE
lExtStyle =
WS_EX_DLGMODALFRAME;//|WS_EX_TOPMOST;//|WS_EX_CONTROLPARENT|WS_EX_NOPARENTNOTIFY;//WS_EX_CLIENTEDGE
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = _nCtrl;
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = 0;
// Menu
*p++ = 0;
// Class
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 10;
// point size; braucht DS_SETFONT
p += nCopyAnsiToWideChar(p,TEXT("Times New Roman"));
// p += nCopyAnsiToWideChar(p,TEXT("Courier New"));
for ( i=1; i<=_nCtrl; i++){
p = (WORD*)(((DWORD)p + 3) & ~3); // WORD align
pD = _pFirst + i; //pD zeigt auf den i-ten DLG_STRUCT-Eintrag
if(es_ist("STATIC")){
lStyle = WS_VISIBLE|WS_CHILD
|SS_NOPREFIX|SS_LEFTNOWORDWRAP;
lExtStyle = 0;//WS_EX_CLIENTEDGE|WS_EX_STATICEDGE;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = 0xffff; //IDOK;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0082;// alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("STATIC"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("BUTTON")){
lExtStyle = 0;//WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab0 //;
lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP
|BS_PUSHBUTTON;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = i; //IDOK;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0080;//alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("BUTTON"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("LISTBOX")){
lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab ;
lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_TABSTOP
|LBS_DISABLENOSCROLL
|LBS_HASSTRINGS|LBS_STANDARD;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = i;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0083;//alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("LISTBOX"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("EDIT")){
lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT;//tab ;//WS_EX_DLGMODALFRAME
lStyle = WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_CLIPSIBLINGS|WS_TABSTOP
|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = i;
// ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0081;// alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("EDIT"));
p += nCopyAnsiToWideChar(p,TEXT(pD->pText));
*p++ = 0;
} else if(es_ist("COMBOBOX")){
lExtStyle = WS_EX_CLIENTEDGE;//|WS_EX_CONTROLPARENT; //tab ;
lStyle = WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|WS_TABSTOP
|CBS_DROPDOWN|CBS_OEMCONVERT|CBS_HASSTRINGS;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = pD->x; *p++ = pD->y;
*p++ = pD->cx; *p++ = pD->cy;
*p++ = i; // ID
*p++ = (WORD)0xffff; *p++ = (WORD)0x0085; //alternativ:
//p += nCopyAnsiToWideChar(p,TEXT("COMBOBOX"));
p += nCopyAnsiToWideChar(p,TEXT(""));//pD->pText));
*p++ = 0;
}
} // ende for
HWND hDlg = CreateDialogIndirectParam(_hInst,
(LPDLGTEMPLATE)pDlgStruct,_hParent,(DLGPROC)dlgProc,(LONG)this);
return hDlg;
}
#undef es_ist
///////////////////////////////////////////
// ende class CREATE_DLG_INDIRECT
///////////////////////////////////////////
};
static BOOL
def_modeless_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
//Achtung! Haupt-CALLBACK braucht:
//case WM_DESTROY: PostQuitMessage(0); break;
static HICON hIcon;
switch ( iMsg ) {
case
WM_ACTIVATE:{
if ( WA_INACTIVE == LOWORD(wParam) ) {
_hModeless = NULL;//wird inactive
} else {
_hModeless = hwnd;//wird active
}
break; }
case WM_INITDIALOG: {
DLG_INDIRECT *pDlg = (DLG_INDIRECT*)lParam;
if(pDlg)if(pDlg->get_hwnd()) {
SendMessage(hwnd,WM_CLOSE,0,0);break;
}
pDlg->set_hwnd(hwnd);
DLG_STRUCT * pLast = pDlg->get_pLast();
DLG_STRUCT * pFirst = pDlg->get_pFirst();
DLG_STRUCT * p
= pFirst;
for ( int i=1; i <= pDlg->get_nCtrl(); i++) { //Ctrl's
p = pFirst + i;
p -> hwnd = GetDlgItem(hwnd, i); // !!!
if(CSTR_EQUAL==CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE,"COMBOBOX",-1,p->pKlasse,-1)){
SetWindowText(p->hwnd,p->pText);
} else if(CSTR_EQUAL==CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE,"LISTBOX",-1,p->pKlasse,-1)){
SendMessage(p->hwnd,LB_ADDSTRING,0L,(LPARAM)p->pText);
}
} //ende for
RECT rc; GetWindowRect(hwnd, &rc);
pLast->x = (WORD) rc.left;
pLast->y = (WORD) rc.top;
pLast->cx = (WORD) (rc.right - rc.left);
pLast->cy = (WORD) (rc.bottom- rc.top);
SetWindowLong(hwnd,GWL_USERDATA,(LONG)pDlg);
HICON hIcon = ExtractIcon(_hInst,"Shell32.dll",41);
SetClassLong(hwnd,GCL_HICON,(long)hIcon );
break; }
case WM_ERASEBKGND: if(IsIconic(hwnd)&&hIcon) {
SendMessage(hwnd,WM_ICONERASEBKGND,wParam,0L);return TRUE;
break; }
case WM_QUERYDRAGICON: return (BOOL)hIcon;
case WM_PAINT: { PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
if(IsIconic(hwnd)) { // If iconic, paint the icon.
if(hIcon) { RECT rc;
GetClientRect(hwnd,&rc) ;
rc.left = (rc.right - GetSystemMetrics(SM_CXICON))>>1;
rc.top = (rc.bottom - GetSystemMetrics(SM_CYICON))>>1;
DrawIcon(ps.hdc,rc.left,rc.top,hIcon);
}
} EndPaint( hwnd, &ps );
break;}
case WM_GETMINMAXINFO:{
if (IsIconic(hwnd))return FALSE;
//DLG_INDIRECT *pDlg=(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA);
DLG_INDIRECT *pDlg = get_pDlg(hwnd);
if(!pDlg)if(!pDlg->get_pFirst())break;
HWND h = pDlg->get_hwnd();
if(h) if( h != hwnd ){SendMessage(hwnd,WM_CLOSE,0,0);break;}
LPMINMAXINFO lpmmi= (LPMINMAXINFO)lParam;
DLG_STRUCT * pLast = pDlg->get_pLast();
lpmmi->ptMinTrackSize.x =3*GetSystemMetrics(SM_CXHTHUMB);
lpmmi->ptMinTrackSize.y = GetSystemMetrics(SM_CYCAPTION);
lpmmi->ptMaxPosition.x = pLast->x;
lpmmi->ptMaxPosition.y = pLast->y;
lpmmi->ptMaxSize.x
=
lpmmi->ptMaxTrackSize.x = pLast->cx;
lpmmi->ptMaxSize.y
=
lpmmi->ptMaxTrackSize.y = pLast->cy;
break; }
case WM_WINDOWPOSCHANGED: {
LPWINDOWPOS lpwp =(LPWINDOWPOS) lParam;
//DLG_INDIRECT *pDlg=(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA);
DLG_INDIRECT *pDlg = get_pDlg(hwnd);
if(!pDlg)if(!pDlg->get_pFirst())break;
DLG_STRUCT * pLast = pDlg->get_pLast();
pLast->x =(WORD) lpwp->x;
pLast->y =(WORD) lpwp->y;
break; }
case WM_CLOSE: { ShowWindow(hwnd,SW_HIDE); break;}
// falls jeder Modeless immer wieder neu
// durch CreateDialog erzeugt wird, ist zu durchdenken ...
// case WM_CLOSE: {
// DLG_INDIRECT *pDlg = get_pDlg(hwnd);
// if(pDlg)if(pDlg->get_hwnd())pDlg->set_hwnd(NULL);
// DestroyWindow(hwnd); oder ggf.
// if( pDlg ) delte pDlg;
// break; }
// case WM_DESTROY: { PostQuitMessage(0); break; }
// ausgewählte Menu-Func aufrufen,
// alle Menu-Tabellen-Einträge durchgehen:
case WM_COMMAND:{
if(HIWORD(wParam))break;
//DLG_INDIRECT *pDlg =(DLG_INDIRECT*)GetWindowLong(hwnd,GWL_USERDATA);
DLG_INDIRECT *pDlg = get_pDlg(hwnd);
pDlg->do_wm_command_func(pDlg,wParam);
break; } //ende WM_COMMAND
} // ende switch(iMsg)
return FALSE;
}
static BOOL
do_wm_command_func( HWND hwnd, MENU_STRUCT * pMenu, WPARAM wParam )
{ MENU_STRUCT *p = pMenu; if(!p) return FALSE;
while ( p->_txt ) {
if ( p->_id == LOWORD(wParam) ) {
if( p->_fn ) return p->_fn(hwnd);
} p++;
} return FALSE;
}
#endif _MYMODELESS_
/////////////////////////////////////////////////////
ende von dlg_modeless.cpp
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
// my_application.cpp
/////////////////////////////////////////////////////
#include <windows.h>
#include <windowsx.h>
#include "dlg_modeless.cpp"
/////////////////////////////////////////////////////
// Zusammenstellung der CALLBACK-Funktionen
/////////////////////////////////////////////////////
static BOOL CALLBACK dlg0_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
BOOL CALLBACK dlg1_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
BOOL CALLBACK dlg2_proc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
/////////////////////////////////////////////////////
// Eintragen der CALLBACK-Funktionen in den Globalen Array
/////////////////////////////////////////////////////
#define
MAX_ANZ_MODELESS 20
static DLG_INDIRECT *g_dlg_ptr [MAX_ANZ_MODELESS];
void do_post_quit_message(void) // alles freigeben
{ int i; HWND hwnd; DLG_INDIRECT *pDlg;
for ( i=0; i<MAX_ANZ_MODELESS;i++) {
pDlg = g_dlg_ptr[i];
if(!pDlg)continue;
hwnd = pDlg->get_hwnd();if(!hwnd)continue;
DestroyWindow(hwnd);
if(pDlg) delete g_dlg_ptr[i];
} PostQuitMessage(0);
}
HMENU create_menu(MENU_STRUCT * pMenu)
{ HMENU hMenu = CreateMenu(), hPopup = NULL;
int j,k=0; if(!pMenu)return NULL;
LPSTR pSave=NULL;
while(pMenu[k]._txt) {
hPopup = CreateMenu();
for(j=k+1; pMenu[j]._id; j++){
AppendMenu(hPopup,MF_STRING,
pMenu[j]._id,
pMenu[j]._txt);
}
AppendMenu(hMenu,MF_POPUP,
(UINT_PTR)hPopup,pMenu[k]._txt);
k = j;
} return hMenu;
}
BOOL set_menu(HWND hwnd, MENU_STRUCT * pMenu)
{
if(!IsWindow(hwnd))return FALSE;
HMENU hMenuNew = create_menu(pMenu); if(!hMenuNew)return FALSE;
HMENU hMenuOld = GetMenu(hwnd);if(hMenuOld) DestroyMenu(hMenuOld);
BOOL ok = SetMenu(hwnd,hMenuNew); if(!ok)return FALSE;
//hinterlege pMenu im Dialog-Window:
MENU_STRUCT *pMenuOld = (MENU_STRUCT*)GetWindowLong(hwnd,GWL_USERDATA);
if(!pMenuOld)return FALSE;
pMenuOld = pMenu; return TRUE;
}
BOOL show_popup_menu_spalte(HWND hwnd, int pos )
{
HMENU hMenu = GetMenu(hwnd);
HMENU hPopup = GetSubMenu(hMenu, pos);
POINT P; GetCursorPos ( &P );
return TrackPopupMenu(hPopup,TPM_LEFTALIGN,P.x,P.y,0,hwnd,NULL);
}
/////////////////////////////////////////////////////
// Zusammenstellung der Menu-Funktionen
/////////////////////////////////////////////////////
BOOL menu_fn100(HWND hwnd)
{
if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless);
MessageBox(0,buf,"info",MB_OK);
return TRUE;
}
BOOL menu_fn110(HWND hwnd)
{
if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless);
MessageBox(0,buf,"info",MB_OK);
return TRUE;
}
BOOL menu_fn120(HWND hwnd)
{
if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless);
MessageBox(0,buf,"info",MB_OK);
return TRUE;
}
BOOL menu_fn200(HWND hwnd)
{
if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless);
MessageBox(0,buf,"info",MB_OK);
return TRUE;
}
BOOL menu_fn210(HWND hwnd)
{
if(hwnd!=_hModeless) MessageBox(0,"kein _hModeless","info",MB_OK);
char buf[256];
wsprintf(buf,"_hModeless ist global _hModeless=%08x",_hModeless);
MessageBox(0,buf,"info",MB_OK);
return TRUE;
}
/////////////////////////////////////////////////////
// Zusammenstellung der modeless-Dialoge
/////////////////////////////////////////////////////
DLG_INDIRECT *create_dlg0(HWND hwnd, DLGPROC dlg_prog )
{
static
// static ist Pflicht!
DLG_STRUCT dlg_struct[] = {// x, y, cx, cy
{0,"DIALOG", "Editor",
100, 35,370,260},//[0]
{0,"BUTTON", "beende",
5,230, 50, 14},//[1]
{0,"BUTTON", "Dlg-Neu2",
315,230, 50, 14},//[2]
{0,"BUTTON", "Suche",
135, 5, 40, 14},//[3]
{0,"BUTTON", "Ersetze",
325, 5, 40, 14},//[4]
{0,"EDIT",
"dlg-Edit",
5, 50,360,170},//[5]
{0,"COMBOBOX","Suche",
5, 5,125,150},//[6]
{0,"COMBOBOX","Ersetze",
195, 5,125,150},//[7]
{0,"BUTTON", "Dlg-Neu1",
80,230, 50, 14},//[8]
{0,NULL,0,0,0,0}};//Endekriterium ist Pflicht
DLG_INDIRECT *pDlg = new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog);
static // static ist Pflicht!
MENU_STRUCT menu_struct[] = {
{
0, "Pop1",
0 },
{ 100, "Item 100", menu_fn100 },
{ 110, "Item 110", menu_fn110 },
{ 120, "Item 120", menu_fn120 },
{
0, "Pop2",
0 },
{ 200, "Item 200", menu_fn200 },
{ 210, "Item 210", menu_fn210 },
{ 220, "Hallo an Curso-Stelle einfügen", 0 },
{0,NULL,0}}; // <== Endekriterium ist Pflicht!
pDlg->set_menu(menu_struct);
return pDlg;
}
/////////////////////////////////////////////////////
DLG_INDIRECT *create_dlg1(HWND hwnd, DLGPROC dlg_prog )
{ //int
i_dlg = 1; // i_dlg = 0,1,...MAX_ANZ_MODELESS
/////////////////////////////////////////////////////
static // static ist Pflicht!
DLG_STRUCT dlg_struct[] = { // x, y, cx, cy
{0,"DIALOG", "dlg1-Titel", 40, 20,100,145},//[0]
{0,"STATIC", "Static-Text",10, 5, 80, 12},//[1]
{0,"LISTBOX", "dlg-List",
10, 20, 80, 40},//[2]
{0,"EDIT",
"dlg-Edit",
10, 85, 80, 40},//[3]
{0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4]
{0,"BUTTON", "OK",
10,130, 80, 12},//[5]
{0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht
/////////////////////////////////////////////////////
return new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog);
}
/////////////////////////////////////////////////////
DLG_INDIRECT *create_dlg2(HWND hwnd, DLGPROC dlg_prog )
{
static
// static ist Pflicht!
DLG_STRUCT dlg_struct[] = { // x, y, cx, cy
{0,"DIALOG", "dlg2-Titel", 50, 40,100,155},//[0]
{0,"STATIC", "Static-Text",10, 5, 80, 12},//[1]
{0,"LISTBOX", "dlg-List",
10, 20, 80, 40},//[2]
{0,"EDIT",
"dlg-Edit",
10, 85, 80, 40},//[3]
{0,"COMBOBOX","dlg-Combo", 10, 60, 80, 60},//[4]
{0,"BUTTON", "OK",
10,130, 80, 12},//[5]
{0,NULL, 0,0,0,0}};//Endekriterium ist Pflicht
DLG_INDIRECT *pDlg = new DLG_INDIRECT(hwnd, dlg_struct, dlg_prog);
static
// static ist Pflicht!
MENU_STRUCT menu_struct[] = {
{
0, "Test1",
0 },
{ 100, "100",
menu_fn100 },
{ 120, "120",
menu_fn120 },
{
0, "Test2",
0 },
{ 200, "200",
menu_fn100 },
{ 210, "210",
menu_fn120 },
{0,NULL,0}}; // <== Endekriterium ist Pflicht!
pDlg -> set_menu(menu_struct);
/////////////////////////////////////////////////////
// einige Einträge in Ctrl's:
/////////////////////////////////////////////////////
// {0,"LISTBOX", "dlg-List",
10,20, 80,40},//[2]
HWND hCtrl2 = pDlg->get_hwnd(2); // [2]
SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"1");
SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"2");
SendMessage(hCtrl2,LB_ADDSTRING,0L,(LPARAM)"3");
// {0,"COMBOBOX","dlg-Combo",10,60, 80,60},//[4]
HWND hCtrl4 = pDlg->get_hwnd(4); // [4]
SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"1");
SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"2");
SendMessage(hCtrl4,CB_ADDSTRING,0L,(LPARAM)"3");
/////////////////////////////////////////////////////
err_if(!pDlg,"In g_dlg_proc[MAX_ANZ_MODELESS]\nist keine dlg_proc");
return pDlg;
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
////////////////////////////////////////////////////
// Zusammenstellung der CALLBACK-Funktionen
////////////////////////////////////////////////////
BOOL CALLBACK dlg0_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam )
{
if(def_modeless_proc(hwnd,iMsg,wParam,lParam))return TRUE;
static
static
static
static
HWND hFind, hRepl, hEdit;
int idxSelStart, idxSelEnd, nChar;
char buf[256], *pBuf,*pFind;
DLG_INDIRECT
*pDlg = g_dlg_ptr[0];
switch ( iMsg ) {
case WM_CLOSE:
do_post_quit_message();//PostQuitMessage(0);
// DestroyWindow(hwnd);
break;
case WM_DESTROY:
//do_post_quit_message();//PostQuitMessage(0);
break;
case WM_RBUTTONDOWN: { show_popup_menu_spalte(hwnd,0);
break;}
case WM_INITDIALOG : {
///////////////////////////////////////////////////////
// Zugriff auf Ctrl-Handle mit der DLG_INDIRECT-Klasse
// {0,"EDIT",
"dlg-Edit",
5, 50,360,170},//[5]
// {0,"COMBOBOX","Suche",
5, 5,125,150},//[6]
// {0,"COMBOBOX","Ersetze",
195, 5,125,150},//[7]
// {0,"", 0,0,0,0}};//Endekriterium ist Pflicht
// Alternative 1:
// wegen create...param()-Aufruf kommt
// lParam als this-Zeiger nur bei WM_INITDIALOG
pDlg = (DLG_INDIRECT *)lParam;
///////////////////////////////////////////////////////
// allg. Alternative 2:
// pDlg (=this-Zeiger) holen vom GWL_USERDATA
pDlg = get_pDlg(hwnd);
///////////////////////////////////////////////////////
// Zugriff auf Ctrl-Handle unter
// WM_INITDIALOG mit GetDlgItem()
// Windows-Standard-Alternative:
hEdit = GetDlgItem(hwnd, 5); //5.Ctrl
hFind = GetDlgItem(hwnd, 6); //6.Ctrl
hRepl = GetDlgItem(hwnd, 7); //7.Ctrl
Edit_SetText(hEdit, "5.Ctrl Edit\r\n2 2 \r\n2 2 \r\n");
ComboBox_SetText (hRepl, "7.Ctrl Ersetze" ) ;
ComboBox_SetText (hFind, "6.Ctrl Suche" ) ;
ComboBox_AddString(hFind, "1" ) ;
ComboBox_AddString(hFind, "2" ) ;
break; }
case WM_SETCURSOR:
if (hEdit==(HWND)wParam) idxSelStart=idxSelEnd=Edit_LineIndex(hEdit,-1);
break;
case WM_COMMAND: {
switch (HIWORD(wParam)) {
case EN_ERRSPACE: { break; }
case EN_MAXTEXT:
{ break; }
case EN_KILLFOCUS: { break; }
case EN_SETFOCUS: { break; }
case CBN_KILLFOCUS: {
if ( 6 == LOWORD(wParam)) {
//err("CBN_KILLFOCUS:");
// {0,"EDIT","dlg-Edit", 5, 50,360,170},//[5]
// {0,"COMBOBOX","Suche",5, 5,125,150},//[6]
//SendMessage(hwnd,WM_COMMAND,MAKELPARAM(5,EN_SETFOCUS),(WPARAM)hEdit);
}
break; }
break; } // ende switch (HIWORD(wParam))
switch (LOWORD(wParam)) {//Buttons, Edit, Combo
case 8: { // {0,"BUTTON", "Dlg-Neu1",
80,230, 50, 14},//[8]
HWND htemp = g_dlg_ptr[1]->get_hwnd();
ShowWindow(htemp,SW_SHOW);
SetForegroundWindow(htemp);
break;}
case 2: { //{0,"BUTTON", "Dlg-Neu2",
315,230, 50, 14},//[2]
HWND htemp = g_dlg_ptr[2]->get_hwnd();
ShowWindow(htemp,SW_SHOW);
SetForegroundWindow(htemp);
break;}
case 1: { //{0,"BUTTON","beende", 13,233, 50, 14},//[1]
//SendMessage(hwnd,WM_CLOSE,0,0);
break; }
case 4: //Replace-Button
//{0,"BUTTON","Repl",337, 7, 34, 14},//[4]
ComboBox_GetText( hRepl, buf, sizeof(buf));
if ( idxSelStart < idxSelEnd )
Edit_ReplaceSel(hEdit, buf);
//fallend in Find-Button
case 3: { //Find-Button
//{0,"BUTTON","Find",134, 7, 43, 14},//[3]
ComboBox_GetText( hFind, buf, sizeof(buf));
nChar = Edit_GetTextLength(hEdit);
if ( pBuf ) {
free(pBuf); pBuf=NULL;
} else {
pBuf = (char *) calloc( nChar+1, sizeof(char) );
}
nChar = Edit_GetText(hEdit, pBuf, nChar);
pFind = strstr( pBuf + idxSelEnd, buf );
if (pFind) {
idxSelStart = pFind - pBuf;
idxSelEnd
= idxSelStart + strlen(buf);
} else {
idxSelEnd = idxSelStart = 0;
}
SetFocus( hEdit );
Edit_SetSel( hEdit, idxSelStart, idxSelEnd);
Edit_ScrollCaret( hEdit);
if (pBuf) { free(pBuf); pBuf=NULL;}
break; } // ende Find-Button
case 220: { //Test: an Cursor-Stelle "Hallo" einfügen:
int curPos = Edit_LineIndex(hEdit,-1);
Edit_SetSel( hEdit,curPos,curPos);
Edit_ReplaceSel(hEdit,"Hallo\r\n");
break; }
} // ende switch ( LOWORD( wParam ) )
break; }// ende WM_COMMAND
} // ende switch ( iMsg )
return FALSE;
}
BOOL CALLBACK dlg1_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam )
{ if(def_modeless_proc(hwnd,iMsg,wParam,lParam)) return TRUE;
switch ( iMsg ) {
case WM_RBUTTONDOWN: {
show_popup_menu_spalte(hwnd, 0);
break;}
case WM_CLOSE:
{
break; }
//case WM_DESTROY: { PostQuitMessage(0); break; }
}
return FALSE;
}
BOOL CALLBACK dlg2_proc( HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam )
{ if(def_modeless_proc(hwnd,iMsg,wParam,lParam)) return TRUE;
switch ( iMsg ) {
case WM_CLOSE: { break; }
case WM_DESTROY:{ break; }
}
return FALSE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{ static MENU_STRUCT * pMenu;
switch ( iMsg ) {
case WM_CREATE: pMenu=(MENU_STRUCT*)((LPCREATESTRUCT)lParam)->lpCreateParams;
break;
case WM_RBUTTONDOWN: show_popup_menu_spalte(hwnd, 0);
break;
case WM_COMMAND: {
if(HIWORD(wParam))break;
do_wm_command_func(hwnd,pMenu,wParam );
break;}//ende WM_COMMAND
case WM_DESTROY: PostQuitMessage(0);
break;
} // ende switch ( iMsg )
return DefWindowProc(hwnd,iMsg,wParam,lParam );
}
BOOL show_dlg1(HWND hwnd)
{
HWND htemp = g_dlg_ptr[1]->get_hwnd();
if(!htemp) return FALSE;
ShowWindow(htemp,SW_SHOW);
return SetForegroundWindow(htemp);
}
BOOL show_dlg2(HWND hwnd)
{
HWND htemp = g_dlg_ptr[2]->get_hwnd();
if(!htemp) return FALSE;
ShowWindow(htemp,SW_SHOW);
return SetForegroundWindow(htemp);
}
//===================
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hiPrev,
PSTR pCmdMain, int sw_show )
{
HWND hwnd = 0; _hInst = hInstance;
/*
WNDCLASSEX wc = { 0 } ;
wc.cbSize
= sizeof( WNDCLASSEX ) ;
wc.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc
= WndProc ;
wc.hInstance
= _hInst;
wc.cbWndExtra
= DLGWINDOWEXTRA;
wc.hCursor
= LoadCursor ( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "my_class" ;
if ( ! RegisterClassEx( & wc ) ) return -1 ;
static
MENU_STRUCT menu_struct[] =
{ 0, "ML-Dialoge",
0
{ 10, "dlg1",
show_dlg1
{ 20, "dlg2",
show_dlg2
{
{
{
{
{
{
{
0,
100,
110,
120,
0,
200,
210,
"Pop1",
"Item 100",
"Item 110",
"Item 120",
"Pop2",
"Item 200",
"Item 210",
{
},
},
},
0
menu_fn100
menu_fn110
menu_fn120
0
menu_fn200
menu_fn210
},
},
},
},
},
},
},
{0,NULL,0}}; // <== Endekriterium ist Pflicht!
hwnd = CreateWindowEx(
WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE,
"my_class", "Main-Window",
WS_CAPTION|WS_VISIBLE|WS_SYSMENU,
120,120,120,420, 0,0,_hInst,menu_struct);
HICON hIcon = ExtractIcon(_hInst,"Shell32.dll",41);
SetClassLong(hwnd,GCL_HICON,(long)hIcon );
set_menu(hwnd, menu_struct );
ShowWindow ( hwnd, sw_show ) ;
UpdateWindow( hwnd ) ;
*/
g_dlg_ptr[0] = create_dlg0(hwnd, dlg0_proc);
g_dlg_ptr[1] = create_dlg1(hwnd, dlg1_proc);
g_dlg_ptr[2] = create_dlg2(hwnd, dlg2_proc);
HWND hwnd0
= g_dlg_ptr[0]->get_hwnd();
ShowWindow(hwnd0, sw_show);
MSG msg ;
while ( GetMessage( &msg,NULL,0,0) ) {
if ( NULL==_hModeless|| !IsDialogMessage(_hModeless,& msg)){
TranslateMessage( &msg );
DispatchMessage ( &msg );
}
}
return msg.wParam ;
}
/////////////////////////////////////////////////////
// ende von my_application.cpp
/////////////////////////////////////////////////////
8. Praktikum
Diese Aufgabe besteht darin, das Erstellen von DLL's zu üben. In der Entwicklungsumgebung sind 2 Projekte anzulegen.
●
●
1.Projekt: auf_08 ( Windows-Applikation )
2.Projekt: myDll ( Windows-DLL ).
In das Projekt myDll ( 2.Projekt ) sind zunächst die beiden Files myDll.h, myDll.cpp einzufügen. Die Übersetzung soll die Files
myDll.dll und myDll.lib erstellen. Später soll die Anwendung ( 1. Projekt: auf_08 ) diese erstellten Files ( myDll.dll und myDll.lib )
nutzen.
Hinweise
DLL's haben Import/Export-Tabellen, d.h. der Linker braucht Hilfe-Stellungen ( storage-class modifiers ). Beispiele sind:
//
//
//
//
//
//
//
//
//
//
//
//
//
//
#define DLL_IMPORT __declspec( dllimport )
#define DLL_EXPORT __declspec( dllexport )
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
#ifdef _DLLBUILD_
#define DLL_API EXTERN_C __declspec( dllexport )
#else
#define DLL_API EXTERN_C __declspec( dllimport )
#endif
DLL's können auch "SHARED"-Daten verwalten. Hierzu benötigt der Linker ebenfalls Hilfe-Stellungen. Der Aufbau ist etwa wie
folgt:
#pragma data_seg("SHARED")
// Definition von einfachen Variablen,
// wie z.B. int, char[] arrays, zeiger
// Keine Klassen verwenden, die einen
// tiefen Copy Constructors brauchen
// Ende des "shared data segment"
// Zurück zum normalen Daten-Segment-Bereich
#pragma data_seg()
// Das folgende Linker-Pragma veranlasst den Linker
// die notwendigen initialisierungen für das
// "shared data segment" zu erzeugen
#pragma comment(linker, "/section:SHARED,RWS")
DLL-Erstellung
Hier kommt ein einführendes Beispiel, das als erste Grundlage zum Erstellen der DLL und der LIB verwendet werden soll. Zunächst
sind die myDll.dll und die myDll.lib zu erstellen. Im Header-File myDll.h werden infolge von
#ifdef _DLLBUILD_
die storage-class modifiers ( automatisch ) umgeschalten, denn was für die DLL ein EXPORT ( #define _DLLBUILD_ ), ist für die
Applikation ein IMPORT ( #undef _DLLBUILD_ ).
File: myDll.h
#ifndef MYDLL_H
#define MYDLL_H
///////////////////
#include <windows.h>
File: myDll.cpp
#define _DLLBUILD_
#include "myDll.h"
///////////////////////////////////
// DllMain ist Pflicht
#ifdef _DLLBUILD_
///////////////////////////////////
#define DLL_API __declspec( dllexport ) BOOL APIENTRY
#else
DllMain(HANDLE hModule,
#define DLL_API __declspec( dllimport )
DWORD ul_reason_for_call,
#endif
LPVOID lpReserved)
{
///////////////////////////////////
switch (ul_reason_for_call) {
// Referenz:
case DLL_PROCESS_ATTACH:
///////////////////////////////////
case DLL_THREAD_ATTACH:
extern DLL_API
int myDllInt;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
///////////////////////////////////
break;
// Funktions-Prototyp:
} return TRUE;
///////////////////////////////////
}
DLL_API int myDllFunc( int i );
///////////////////////////////////
// einige Tests
///////////////////////////////////
///////////////////////////////////
// C++-Klasse:
DLL_API void func();
//
ohne tiefen Copy-Konstruktor!
DLL_API int i = 10;
///////////////////////////////////
DLL_API int j;
class DLL_API myDllClass {
DLL_API int n;
public:
myDllClass(void); //Konstruktor
///////////////////////////////////
};
// Konstruktor der Klasse
///////////////////////////////////
///////////////////////////////////
#endif //MYDLL_H
myDllClass::myDllClass() {
///////////////////////////////////
return;
}
#pragma data_seg("SHARED")
//exportierte Variable
DLL_API int myDllInt=1;
//exportierte Funktion.
DLL_API int myDllFunc(int i) {
char buf[256];
int j = i + myDllInt;
myDllInt += 10;
wsprintf( buf, "i + myDllInt = %d", j );
MessageBox(0,buf,0,MB_OK);
return j;
}
#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")
Applikation-Erstellung
Das 1.Projekt: auf_08 enthält die Windows-Applikation. Weil der auf_08.exe-File die Dll zunächst im eigenen Direktory sucht, so ist
es günstig die Linker-Ausgabe in das Debug-Verzeichnis des DLL-Projektes umzuleiten. Dort befinden sich bereits myDll.dll und
myDll.lib. Dem Linker muss noch die benötigte LIB ( myDll.lib ) mitgeteilt werden. Dies kann erfolgen mit:
#include "myDll.h"
#pragma comment(lib, "myDll.lib")
Ein Test ist:
///////////////////
// hier folgt myApp.cpp
//
// Teste z.B.
// int i1 = myDllInt;
// i1 = ???
// int i2 = myDllFunc(i1); // i2 = ???
// int i3 = myDllInt;
// i3 = ???
Erweiterungen
Die DLL ist sinnvoll zu erweitern, wie z.B. durch
void heap_size( void )
{ CHAR Buf [1024]; LPSTR pp = Buf;
OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(!GetVersionEx(&os)) return;
switch(os.dwPlatformId){
case VER_PLATFORM_WIN32s:
pp += wsprintf(pp, "Win32s or Windows 3.1 \tVers: %ld.%ld",
os.dwMajorVersion,os.dwMinorVersion);
break;
case VER_PLATFORM_WIN32_WINDOWS:
if(0 == os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 95");
if(0 < os.dwMinorVersion) pp += wsprintf(pp,"%s","Windows 98");
break;
case VER_PLATFORM_WIN32_NT:
pp += wsprintf(pp, "Win32 or NT \tVers: %ld.%ld",
os.dwMajorVersion,os.dwMinorVersion);
break;
default: pp += wsprintf(pp, "unbekannt");
break;
}
pp += wsprintf(pp, " \tServicePack: %s",os.szCSDVersion);
MEMORYSTATUS ms;
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus( &ms ) ;
pp += wsprintf(pp,"\nmemory
in use\t:%12ld %%",ms.dwMemoryLoad);
pp += wsprintf(pp,"\nphys
mem free/total\t:%12ld \t%12ld" ,
ms.dwAvailPhys , ms.dwTotalPhys ) ;
pp += wsprintf(pp,"\npaging file free/total\t:%12ld \t%12ld" ,
ms.dwAvailPageFile , ms.dwTotalPageFile ) ;
pp += wsprintf(pp,"\nuser space free/total\t:%12ld \t%12ld" ,
ms.dwAvailVirtual , ms.dwTotalVirtual ) ;
pp += wsprintf(pp,"\n_______________________________________________" ) ;
MessageBox(auxGetHWND(),Buf,"Heap-Size",MB_OK);
}
9. Praktikum
Diese Aufgabe besteht darin, in die MFC einzuführen. Der Anwendungs-Assistent ( Datei==< Projekt ==<
... ) unterstützt Applikationen für SDI ( = Single-Document Interface ) und MDI ( = Multiple-Document
Interface). Für einen einfacheren "MFC-Durchblick" soll mit Hilfe der automatischen textgenerierung eine
möglichst kleine mfcApp-SDI-Anwendung ( Single Document Interface, mfc.h, mfc.cpp ) erstellt werden.
Die mfcApp soll keine externe MFC42DEU.DLL verwenden. Erzeugt werden CMainFrame ( MainFrm.h,
MainFrm.cpp ) und CChildView ( ChildView.h, ChildView.cpp )
●
●
●
●
●
●
Schauen Sie sich im Arbeitsbereich die erstellten Ressourcen an. Welche sind es?
Schauen Sie sich im Arbeitsbereich die erstellten Klassen an. Welche sind es?
Schauen Sie sich im Arbeitsbereich die erstellten Files an. Welche sind es?
Schauen Sie sich die cwl-Datei an ( Header-File-Namen, Klassen-Namen, Resourcen-Namen )
Schauen Sie sich das Erstellungsprotokoll *.plg an ( html ).
Schauen Sie sich den File readme.txt ( Zusammenfassung, z.B. *.dsp: Projektdatei; *.clw:
enthält Infos für Klassen-Assistenten )
Wozu dient *.pch?
Schauen Sie sich den MFC-Quelltext an ( z.B. werden Member-Variablen durch ein m_-Präfix
gekennzeichnet, wie m_hDC ).
Von welcher Klasse ist CAboutDlg abgeleitet?
Von welcher Klasse ist CChildView abgeleitet?
Von welcher Klasse ist mfcApp abgeleitet?
Schauen Sie sich den Quelltext von einfachen MFC-Klassen an ( z.B. class CSize; class CPoint;
class CRect; )
Was bedeutet bei einer Console-Applikation ( wie bei OpenGL )
#pragma comment(linker, "/defaultlib:kernel32.lib")
#pragma comment(linker, "/entry:mainCRTStartup")
#pragma comment(linker, "/subsystem:windows")
Wie können Warnunge unterdrückt werden?
#pragma ...
Wozu dient #define ASSERT(f) ((void)0) ?
Wozu dient
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
Wozu dient #ifndef _DEBUG ... #define ASSERT(f) ((void)0) ... #end ? ASSERT() dient der
Prüfung von Variablen und der Anzeige von Fehler-Hinweisen.
Schreiben und testen Sie ein einfaches, eigenes MY_ASSERT(boolBed,AusgabeTxt)-Macro.
Was bedeutet:
#if
!defined(AFX_MAINFRM_H__7850FD27_9D7F_11D7_BDB2_00F944C10000__INCLUDED_)
#define AFX_MAINFRM_H__7850FD27_9D7F_11D7_BDB2_00F944C10000__INCLUDED_
Die //{{...//}} Klammerung dient als Positionsangabe zum Einfügen/Entfernen von MappingMakros ( z.B. ON_WM_SETFOCUS() ) durch den Klassen-Assistenten
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_SETFOCUS()
//}}AFX_MSG_MAP
Weitere Untersuchungen
Versuchen Sie die Tabelle herauszufinden, die die WM_Nachrichten den Funktionen zuordnet. Ein Anfang
ist:
struct AFX_MSGMAP_ENTRY {
UINT nMessage;
// windows message
UINT nCode;
// control code or WM_NOTIFY code
UINT nID;
// control ID (or 0 for windows messages)
UINT nLastID;
// used for entries specifying a range of control id's
UINT nSig;
// signature type (action) or pointer to message #
AFX_PMSG pfn;
// routine to call (or special value)
};
DECLARE_MESSAGE_MAP() fügt ein:
private: static const
AFX_MSGMAP_ENTRY _messageEntries[];
protected:
static AFX_DATA const
AFX_MSGMAP messageMap;
virtual const AFX_MSGMAP* GetMessageMap() const;