Systemprogrammierung II (SP II,Script 2005) - Benutzer

Transcrição

Systemprogrammierung II (SP II,Script 2005) - Benutzer
Systemprogrammierung II (SP II,Script 2005)
Inhaltsverzeichnis
: MENU | Infos | SP2-Script-Download | SP2-Praktikum | Betriebssystem | Win-Typen | "Hallo Welt"-Grundgerüst |
Nachrichten | Entwicklungsumgebung | Objekte | Resourcen | Dialoge | DLL's | MFC
SP II : MENU | Infos
↑ Praktikum
| auf01 | auf02 | rahmen-src | WM_-Protokollierung | gdi-class | auf03 | Test-Rahmen |
wc | auf04 | auf05 | auf06 | auf07
↑ Einleitung
| SP2-Einleitung | Ziel der Veranstaltung | Kognitive Ziele | Praktische Ziele | Was ist
ein Programm? | Programmiermodell | Was ist ein System? | ./img/fachwerk.jpg |
Objektbezogene Systembezeichnungen | ./img/telefon.jpg | Was sind Schnittstellen? |
Software-Ergonomie | Kybernetik | ./img/kybernetik.jpg | Beispiel: menschlicher
Körper | Was ist eine normal? | Was ist eine Norm? | Beispiele für Normen | Nationale
Normungsinstitutionen | Internationale Normungsinstitutionen | ECMA Standards |
Historisches | Einheiten | Prae-Potenzen
↑ Betriebssystem
| Betriebssystem | ./img/intel_architektur.gif | ./img/memory_management.gif |
./img/descriptor1.gif | ./img/descriptor2.gif | MS-DOS | Starten von DOS | SoftwareInterrupt | UNIX | UNIX und C | UNIX-Standardisierungen | Windows | Architektur
des NT-Betriebssystem | Struktur des NT 4.x-Betriebssystems | ./img/nt4.gif
↑ Windows Data Types
| Datentypen aus Hardwaresicht | Binärzahlen.htm | Beispiel: Gleitpunktzahlen |
Beispiel: Unicode | Beispiel: Unicode | Wie wird generischer UNICODE verwendet? |
C++Grundtypen | Standard C- Bibliotheks-Header-Files || C-Header-Files (
Funktionsnamen ) | Standard C++ Bibliotheks-Header-Files | Schlüsselwörter | C-/C++MACROS || windowsx.h | Windows Data Types | Windows-Standard Typen | RTLTypen | Ungarische Notation | Windows-Header-Files
↑ Entwicklungsumgebung
| Entwicklungsumgebung | ./img/ecma.gif | *.LIB - Files | Linker - Fehler | *.RC Files | Übersetzungsvorgang | Betriebssystem-Kern | KRNL386.EXE | USER.EXE |
GDI.EXE | Beispiel: GetDeviceCaps() | Beispiel: GetSystemMetrics()
↑ C/CPP-Grundgerüst
| Win - Grundgerüst | WinMain() initialisiert Register | WinMain() initialisiert den
Stack | WinMain() richtet Application-Message-Queue ein | WinMain() initialisiert die
C - Laufzeit - Bibliothek | WinMain() entfernt Prä - Nachrichten | WNDCLASSEXStruktur | RegisterClassEx() | CreateWindowEx() | Was ist ein Handle? |
Nachrichtenschleife | GetMessage() | Hot-Key's || ./img/translate_accelerator.gif |
TranslateMessage() | DispatchMessage() | CALLBACK - Funktion |
DEFAULT_WINDOW_PROC.htm | Beispiel: WM_PAINT - Nachricht | Wann wird
WM_PAINT ausgelöst? | BeginPaint(), EndPaint() | InvalidateRect(), ValidateRect(),
GetUpdateRect() | Sichtbarkeit von Fenstern | WM_CLOSE - Nachricht |
DefWindowProc() | DEFAULT_WINDOW_PROC.htm | "Hallo Welt" | WinMain()
↑ Windows Nachrichten
| Windows-Nachrichten | Application-Message-Queue | System-Message-Queue
||./img/system_message_queu.gif ||./img/keyboard_lparam.gif |
DEFAULT_WINDOW_PROC.htm | DEFAULT_DLG_PROC.htm | Tabelle der
Nachrichten-Prefixe | Message - Cracker - Macros | Portabilität | Win32 | Win16 |
Tastatur - Nachrichten | Tasten - Scan - Code | Tabelle der WM - Tastatur Nachrichten ||./img/key1.gif | Virtual - Tasten - Code | Tabelle der Virtual - Tasten Codes | Tasten - Zustand - Flags | Wie kann eine gedrücke SHIFT - Taste abgefragt
werden? | Wie kann eine Berechnung abgebrochen werden? | Wie kann eine gedrückte
CTRL - Taste
( VK_CONTROL ) per Programm simuliert werden? | Wie kann die CAPS - LOCK Taste
( VK_CAPITAL ) invertiert werden? | Wie kann ein "floating-pop-up-menu"
nach der Anzeige sichtbar bleiben? | lParam - Tastenflags | Maus - Nachrichten |
WM_MOUSE - Nachrichten | Nachrichtenverfolgung |
DEFAULT_WINDOW_PROC.htm
↑ Objekte
| Objekte | Lebensdauer von Objekten | Gegenüberstellung | Klassen - Objekte |
Fenster - Objekte || ./img/virtual_heap.gif | Beispiel CreateWindow(),
DestroyWindow() || ./img/object1.gif || ./img/object2.gif | GDI - Objekte | Device
Kontext | Funktionen zum Zeichnen MoveToEx(), LineTo(), Polyline() | Rectangle(),
MoveToEx(), LineTo(), MoveToEx(), LineTo(), Ellipse(), RoundRect() | Funktionen
zum Schreiben TextOut() | Beispiel: DrawText()
↑ Resourcen
| Resourcen | *.RC-Syntax | Vordefinierte Resourcen - Typen |
MAKEINTRESOURCE() - Macro | Resourcen - Itentifizierer | Benutzerdefinierte
Resourcen - Macros | Resource-Funktionen | Cursor - Resource | Icon - Resource |
String - Table - Resource | Menu - Resourcen | System - Menu | Beschleunigungs Tasten | LoadMenuIndirect || ./img/menu_indirect.gif | CREATE_DLG_INDIRECT ||
./img/dlg_indirect.gif | Ressourcen von dll's
↑ Dialoge
| Dialoge | Eingebaute klassen zur Ereignisbehandlung | Modale Dialoge |
MessageBox() | Beispiele: MessageBox || ./img/messagebox0.gif ||
./img/messagebox1.gif || ./img/messagebox4.gif || ./img/messagebox3.gif ||
./img/messagebox2.gif || ./img/messagebox5.gif | DialogBox() | Beispiel: DialogBox
als Hauptprogramm | About-Dialog | *.RC-File-Ausschnitt | Aufruf des About-Dialogs:
| Modless Dialoge | für Modeless: Haupnachrichten-Schleife | für Modeless: in der
CALLBACK | für Modeless: Aufruf | für Modeless: im Fenster hinterlegen |
CreateDialog() - Aufruf | für Modeless: | *.RC enthält | *.CPP enthält | Interne Dialog CALLBACK - Funktion | Standard - Dialoge | Controls | Static Text Control | Button
Control | Edit Control | Beispiel zu Edit | List Box Control | Combo Box Control |
Beispiel: Stringtable | Scroll Bar Control | Arrow - Keys und Notification Nachrichten
|| ./img/scroll.gif | Keyboard - Interface für Scroll - Bars | Custom Controls | HexRechner1 mit *.rc || ./img/rechner.gif | Hex-Rechner1 ohne *.rc | hex_rechner2 |
Eingebaute Klassen (Methode 1) | Eingebaute Klassen (Methode 2) | Sub-Classing |
Dialog-Erzeugung | Hauptnachrichten-Schleife für Modeless | Textausgabe in Control |
Taschenrechner mit Texteingabe
↑ DLL's
| DLLs | Lebensdauer von Objekten | Static-Linking | Dynamic-Linking |
Unterschiede zwischen Static-Dynamic-Linking | shared data segment | Verwenden
einer Funktion aus einer DLL
↑ MFC
| MFC | Grober Zusammenhang mit ATL | Entwicklungskriterien | MFC und
Nachrichten | MFC-Klassen-Typen | MFC-Schreibweise | Hinweise zur
Programmierung | Beispiel für CWND_Member-Funktion | CArray-Beispiel | Handles
und MFC | MFC-Klassenhirachie (CE) | MFC-Klassenhirachie ||
./img/mfc_hierachy_categories.gif || ./img/mfc_1.gif || ./img/mfc_2.gif | Hinweise zum
Übersezungsvorgang
↑ CSharp-Einführung
| C Sharp (Einführung) | Was ist .NET? | CS-Entwickler-Tools | CS-keywords | CSkeywords | Typen in C# | Boxing and Unboxing | dll-Funktionen in C# | CS-ConsoleApplikation | Beispiel für cs-Console-Applikation
SP2-Praktikum-Gruppeneinteilung
Mi 1.
8.00- 9.30
C405: Gruppe A1, ..
Mi 2.
9.50-11.20
C405: Gruppe B1, B2
Mi 3.
11.30-13.00
C405: Gruppe C1, ..
-------------------------------------------Do 4.
14.00-15.30
Do 5.
15.45-17.15
F305: Vorlesung
Do 6.
17.30-19.00
C405: Gruppe D1
Wie wird das SP2-Praktikum durchgeführt?
1.
2.
3.
4.
Aufgaben per Internet
Bearbeitungszeit 1 Woche
Punktbewertung + Kontrollfragen
keine Überschreitung der Bearbeitungszeit
Kontroll-Fragen | Teil 1 | Teil 2 | Teil 3 | Teil 4 | h: MS-Visual Studio .NET | h:Console (main-) Programm | h: Macros, Datentypen, Zeigern | Datentypen aus
Hardwaresicht
Für das Praktikum bitte unbedingt anmelden: [hier Klicken]
1. SP2-Praktikum (SS 2005)
Dieses Praktikum führt in die Windows-Projekt-Erstellung ein und wiederholt (mit groben Sprüngen) Programmierkenntnisse
und Voraussetzungen. Es ist günstig, die vorgegebene Bearbeitungsreihenfolge einzuhalten. Alle Tests, Kontrollfragen und
Lösungen sollen in EINEM einfachen Protokoll.txt-File (von Hand) mit-protokolliert werden.
Protokoll.txt-File etwa:
==============================================================
1. SP2-Praktikum (SS 2005)
bearbeitet von:
==============================================================
Aufgaben und Tests:
===================
1. Bemerkungen zur Console-Applikation:
...
2. Die Console-Applikation ergab:
...
3. ...
Kontroll-Fragen:
================
1. ...
2. ...
3. ...
...
↑
Aufgaben im einzelnen:
1. Es ist eine einfache Console-Applikation zu erstellen, mit der einige Tests durchzuführen sind.
2. Die Definition von Windows-Datentypen ist mit Hilfe einer Console-Applikation und
freopen() zu untersuchen
3. Es sind die unten angegebenen Tests durchzuführen und die Macros, Datentypen, Zeiger zu
verstehen:
❍
windows.h definiert zahlreiche Typen ( siehe z.B. windef.h ).
Welche typedef's sind richtig?
typedef char *LPSTR;
typedef unsigned int *PUINT;
typedef long BOOL;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned int UINT;
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 | HardwareArchtektur von Dadatypen
Welche Änderungen ergeben sich mit #define UNICODE für
❍
String und Char?
4. 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
zu MS-Visual Studio .NET
●
A. Ein neues Projekt anlegen:
.NET-Studio-Haupt-Menu:
DATEI NEU PROJEKT
Win32ConsoleAnwendung
LEERES C++-PROJEKT erstellen.
Beim Dialog des Anwendungsassistenten anstelle von "ÜBERBLICK"
bitte "ANWENDUNGSEINSTELLUNGEN" auswählen.
Dort wird KONSOLE-Anwendung und LEERES Projekt angeklickt.
Auchtung! Nur hier beim 1. Praktikum wird ein Win32-Konsole-Projekt
(main-Funktion) verwendet.
Später meistens eine WINDOWS-ANWENDUNG oder eine DLL-Erstellung.
Projektname: myauf01
Pfad wählen: ...
●
B. Einen CPP-Quelltext-File ins Projekt einfügen:
.NET-Studio-Haupt-Menu:
DATEI NEUES ELEMENT HINZUFÜGEN DATEIEN C++-Quellcodedatei
[x] dem Projekt hinzufügen
↑
Console-Applikation
Zum Ausführen von Tests (bitte Ergebnisse protokollieren) ist mit MS-Visual Studio .NET eine Console-Applikation zu erstellen:
#include <stdio.h>
#include <windows.h>
void main()
{
printf("sizeof(PSZ)
}
↑Tests
=%d\n", sizeof(PSZ));
zu Macros,Datentypen, Zeigern
Mit dieser Console-Applikation sollen Macros für die Ausgabe-Umleitung erstellt und getestet werden. Hier einige MacroBeispiele:
#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) kann definiert und für die Umleitung der Ausgabe auf die Console oder die Umleitung der
Ausgabe in den Quelltext-File verwendet werden:
#define stdout_to(f) if((freopen(f,"at",stdout)) == NULL) \
{fprintf(stderr,"\nredir-err\n");exit(-1);}
stdout_to("CON");
// Dieser Macro-Aufrufe schaltet die
// folgenden printf-Ausgaben auf die Konsole.
stdout_to(__FILE__);// Dieser Macro-Aufrufe gibt die
// folgenden printf-Ausgaben
// im aktuellen cpp-Quelltext-File aus.
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 verwendet wird:
#define UNICODE
#include <windows.h>
TCHAR a=(char)0xff;
LPSTR p="ABC";
LPTSTR pt=...
Etwas Wiederholung:
// Gegeben:
int x[] = { 8, 1, 7, 2, 6, 3, 5, 4, 0, -1, 1, -2, 2, -3 };
int k = 2, *z = &x[5];
// Gesucht: Welche Werte haben damit die folgenden Ausdrücke:
1
*z+k
ergibt .....
2
*(z+k)
ergibt .....
3
z-x
ergibt .....
4
*(z-k)
ergibt .....
5
x[2]-*(z+2)
ergibt .....
6
x[2]-(*z+2)
ergibt .....
7
x[k+1] << *z
ergibt .....
8
x[*z+k]
ergibt .....
9
x[k**z]
ergibt .....
10 x[k**z+3]**z+3 ergibt .....
11
x[x[k]]
ergibt .....
12
x[x[k]]
ergibt .....
Machen sie sich bitte mit dem folgenden Programm das Prinzip von CALLBACK-Funktionen klar. Welchen Typ haben die
meisten Windows-CALLBACK-Funktionen?
#include <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 ) und zu erklären.
↑
Kontroll-Fragen:
1. Nenne Sie Unterschiede zwischen Console-Applikation und Window-Applikation!
2. Worin unterscheiden sich Console-Applikation/Win32-Applikation/AFC-Applikation?
3. Warum werden bei Windows so (entsetzlich) viele neue Variablen- und Struktur-Typen (z.B.
typedef unsigned short WORD;) eingeführt und wozu werden diese gebraucht?
4. Wieviele Byte hat ein double-Variable und wie ist eine double-Zahl intern (bitweise)
aufgebaut?
5. Wieviele Byte hat ein UNICODE-Char und mit wievielen 0-Bytes wird ein UNICODE-String
beendet?
6. In welchem Windows-Header-File ist das tolower-Macro definiert?
7. Was enthält ein dll-File?
8. Wozu dienen die folgenden Zeilen?
#include <stdio.h>
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
wchar_t *pwsz = __WFILE__;
9. Welches (Entwicklungs-Übersetzungs-) Programm untersucht und verwendet *.h, *.lib, *.res?
10. Wiederholung. Überlegen Sie bitte, 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]]
= ....
| Betriebssystem | ./img/intel_architektur.gif | ./img/memory_management.gif | ./img/descriptor1.gif | ./img/descriptor2.gif | MS-DOS | Starten von DOS | Software-Interrupt | UNIX | UNIX und C | UNIXStandardisierungen | Windows | Architektur des NT-Betriebssystem | Struktur des NT 4.x-Betriebssystems | ./img/nt4.gif
| Datentypen aus Hardwaresicht | Binärzahlen.htm | Beispiel: Gleitpunktzahlen | Beispiel: Unicode | Beispiel: Unicode | Wie wird generischer UNICODE verwendet?
| C++Grundtypen | Standard C- Bibliotheks-Header-Files || C-Header-Files ( Funktionsnamen ) | Standard C++ Bibliotheks-Header-Files | Schlüsselwörter | C-/C++-MACROS || windowsx.h | Windows Data
Types | Windows-Standard Typen | RTL-Typen | Ungarische Notation | Windows-Header-Files
| Entwicklungsumgebung | ./img/ecma.gif | *.LIB - Files | Linker - Fehler | *.RC - Files | Übersetzungsvorgang | Betriebssystem-Kern | KRNL386.EXE | USER.EXE | GDI.EXE | Beispiel: GetDeviceCaps() |
Beispiel: GetSystemMetrics()
| Win - Grundgerüst | WinMain() initialisiert Register | WinMain() initialisiert den Stack | WinMain() richtet Application-Message-Queue ein | WinMain() initialisiert die C - Laufzeit - Bibliothek | WinMain()
entfernt Prä - Nachrichten | WNDCLASSEX-Struktur | RegisterClassEx() | CreateWindowEx() | Was ist ein Handle? | Nachrichtenschleife | GetMessage() | Hot-Key's || ./img/translate_accelerator.gif |
TranslateMessage() | DispatchMessage()
| CALLBACK - Funktion | Beispiel: WM_PAINT - Nachricht | Wann wird WM_PAINT ausgelöst? | BeginPaint(), EndPaint() | InvalidateRect(), ValidateRect(), GetUpdateRect() | Sichtbarkeit von Fenstern |
WM_CLOSE - Nachricht | DefWindowProc() | "Hallo Welt" | WinMain()
↑
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 haben
( Memory-Management: Segnmentierung, Paging ):
Moderne Prozessoren können Descriptoren haben:
( Zugriffstypen, Zugriffrechte, Privilege Level, Call Gates, Interrupt and Exception-Handling, usw. )
Ein Betriebssystem ( Operating System, Systemsoftware, Basisprogramme ) besteht aus Software mit Basisroutinen für die Hardware - Ansteuerung und die Hardware Resourcen - Verwaltung. Ein Betriebssystem erfüllt 2 Aufgaben:
1. Virtuelle Maschine,
2. Resourcen-Verwalter
Die Betriebssystem - Architektur ( Instruktionssatz der zentralen Verarbeitungseinheit, der Speicher- organisation, Ein/Ausgabe auf Platten und Disketten, Bildschirm )
erfordert die (schwierige) Programmierung der Kontrollerbausteine. Diese Maschinen - Programme, wie Unterbrechungen ( interrupt ), Zeitgeber ( timer ) und die
Speicherverwaltung ( memory management ) sind in den BIOS enthalten. Für den Anwender ist die Benutzung dieser Programmteile einfacher, als die direkte
Programmierung der zugrundeliegende Hardware. Für den Anwender verhaelt sich das Betriebssystem wie eine Virtuelle Maschine.
Wenn auf einem Computer mehrere Benutzer gleichzeitig arbeiten wollen, entsteht die Notwendigkeit, Speicher, Ein-/Ausgabegeraete und andere ( teure ) Komponenten
zu verwalten und zu sichern. Aus dieser Sicht hat das Betriebssystem die Aufgabe, festzustellen, wer welche Resourcen verwendet, Resourcen auf Anforderung zu
gewaehren, Unterbrechungens - Informationen zu sammeln und zwischen den gegenseitig sich überschneidenden Anforderungen mehrerer Benutzer oder Programme zu
vermitteln.
Die Software - Schichten:
1. Physikalische Geräte
2. Mikroprogrammierung
3. Maschinensprache
4. Betriebssystem
5. Kommando - Interpreter, Editoren, Compiler
6. Anwendungsprogramme
Die Punkte 1, 2, 3 werden auch zu einer Hardware - Schicht zusammengefaßt. Die Punkte 4, 5 bilden die Systemprogramme. Zu den Applikationen (
Anwendungsprogrammen 6 ) gehören Datenbanken, CAD, Spiele, Banksystem, Simulatoren, usw. ).
↑
MS-DOS
Etwa 1980 hat Jim Paterson (ausgehend vom CP/M-80) ein 6 KB umfassendes Betriebssystem QDOS (Quick and Durty Operating System) entwickelt. IBM wollte eine
neue 16-Bit-Maschine auf Intel-Basis auf den Markt bringen. Mircosoft übernahm Jim Paterson und entwickelte MS-DOS unter strenger Geheimhaltung die Version 1.0
(1981). 1983 war die Version 2.0 ( hierarchisches Dateisystem mit 9 Sektoren für 360 kB Laufwerke, installierbare Geraetetreiber, Bildschirmtreiber ANSI.SYS,
Backgroundprozessing ). 1984 entstand für den PC-AT die Version 3.0 ( Netzwerk, 20 MB Festplatte, 1.2 MB Diskettenlaufwerke, Verbesserungen der Ausführungszeiten
).
Der interne Aufbau des DOS - Kerns
DOS-BIOS
(
: ROM)
DOS-Kern
( I/O : IBMDOS.COM)
Kommandoprozessor (Shell: COMMAND.COM)
Unter DOS ausführbare DOS-Programme sind z.B. *.EXE und *.COM. *.COM-Programme können maximal 64 KB Code enthalten. Beim Laden von *.EXE Programmen
werden die absoluten Speicher- bezüge angepasst.
↑
Starten von DOS
Nach dem Einschalten wird geprüft ob im Laufwerk A: (falls leer dann B:, dann C:, usw.) eine Diskette ist. Der Boot-Sektor wird automatisch geladen, die Boot-Routine
wird ausgeführt und IBMBIO.COM und IBMDOS.COM geladen. Nun wird die Datei CONFIG.SYS gesucht und die in CONFIG.SYS enthaltenen Treiber werden geladen
(DEVICE-Befehl). Dadurch wird der Kern des Betriebssystems zusammengebaut (SYStem CONFIGurieren). Dann wird der Kommando- prozessor (COMMAND.COM)
geladen, der automatisch die in
Beim Starten von DOS wird zuerst die Datei CONFIG.SYS (Gerätetreiber) und dann die Datei AUTOEXEC.BAT abgearbeitet. Die in AUTOEXEC.BAT enthaltenen
*.COM- und *.EXE-Programme der Reihe nach ausführt. *.Bat steht für eine BATch-Job-Stapeldatei.
Achtung! Das folgenden Beispiele ( DOS 5.0 ) können nicht kritiklos übernommen werden!
Beispiel für CONFIG.SYS:
Beispiel für AUTOEXEC.BAT:
shell =c:\dos\command.com c:\dos\ /e:256 /p
country=49,,c:\dos\country.sys
device =c:\dos\himem.sys
device =c:\dos\emm386.exe 2048 noems
dos=high,umb
lastdrive = g
files =30
buffers=15
dh =c:\dos\smartdrv.sys 2048 1024
dh =c:\dos\ansi.sys
dh =c:\dos\ramdrive.sys 1024 /e
install=c:\dos\share.exe
@ECHO OFF
set comspec=c:\dos\command.com
path C:\DOS;c:\bc\bin;
append=c:\dos
in not "%prompt%"=="" goto ende
prompt $p$g
lh keyb gr
lh c:\dos\mouse.com
nc
:ende
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.
↑
Software-Interrupt
TabellenIndex
Speicher-Bild:
+-----------------------------------+
|
|
↑
↓
|----|----|----| ... |----|----|----| ... |----|-- ... ------------0.
1.
2.
33. 34. 35.
255.
Zielstelle
Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Dadurch ergeben sich die folgenden Vorteile: Wird das
Betriebssystem verbessert oder erweitert, so wird der Maschinencode an der Zielstelle geändert. Die Folge der Adressen an den Zielstellen verschieben sich. Wenn
Anwendungsprogramme die direkte Adresse der Zielstelle verwenden würden, so müßten bei jeder Betriebssystemänderung alle Anwendungsprogramme
angepaßt werden. Wenn ein Anwendungsprogramm Funktionen des Betriebssystems verwendet, so wird lediglich den Index der Interrupt - Tabelle benutzt ( z.B. INT
21h ). Dadurch funktionieren die alten Anwendungsprogramme auch unter einer neueren Version des Betriebssystems.
↑
UNIX
UNIX ist ein Mehrprogrammsystem. Die einzigen aktiven Einheiten in einem UNIX-System sind die ( sequeltiellen ) Prozesse. Jeder Prozess hat einen eigenen
Programmzähler. Viele Prozesse laufen im Hintergrund ( Dämon, z.B.Terminplanung mit cron ).
↑
UNIX und C
Nachdem Ken Thomson aus dem MIT - Projekt ( MULTiplexed Information and Computing Service, PL/I ) verlassen hatte, schrieb er auf der PDP-7 ein kleineres
Betriebssystem UNICS ( UNiplexed Information and Computing Service, kastriertes MULTICS, späterer Name UNIX ). Die Übertragung des gesamten Assembler Codes auf PDP-11/20, PDP-11/45, PDP-11/70 war schwierig. Deshalb wurde ein Programmiersprache B ( vereinfachtes BCPL, stark vereinfachtes PL/I ) entwickelt. B
hatte keine Strukturen. Dennis Ritchie erweiterte B zu C.
Um das Betriessystem auf einen neuen Computer zu übertragen wurde zunächste ( mit mittleren Aufwand ) der C - Compiler portiert. Die meisten Software - Anteile
konnten dann übernommen werden. Der Quellcode wurde kostenlos an Universitäten abgegeben.
C wurde die Sprache der Systemprogrammierung.
Ausgehend von der typenlosen Sprache BCPL wurde die Programmiersprache C von Ken Thomson und Dennis Ritchie bei den Bell Laboratories auf einer PDP-11
entwickelt. Das Betriebssystem UNIX ist weitgehend in C geschrieben. UNIX Ver. 6 ist zu 95% in C geschrieben. C ist eine einfache und universelle Programmiersprache,
die auch bei Mikrocontrollern als Assembler-Ersatz verwendbar ist. C ist heute i.a. die erste hoehere Programmiersprache, die auf einem neuen Computer,
Microcomputers, Minicomputers oder Mainframe laeuft. Wir wollen immer zwischen der Programmiersprache C und den Bibliotheken unterscheiden. Bibliotheken
enthalten eingebaute Funktionen und Dienstleistungen. Bei Projekten werden solche Bibliotheken mit Hilfe eines C-Compilers oft selbst erstellt (z.B. Window-, Grafik-,
Device-Bibliotheken). 1988 wurde ANSI-C X3J11 genormt.
C ist für Programmier-Anfaenger wegen der cryptischen-Schreibweise nicht so einfach wie z.B. BASIC. Mit C kann man flexibel bis auf Betriebssystem- und
Maschinenebene programmieren. Anders als z.B. bei OBERON gilt:
Die Verantwortung beim Programmieren mit C
( C++ ) liegt stets beim Programmierer!
↑
UNIX-Standardisierungen
Die Universität Kalifornia in Berkeley nutzte den C - Quellcode und entwickelte eigene UNIX-Erweiterungen ( vi, csh, Compiler für Pascal und Lisp, usw. ). Sun baute auf
dem Berkeley-Unix auf. Es gab unterschiedliche Unix-Normungsgremien z.B. AT&T SVID ( System V Interface Definition ), BSD ( Berkeley Sooftware Distribution ),
IEEE POSIX 1003.1 ( Portaples Operating System ). OSF ( IBM und weitere, Open Software Foundation, starke Erweiterungen X11, MOTIF, DCE, DME ), UI ( AT&T
und weitere, Unix International ).
Für UNIX hat sich die sogenannte Mach Gruppe schon frühzeitig bemüht, einen Kernel weiter zu entwickeln, der die folgenden Eigenschaften vereint:
●
Beibehaltung Schnittstelle
●
abstraktes Modell der Speicherverwaltung ( großer und nicht dicht besetzter Adreßraum, memory mapped files, Speicherverwaltungsmodule
für den Benutzer,
●
Interprozeßkommunikation ( Transparenz im Netz, Schutzmechanismen, Austauschbare Datenmengen )
●
Beachtung von neuen Technologien ( Vernetzung, Mehrprozeßortechnik, enge und lose Kopplung, Prozeß in Tasks und Threads abbilden )
●
Werkzeuge ( im Kern eingebaute Testhilfe, Debugger, transparente Zugriffe auf andere Rechner, remote File access, remote Procedure Call
für C, Pascal und Common Lisp )
↑
Windows
Windows ist überwiegend in ANSI - C geschrieben. Einige wenige zeitkritische Teile des Betriebssystem - Kerns für die Hardware Abstraktions Layer ( HAL ) sind in
Assembler - Code geschrieben. Das Betriebssystem ist modular. Bei Bedarf werden die benötigten Teile ( DLL's ) geladen/entfernt.
Es gibt verschiedene Windows-Betriebssysteme:
1985
1987
1987
1988
1990
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;
1992 Windows 3.1;
1993 Windows 3.11;
1993 Windows NT ( Windows New Technology, 32-Bit-Betriebssystem,
für Workstations Windows NT 3.1, für Windows NT 3.1 Advanced
Server und Netzwerke );
1996 Windows NT 3.5, und Windows NT 4.0, Sicherheit, Erweiterbarkeit,
Stabilität und Skalierbarkeit, zentrale Administration,
NT-Server tritt in Konkurrenz zu Novell, Banyan oder UNIX
1995 Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte
Plug-and-Play-Technologie, mitgeliefert wurde der Internet-Browser
Internet Explorer, für Heimmarkt = Small Office/Home Office;
1998 Windows 98 ( Update für Windows 95, Active Desktop bindet den
Webbrowser Internet Explorer, unterstützt werden: FAT32, 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
NT-Server
●
Kompatibilität: Durch seine Submodule ist Windows
●
Die Server - Version unterstützt beliebig viele
NT in der Lage, Applikationen für die Betriebssyteme
gleichzeitige Datei- und Druckerverbindungen,
Windows 3.x, Windows 95, MS-DOS, OS/2 und
Datei- und Druckerserver auch für Macintosh,
POSIX zu betreiben.
●
●
Die Benutzerinformationen stehen allen Servern zur
Verfügung (Domänen Konzept),
Portierbarkeit: Windows NT ist fast vollständig in C
geschrieben. Für eine neue Hardware Architektur muß
deswegen lediglich eine neue HAL (Hardware
●
Benutzeradministration, Verzeichnis-Replikation,
Abstraction Layer) geschrieben werden und ein NTkomformer Compiler verfügbar sein.
●
●
TCP/IP Unterstützung ( DHCP, WINS, DNS, etc.),
●
NetWare Unterstützung ( GSNW, Migration Tool,
Skalierbarkeit: Windows NT unterstützt das
symmetrische Multiprocessing.
●
FPNW kompatibel ),
Sicherheit: Windows NT beinhaltet ein
●
durchgängiges Sicherheitskonzept, das darauf
(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 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.
fehlertolerante Plattenkonzepte werden unterstützt (
Parity, RAID 5 ),
ausgelegt ist, die Sicherheitsanforderungen des
Amerikanischen Verteidungsministeriums zu erfüllen
NT-Server ermöglicht eine zentrale
●
Multiuser Remote Access Service
●
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
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:
NT-Objekte
Ein NT-Thread:
●
Dateien
●
Gemeinsam
Segment eines
benutzter Speicher
Prozesses mit
Service Pack 3 die C2-
anderen Threads,
Zertifizierung für NT-Rechner
●
teilt sich das Code-
NT-Objekte
Unterschiedliche Objekte sind:
●
Executive Objects
●
hat bereits Windows NT 3.5 mit
und Daten-
●
Physikalische
Geräte jeder Art
●
ohne Netzwerkanbindung
●
erhalten.
hat seine eigenen
CPU-Register,
Prozesse/Threads
Stack-Raum und
●
NT ist für B1-Security ausgelegt.
●
Für jedes Objekt gibt es ein
einen eigenen
Instruktions Zähler,
●
erhält vom System
eine gewisse CPU Zeit, so daß alle
Threads des
Zugriffstoken
Prozesses
gleichzeitig
ausgeführt werden.
Dateisysteme:
Die von Windows NT unterstützten Dateisysteme können parallel nebeneinander laufen.
●
NTFS: New Technology File System, das eigentliche 64-Bit-Dateisystem von Windows NT mit starkem Fokus auf Sicherheit. Maximale
Dateigröße: 17 Milliarden Gbytes
●
HPFS: High Performance File System, OS/2-Dateisystem. Maximal Dateigröße: 4 bis 8 Gbytes ( wird ab NT 4.0 nicht mehr unterstützt ).
●
FAT: File Allocation Table, DOS Dateisystem und Diskettenformat unter NT. Maximale Dateigröße: 4 Gbytes.
↑
Datentypen aus Hardwaresicht
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
= bin 0110 0100 0100
= bin 0110 0100 0100
( . um 14 Positionen
2.567834*104 =
1110.0101 0111 =
1110. 0101 0111 =
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 füllbare Hüllkurven-Konturen ).
Bitmapped-Fonts entsprechen binären Bildern. Ein Font besteht z.B. aus einer "Bildersammlung" aus 256 einzelnen Elementen, die mit 8 Bits eindeutig identifiziert
werden können ( Code, z.B. ASCII ). Der Windows-ANSI-Zeichensatz enthält 256 Zeichen. Die ersten 32 Zeichen sind Steuerbefehle. Der ANSI-Zeichensatz ist von
Zeichen 32 bis Zeichen 127 mit dem ASCII-Zeichensatz identisch.
Unicode benutzt 16 Bits und kann 216 = 65536 verschieden Zeichen adressieren. Zu einem Zeichensatz gehören:
●
Steuerzeichen ( Silbentrennzeichen, Tabulatorzeichen )
●
Sonderzeichen und Einzelteile von Zeichen ( z.B. Doppelpunkt, deutsche Umlauten, usw. )
●
Zeichen für Zahlen ( mathematischer Formeln )
●
Silbenzeichen oder Wortzeichen für fernöstlicher Schriftkulturen
●
Schreibrichtung ( bei arabischen Zeichen etwa ist die Schreibrichtung von rechts nach links )
Bei der darstellung von Zeichen können diese auch dynamisch kombiniert werden ( z.B."ä" aus "a" und darüber gesetzten Doppelpunkt ).
Das Unicode-Konsortium ( gegründet 1991, Linguisten, Fachleute ) koordiniert die weltweiten Schrift-Zeichen-Standardisierungen. Zeichen-Codes sollten
systemunabhängig, programmunabhängig, sprachunabhängig sein und dennoch eine Vielfalt der Zeichen-Darstellung unterstützen.
●
US-ASCII: Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986.
●
ISO-646: International Standard--Information Processing--ISO 7-bit coded character set for information interchange, ISO 646:1983.
●
ISO-2022: International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension techniques, ISO
2022:1986.
●
ISO-8859: Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987.
Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4,
1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO
8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990.
●
ISO/IEC 10646: Unicode
Die vergebenen Codes ( Zahl-Zeichenwert-Zuordnung ) haben verbindlichen Charakter. Das Unicode-System ( Version 2.0 ) ist eine internationale Norm ISO/IEC 10646.
Das Unicode-System ist in Zahlenbereiche aufgeteilt ( ASCII, Schriftkultur, Sonderzeichen, auch noch Platz für Zukünftiges ).
Windows-Zeichen-Typen
Generisch
TCHAR
LPTSTR
ANSI
UNICODE
ANSI
UNICODE
Explizit
CHAR
WCHAR
LPSTR
LPWSTR
Aufgelöst
char
wchar_t
char *
wchar_t
Unicode
Damit die generischen Typen den Unicode-Size verwenden, muß #define UNICODE ( vor den #include ) definiert sein.
ANSI-Zeichen werden auf dem Tastatur-Ziffernblock unter Windows erzeugt durch:
[Alt]-Taste drücken und die ANSI-Nummer mit vorangestellter [0] eingeben.
Beispiel: ø = [Alt]+[0]+[2]+[4]+[8].
Generic-Text Data Type Mappings
TCHAR.H enthält Typen für die "automatische" Anpassung von MBCS (Multi-Byte-Characters) und SBCS (Single-Byte-Characters).
Generic-text
data type name
SBCS
(_UNICODE, _MBCS not defined)
_MBCS defined
_UNICODE defined
char
wchar_t
int
wint_t
_TSCHAR signed char
signed char
wchar_t
_TUCHAR unsigned char
unsigned char
wchar_t
_TXCHAR char
unsigned char
wchar_t
_TCHAR char
_TINT int
_T or _TEXT No effect (removed by preprocessor)
No effect (removed by
preprocessor)
L (converts following
character or string to its
Unicode counterpart)
Generische Textroutinen sind: _fgetts, _fputtc, _fputts, _ftprintf, _ftscanf, _gettchar, _getts, _istascii, _istcntrl,
_istgraph, _istlower, _istprint, _istpunct, _istspace, _istupper, _istxdigit, _itot, _ltot, _puttchar, _putts,
_sntprintf, _stprintf, _stscanf, _tcscat, _tcschr, _tcsclen, _tcscmp, _tcscpy, _tcscspn, _tcsdup, _tcsicmp,
_tcslen, _tcslwr, _tcsncat, _tcsnccat, _tcsncmp, _tcsnccmp, _tcsnccpy, _tcsncpy, _tcsncicmp, _tcsnset, _tcsncset,
_tcspbrk, _tcsrchr, _tcsrev, _tcsset, _tcsspn, _tcsstr, _tcstod, _tcstok, _tcstol, _tcstoul, _tfdopen, _tfopen,
_tfreopen, _totlower, _totupper, _tprintf, _tscanf, _ttoi, _ttol, _ultot, _ungettc, _vftprintf, _vsntprintf,
_vstprintf, _vtprintf
printf() verwendet char*
_tprintf() verwendet generische _TCHAR
kann generische _TCHAR verwenden
_tprintf() bei #define UNICODE wird wprintf() benutzt,
ohne #define UNICODE wird printf() benutzt
Wie wird generischer UNICODE verwendet?
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
/* hFile möge bereits existieren ... */
TCHAR Buf[1024];
int cc = wsprintf(Buf, TEXT("\r\n hwnd=0x%08x"),hwnd);
#ifdef UNICODE
char buf[512]; /* ansi-Buffer */
WideCharToMultiByte(CP_ACP,0,Buf,-1,buf,sizeof(buf),NULL,NULL);
cc = (cc+1)/2;
fwrite(buf, sizeof(TCHAR), cc, hFile);
#else
fwrite(Buf, sizeof(TCHAR), cc, hFile);
#endif
↑
Schlüsselwörter
Ein Betriessystem wird oft mit speziellen Entwicklungswerkzeugen entwickelt und gepflegt. Neuerungen (z.B. Einführung von DLL's) ändern auch die Unterstützung
durch "Standard-CPP-Compiler". CPP-Schlüsselwörter (hier MS-Keywords) sind reservierte, vordefinierte Identifizierer, die eine besondere Bedeutung haben und deshalb
im eigenen C++-Quelltext nicht frei verwende werden können. Identifizierer mit führenden Underscores ("__...") sind MS-Erweiterungen.
Schlüsselwörter des CPP-Betriessystem-Compilers
↑
__abstract
__alignof
__asm
__assume
__based
__box
__cdecl
__declspec
__delegate
__event
__except
__fastcall
__finally
__forceinline
__gc
__hook
__identifier
__if_exists
__if_not_exists __inline
__int8
__int16
__int32
__int64
__interface
__leave
__m128
__m128d
__m128i
__multiple_inheritance __nogc
__noop
__pin
__property
__raise
__sealed
__single_inheritance __stdcall
__try_cast
__try/__except,
__try/__finally
__unhook
__uuidof
__value
__virtual_inheritance __w64
bool
break
case
catch
char
class
const
const_cast
continue
default
delete
deprecated dllexport
dllimport
do
double
dynamic_cast else
enum
explicit
extern
false
float
for
friend
goto
if
inline
int
long
mutable
naked
namespace new
noinline
noreturn
nothrow
novtable
operator
private
property
protected
public
register
reinterpret_cast
return
selectany
short
signed
sizeof
static
static_cast
struct
switch
template
this
thread
throw
true
try
typedef
typeid
typename
union
unsigned
using declaration, uuid
using directive
virtual
void
volatile
wchar_t,__wchar_t while
C-/C++-MACROS
Windows verwendet zahlreiche MACROS, die in C/C++-Header-File enthalten sind. Beispiel: Windows-Header-File windowsx.h
__super
↑
C++Grundtypen
C++ kennt main() für Program Startup and Termination und die Standard-Streams: cin ( for standard input ), cout ( for standard output ), cerr ( for unbuffered standard
error output ), clog ( for buffered standard error output ).
C++ kennt die Header-Files ( bzw. subset ) : algorithm, bitset, cassert, cctype, cerrno, cfloat, ciso646, climits, clocale, cmath, complex, csetjmp, csignal, cstdarg, cstddef,
cstdio, cstdlib, cstring, ctime, cwchar, cwctype, deque, exception, fstream, functional, iomanip, ios, iosfwd, iostream, istream, iterator, limits, list, locale, map, memory,
numeric, ostream, queue, set, sstream, stack, stdexcept, streambuf, string, strstream, utility, valarray, vector
Unterschiedliche Maschinen haben unterschiedlich geeignete Darstellungen ( Speicherbedarf, Geschwindigkeit, Vorzeichen, Big/Little Endian, usw. ).
Typ
C++ garantiert die folgenden Relationen:
1 == sizeof(char) <= sizeof(short) <= sizeof(int)
<= sizeof(long) <= sizeof(float) <= sizeof(double)
Beispiel
Typen für Integer
char entspricht bei vielen Maschinen einem 8-Bit-signed-Wert;
char
char
char
char
//
char
//
//
//
//
//
char
//
t =
c0 =
*p =
c[5]
'\t'; /* 0x09 */
( char ) 0x61;/* 'a' */
& c0; /* pStr -> c0 */
= {'A', 'B', 'C'};
0x41 0x42 0x43 0x00 0x00
*ptrs[5] = {"abc","ABC"};
ptrs[0] -> 0x61 0x62 0x63 0x00 0x00
ptrs[1] -> 0x41 0x42 0x43 0x00 0x00
ptrs[2] == NULL
ptrs[3] == NULL
ptrs[4] == NULL
*pStr = "ABC";
pStr -> 0x61 0x62 0x63 0x00
short int entspricht signed short int vorzeichbehaftete Zahl, bei 32 Bit Maschinen meist 2 Byte;
int entspricht signed int; all. darf int bei mehrfach Kombinationen weggelassen werden; bei 32 Bit Maschinen meist sizeof(int) = 4;
int i1 = 256+255; char ch = i1;/* ch=255 */ int i2 = ch; /* i2 = -1 oder 255 */
long int entspricht signed long int; bei 32 Bit Maschinen meist sizeof(long) = 4
Typen für Fließkommazahlen
float bei 32 Bit Maschinen meist sizeof(float) = 4
double bei 32 Bit Maschinen meist sizeof(double) = 8
long double bei 32 Bit Maschinen meist sizeof(double) = 8
Typen für vorzeichenlose Integer, logische Werte, Bitfelder, usw.
unsigned char entspricht bei 32 Bit Maschinen meist 1 Byte;
unsigned short int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 2 Byte; unsigned short int shorti = -1; liefert ...
unsigned int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned int ui = -1; liefert ...
unsigned long int vorzeichenlose ganze Zahlen, bei 32 Bit Maschinen meist 4 Byte; unsigned long l = -1; liefert ...
↑
Standard C- Bibliotheks-Header-Files
Hier sind einige C-Header-Files ( Funktionsnamen ).
Zum Vergleich siehe EINEN Windows-Header-File: windowsx.h
↑
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
cassert.h
for enforcing assertions when functions execute
cerrno.h
for testing error codes reported by library functions
ciso646.h for programming in ISO 646 variant character sets
clocale.h
for adapting to different cultural conventions
complex.h for defining a template class that supports complex arithmetic
csignal.h
for controlling various exceptional conditions
cstddef.h for defining several useful types and macros
cstdlib.h
for performing a variety of operations
ctime.h
for converting between various time and date formats
cwctype.h for classifying wide characters
exception.h for defining several functions that control exception handling
bitset.h
cctype.h
cfloat.h
climits.h
cmath.h
csetjmp.h
cstdarg.h
cstdio.h
cstring.h
cwchar.h
deque.h
fstream.h
for defining a template class that administers sets of bits
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
functional.h for defining several templates that help construct predicates
iomanip.h
for the templates defined in algorithm.h and numeric.h
ios.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 streams iso646.h.h
istream.h for defining the template class that performs extractions
iterator.h
limits.h
for testing numeric type properties
list.h
locale.h
for defining several classes and templates that control locale-specific map.h
behavior, as in the iostreams classes
memory.h for defining several templates that allocate and free storage for
new.h
various container classes
numeric.h for defining several templates that implement useful numeric functions ostream.h
queue.h
for defining a template class that implements a queue container
set.h
sstream.h
for defining several iostreams template classes that manipulate
string containers
stdexcept.h for defining several classes useful for reporting exceptions
string.h
for defining a template class that implements a string container
typeinfo.h for defining class type_info, the result of the typeid operator
valarray.h for defining several classes and template classes
that support value-oriented arrays
↑
stack.h
for declaring several iostreams manipulators that take an argument
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
for declaring several functions that allocate and free storage
for defining the template class that performs insertions
for defining template classes that implement associative containers
with unique elements
for defining a template class that implements a stack container
streambuf.h for defining template classes that buffer iostreams operations
strstream.h for defining several iostreams classes that manipulate in-memory
character sequences
utility.h
for defining several templates of general utility
vector.h
for defining a template class that implements a vector container
Windows-Standard Typen
Ein Betriessystem ( im Gegensatz zur C++-Definition ) arbeitet mit ( exakt ) festgelegten Typen, Strukturen und Speicherabbildern.
↑
Windows Data Types
Es gibt Zahlreiche Betriebssystemstrukturen (Interface-Funktionen, Parameterart und -folge auf Stack, Nachrichtenspezifikationen, Systemparamter, Alignment, Hardwareund Treiber-Abhängigkeiten, usw.). 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.
Term
Header
Description
ATOM
Windef.h: typedef WORD ATOM;
Atom
BOOL
Windef.h: typedef int BOOL;
Boolean variable (should be TRUE or FALSE).
BOOLEAN
Winnt.h:typedef BYTE BOOLEAN;
Boolean variable (should be TRUE or FALSE).
BYTE
Windef.h: typedef unsigned char BYTE;
Byte (8 bits).
CALLBACK
Windef.h: #define CALLBACK __stdcall
Calling convention for callback functions.
CHAR
Winnt.h: typedef char CHAR;
8-bit Windows (ANSI) character.
COLORREF
Windef.h: typedef DWORD COLORREF;
Red, green, blue (RGB) color value (32 bits). See
CONST
Windef.h:#define CONST const
Variable whose value is to remain constant
during execution.
DWORD
Windef.h: typedef unsigned long DWORD;
32-bit unsigned integer.
DWORDLONG
Winnt.h:typedef ULONGLONG DWORDLONG;
64-bit unsigned integer.
DWORD_PTR
Basetsd.h: typedef ULONG_PTR DWORD_PTR;
Unsigned long type for pointer precision. Use
when casting a pointer to a long type to perform
pointer arithmetic. (Also commonly used for
general 32-bit parameters that have been
extended to 64 bits in 64-bit Windows. )
DWORD32
Basetsd.h:typedef unsigned int DWORD32;
32-bit unsigned integer.
DWORD64
Basetsd.h: typedef unsigned __int64 DWORD64;
64-bit unsigned integer.
FLOAT
Windef.h: typedef float FLOAT;
Floating-point variable.
HACCEL
Windef.h: typedef HANDLE HACCEL;
Handle to an ACCEL-Tab
HANDLE
Winnt.h: typedef PVOID HANDLE;
Handle to an object.
HBITMAP
Windef.h typedef HANDLE HBITMAP;
Handle to a
HBRUSH
Windef.h: typedef HANDLE HBRUSH;
Handle to a
HCOLORSPACE
Windef.h if(WINVER >= 0x0400) typedef HANDLE HCOLORSPACE;
Handle
HCONV
Ddeml.h: typedef HANDLE HCONV;
Handle to a dynamic data exchange (DDE)
conversation.
HCONVLIST
Ddeml.h: typedef HANDLE HCONVLIST;
Handle to a DDE conversation list.
HCURSOR
Windef.h: typedef HICON HCURSOR;
Handle to a
HDC
Windef.h :typedef HANDLE HDC;
Handle to a
HDDEDATA
Ddeml.h: typedef HANDLE HDDEDATA;
Handle to DDE data.
HDESK
Windef.h: typedef HANDLE HDESK;
Handle to a
HDROP
Shellapi.h :typedef HANDLE HDROP;
Handle to an internal drop structure.
HDWP
Winuser.h: typedef HANDLE HDWP;
Handle to a deferred window position structure.
HENHMETAFILE
Windef.h: typedef HANDLE HENHMETAFILE;
Handle to an
HFILE
Windef.h: typedef int HFILE;
Handle to a file opened by
HFONT
Windef.h : typedef HANDLE HFONT;
Handle to a
HGDIOBJ
Windef.h: typedef HANDLE HGDIOBJ;
Handle to a GDI object.
HGLOBAL
Windef.h: typedef HANDLE HGLOBAL;
Handle to a global memory block.
HHOOK
Windef.h: typedef HANDLE HHOOK;
Handle to a
HICON
Windef.h: typedef HANDLE HICON;
Handle to an
HINSTANCE
Windef.h: typedef HANDLE HINSTANCE;
Handle to an instance.
HKEY
Windef.h: typedef HANDLE HKEY;
Handle to a registry key.
HKL
Windef.h: typedef HANDLE HKL;
Input locale identifier.
HLOCAL
Windef.h: typedef HANDLE HLOCAL;
Handle to a local memory block.
HMENU
Windef.h: typedef HANDLE HMENU;
Handle to a
HMETAFILE
Windef.h: typedef HANDLE HMETAFILE;
Handle to
HMODULE
Windef.h: typedef HINSTANCE HMODULE;
Handle to a module. The value is the base
address of the module.
HMONITOR
Windef.h : if(WINVER >= 0x0500) typedef HANDLE HMONITOR;
Handle to a display monitor.
HPALETTE
Windef.h: typedef HANDLE HPALETTE;
Handle to a
HPEN
Handle to a Pen
HRESULT
Winnt.h: typedef LONG HRESULT;
Return code used by interfaces. It is zero upon
success and nonzero to represent an error code or
status information.
HRGN
Windef.h: typedef HANDLE HRGN;
Handle to a
HRSRC
Windef.h: typedef HANDLE HRSRC;
Handle to a resource.
HSZ
Ddeml.h: typedef HANDLE HSZ;
Handle to a DDE string.
HWINSTA
Windef.h: typedef HANDLE WINSTA;
Handle to a
HWND
Windef.h: typedef HANDLE HWND;
Handle to a
INT
Windef.h:typedef int INT;
32-bit signed integer.
INT_PTR
Basetsd.h:#if defined(_WIN64) typedef __int64 INT_PTR; #else
typedef int INT_PTR;
Signed integral type for pointer precision. Use
when casting a pointer to an integer to perform
pointer arithmetic.
INT32
Basetsd.h: typedef signed int INT32;
32-bit signed integer.
INT64
Basetsd.h: typedef signed __int64 INT64;
64-bit signed integer.
LANGID
Winnt.h: typedef WORD LANGID;
Language identifier.
LCID
Winnt.h: typedef DWORD LCID;
Locale identifier.
LCTYPE
Winnls.h: typedef DWORD LCTYPE;
Locale information type.
LGRPID
Language group identifier.
LONG
Winnt.h: typedef long LONG;
32-bit signed integer.
LONGLONG
Winnt.h: #if !defined(_M_IX86) typedef __int64 LONGLONG; #else
typedef double LONGLONG;
64-bit signed integer.
LONG_PTR
Basetsd.h: #if defined(_WIN64) typedef __int64 LONG_PTR; #else
typedef long LONG_PTR;
Signed long type for pointer precision. Use when
casting a pointer to a long to perform pointer
arithmetic.
LONG32
Basetsd.h: typedef signed int LONG32;
32-bit signed integer
LONG64
Basetsd.h: typedef __int64 LONG64;
64-bit signed integer
LPARAM
Windef.h: typedef LONG_PTR LPARAM;
Message parameter.
LPBOOL
Windef.h:typedef BOOL *LPBOOL;
Pointer to a BOOL.
LPBYTE
Windef.h: typedef BYTE *LPBYTE;
Pointer to a BYTE.
LPCOLORREF
Windef.h: typedef DWORD *LPCOLORREF;
Pointer to a COLORREF value.
LPCSTR
Winnt.h: typedef CONST CHAR *LPCSTR;
Pointer to a constant null-terminated string of 8bit Windows (ANSI) characters.
LPCTSTR
Winnt.h: #ifdef UNICODE typedef LPCWSTR LPCTSTR; #else typedef
LPCSTR LPCTSTR;
An LPCWSTR if is defined, an LPCSTR
otherwise.
LPCVOID
Windef.h: typedef CONST void *LPCVOID;
Pointer to a constant of any type.
LPCWSTR
Winnt.h: typedef CONST WCHAR *LPCWSTR;
Pointer to a constant null-terminated string of 16bit Unicode characters.
LPDWORD
Windef.h: typedef DWORD *LPDWORD;
Pointer to a DWORD.
LPHANDLE
Windef.h: typedef HANDLE *LPHANDLE;
Pointer to a HANDLE.
LPINT
Windef.h: typedef int *LPINT;
Pointer to an INT.
LPLONG
Windef.h: typedef long *LPLONG;
Pointer to a LONG.
LPSTR
Winnt.h: typedef CHAR *LPSTR;
Pointer to a null-terminated string of 8-bit
Windows (ANSI) characters.
LPTSTR
Winnt.h: #ifdef UNICODE typedef LPWSTR LPTSTR; #else typedef
LPSTR LPTSTR;
An LPWSTR if is defined, an LPSTR otherwise.
LPVOID
Windef.h: typedef void *LPVOID;
Pointer to any type.
LPWORD
Windef.h: typedef WORD *LPWORD;
Pointer to a WORD.
LPWSTR
Winnt.h: typedef WCHAR *LPWSTR;
Pointer to a null-terminated string of 16-bit
Unicode characters.
LRESULT
Windef.h: typedef LONG_PTR LRESULT;
Signed result of message processing.
PBOOL
Windef.h: typedef BOOL *PBOOL;
Pointer to a BOOL.
PBOOLEAN
Winnt.h: typedef BOOLEAN *PBOOLEAN;
Pointer to a BOOL.
PBYTE
Windef.h: typedef BYTE *PBYTE;
Pointer to a BYTE.
PCHAR
Winnt.h: typedef CHAR *PCHAR;
Pointer to a CHAR.
PCSTR
Winnt.h: typedef CONST CHAR *PCSTR;
Pointer to a constant null-terminated string of 8bit Windows (ANSI) characters.
PCTSTR
Winnt.h: #ifdef UNICODE typedef LPCWSTR PCTSTR; #else typedef
LPCSTR PCTSTR;
PCWSTR
Winnt.h: typedef CONST WCHAR *PCWSTR;
Pointer to a constant null-terminated string of 16bit Unicode characters.
PDWORD
Windef.h: typedef DWORD *PDWORD;
Pointer to a DWORD.
PDWORDLONG
Winnt.h: typedef DWORDLONG *PDWORDLONG;
Pointer to a DWORDLONG.
PDWORD_PTR
Basetsd.h: typedef DWORD_PTR *PDWORD_PTR;
Pointer to a DWORD_PTR.
PDWORD32
Basetsd.h: typedef DWORD32 *PDWORD32;
Pointer to a DWORD32.
PDWORD64
Basetsd.h: typedef DWORD64 *PDWORD64;
Pointer to a DWORD64.
PFLOAT
Windef.h: typedef FLOAT *PFLOAT;
Pointer to a FLOAT.
PHANDLE
Winnt.h: typedef HANDLE *PHANDLE;
Pointer to a HANDLE.
PHKEY
Windef.h: typedef HKEY *PHKEY;
Pointer to an HKEY.
A PCWSTR if is defined, a PCSTR otherwise.
PINT
Windef.h: typedef int *PINT;
Pointer to an INT.
PINT_PTR
Basetsd.h: typedef INT_PTR *PINT_PTR;
Pointer to an INT_PTR.
PINT32
Basetsd.h: typedef INT32 *PINT32;
Pointer to an INT32.
PINT64
Basetsd.h: typedef INT64 *PINT64;
Pointer to an INT64.
PLCID
Winnt.h: typedef PDWORD PLCID;
Pointer to an LCID.
PLONG
Winnt.h: typedef LONG *PLONG;
Pointer to a LONG.
PLONGLONG
Winnt.h: typedef LONGLONG *PLONGLONG;
Pointer to a LONGLONG.
PLONG_PTR
Basetsd.h: typedef LONG_PTR *PLONG_PTR;
Pointer to a LONG_PTR.
PLONG32
Basetsd.h: typedef LONG32 *PLONG32;
Pointer to a LONG32.
PLONG64
Basetsd.h: typedef LONG64 *PLONG64;
Pointer to a LONG64.
POINTER_32
Basetsd.h: #if defined(_WIN64) #define POINTER_32 __ptr32 #else
#define POINTER32
32-bit pointer. On a 32-bit system, this is a native
pointer. On a 64-bit system, this is a truncated 64bit pointer.
POINTER_64
Basetsd.h: #define POINTER_64 __ptr64
64-bit pointer. On a 64-bit system, this is a native
pointer. On a 32-bit system, this is a signextended 32-bit pointer.
PSHORT
Winnt.h: typedef SHORT *PSHORT;
Pointer to a SHORT.
PSIZE_T
Basetsd.h: typedef SIZE_T *PSIZE_T;
Pointer to a SIZE_T.
PSSIZE_T
Basetsd.h: typedef SSIZE_T *PSSIZE_T;
Pointer to a SSIZE_T.
PSTR
Winnt.h: typedef CHAR *PSTR;
Pointer to a null-terminated string of 8-bit
Windows (ANSI) characters.
PTBYTE
Winnt.h: typedef TBYTE *PTBYTE;
Pointer to a TBYTE.
PTCHAR
Winnt.h: typedef TCHAR *PTCHAR;
Pointer to a TCHAR.
PTSTR
Winnt.h: #ifdef UNICODE typedef LPWSTR PTSTR; #else typedef LPSTR
A PWSTR if is defined, a PSTR otherwise.
PTSTR;
PUCHAR
Windef.h: typedef UCHAR *PUCHAR;
Pointer to a UCHAR.
PUINT
Windef.h: typedef UINT *PUINT;
Pointer to a UINT.
PUINT_PTR
Basetsd.h: typedef UINT_PTR *PUINT_PTR;
Pointer to a UINT_PTR.
PUINT32
Basetsd.h: typedef UINT32 *PUINT32;
Pointer to a UINT32.
PUINT64
Basetsd.h: typedef UINT64 *PUINT64;
Pointer to a UINT64.
PULONG
Windef.h: typedef ULONG *PULONG;
Pointer to a ULONG.
PULONGLONG
Windef.h: typedef ULONGLONG *PULONGLONG;
Pointer to a ULONGLONG.
PULONG_PTR
Basetsd.h: typedef ULONG_PTR *PULONG_PTR;
Pointer to a ULONG_PTR.
PULONG32
Basetsd.h: typedef ULONG32 *PULONG32;
Pointer to a ULONG32.
PULONG64
Basetsd.h: typedef ULONG64 *PULONG64;
Pointer to a ULONG64.
PUSHORT
Windef.h: typedef USHORT *PUSHORT;
Pointer to a USHORT.
PVOID
Winnt.h: typedef void *PVOID;
Pointer to any type.
PWCHAR
Winnt.h: typedef WCHAR *PWCHAR;
Pointer to a WCHAR.
PWORD
Windef.h: typedef WORD *PWORD;
Pointer to a WORD.
PWSTR
Winnt.h: typedef WCHAR *PWSTR;
Pointer to a null-terminated string of 16-bit
Unicode characters.
SC_HANDLE
Winsvc.h: typedef HANDLE SC_HANDLE;
Handle to a service control manager database.
SC_LOCK
Winsvc.h: typedef LPVOID SC_LOCK;
Lock to a service control manager database.
SERVICE_STATUS Winsvc.h: typedef HANDLE SERVICE_STATUS_HANDLE;
_HANDLE
Handle to a service status value.
SHORT
Winnt.h: typedef short SHORT;
Short integer (16 bits).
SIZE_T
Basetsd.h: typedef ULONG_PTR SIZE_T;
The maximum number of bytes to which a
pointer can point. Use for a count that must span
the full range of a pointer.
SSIZE_T
Basetsd.h: typedef LONG_PTR SSIZE_T;
Signed SIZE_T.
TBYTE
Winnt.h: #ifdef UNICODE typedef WCHAR TBYTE; #else typedef
unsigned char TBYTE;
A WCHAR if is defined, a CHAR otherwise.
TCHAR
Winnt.h: #ifdef UNICODE typedef WCHAR TCHAR; #else typedef char
TCHAR;
A WCHAR if is defined, a CHAR otherwise.
UCHAR
Windef.h: typedef unsigned char UCHAR;
Unsigned CHAR.
UINT
Windef.h: typedef unsigned int UINT;
Unsigned INT.
UINT_PTR
Basetsd.h: #if defined(_WIN64) typedef unsigned __int64 UINT_PTR;
#else typedef unsigned int UINT_PTR;
Unsigned INT_PTR.
UINT32
Basetsd.h: typedef unsigned int UINT32;
Unsigned INT32.
UINT64
Basetsd.h: typedef usigned __int 64 UINT64;
Unsigned INT64.
ULONG
Windef.h: typedef unsigned long ULONG;
Unsigned LONG.
↑
ULONGLONG
Winnt.h: #if !defined(_M_IX86) typedef unsigned __int64
ULONGLONG; #else typedef double ULONGLONG
ULONG_PTR
Basetsd.h: #if defined(_WIN64) typedef unsigned __int64 ULONG_PTR;
Unsigned LONG_PTR.
#else typedef unsigned long ULONG_PTR;
ULONG32
Basetsd.h: typedef unsigned int ULONG32;
Unsigned LONG32.
ULONG64
Basetsd.h: typedef unsigned __int64 ULONG64;
Unsigned LONG64.
USHORT
Windef.h: typedef unsigned short USHORT;
Unsigned SHORT.
USN
Winnt.h: typedef LONGLONG USN;
Update sequence number (USN).
VOID
Winnt.h: #define VOID void
Any type.
WCHAR
Winnt.h: typedef wchar_t WCHAR;
16-bit Unicode character.
WINAPI
Windef.h: #define WINAPI __stdcall
Calling convention for system functions.
WORD
Windef.h: typedef unsigned short WORD;
16-bit unsigned integer.
WPARAM
Windef.h: typedef UINT_PTR WPARAM;
Message parameter.
64-bit unsigned integer.
RTL-Typen
Windows-Standard Typen der RTL ( Run-Time Library )
Typ
clock_t structure
_complex structure
Beschreibung
Stores time values; used by clock.
TIME.H
Stores real and imaginary parts of complex numbers; used by _cabs.
MATH.H
_dev_t short or unsigned integer Represents device handles.
div_t, ldiv_t structures
deklariert in
SYS\TYPES.H
Store values returned by div and ldiv, respectively.
STDLIB.H
Stores error information for _matherr.
MATH.H
Stores information about current state of stream; used in all stream I/O operations.
STDIO.H
_finddata_t,
_wfinddata_t
_wfinddatai64_t
structures
_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.
_finddata_t: IO.H
_wfinddata_t: IO.H, WCHAR.H
_wfinddatai64_t: IO.H, WCHAR.H
_FPIEEE_RECORD structure
Contains information pertaining to IEEE floating-point exception; passed to userdefined trap handler by _fpieee_flt.
FPIEEE.H
_exception structure
FILE structure
fpos_t
(long integer, __int64,
or structure, depending
on the target platform)
Used by fgetpos and fsetpos to record information for uniquely specifying every
position within a file.
STDIO.H
_HEAPINFO structure
Contains information about next heap entry for _heapwalk.
MALLOC.H
jmp_buf array
Used by setjmp and longjmp to save and restore program environment.
SETJMP.H
lconv structure
Contains formatting rules for numeric values in different countries.
LOCALE.H
Represents file-offset value.
SYS\TYPES.H
Returned by _onexit.
STDLIB.H
Type of argument to _set_new_handler.
NEW.H
Result of subtraction of two pointers.
STDDEF.H
Type of object that can be modified as atomic entity, even in presence of
asynchronous interrupts; used with signal.
SIGNAL.H
Result of sizeof operator.
STDDEF.H and other include files
Contains file-status information returned by _stat and _fstat.
SYS\STAT.H
time_tlong integer
Represents time values in mktime and time.
TIME.H
_timeb structure
Used by _ftime to store current system time.
SYS\TIMEB.H
_off_t long integer
_onexit_t pointer
_PNH pointer to function
ptrdiff_t integer
sig_atomic_t integer
size_t unsigned integer
_stat structure
tm structure
_utimbuf structure
va_list structure
Used by asctime, gmtime, localtime, mktime, and strftime to store and retrieve time TIME.H
information.
Stores file access and modification times used by _utime to change file-modification SYS\UTIME.H
dates.
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.
STDARG.H
Useful for writing portable programs for international markets.
STDDEF.H, STDLIB.H
wctrans_t integer
Represents locale-specific character mappings.
WCTYPE.H
wctype_t integer
Can represent all characters of any national character set.
WCHAR.H
Type of data object that can hold any wide character or wide end-of-file value.
WCHAR.H
wchar_t internal
type of a wide character
wint_t integer
Die Typen und Strukturen eines Betriessystems sind vielfältig und umfangreich. Windows-Typen werden u.a. für Funktions - Parameter, Funktions-Rückgabe-Werte, und
für Nachrichten benötigt.
Handles werden benutzt, um mit einer Deskriptor-Tabelle auf geladenen Resourcen oder einen benötigten globalen Kontext zuzugreifen. Ein Handle entspricht dem Index
der Deskriptor-Tabelle. Ein 8-Byte Deskriptor-Eintrag enthält die Ziel-Byte-Adresse, den Byte-Umfang, die Zugriffsrechte.
↑
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,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
//
//
//
//
//
//
//
//
//
//
//
//
extended window style
pointer to registered class name
pointer to window name
window style
horizontal position of window
vertical position of window
window width
window height
handle to parent or owner window
handle to menu, or child-window identifier
handle to application instance
pointer to window-creation data
| Prefix Naming Conventions
↑
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
Hungarian Notation (nach MS):
Prefix Description
↑
Prefix Description
a
Array
b
BOOL (int)
c
Char
cb
Count of bytes
n
Short int
cr
Color reference value
p
Pointer
cx
Count of x (short)
s
String
DWORD (unsigned
long)
sz
Zero terminated String
dw
tm
Text metric
u
Unsigned int
ul
Unsigned long
(ULONG)
w
WORD (unsigned
short)
x,y
x, y coordinates
(short)
f
Flags (usually multiple
bit values)
fn
Function
g_
Global
h
Handle
i
Integer
l
Long
Windows-Header-Files
lp
Long pointer
m_
Data member of a
class
Prefix Combination Description
pszMyString
m_pszMyString
Convention
CMyClass
A pointer to a string.
A pointer to a string that is a data
member of a class.
Description
Prefix 'C' for C++ class names.
COMyObjectClass
Prefix 'CO' for COM object class
names.
CFMyClassFactory
Prefix 'CF' for COM class factory
names.
IMyInterface
Prefix 'I' for COM interface class
names.
CImpIMyInterface
Prefix 'CImpI' for COM interface
implementation classes.
Das Betriessystem wurde überwiegend mit C/C++ entwickelt. Die System-Funktionen sind als Maschinencode in DLL's enthalten. Für die Entwicklung der SystemFunktionen wurden Header-Quelltext-Files benutzt. Diese Header-Files werden auch für die Programm-Entwicklungen verwendet. Es gibt zahlreiche Windows-HeaderFiles:
_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
siehe z.B.: windowsx.h
↑
Entwicklungsumgebung
Um aus ASCII-Files ein lauffaehiges *.EXE-Programm zu erstellen werden Übersetzungsprogramme benötigt, die aus lesbarem Buchstaben-Code maschinen-Code
generieren. 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
*.asm für Assembler - Quelltexte, *.c für C-QuellTexte, *.cpp für C++-Quell-Texte,
●
*.obj für binärer OpCode nach dem Compilieren,
●
*.lib für Bibliotheks-Routinen und Dll-Zuordnungen,
Maschinencode ),
●
*.rc für Resourcen - Quelltexte,
●
Linker ( fügt compilierte Files zusammen ),
●
*.res für binärere Resourcen - Files,
●
Projektverwaltung ( überwacht den Build-Prozess ),
●
*.map für die DLL - Adressen,
●
Resourcen - Tools ( erstellt, übersetzt Properties ),
●
*.exe für den executierbarer File,
●
Debugger ( schrittweiser Programmablauf ) ,
●
*.rtf für ASCII-Rich-Text-File incl. Formatierung,
●
Nachrichten - Verfolgung ( Spy - Tools ),
●
*.hlp für binärer HeLP-Files
●
On-Line-Hilfe ( Dokumentation )
Maschinencode ),
●
Compiler ( übersetzt in Assembler bzw.
Moderne Werkzeuge bestehen aus Software - Komponenten zur Programmentwicklung. Die Zahl der benötigten Tools wächst. Anstatt diese Programme einzeln (oder mit
Kommandozeile, bzw. make-File) zu verwenden, werden integrierende Bedienungsumgebung interaktiv verwendet. Es bestehen vielschichtige Abhängigkeiten zu (
standardisierten ) Software-Systemen, die durch die gleiche Bedienungsumgebung unterstützt werden und Entwicklungen mit unterschiedlichen Biblioteken und
Programmiersprachen (Java, C, Assembler, C++, VB, usw.) ermöglichen. Je moderner und komplexer ein Entwicklungssystem ist, um so größer ist die Zahl der
Einstellungen und Variationen und die Einarbeitungszeit.
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
SC_
System Menu Command Values
SIZE_
WM_SIZE message wParam values
SORT_
Sorting IDs.
SS_
Static Control Constants
SW_
ShowWindow() Commands
TBS_
Tab style
VK_
Virtual Keys, Standard Set
WA_
WM_ACTIVATE state values
WM_
Window Messages
WM_DDE_
DDE - Mesages
WS_
Window Styles
WS_EX_
Extended Window Styles
WVR_
WM_NCCALCSIZE return values
*.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:
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 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.
↑
Betriebssystem-Kern
Am Anfang bestand das Windows-Betriebssystem aus weniger als 10 DLL's. Bei XP gibt es bis zu 2000 DLL's. Der eigentliche Betriebssystem - Kern besteht aus den drei
Dateien (nativ-Funktionen in DLL). Diese DLL's werden bei Start des Betriessystems geladen (und heissen deshalb nicht .dll sondern .exe).
●
KERNEL: ( 85 kB, 377 kB ), (bei XP: 91 kB, 981 kB)
●
USER: ( 47 kB, 321 kB ), (bei XP: 47 kB, 549 kB)
●
GDI: ( 21 kB, 162 kB ), (bei XP: 24 kB, 245 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
CreateEvent,
Event
OpenEvent
CloseHandle
File CreateFile
CloseHandle,
DeleteFile
Object Creator function
Destroyer function
device GetStdHandle
CloseHandle
OpenEventLog,
Event log RegisterEventSource, CloseEventLog
OpenBackupEventLog
File mapping
CreateFileMapping,
OpenFileMapping
Find file FindFirstFile
FindClose
Mailslot CreateMailslot
CloseHandle
Module
LoadLibrary,
GetModuleHandle
FreeLibrary
CloseHandle
Pipe
CreateNamedPipe,
CreatePipe
CloseHandle,
DisconnectNamedPipe
Semaphore
CreateSemaphore,
OpenSemaphore
CloseHandle
Mutex
CreateMutex,
OpenMutex
CreateProcess,
Process OpenProcess,
GetCurrentProcess
CloseHandle,
TerminateProcess
Heap HeapCreate
CloseHandle
HeapDestroy
CreateThread,
Thread CreateRemoteThread,
GetCurrentThread
Update resource BeginUpdateResource
↑
CloseHandle,
TerminateThread
Timer
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
Programmierschnittstelle (
Funktionen für die
lesbare Daten ( Resources )
Shell and Common Controls
Dialogelemente ( Controls ):
sind:
):
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 ), Alt-Tasten (
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
Mit Fonts und Texten werden die folgenden Funktionen benutzt:
CreateCompatibleDC
DrawEscape
GetDC
GetGraphicsMode
RestoreDC
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
cpp-Rahmen für Window-Applikation
Weil bereits ein erstes Programm unübersichtlich ist, wird das Grundgerüst zunächst im Pseudocode betrachtet. Ein einfaches Programm hat die folgende Struktur: Ein
Window-Programm besteht aus der WinMain()-Funktion, die
1. ... mit Hilfe von RegisterClassEx() eine Klasse einrichtet
2. ... mit Hilfe von CreateWindow die Daten für ein Fenster (zur Klasse) anlegt
3. ... eine Haupt-Nachrichten-Schleife einrichtet, die die Nachrichten an die (zu ergänzende)
CALLBACK-Funktion WndProc() sendet. WndProc() bearbeitet Nachrichten.
Wegen der vielen Parameter wird der C/C++ - Quelltext z.T. bereits unuebersichtlich. Auch verfuegbare Klassen - Bibliotheken verwenden den gleichen Aufbau ( und sind
oft 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. //
cpp-Rahmen für Window-Applikation:
#define UNICODE
#include <windows.h>
#include <stdio.h>
//#include <math.h>
LRESULT CALLBACK WndProc
(HWND hwnd, UINT umsg,WPARAM wParam, LPARAM lParam)
{
switch(umsg)
{
case WM_DESTROY: { PostQuitMessage(0);
break; }
case WM_RBUTTONDOWN: {
int xPos = (int)LOWORD(lParam);
break; }
case WM_KEYDOWN:{
switch (wParam) {
case VK_CLEAR:
case VK_NUMPAD5:
break; } // ende switch
break; } // ende WM_KEYDOWN
case WM_SIZE:{ // w = (int)LOWORD(lParam); h = (int)HIWORD(lParam);
break; }
case WM_PAINT:{ PAINTSTRUCT
ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc; GetClientRect(hwnd, &rc) ;
DrawText(hdc,TEXT("Hallo, Win!"),1,&rc,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 20, 20, NULL);
LineTo(hdc, 200, 100);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
break; }
default: return DefWindowProc(hwnd,umsg,wParam,lParam);
}
return 0;
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
// HINSTANCE hInstance = GetModuleHandle(0);
WNDCLASSEX wndClass = {0};
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc
= WndProc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 0;
wndClass.cbWndExtra
= 0;
wndClass.hInstance
= hInstance;
wndClass.lpszMenuName
= NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hIcon
wndClass.hCursor
wndClass.hIconSm
= LoadIcon (NULL, IDI_APPLICATION);
= LoadCursor(NULL, IDC_ARROW);
= LoadIcon (NULL, IDI_APPLICATION ) ;
if (!RegisterClassEx(&wndClass)) return -1 ;
HWND hwnd = CreateWindow(
TEXT("my_class"),
// window class name
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
20, 20,// initial position x,y,(CW_USEDEFAULT)
500,500,// initial x size cx,cy, (CW_USEDEFAULT)
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL);
// creation parameters
ShowWindow (hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG msg ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
// hier kann aufgräumt werden
return (int) msg.wParam;
// ende WinMain
Diese Programm besteht aus Teilen:
●
der CLALLBACK - Funktion LRESULT CALLBACK WndProc( HWND hWnd , UINT uMsg, WPARAM wParam, LPARAM lParam ) {
... } und
●
der Funktion int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { ... }
WinMain entspricht der main() - Funktion in C. Der (W)indow -(S)tyle WS_OVERLAPPEDWINDOW entspricht
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX)
#define WS_POPUPWINDOW
(WS_POPUP|WS_BORDER|WS_SYSMENU)
↑
WinMain()
Die Start - Adresse einer Window - Applikation ist die WinMain() - Funktion( APIENTRY ). WinMain ist der Haupt - Eintritts - Punkt für eine Windows - Anwendung.
Diese Funktion entspricht der Funktion main() bei einem C-Programm. Der WinMain - Startup - Code ruft die WinMain-Funktion durch den Namen auf. Windows
verwendet diese Funktion als "initial entry point" APIENTRY). Beim Start wird der Startup-Code ausgeführt, der u.a. die Windows-Funktionen
●
InitTask ( KRNL386 ),
●
InitApp ( USER ) und
●
WaitEvent( KERNEL)
aufruft. Danach ruft der Startup - Code unsere WinMain - Funktion auf. Diese Schritte bei Start eines Win - Programmes können grob skizziert werden:
↑
WinMain() initialisiert Register
InitTask füllt bei Win16 die folgenden Register mit Werten, die beim Laden der Applikation auf den Stack gelegt werden:
BX
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,
HINSTANCE hInstance,
LPVOID lpParam
);
//
//
//
//
//
//
//
//
//
//
//
//
extended window style
pointer to registered class name
pointer to window name
window style
horizontal position of window
vertical position of window
window width
window height
handle to parent or owner window
handle to menu, or child-window identifier
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.
↑
Was ist ein 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.
Nachrichtenschleife
// Die Nachrichtenschleife enthält:
while ( GetMessage( & msg, NULL, 0, 0 ) ) {
TranslateMessage( & msg ) ;
DispatchMessage ( & msg ) ;
}
↑
GetMessage()
GetMessage() holt aus dem Applikations - Buffer ( thread's message queue ) die nächste Nachricht und stellt diese in der MSG - Struktur zur Verfügung. GetMessage()
erhält keine Nachrichten von einer anderen Applikation. Entnimmt GetMessage() dem Buffer die WM_QUIT - Nachricht, so sendet die aufgerufene DefWindowProc()
WM_DESTROY und PostQuitMessage(); beendet die Haupt-Nachrichtenschleife.
BOOL GetMessage(
LPMSG lpMsg,
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.
↑
Hot-Keys
Existiert Accelerator-Tabelle hAccel ("Hot-Keys" für das Menü), so können in der Hauptnachrichten-Schleife, nach GetMessage(), die "Hot-Keys"-Ereignisse abgefangen
und mit Hilfe der Funktion
int TranslateAccelerator(HWND hWnd, HACCEL hAccel, LPMSG lpMsg);
die dem hWnd-Fenster zugeordnete CALLBACK-Funktion aufgerufen werden.
↑
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 uMsg, 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
uMsg = 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
Das Update- Rechteck wird in einer
RECT- Struktur gespeichert
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;
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
./img/wm_close.gif
x - Mausklick die uMsg = WM_CLOSE - Nachricht ausgelöst,
so wird die CALLBACK - Funktion
●
LRESULT CALLBACK WndProc( HWND hWnd , UINT uMsg, WPARAM wParam, LPARAM lParam )
mit uMsg = 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 uMsg, WPARAM wParam, LPARAM lParam )
Funktion wird mit uMsg = 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_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_NCHITTEST,
WM_GETTEXTLENGTH,
WM_SYSCOMMAND,
WM_SETCURSOR,
WM_NCMOUSEMOVE,
WM_CLOSE,
WM_DRAWITEM,
WM_NCPAINT,
WM_PAINT,
WM_ACTIVATE,
WM_MOUSEACTIVATE,
WM_KEYDOWN,
WM_QUERYOPEN,
WM_GETHOTKEY,
WM_NCACTIVATE,
WM_PAINTICON,
WM_SETREDRAW,
WM_SHOWWINDOW,
WM_SYSKEYDOWN,
WM_QUERYENDSESSION,
WM_SETHOTKEY,
WM_CANCELMODE,
WM_ERASEBKGND,
WM_WINDOWPOSCHANGING,
WM_NCLBUTTONDOWN,
WM_KEYUP,
WM_ISACTIVEICON,
WM_QUERYDRAGICON,
Kontroll-Fragen: Kontroll-Fragen | cpp-Rahmen-Programm(cpp-Quelltext) | Nachrichtenprotokollierung.cpp-Quelltext | gdi-class-Quelltext
| 2. SP2-Praktikum (SS 2005) | Hallo Welt | Text in Titelzeile | Maus-Postion in Titelzeile | Hinweise zu wsprintf() | Hinweise zur MessageBox()
Hinweise zur Nachrichtenprotokollierung | Hinweise zu WM_CHAR | Hinweise zu WM_KEYDOWN
↑
|
2. SP2-Praktikum (SS 2005)
Es soll ein erste "Hallo Welt"-Windows-Applikation geschrieben, getestet und erweitert werden. Hierzu sollen die TeilAufgabe 1, 2, 3, ..., usw. bearbeitet werden. Zur Reduzierung der Tipp-Tätigkeit darf von dem angegebenen cpp-RahmenProgramm ausgegangen werden. Das cpp-Rahmen-Programm wird erweitern.
Zum besseren Verstehen des Nachrichten-Konzeptes sind einige Tests durchzuführen. Es ist z.B. aktuelle MausPosition in der Titelzeile auszugeben, eine MessageBox() ist angezeigen. Die Nachrichten sollen in einem .txt-File
geschrieben werden. Später einmal sind die Nachrichten mit dem Spy-Werkzeug ( Spy ) zu verfolgen ( MausNachrichten, Tasten-Nachrichten, Fenstervergrößerung, usw. ). und die verwendeten Windows-Datenstrukturen mit
dem Debugger schrittweise anzuschauen.
1. Mit WinMain() ist eine Windows-Applikation zu schreiben. Ein Programm "Hallo
Welt" ist mit WinMain() und WndProc() zu erstellen. Verwenden Sie bitte das .cppRahmen-Programm.
2. Der Text in der Titelzeile ist bei WM_RBUTTONDOWN zu ändern
3. Die Maus-Position ( bei Klick mit der rechten Maus-Taste ) ist SetWindowText() in die
in Titelzeile zu schreiben.
4. Nun soll bei Klick mit der rechten Maus-Taste zusätzlich zur Maus-Position auch noch
MK_SHIFT oder/und MK_CONTROL in die in Titelzeile geschrieben werden.
MK_SHIFT (bzw. MK_CONTROL) soll die gleichzeit-gedrückte Shift-Taste (bzw.
Strg-Taste) anzeigen.
5. Es soll eine MessageBox() angezeigt werden, wenn die [A] Taste gedückt wird.
Verwenden Sie das Tasten-Ereignis WM_CHAR. In der MessageBox() soll die
Fenstergrösse (Breite,Höhe) ausgegeben werden.
6. An dieser Stelle soll das Nachrichten-Konzept besser verstanden werden. Hierzu ist die
WM_-Nachrichten-FOLGE zu prokollieren. Welches sind die ersten Nachrichten?
Welches sind die letzten Nachrichten? Welche Nachrichten wird beim "runter-drücken"
der A-Taste gesendet? Hier ist mehr zur Nachrichtenprotokollierung.
7. Die Tastatur soll nun "verfeinert" verwendet werden. Verwenden Sie hierzu das TastenEreignis WM_KEYDOWN. Wenn die [A] Taste gedückt wird, soll eine MessageBox()
angezeigt werden. Es soll eine ander MessageBox() angezeigt werden, wenn auf dem
Ziffernblock die [5] (bei aus-geschalteter NUM-Taste) gedrückt wird. Es soll eine ander
MessageBox() angezeigt werden, wenn auf dem Ziffernblock die [5] (bei eingeschalteter NUM-Taste) gedrückt wird.
8. Das "Hallo Welt"-Beispiel ist zu debuggen.
9. Es ist eine gdi-Klasse zu schreiben, zu testen und um die Möglichkeit einer FontBenutzung zu erweitern. Für Source-Hinweis siehe gdi-class-Quelltext
10. Die Nachrichten sind mit einem geeigneten Werkzeug ( Spy ) zu verfolgen.
11. optional: Es ist eine einfache Grafik zu erstellen, die die Funktionen MoveToEx(),
LineTo(), Ellipse(), Rectangle(), RoundRect(), Polyline(), PolyPolyline() verwendet.
12. optional: Mit einer Windows-Applikation sind unterschiedliche Parameter der
MessageBox()-Funktion zu untersuchen.
↑
Hallo Welt
Es ist ein einfaches, kleines Beispiel mit WinMain() und einer WndProc() - CALLBACK - Funktion sorgfältig zu
durchdenken. Hier ist ein cpp-Rahmen-Programm
Mit dem Debugger ist das Programm schrittweise durchzugehen. Das "Hallo Welt"-Beispiel ist zu debuggen und zu
kommentieren. Die Window-Daten-Strukturen sind anzuschauen (z.B. als Kommentar am Programm-Anfang in den
Quelltext 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-Postion 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:
↑
Hinweise zu wsprintf()
Die wsprintf()-Funktion kann (ähnlich zu printf) in einen Buffer formatierten text schreiben. Beispiel:
xPos = (int)LOWORD(lParam);
yPos = (int)HIWORD(lParam);
TCHAR Buf[1024]; int cc = 0;
cc += wsprintf(Buf[cc],TEXT("x=%4u"),xPos);
cc += wsprintf(Buf[cc],TEXT("y=%04u"),yPos);
SetWindowText( hwnd, Buf );
// oder z.B.:
MessageBox(0,Buf,TEXT("Titel"),MB_OK|MB_ICONINFORMATION);
↑
Hinweise zur MessageBox()
Die MessageBox() ist zu testen, indem bei einem Tasten-Anschlag ( siehe WM_CHAR ) eine "Hallo-Welt"MessageBox() angezeigt wird.
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
Bitte beachten Sie den Rückgabewert von MessageBox(). Ändern Sie bitte den Default-Button der MessageBox()
Verwenden Sie bitte verschiedene Icons
MB_ICONHAND
MB_ICONERROR
MB_ICONASTERISK
MB_ICONWARNING
MB_ICONSTOP
MB_ICONQUESTION
MB_ICONEXCLAMATION
MB_ICONINFORMATION
Erstellen Sie eine MessageBox(), die den eigenen Quelltext-Aufruf ( mit den \"-Zeichen ) im Client-Bereich anzeigt
↑
Hinweise zur Nachrichtenprotokollierung
Die Funktion begin_MSG_write(&hFile) öffnet im aktuellen Verzeichnis einen Textfile "nachrichten.txt" und wird
unmittelbar nach WinMain() aufgerufen. Der Textfile "nachrichten.txt" wird durch end_MSG_write(hFile)
geschlossen. end_MSG_write(hFile) wird unmittelbar vor return (int) msg.wParam; aufgerufen. Die Funktion
do_msg_write(hFile, hwnd,uMsg,wParam,lParam) protokolliert die Nachrichten im Textfile "nachrichten.txt".
do_msg_write(hFile, hwnd,uMsg,wParam,lParam) wird unmittelbar nach der CALLBACK-Funktion WndProc()
aufgerufen. Hier steht Quelltext zur Nachrichtenprotokollierung.
↑
Hinweise zu WM_CHAR
Nach WM_KEYDOWN wird WM_CHAR gesendet. Die TranslateMessage()-Funktion der Hauptnachrichten-Schleife
wandelt den Scan-Code in den Character-Code (Ascii). In der CALLBACK-Funktion steht etwa:
case WM_CHAR : {
switch ( wParam ) {
case 'A': break; //A-Taste
case '\b':
case '\t':
case '\n':
default :
}
break;
break;
break;
break;
//Rücktaste
//Tabulatortaste
//LF-Taste
//anderes Zeichen
}
Das innere des Fensters ist der Client-Bereich. GetClientRect() schreibt die Fenstergröße in rc.
RECT rc; //rc.left;rc.top;rc.right;rc.bottom;
GetClientRect(hwnd, &rc);
wsprintf() schreibt Text in den Buf. Eine MessageBox() kann Text anzeigen.
TCHAR Buf[1024]; /* Buffer */
int cc = wsprintf(Buf,TEXT("w=%4u, h=%4u"), ???, ???);
MessageBox(hwnd,Buf,TEXT("Fenstergroesse"),MB_OK|MB_ICONINFORMATION);
↑
Hinweise zu WM_KEYDOWN
Um WM_KEYDOWN-Nachrichten zu bearbeiten, steht in der CALLBACK-Funktion etwa:
switch(uMSG)
{
case WM_KEYDOWN:{
switch (wParam) {
case VK_CLEAR: {
case VK_NUMPAD5:{
} // ende switch
break; } // ende WM_KEYDOWN
break; }
break; }
Zur Überprüfung, ob die Shift-Taste gedrückt wurde, kann verwendet werden:
if ( GetKeyState(VK_SHIFT) & 0x80000000L) {
/* auch die SHIFT-Taste ist gedrückt */
...
}
↑
Kontroll-Fragen:
1. Welcher Unterschied besteht zwischen WNDCLASSEX wc = { 0 } ; und
ZeroMemory(&wc, sizeof(WNDCLASSEX));und memset(
&wc,0,sizeof(WNDCLASSEX)); ?
2. hInstance wird bei WinMain() übergeben. und kann anderseits durch HINSTANCE
hInstance = GetModuleHandle(0) erhalten werden. Stellen Sie (z.B. mit dem Debugger)
fest, ob hInstance den gleichen Inhalt hat .
3. Bei welchen API-Funktionen wird hInstance benötigt ?
4. Bei C/C++ steht vor der Funktionsdefinition nur der Rückgabetyp. Bei WindowsCALLBACK-Funktionen, wie z.B. bei
LRESULT CALLBACK WndProc
(HWND hwnd, UINT uMsg,WPARAM wParam, LPARAM lParam)
kommt zusätzliche CALLBACK hinzu. Was bedeutet CALLBACK? Wozu dient es ?
5. Was bedeutet typedef __int32 LRESULT; und bei welchen Funktionsdefinitionen wird
LRESULT verwendet ?
6. Welche Bedeutung haben die WindowProc()-Parameter HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam ?
7. Welche übergebene Nachricht kündigt das Schließen des Fensters an ?
8. Wodurch wird die WM_PAINT-Nachrichten ausgelöst ?
9. Was hat BeginPaint() mit sizing, moving, creating, scrolling und der Clipping-Region
zu tun ?
10. Wozu dient der Device-Context ? Welche Funktionen benutzen den Device-Context ?
11. Wozu dient WNDCLASSEX wc = { 0 }; ?
12. Wozu braucht ein mit CreateWindowEx() erstelltes Fenster eine Fensterklasse, die mit
RegisterClassEx() erstellt wurde ?
13. Wodurch werden die folgenden Nachrichten ausgelöst ?
a) WM_LBUTTONDOWN,
b) WM_CHAR
14. Wodurch werden die folgenden Nachrichten ausgelöst ?
a) WM_PAINT,
b) WM_DESTROY
15. Welches sind die ersten Nachrichten ?
16. Welches sind die letzten Nachrichten ?
17. Welche Nachrichten werden beim "runter-drücken" der A-Taste gesendet ? Ein Fenster
hat oben rechts ein [X]. Welche Nachricht wird durch einen Mausklick auf [X]
ausgelöst ?
18. Durch welche Windows-API-Funktion wird die Hauptnachrichten-Schleife beendet ?
19. Wozu werden die Windows-API-Funktionen InvalidateRect(hwnd,0,TRUE) und
UpdateWindow(hwnd) benötigt ?
20. Durch welche Funktionsfolge kann kann in ein Hauptfenster ein Ausgabe-Text zentriert
geschrieben
werden ?
cpp-Rahmen für Window-Applikation
Ein Window-Programm besteht aus der WinMain()-Funktion, die
1. ... mit Hilfe von RegisterClassEx() eine Klasse einrichtet
2. ... mit Hilfe von CreateWindow die Daten für ein Fenster (zur Klasse) anlegt
3. ... eine Haupt-Nachrichten-Schleife einrichtet, die die Nachrichten an die (zu ergänzende)
CALLBACK-Funktion WndProc() sendet. WndProc() bearbeitet Nachrichten.
// cpp-Rahmen für Window-Applikation:
#define UNICODE
#include <windows.h>
#include <stdio.h>
//#include <math.h>
LRESULT CALLBACK WndProc
(HWND hwnd, UINT umsg,WPARAM wParam, LPARAM lParam)
{
switch(umsg)
{
case WM_DESTROY: { PostQuitMessage(0);
break; }
case WM_RBUTTONDOWN: {
int xPos = (int)LOWORD(lParam);
break; }
case WM_KEYDOWN:{
switch (wParam) {
case VK_CLEAR:
case VK_NUMPAD5:
break; } // ende switch
break; } // ende WM_KEYDOWN
case WM_SIZE:{ // w = (int)LOWORD(lParam); h = (int)HIWORD(lParam);
break; }
case WM_PAINT:{ PAINTSTRUCT
ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc; GetClientRect(hwnd, &rc) ;
DrawText(hdc,TEXT("Hallo, Win!"),1,&rc,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 20, 20, NULL);
LineTo(hdc, 200, 100);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
break; }
default: return DefWindowProc(hwnd,umsg,wParam,lParam);
}
return 0;
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
// HINSTANCE hInstance = GetModuleHandle(0);
WNDCLASSEX wndClass = {0};
wndClass.cbSize
wndClass.style
wndClass.hInstance
wndClass.lpszClassName
wndClass.lpfnWndProc
wndClass.cbClsExtra
wndClass.cbWndExtra
wndClass.lpszMenuName
wndClass.hbrBackground
wndClass.hCursor
wndClass.hIcon
=
=
=
=
=
=
=
=
=
=
=
sizeof( WNDCLASSEX ) ;
CS_HREDRAW | CS_VREDRAW;
hInstance;
TEXT("my_class");
WndProc;
0;
0;
NULL;
(HBRUSH)GetStockObject(WHITE_BRUSH);
LoadCursor(NULL, IDC_ARROW);
LoadIcon (NULL, IDI_APPLICATION);
wndClass.hIconSm
= LoadIcon
(NULL, IDI_APPLICATION ) ;
if (!RegisterClassEx(&wndClass)) return -1 ;
HWND hwnd = CreateWindow(
TEXT("my_class"),
// window class name
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
20, 20,// initial position x,y,(CW_USEDEFAULT)
500,500,// initial x size cx,cy, (CW_USEDEFAULT)
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
// program instance handle
NULL);
// creation parameters
ShowWindow (hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG msg ;
while ( GetMessage ( & msg, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
// hier kann aufgräumt werden
return (int) msg.wParam;
// ende WinMain
Hilfe um WM_-Nachrichten in File zu schreiben
Die Funktion begin_MSG_write(&hFile) öffnet im aktuellen Verzeichnis einen Textfile "msg_protokoll.txt" und wird unmittelbar nach
WinMain() aufgerufen. Wird begin_MSG_write(&hFile) auskommentiert, so findet keine Protokollierung statt.
Der Textfile "msg_protokoll.txt" wird durch end_MSG_write(&hFile) geschlossen.
end_MSG_write(&hFile) wird unmittelbar vor return (int) msg.wParam; aufgerufen.
Die Funktion do_MSG_write(&hFile, hwnd,uMsg,wParam,lParam) protokolliert die Nachrichten im Textfile "msg_protokoll.txt".
do_MSG_write(&hFile, hwnd,uMsg,wParam,lParam) wird z.B. als erste Funktion in der CALLBACK-Funktion WndProc()
aufgerufen.
Wird für bestimmte Nachrichten KEINE Protokollierung gewünscht, so können diese Nachrichten in der MSGdesc[]-Array-Definition
auskommentiert werden, etwa gemäss:
// {TEXT("WM_MOUSEMOVE"), WM_MOUSEMOVE},// 0x0200
/*
Filename: msg_protokoll.h
msg_protokoll.h wird dem Projekt hinzugefügt.
Im .cpp-File wird hinter ... #include <windows.h> ... eingefügt:
#include "msg_protokoll.h"
*/
////////////////////////////////////
FILE *hFile; // globaler File-Buffer
////////////////////////////////////
void begin_MSG_write(FILE **hFile)
{
#ifdef UNICODE
*hFile = _wfopen(TEXT("msg_protokoll.txt"),TEXT("w"));
#else
*hFile = fopen("msg_protokoll.txt","w");
#endif
}
////////////////////////////////////
void end_MSG_write(FILE **hFile)
{
if(*hFile) fclose(*hFile);
}
////////////////////////////////////
void do_MSG_write(FILE **hFile, HWND hwnd, UINT uMSG,WPARAM wParam,LPARAM lParam)
{
if(!*hFile) return;
typedef struct { LPTSTR psz; UINT uMSG;} MSGDESC;
MSGDESC MSGdesc[] = {
{TEXT("WM_NULL"), WM_NULL},
{TEXT("WM_CREATE"), WM_CREATE},
{TEXT("WM_DESTROY"), WM_DESTROY},
{TEXT("WM_MOVE"), WM_MOVE},
{TEXT("WM_SIZE"), WM_SIZE},
{TEXT("WM_ACTIVATE"), WM_ACTIVATE},
{TEXT("WM_SETFOCUS"), WM_SETFOCUS},
{TEXT("WM_KILLFOCUS"), WM_KILLFOCUS},
{TEXT("WM_ENABLE"), WM_ENABLE},
{TEXT("WM_SETREDRAW"), WM_SETREDRAW},
{TEXT("WM_SETTEXT"), WM_SETTEXT},
{TEXT("WM_GETTEXT"), WM_GETTEXT},
{TEXT("WM_GETTEXTLENGTH"), WM_GETTEXTLENGTH},
//
//
//
//
//
//
//
//
//
//
//
//
//
0x0000
0x0001
0x0002
0x0003
0x0005
0x0006
0x0007
0x0008
0x000A
0x000B
0x000C
0x000D
0x000E
{TEXT("WM_PAINT"), WM_PAINT},
// 0x000F
{TEXT("WM_CLOSE"), WM_CLOSE},
// 0x0010
{TEXT("WM_QUERYENDSESSION"), WM_QUERYENDSESSION},// 0x0011
{TEXT("WM_QUIT"), WM_QUIT},
// 0x0012
{TEXT("WM_QUERYOPEN"), WM_QUERYOPEN},
// 0x0013
{TEXT("WM_ERASEBKGND"), WM_ERASEBKGND},
// 0x0014
{TEXT("WM_SYSCOLORCHANGE"), WM_SYSCOLORCHANGE}, // 0x0015
{TEXT("WM_ENDSESSION"), WM_ENDSESSION},
// 0x0016
{TEXT("WM_SHOWWINDOW"), WM_SHOWWINDOW},
// 0x0018
{TEXT("WM_WININICHANGE"), WM_WININICHANGE},
// 0x001A
{TEXT("WM_DEVMODECHANGE"), WM_DEVMODECHANGE},
// 0x001B
{TEXT("WM_ACTIVATEAPP"), WM_ACTIVATEAPP},
// 0x001C
{TEXT("WM_FONTCHANGE"), WM_FONTCHANGE},
// 0x001D
{TEXT("WM_TIMECHANGE"), WM_TIMECHANGE},
// 0x001E
{TEXT("WM_CANCELMODE"), WM_CANCELMODE},
// 0x001F
{TEXT("WM_SETCURSOR"), WM_SETCURSOR},
// 0x0020
{TEXT("WM_MOUSEACTIVATE"), WM_MOUSEACTIVATE},
// 0x0021
{TEXT("WM_CHILDACTIVATE"), WM_CHILDACTIVATE},
// 0x0022
{TEXT("WM_QUEUESYNC"), WM_QUEUESYNC},
// 0x0023
{TEXT("WM_GETMINMAXINFO"), WM_GETMINMAXINFO},
// 0x0024
{TEXT("WM_PAINTICON"), WM_PAINTICON},
// 0x0026
{TEXT("WM_ICONERASEBKGND"), WM_ICONERASEBKGND}, // 0x0027
{TEXT("WM_NEXTDLGCTL"), WM_NEXTDLGCTL},
// 0x0028
{TEXT("WM_SPOOLERSTATUS"), WM_SPOOLERSTATUS},
// 0x002A
{TEXT("WM_DRAWITEM"), WM_DRAWITEM},
// 0x002B
{TEXT("WM_MEASUREITEM"), WM_MEASUREITEM},
// 0x002C
{TEXT("WM_DELETEITEM"), WM_DELETEITEM},
// 0x002D
{TEXT("WM_VKEYTOITEM"), WM_VKEYTOITEM},
// 0x002E
{TEXT("WM_CHARTOITEM"), WM_CHARTOITEM},
// 0x002F
{TEXT("WM_SETFONT"), WM_SETFONT},
// 0x0030
{TEXT("WM_GETFONT"), WM_GETFONT},
// 0x0031
{TEXT("WM_SETHOTKEY"), WM_SETHOTKEY},
// 0x0032
{TEXT("WM_GETHOTKEY"), WM_GETHOTKEY},
// 0x0033
{TEXT("WM_QUERYDRAGICON"), WM_QUERYDRAGICON},
// 0x0037
{TEXT("WM_COMPAREITEM"), WM_COMPAREITEM},
// 0x0039
{TEXT("WM_COMPACTING"), WM_COMPACTING},
// 0x0041
{TEXT("WM_WINDOWPOSCHANGING"), WM_WINDOWPOSCHANGING}, // 0x0046
{TEXT("WM_WINDOWPOSCHANGED"), WM_WINDOWPOSCHANGED},// 0x0047
{TEXT("WM_POWER"), WM_POWER},
// 0x0048
{TEXT("WM_COPYDATA"), WM_COPYDATA},
// 0x004A
{TEXT("WM_CANCELJOURNAL"), WM_CANCELJOURNAL},
// 0x004B
{TEXT("WM_NCCREATE"), WM_NCCREATE},
// 0x0081
{TEXT("WM_NCDESTROY"), WM_NCDESTROY},
// 0x0082
{TEXT("WM_NCCALCSIZE"), WM_NCCALCSIZE},
// 0x0083
{TEXT("WM_NCHITTEST"), WM_NCHITTEST},
// 0x0084
{TEXT("WM_NCPAINT"), WM_NCPAINT},
// 0x0085
{TEXT("WM_NCACTIVATE"), WM_NCACTIVATE},
// 0x0086
{TEXT("WM_GETDLGCODE"), WM_GETDLGCODE},
// 0x0087
{TEXT("WM_NCMOUSEMOVE"), WM_NCMOUSEMOVE},
// 0x00A0
{TEXT("WM_NCLBUTTONDOWN"), WM_NCLBUTTONDOWN},
// 0x00A1
{TEXT("WM_NCLBUTTONUP"), WM_NCLBUTTONUP},
// 0x00A2
{TEXT("WM_NCLBUTTONDBLCLK"), WM_NCLBUTTONDBLCLK}, // 0x00A3
{TEXT("WM_NCRBUTTONDOWN"), WM_NCRBUTTONDOWN},
// 0x00A4
{TEXT("WM_NCRBUTTONUP"), WM_NCRBUTTONUP},
// 0x00A5
{TEXT("WM_NCRBUTTONDBLCLK"), WM_NCRBUTTONDBLCLK}, // 0x00A6
{TEXT("WM_NCMBUTTONDOWN"), WM_NCMBUTTONDOWN},
// 0x00A7
{TEXT("WM_NCMBUTTONUP"), WM_NCMBUTTONUP},
// 0x00A8
{TEXT("WM_NCMBUTTONDBLCLK"), WM_NCMBUTTONDBLCLK}, // 0x00A9
{TEXT("EM_GETSEL"), EM_GETSEL},
// 0x00B0
{TEXT("EM_SETSEL"), EM_SETSEL},
// 0x00B1
{TEXT("EM_GETRECT"), EM_GETRECT},
// 0x00B2
{TEXT("EM_SETRECT"), EM_SETRECT},
// 0x00B3
{TEXT("EM_SETRECTNP"), EM_SETRECTNP},
// 0x00B4
{TEXT("EM_SCROLL"), EM_SCROLL},
// 0x00B5
{TEXT("EM_LINESCROLL"), EM_LINESCROLL},
// 0x00B6
{TEXT("EM_SCROLLCARET"), EM_SCROLLCARET},
// 0x00B7
{TEXT("EM_GETMODIFY"), EM_GETMODIFY},
// 0x00B8
{TEXT("EM_SETMODIFY"), EM_SETMODIFY},
// 0x00B9
{TEXT("EM_GETLINECOUNT"), EM_GETLINECOUNT},
// 0x00BA
{TEXT("EM_LINEINDEX"), EM_LINEINDEX},
// 0x00BB
{TEXT("EM_SETHANDLE"), EM_SETHANDLE},
// 0x00BC
{TEXT("EM_GETHANDLE"), EM_GETHANDLE},
// 0x00BD
{TEXT("EM_GETTHUMB"), EM_GETTHUMB},
// 0x00BE
{TEXT("EM_LINELENGTH"), EM_LINELENGTH},
// 0x00C1
{TEXT("EM_REPLACESEL"), EM_REPLACESEL},
// 0x00C2
{TEXT("EM_GETLINE"), EM_GETLINE},
// 0x00C4
{TEXT("EM_LIMITTEXT"), EM_LIMITTEXT},
// 0x00C5
{TEXT("EM_CANUNDO"), EM_CANUNDO},
// 0x00C6
{TEXT("EM_UNDO"), EM_UNDO},
// 0x00C7
{TEXT("EM_FMTLINES"), EM_FMTLINES},
// 0x00C8
{TEXT("EM_LINEFROMCHAR"), EM_LINEFROMCHAR},
// 0x00C9
{TEXT("EM_SETTABSTOPS"), EM_SETTABSTOPS},
// 0x00CB
{TEXT("EM_SETPASSWORDCHAR"), EM_SETPASSWORDCHAR}, // 0x00CC
{TEXT("EM_EMPTYUNDOBUFFER"), EM_EMPTYUNDOBUFFER}, // 0x00CD
{TEXT("EM_GETFIRSTVISIBLELINE"), EM_GETFIRSTVISIBLELINE}, // 0x00CE
{TEXT("EM_SETREADONLY"), EM_SETREADONLY},
// 0x00CF
{TEXT("EM_SETWORDBREAKPROC"), EM_SETWORDBREAKPROC},// 0x00D0
{TEXT("EM_GETWORDBREAKPROC"), EM_GETWORDBREAKPROC},// 0x00D1
{TEXT("EM_GETPASSWORDCHAR"), EM_GETPASSWORDCHAR}, // 0x00D2
{TEXT("SBM_SETPOS"), SBM_SETPOS},
// 0x00E0
{TEXT("SBM_GETPOS"), SBM_GETPOS},
// 0x00E1
{TEXT("SBM_SETRANGE"), SBM_SETRANGE},
// 0x00E2
{TEXT("SBM_GETRANGE"), SBM_GETRANGE},
// 0x00E3
{TEXT("SBM_ENABLE_ARROWS"), SBM_ENABLE_ARROWS}, // 0x00E4
{TEXT("SBM_SETRANGEREDRAW"), SBM_SETRANGEREDRAW}, // 0x00E6
{TEXT("BM_GETCHECK"), BM_GETCHECK},
// 0x00F0
{TEXT("BM_SETCHECK"), BM_SETCHECK},
// 0x00F1
{TEXT("BM_GETSTATE"), BM_GETSTATE},
// 0x00F2
{TEXT("BM_SETSTATE"), BM_SETSTATE},
// 0x00F3
{TEXT("BM_SETSTYLE"), BM_SETSTYLE},
// 0x00F4
{TEXT("WM_KEYDOWN"), WM_KEYDOWN},
// 0x0100
{TEXT("WM_KEYUP"), WM_KEYUP},
// 0x0101
{TEXT("WM_CHAR"), WM_CHAR},
// 0x0102
{TEXT("WM_DEADCHAR"), WM_DEADCHAR},
// 0x0103
{TEXT("WM_SYSKEYDOWN"), WM_SYSKEYDOWN},
// 0x0104
{TEXT("WM_SYSKEYUP"), WM_SYSKEYUP},
// 0x0105
{TEXT("WM_SYSCHAR"), WM_SYSCHAR},
// 0x0106
{TEXT("WM_SYSDEADCHAR"), WM_SYSDEADCHAR},
// 0x0107
/* brauchen Header...
{TEXT("WM_WNT_CONVERTREQUESTEX"), WM_WNT_CONVERTREQUESTEX},// 0x0109
{TEXT("WM_CONVERTREQUEST"), WM_CONVERTREQUEST}, // 0x010A
{TEXT("WM_CONVERTRESULT"), WM_CONVERTRESULT},
// 0x010B
{TEXT("WM_INTERIM"), WM_INTERIM},
// 0x010C
*/
{TEXT("WM_IME_STARTCOMPOSITION"), WM_IME_STARTCOMPOSITION}, // 0x010D
{TEXT("WM_IME_ENDCOMPOSITION"),
WM_IME_ENDCOMPOSITION},
// 0x010E
{TEXT("WM_IME_COMPOSITION"),
WM_IME_COMPOSITION},
// 0x010F
{TEXT("WM_INITDIALOG"), WM_INITDIALOG},
// 0x0110
{TEXT("WM_COMMAND"), WM_COMMAND},
// 0x0111
{TEXT("WM_SYSCOMMAND"), WM_SYSCOMMAND},
// 0x0112
{TEXT("WM_TIMER"), WM_TIMER},
// 0x0113
{TEXT("WM_HSCROLL"), WM_HSCROLL},
// 0x0114
{TEXT("WM_VSCROLL"), WM_VSCROLL},
// 0x0115
{TEXT("WM_INITMENU"), WM_INITMENU},
// 0x0116
{TEXT("WM_INITMENUPOPUP"), WM_INITMENUPOPUP},
// 0x0117
{TEXT("WM_MENUSELECT"), WM_MENUSELECT},
// 0x011F
{TEXT("WM_MENUCHAR"), WM_MENUCHAR},
// 0x0120
{TEXT("WM_ENTERIDLE"), WM_ENTERIDLE},
// 0x0121
{TEXT("WM_CTLCOLORMSGBOX"), WM_CTLCOLORMSGBOX}, // 0x0132
{TEXT("WM_CTLCOLOREDIT"), WM_CTLCOLOREDIT},
// 0x0133
{TEXT("WM_CTLCOLORLISTBOX"), WM_CTLCOLORLISTBOX}, // 0x0134
{TEXT("WM_CTLCOLORBTN"), WM_CTLCOLORBTN},
// 0x0135
{TEXT("WM_CTLCOLORDLG"), WM_CTLCOLORDLG},
// 0x0136
{TEXT("WM_CTLCOLORSCROLLBAR"), WM_CTLCOLORSCROLLBAR}, // 0x0137
{TEXT("WM_CTLCOLORSTATIC"), WM_CTLCOLORSTATIC}, // 0x0138
{TEXT("CB_GETEDITSEL"), CB_GETEDITSEL},
// 0x0140
{TEXT("CB_LIMITTEXT"), CB_LIMITTEXT},
// 0x0141
{TEXT("CB_SETEDITSEL"), CB_SETEDITSEL},
// 0x0142
{TEXT("CB_ADDSTRING"), CB_ADDSTRING},
// 0x0143
{TEXT("CB_DELETESTRING"), CB_DELETESTRING},
// 0x0144
{TEXT("CB_DIR"), CB_DIR},
// 0x0145
{TEXT("CB_GETCOUNT"), CB_GETCOUNT},
// 0x0146
{TEXT("CB_GETCURSEL"), CB_GETCURSEL},
// 0x0147
{TEXT("CB_GETLBTEXT"), CB_GETLBTEXT},
// 0x0148
{TEXT("CB_GETLBTEXTLEN"), CB_GETLBTEXTLEN},
// 0x0149
{TEXT("CB_INSERTSTRING"), CB_INSERTSTRING},
// 0x014A
{TEXT("CB_RESETCONTENT"), CB_RESETCONTENT},
// 0x014B
{TEXT("CB_FINDSTRING"), CB_FINDSTRING},
// 0x014C
{TEXT("CB_SELECTSTRING"), CB_SELECTSTRING},
// 0x014D
{TEXT("CB_SETCURSEL"), CB_SETCURSEL},
// 0x014E
{TEXT("CB_SHOWDROPDOWN"), CB_SHOWDROPDOWN},
// 0x014F
{TEXT("CB_GETITEMDATA"), CB_GETITEMDATA},
// 0x0150
{TEXT("CB_SETITEMDATA"), CB_SETITEMDATA},
// 0x0151
{TEXT("CB_GETDROPPEDCONTROLRECT"), CB_GETDROPPEDCONTROLRECT}, // 0x0152
{TEXT("CB_SETITEMHEIGHT"), CB_SETITEMHEIGHT},
// 0x0153
{TEXT("CB_GETITEMHEIGHT"), CB_GETITEMHEIGHT},
// 0x0154
{TEXT("CB_SETEXTENDEDUI"), CB_SETEXTENDEDUI},
// 0x0155
{TEXT("CB_GETEXTENDEDUI"), CB_GETEXTENDEDUI},
// 0x0156
{TEXT("CB_GETDROPPEDSTATE"), CB_GETDROPPEDSTATE}, // 0x0157
{TEXT("CB_FINDSTRINGEXACT"), CB_FINDSTRINGEXACT}, // 0x0158
{TEXT("CB_SETLOCALE"), CB_SETLOCALE},
// 0x0159
{TEXT("CB_GETLOCALE"), CB_GETLOCALE},
// 0x015A
{TEXT("STM_SETICON"), STM_SETICON},
// 0x0170
{TEXT("STM_GETICON"), STM_GETICON},
// 0x0171
{TEXT("LB_ADDSTRING"), LB_ADDSTRING},
// 0x0180
{TEXT("LB_INSERTSTRING"), LB_INSERTSTRING},
// 0x0181
{TEXT("LB_DELETESTRING"), LB_DELETESTRING},
// 0x0182
{TEXT("LB_SELITEMRANGEEX"), LB_SELITEMRANGEEX}, // 0x0183
{TEXT("LB_RESETCONTENT"), LB_RESETCONTENT},
// 0x0184
{TEXT("LB_SETSEL"), LB_SETSEL},
// 0x0185
{TEXT("LB_SETCURSEL"), LB_SETCURSEL},
// 0x0186
{TEXT("LB_GETSEL"), LB_GETSEL},
// 0x0187
{TEXT("LB_GETCURSEL"), LB_GETCURSEL},
// 0x0188
{TEXT("LB_GETTEXT"), LB_GETTEXT},
// 0x0189
{TEXT("LB_GETTEXTLEN"), LB_GETTEXTLEN},
// 0x018A
{TEXT("LB_GETCOUNT"), LB_GETCOUNT},
// 0x018B
{TEXT("LB_SELECTSTRING"), LB_SELECTSTRING},
// 0x018C
{TEXT("LB_DIR"), LB_DIR},
// 0x018D
{TEXT("LB_GETTOPINDEX"), LB_GETTOPINDEX},
// 0x018E
{TEXT("LB_FINDSTRING"), LB_FINDSTRING},
// 0x018F
{TEXT("LB_GETSELCOUNT"), LB_GETSELCOUNT},
// 0x0190
{TEXT("LB_GETSELITEMS"), LB_GETSELITEMS},
// 0x0191
{TEXT("LB_SETTABSTOPS"), LB_SETTABSTOPS},
// 0x0192
{TEXT("LB_GETHORIZONTALEXTENT"), LB_GETHORIZONTALEXTENT}, // 0x0193
{TEXT("LB_SETHORIZONTALEXTENT"), LB_SETHORIZONTALEXTENT}, // 0x0194
{TEXT("LB_SETCOLUMNWIDTH"), LB_SETCOLUMNWIDTH}, // 0x0195
{TEXT("LB_ADDFILE"), LB_ADDFILE},
// 0x0196
{TEXT("LB_SETTOPINDEX"), LB_SETTOPINDEX},
// 0x0197
{TEXT("LB_GETITEMRECT"), LB_GETITEMRECT},
// 0x0198
{TEXT("LB_GETITEMDATA"), LB_GETITEMDATA},
// 0x0199
{TEXT("LB_SETITEMDATA"), LB_SETITEMDATA},
// 0x019A
{TEXT("LB_SELITEMRANGE"), LB_SELITEMRANGE},
// 0x019B
{TEXT("LB_SETANCHORINDEX"), LB_SETANCHORINDEX}, // 0x019C
{TEXT("LB_GETANCHORINDEX"), LB_GETANCHORINDEX}, // 0x019D
{TEXT("LB_SETCARETINDEX"), LB_SETCARETINDEX},
// 0x019E
{TEXT("LB_GETCARETINDEX"), LB_GETCARETINDEX},
// 0x019F
{TEXT("LB_SETITEMHEIGHT"), LB_SETITEMHEIGHT},
//
{TEXT("LB_GETITEMHEIGHT"), LB_GETITEMHEIGHT},
//
{TEXT("LB_FINDSTRINGEXACT"), LB_FINDSTRINGEXACT},
{TEXT("LB_SETLOCALE"), LB_SETLOCALE},
//
{TEXT("LB_GETLOCALE"), LB_GETLOCALE},
//
{TEXT("LB_SETCOUNT"), LB_SETCOUNT},
//
{TEXT("WM_MOUSEMOVE"), WM_MOUSEMOVE},
//
{TEXT("WM_LBUTTONDOWN"), WM_LBUTTONDOWN},
//
{TEXT("WM_LBUTTONUP"), WM_LBUTTONUP},
//
{TEXT("WM_LBUTTONDBLCLK"), WM_LBUTTONDBLCLK},
//
{TEXT("WM_RBUTTONDOWN"), WM_RBUTTONDOWN},
//
{TEXT("WM_RBUTTONUP"), WM_RBUTTONUP},
//
{TEXT("WM_RBUTTONDBLCLK"), WM_RBUTTONDBLCLK},
//
{TEXT("WM_MBUTTONDOWN"), WM_MBUTTONDOWN},
//
{TEXT("WM_MBUTTONUP"), WM_MBUTTONUP},
//
{TEXT("WM_MBUTTONDBLCLK"), WM_MBUTTONDBLCLK},
//
{TEXT("WM_PARENTNOTIFY"), WM_PARENTNOTIFY},
//
{TEXT("WM_ENTERMENULOOP"), WM_ENTERMENULOOP},
//
{TEXT("WM_EXITMENULOOP"), WM_EXITMENULOOP},
//
{TEXT("WM_MDICREATE"), WM_MDICREATE},
//
{TEXT("WM_MDIDESTROY"), WM_MDIDESTROY},
//
{TEXT("WM_MDIACTIVATE"), WM_MDIACTIVATE},
//
{TEXT("WM_MDIRESTORE"), WM_MDIRESTORE},
//
{TEXT("WM_MDINEXT"), WM_MDINEXT},
//
{TEXT("WM_MDIMAXIMIZE"), WM_MDIMAXIMIZE},
//
{TEXT("WM_MDITILE"), WM_MDITILE},
//
{TEXT("WM_MDICASCADE"), WM_MDICASCADE},
//
{TEXT("WM_MDIICONARRANGE"), WM_MDIICONARRANGE}, //
{TEXT("WM_MDIGETACTIVE"), WM_MDIGETACTIVE},
//
{TEXT("WM_MDISETMENU"), WM_MDISETMENU},
//
{TEXT("WM_ENTERSIZEMOVE"), WM_ENTERSIZEMOVE},
//
{TEXT("WM_EXITSIZEMOVE"), WM_EXITSIZEMOVE},
//
{TEXT("WM_DROPFILES"), WM_DROPFILES},
//
{TEXT("WM_MDIREFRESHMENU"), WM_MDIREFRESHMENU}, //
0x01A0
0x01A1
// 0x01A2
0x01A5
0x01A6
0x01A7
0x0200
0x0201
0x0202
0x0203
0x0204
0x0205
0x0206
0x0207
0x0208
0x0209
0x0210
0x0211
0x0212
0x0220
0x0221
0x0222
0x0223
0x0224
0x0225
0x0226
0x0227
0x0228
0x0229
0x0230
0x0231
0x0232
0x0233
0x0234
};
static UINT j;
/* fortlaufende Nummer der Nachricht */
TCHAR Buf[1024]; /* Buffer */
UINT n = sizeof(MSGdesc)/sizeof(MSGdesc[0]);
for(UINT i = 0; i < n; i++)
{
if(uMSG == MSGdesc[i].uMSG) {
j++; if(j > 1000) continue;
int cc = wsprintf(Buf,
TEXT("\r\n// %04u|hwnd=0x%08x,wPar=0x%08x,lPar=0x%08x||0x%04x=%s"),
j,
hwnd,
wParam,
lParam,i,MSGdesc[i].psz);
#ifdef UNICODE
char buf[512];
// ansi-Buffer
memset(buf,0,sizeof(buf));// beendet mit \0\0
WideCharToMultiByte
(CP_ACP,0,Buf,-1,buf,sizeof(buf),NULL,NULL);
cc = (cc+1)/2;
fwrite(buf, sizeof(TCHAR), cc, *hFile);
#else
fwrite(Buf, sizeof(TCHAR), cc, *hFile);
#endif
}
}
}
cpp-Quelltext
gdi-class für Window-Applikation
Zu Lehrzwecken wird eine einfache gdi-class betrachtet, die OpenGL "nach-empfunden" ist. Das Windows-GDI hat zahlreiche
Funktionen, die mit ganzzahligen Gerätekoordinaten und dem Device-Kontext arbeiten. Es gibt z.B. die Funktionen
MoveToEx(), LineTo(), Ellipse(), Rectangle(), RoundRect(), Polyline(), PolyPolyline() , usw.
In ein Hauptfenster kann z.B. Text zentriert hinein geschrieben werden.
GetClientRect( hwnd, & rect ) ;
DrawText
( hdc, "Hallo, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER |
DT_VCENTER ) ;
Die folgende Tabelle enthält Erklärungen zur gdi-class:
Member-Funktionen
Erklärungen
class GDI { ... }
verwendet die Member-Variablen:
HWND
HDC
PAINTSTRUCT
COLORREF
UINT
HPEN
RECT
m_hwnd;
// Fenster-Daten-"Pointer"
m_hdc;
// DeviceContext
m_ps;
// für BeginPaint()
m_crColor; // Farbe
m_PenWidth;// Zeichenstift
m_hPen, m_hPenOld;
m_rc;
// Rechteck-Koordinaten
use_gdi soll auch 2D-Transformationsfunktionen (ein wenig ähnlich zu OpenGL)
ermöglichen.
#ifdef use_gdi
int
_t;
// Tiefe von mat_push(), mat_pop()
int
_w,_h;
// Breite, Höhe
double m_xMin, m_xMax, m_yMin, m_yMax; // 2D-Welt
BOOL m_isotrop;
double _M[6*8];// für 2D-Transformationen
#endif
GDI()
Translation
mat_transl(dx, dy)
Skalierung
mat_scale(sx,sy)
Rotation
mat_rotat(w)
Der Class-Konstruktor GDI() { ... } initialisiert auf Gerätebasis das Fensterhandle
m_hwnd = NULL; die Farbe m_crColor = RGB(0,0,0); die mat_push()-Schachtelunstiefe
_t = 0; und die Matrixelemente (Einheitsmatrix) _M[0]=1.0; _M[1]=0.0; _M[2]=0.0;
_M[3]=0.0; _M[4]=1.0; _M[5]=0.0;
void mat_transl(dx, dy) {
double m[6];
m[0]=1.0; m[1]=0.0; m[2]=dx;
m[3]=0.0; m[4]=1.0; m[5]=dy;
mat_mult(m); // _M := _M * m
}
sx > 1.0 streckt in x-Richtung,
sx < 1.0 staucht in x-Richtung,
sy > 1.0 streckt in y-Richtung,
sy < 1.0 staucht in y-Richtung
Der Winkel w wird in Grad angegeben
Grösse der 2D-Welt
mat_ortho() berechnet und setzt die Abbildungsfaktoren,
mat_ortho(xMin,xMax,yMin,yMax) _M[0], _M[1], _M[2],
_M[3], _M[4], _M[5]=0.0;
die für jede Umrechnung von der 2D-xy-Welt auf die i,j-Pixel gebraucht werden.
Betriebssysteme unterstützen (ganzzahlige) Gerätekoordinaten.
begin_paint()
begin_paint() setzt mit Hilfe von BeginPaint() den DeviceKontext m_hdc
set_color()
set_color() rechnet die r,g,b-Werte
0.0 <= double r <= 1.0
0.0 <= double g <= 1.0
0.0 <= double b <= 1.0
auf die (ganzzahlige) Gerätefarbe um.
begin_pen()
end_pen()
begin_pen() und end_pen() hinterlegen Windows-Objekt im Device-Kontext. Mit
begin_pen(INT idxStyle, UINT nWidth) können "trickreiche" Zeichenstift-Muster gesetzt
werden.
move_to(x,y)
move_to(x,y) rechnet x,y in i,j um und verwendet dann die Windows-GDI-Funktion
MoveToEx(). move_to() ist ein "hingehen ohne Zeichnen".
line_to(x,y)
line_to(x,y) rechnet x,y in i,j um und verwendet dann die Windows-GDI-Funktion
LineTo(). LineTo() ist ein "hingehen mit Zeichnen".
gdi-class-Quelltext
#define UNICODE
#include <windows.h>
#include <stdio.h>
#include <math.h>
#define use_gdi
class GDI {
HWND
HDC
PAINTSTRUCT
COLORREF
UINT
HPEN
RECT
m_hwnd;
// Fenster-Daten-"Pointer"
m_hdc;
// DeviceContext
m_ps;
// für BeginPaint()
m_crColor; // Farbe
m_PenWidth;// Zeichenstift
m_hPen, m_hPenOld;
m_rc;
// Rechteck-Koordinaten
#ifdef use_gdi
int
_t;
// Tiefe von mat_push(), mat_pop()
int
_w,_h;
// Breite, Höhe
double m_xMin, m_xMax, m_yMin, m_yMax; // 2D-Welt
BOOL m_isotrop;
double _M[6*8];// für 2D-Transformationen
#endif
public:
~GDI() { /* Destruktor: delete ...;
*/ }
GDI() { /* Konstruktor: initialisiere ... */
m_hwnd = NULL;
m_crColor = RGB(0,0,0);
m_PenWidth = 1;
set_rect(); // init Client-RECT m_rc;
#ifdef use_gdi
_t = 0; m_isotrop = TRUE;
m_xMin=-1.0; m_xMax=+1.0;
m_yMin=-1.0; m_yMax=+1.0;
_M[0]=1.0; _M[1]=0.0; _M[2]=0.0;
_M[3]=0.0; _M[4]=1.0; _M[5]=0.0;
#endif
}
#ifdef use_gdi
void mat_push()
{
int k = _t, n = sizeof(_M)/sizeof(_M[0]);
_t += 6; if(_t > n ) _t = 0;
_M[_t+0] = _M[k+0]; _M[_t+1] = _M[k+1]; _M[_t+2] = _M[k+2];
_M[_t+3] = _M[k+3]; _M[_t+4] = _M[k+4]; _M[_t+5] = _M[k+5];
}
void mat_pop()
{
_t -= 6; if(_t < 0) _t = 0;
}
void mat_mult(double *m) {
double aa, bb,cc;
aa = _M[_t+0]*m[0]+_M[_t+1]*m[3];
bb = _M[_t+0]*m[1]+_M[_t+1]*m[4];
cc = _M[_t+0]*m[2]+_M[_t+1]*m[5]+_M[_t+2];
_M[_t+0]=aa;_M[_t+1]=bb;_M[_t+2]=cc;
aa = _M[_t+3]*m[0]+_M[_t+4]*m[3];
bb = _M[_t+3]*m[1]+_M[_t+4]*m[4];
cc = _M[_t+3]*m[2]+_M[_t+4]*m[5]+_M[_t+5];
_M[_t+3]=aa;_M[_t+4]=bb;_M[_t+5]=cc;
}
void mat_scale(double
double m[6];
m[0]= sx; m[1]=0.0;
m[3]=0.0; m[4]= sy;
mat_mult(m); // _M
}
sx, double sy) {
m[2]=0.0;
m[5]=0.0;
:= _M * m
void mat_transl(double dx, double dy) {
double m[6];
m[0]=1.0; m[1]=0.0; m[2]=dx;
m[3]=0.0; m[4]=1.0; m[5]=dy;
mat_mult(m); // _M := _M * m
}
void mat_rotat(double w) {
double m[6];w *= 3.141592653589793/180.0;
m[0]= cos(w); m[1]=-sin(w); m[2]=0.0;
m[3]= sin(w); m[4]= cos(w); m[5]=0.0;
mat_mult(m); // _M := _M * m
}
void mat_viewport(HWND hwnd, int w, int h)
{
m_hwnd = hwnd; _w = w; _h = h;
}
void set_isotrop()
{ m_isotrop = TRUE; }
void set_anisotrop() { m_isotrop = FALSE; }
void mat_ortho(double xMin,double xMax, double yMin,double yMax)
{ if (_h<1)return; //if(!m_hwnd) return;
if (m_isotrop) { double tem = 1.0*_w/_h;
if (_w < _h) { yMin /= tem; yMax /= tem;
} else
{ xMin *= tem; xMax *= tem; }
}
m_xMin = xMin; m_xMax = xMax;
m_yMin = yMin; m_yMax = yMax;
_M[0]=1.0; _M[1]=0.0; _M[2]=0.0;
_M[3]=0.0; _M[4]=1.0; _M[5]=0.0;
double sx = (double)_w/(m_xMax-m_xMin);
double sy = (double)_h/(m_yMax-m_yMin);
mat_transl(-sx*m_xMin, sy*m_yMax);
mat_scale ( sx,
-sy);
}
#endif // ifdef use_gdi
void begin_paint(HWND hwnd) {
m_hwnd = hwnd;
m_hdc = BeginPaint(m_hwnd, &m_ps);
}
void end_paint() {
EndPaint(m_hwnd, &m_ps); m_hdc = NULL;
}
void set_color(double r,double g,double b)
{
#pragma warning(disable: 4244)
r *= r*255.0+.5;
g *= g*255.0+.5;
b *= b*255.0+.5;
int rr = floor(r); if(rr>255) rr = 255;
int gg = floor(g); if(gg>255) gg = 255;
int bb = floor(b); if(bb>255) bb = 255;
m_crColor = RGB(rr,gg,bb);
}
void begin_pen(double r,double g,double b)
{
set_color(r,g,b);
begin_pen();
}
void begin_pen()
{ // HPEN m_hPen,m_hPenOld;COLORREF m_crColor;
m_hPen = CreatePen(PS_SOLID,m_PenWidth,m_crColor);
if(!m_hdc) end_pen();
if(!m_hPen) end_pen();
m_hPenOld = (HPEN) SelectObject(m_hdc, m_hPen);
}
void end_pen() {
if(!m_hdc) return; if(!m_hPenOld) return;
SelectObject(m_hdc,m_hPenOld);
if(!m_hPen) return;
DeleteObject(m_hPen);m_hPen = NULL;
}
void begin_pen(INT idxStyle, UINT nWidth)
{
if(m_hPen) end_pen(); m_PenWidth = 1;
UINT uStyle[]={PS_SOLID,PS_DASH,PS_DOT,
PS_DASHDOT,PS_DASHDOTDOT};
UINT uHatch[]={-1,HS_HORIZONTAL,HS_VERTICAL,
HS_FDIAGONAL,HS_BDIAGONAL,
HS_CROSS,HS_DIAGCROSS};
UINT idx = abs(idxStyle);
if (idxStyle == 0) {
m_hPen = CreatePen(PS_SOLID, nWidth, m_crColor);
} else if (idxStyle > 0) { m_PenWidth = 1;
idx %= sizeof(uStyle)/sizeof(uStyle[0]);
LOGBRUSH lb = {BS_SOLID, m_crColor, 0};
m_hPen = ExtCreatePen(PS_COSMETIC|uStyle[idx],1,&lb,0,NULL);
} else if (idxStyle < 0) {
idx %= sizeof(uHatch)/sizeof(uHatch[0]);
LOGBRUSH lb = {BS_HATCHED,m_crColor,uHatch[idx]};
m_hPen = ExtCreatePen(PS_GEOMETRIC,nWidth,&lb,0,NULL);
}
m_hPenOld = (HPEN) SelectObject(m_hdc, m_hPen);
}
void move_to(double x,double y)
{
#ifndef use_gdi
int i = (int)floor(.5 + x);
int j = (int)floor(.5 + y);
#else
int i = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
int j = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
MoveToEx(m_hdc, i, j, NULL);
}
void line_to(double x,double y)
{
#ifndef use_gdi
int i = (int)floor(.5 + x);
int j = (int)floor(.5 + y);
#else
int i = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
int j = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
LineTo(m_hdc, i, j );
}
void text_to(double x,double y, TCHAR *sz)
{
// TEXT("Hallo")
#ifndef use_gdi
int i = (int)floor(.5 + x);
int j = (int)floor(.5 + y);
#else
int i = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
int j = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
TextOut(m_hdc, i, j, sz, lstrlen(sz));
}
void text_to(double x,double y, int num)
{
#ifndef use_gdi
int i = (int)floor(.5 + x);
int j = (int)floor(.5 + y);
#else
int i = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
int j = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
TCHAR sz[1024]; wsprintf(sz,TEXT("%i"),num);
TextOut(m_hdc, i, j, sz,lstrlen(sz));
}
void text_to(double x,double y, double num)
{
#ifndef use_gdi
int i = (int)floor(.5 + x);
int j = (int)floor(.5 + y);
#else
int i = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
int j = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
char sz[256];
_gcvt(num,9,sz);
#ifndef UNICODE
TextOut(m_hdc, i, j, sz,strlen(sz));
#else
TCHAR SZ[256];
MultiByteToWideChar(CP_ACP,0,sz,-1,SZ,sizeof(SZ));
// ... LPSTR lpAnsiIn, LPWORD lpWCStr
// int nChar = 0;
// do {*lpWCStr++ = (WORD) *lpAnsiIn; nChar++;}
// while (*lpAnsiIn++); return nChar;
TextOut(m_hdc,i, j, SZ,lstrlen(SZ));
#endif
}
void set_rect()
{ // RECT m_rc;
GetClientRect(m_hwnd, &m_rc);
}
void set_rect(double x,double y,double cx,double cy)
{
#ifndef use_gdi
m_rc.left
= (int)floor(.5 + x);
m_rc.top
= (int)floor(.5 + y);
m_rc.right = (int)floor(x+cx);
m_rc.bottom = (int)floor(y+cy);
#else
m_rc.left
= floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
m_rc.top
= floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
x += cx; y += cy;
m_rc.right = floor(_M[_t+0]*x + _M[_t+1]*y + _M[_t+2]);
m_rc.bottom = floor(_M[_t+3]*x + _M[_t+4]*y + _M[_t+5]);
#endif
}
void text_to_rect(TCHAR *sz)
{
DrawText(m_hdc, sz, -1, &m_rc,
DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
}; // ende GDI-Klasse
GDI g = GDI();
typedef struct tagRXY { double x; double y; } RXY;
void draw_netz( RXY P1, RXY P2, RXY Q1, RXY Q2 )
{
double Px,Py, Qx,Qy, u;
//g.set_color(1.0,0.0,0.0);
g.begin_pen(-5, 3);
for ( u = 0.0; u < 1.01; u += 0.03 ) {
Px = P1.x + ( P2.x - P1.x ) * u;
Py = P1.y + ( P2.y - P1.y ) * u;
Qx = Q1.x + ( Q2.x - Q1.x ) * u;
Qy = Q1.y + ( Q2.y - Q1.y ) * u;
g.move_to(Px,Py);
g.line_to(Qx,Qy);
//if(u == 0.0) {
} else { }
}
g.end_pen();
}
void zeichne()
{
// 2D-Welt: xMin,xMax, yMin,yMax
g.begin_pen(0.0,0.0,1.0);
g.end_pen();
g.begin_pen();
for (double t=0.0; t < 6.29; t += 0.1)
{
double x = 0.62*cos(t);
double y = 0.62*sin(t);
g.move_to( x, y);
g.line_to(0.0,0.0);
}
g.end_pen();
RXY P1={ -1.0, +0.7 };
RXY P2={ -1.0, -1.0 };
RXY P3={ +0.62, -1.0 };
g.set_color(0.3,0.9,0.5); draw_netz(P1,P2, P2,P3);
RXY P4={1.0,+0.7};
RXY P5={1.0,-1.0};
RXY P6={ -0.62, -1.0 };
g.set_color(0.9,0.3,0.0); draw_netz(P4,P5, P5,P6);
}
void on_WM_PAINT()
{
g.mat_push();
zeichne();
g.mat_pop();
g.mat_push();
g.mat_transl(0.0, 0.5);
g.mat_scale(0.82,0.38);
g.mat_rotat(-90.0); zeichne();
g.mat_rotat(180.0); zeichne();
g.text_to(-0.5,0.75,TEXT("Hallo GDI ..."));
g.set_rect(-.5,-.5, 1,1);
g.text_to_rect(TEXT("MITTE"));
g.mat_pop();
}
LRESULT CALLBACK WndProc
(HWND hwnd, UINT uMSG,WPARAM wParam, LPARAM lParam)
{
switch(uMSG)
{
case WM_DESTROY: { PostQuitMessage(0);
break; }
case WM_SIZE:{
int w = LOWORD(lParam);
int h = HIWORD(lParam);
g.mat_viewport(hwnd, w, h);
g.mat_ortho(-1.0,1.0, -1.0,1.0);
return 0; }
case WM_PAINT:{
g.begin_paint(hwnd);
// on_???;
g.end_paint();
break; }
default: return DefWindowProc(hwnd,uMSG,wParam,lParam);
}
return 0;
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
// HINSTANCE hInstance = GetModuleHandle(0);
WNDCLASSEX wndClass = {0};
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc
= WndProc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 0;
wndClass.cbWndExtra
= 0;
wndClass.hInstance
= hInstance;
wndClass.lpszMenuName
= NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hIcon
= LoadIcon (NULL, IDI_APPLICATION);
wndClass.hCursor
= LoadCursor(NULL, IDC_ARROW);
wndClass.hIconSm
= LoadIcon (NULL, IDI_APPLICATION ) ;
if (!RegisterClassEx(&wndClass)) return -1 ;
HWND hwnd = CreateWindow(
TEXT("my_class"),
// window class name
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
20, 20,// initial position x,y,(CW_USEDEFAULT)
500,500,// initial x size cx,cy, (CW_USEDEFAULT)
NULL,
// parent window handle
NULL,
// window menu handle
hInstance,
NULL);
// program instance handle
// creation parameters
ShowWindow (hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG MSG ;
while ( GetMessage ( & MSG, NULL, 0, 0 ) ) { //TRUE, FALSE, -1
TranslateMessage ( & MSG ) ;
DispatchMessage ( & MSG ) ;
}
}
// hier kann aufgräumt werden
return (int) MSG.wParam;
// ende WinMain
| Test-Rahmen WIN_CLASS | CLASS mit Menu
3. SP2-Praktikum (SS 2005)
Dieses Praktikum erfordert 2 Projekte (Tei A, Tei B).
Die Aufgabe (A) besteht darin, das "Hallo Welt" - Windows - Programm in eine WIN_CLASS umzuwandeln. Als Applikations-Icon soll ein Icon
aus der Shell32.dll gesetzt werden. Mit HICON hIcon = ExtractIcon(GetModuleHandle(0),"Shell32.dll",43) kann hIcon "geholt" werden. hIcon ist
in der Klasse zu setzen.
Die Aufgabe (B) besteht darin, das "Hallo Welt" - Windows - Programm OHNE externe Ressourcen objektorientiert und schrittweise in eine Klasse
abzubilden und zu testen. Auch soll per C++ ein Menu und eine Accel-Tabelle erstellt, die mit LoadMenuIndirect() gesetzt werden.
Teil A
1. Verwenden Sie als Ausgangspunkt bitte diesen WIN_CLASS-Test-Rahmen als C++-Grundgerüst. Schrittweise sind die
folgenden Member-Funktionen zu testen:
HWND create_main_window(int xPos,int yPos, int dx,int dy, WNDPROC WndProc)
void show(HWND hwnd){...}
void main_loop() { ...}
2. Das Programm soll sicher beendet werden. Mit einer MessageBox() ist vor dem Beenden des Programmes (bei
WM_CLOSE) eine Sicherheits - Rückfrage ( "Exit?" ) auszulösen Die CALLBACK-Funktion ist zu ergänzen so,
dass das Programm abgesichert beendet wird.
// bei WM_CLOSE
TCHAR buf[1024]; //1024 == sizeof(buf)/sizeof(TCHAR)
GetWindowText(hwnd, buf, 1024);
int id = MessageBox(hwnd,TEXT("Exit?"),
buf, MB_ICONQUESTION | MB_YESNO);
if(id == IDYES) ...
3. Mit dem Ressourcen-Workshop sind Ressourcen zu erstellen (Menu, Accelerator), d.h.es soll ein einfaches Menu
und eine Accellerator-Tabelle erstellt werden (ressource.rc). Diese sind im Window-Gerüst zu verwenden
(hMenu+hAccel setzen).
4. Die erstellten ASCI-Files sind zu betrachten (ressource.h, resource.rc).
Teil B
Die folgende Arbeit erfordert ein neues Projekt. Es soll (besonders für blinde Studierende) gezeigt werden, wie ein Menu und Accellerators ohne
Ressourcen-File (im Speicher) zusammen gebastelt werden.
Kontroll-Fragen:
1. Wozu dient der Rückgabewert von MessageBox()?
2. Enthält eine MessageBox() eine eigene Hauptnachrichtenschleife?
3. Was bedeutet modal?
4. Eine MessageBox(hwnd,"test","Tuitel",MB_...) soll ein Fragezeichen, einen OK-Button und einen CANCELButton (Voreinstelltung für Ret-Taste) anzuzeigen. Wie sind die Parameter?
5. Testen Sie bitte, ob sich das System-Menu erweitern läßt. Dazu wird zunächst z.B. in WM_CREATE eingefügt:
// unter WM_CREATE
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;
6. Wieviele Pixel enthält ein Icon?
7. Welche Nachricht WM_... wird infolge eines Menu-Item-Klicks ausgelöst?
8. Was enthält wParam bei einem Aufruf der CALLBACK-Funktion infolge Was würden Sie anstelle von
GetClientRect() verwende, wenn die äußeren Abmessungen des Fensters gebraucht werden?
9. Warum wird ein DestroyWindow(ghwnd[0]) aber kein DestroyWindow(ghwnd[1]) benötigt?
10. Welche Prä-Zeichen (??_...) verwendet die "EDIT"-Klasse für Edit-Nachrichten?
11. Anstelle von HWND hEdit = GetTopWindow(ghwnd[1]); kann auch verwendet werden: HWND hEdit =
GetDlgItem(ghwnd[1],(int)ghwnd[1]);
12. Warum "funktioniert die Dlg-Funktion GetDlgItem()?
13. Welche alternativen Möglichkeiten gibt es anstelle der Verwendung von Virtual-Mem-Speicher?
14. Wozu dient LoadAccelerators()?
15. Wodurch wird ein WS_CHILD-Fenster zerstört?
16. Wie kann CreateWindowEx() eine vorhandene Klasse von MS verwenden?
17. Was bedeutet Window Sub-Classing?
Test-Rahmen für WIN_CLASS
/////////////////////////////////////////////////
// cpp-Rahmen für Window-Klasse (ZUM TESTEN)
/////////////////////////////////////////////////
#define STRICT
#define UNICODE
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>
//#include <math.h>
#define err_if(e,errStr) if(e)if(IDOK!=MessageBox(0,TEXT(errStr),0,\
MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP|MB_SETFOREGROUND))exit(-1);
///////////////////////////////
// WIN_CLASS (Grobstruktur):
///////////////////////////////
class WIN_CLASS
{
protected:
public:
WIN_CLASS() { } // Konstruktor
~WIN_CLASS() { } // Destruktor
}; // ende class WIN_CLASS
///////////////////////////////
// lege globale Instanz win an:
///////////////////////////////
WIN_CLASS g = WIN_CLASS();
LRESULT CALLBACK WndProc
(HWND hwnd, UINT uMsg,WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY: { PostQuitMessage(0);
break; }
case WM_PAINT:{ PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HPEN hPen = CreatePen(PS_SOLID, 5, RGB(0, 0, 255));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 120, 20, NULL);
LineTo(hdc,
20, 200);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
break; }
default: return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
///////////////////////////////
// globale Daten, die zu Member// Variablen werden sollen:
///////////////////////////////
MSG
m_msg;
// aktuelle Nachricht
HACCEL m_hAccel;
HICON m_hIcon;
// aktuelle Accel-Tabelle
// Icom der Applikation
INT WINAPI WinMain(HINSTANCE,HINSTANCE,PSTR,INT)
{
//HWND create_main_window(int xPos,int yPos, int dx,int dy, WNDPROC wnd_class_proc)
// existiert "my_class" bereits?
WNDCLASSEX tem = {0}; tem.cbSize = sizeof(WNDCLASSEX) ;
BOOL ok1 = GetClassInfoEx(GetModuleHandle(0),TEXT("my_class"),&tem);
if(!ok1) // "my_class" nur einmal anlegen:
{
WNDCLASSEX wndClass = {0};
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.lpfnWndProc
= WndProc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 4;
wndClass.cbWndExtra
= 4;
wndClass.hInstance
= GetModuleHandle(0);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor
= LoadCursor(NULL, IDC_ARROW);
ATOM ok = RegisterClassEx(&wndClass);
err_if(!ok,"RegisterClassEx()"); if(!ok)return 0;
}
int xPos=20, yPos=20, dx=500, dy=500; //(CW_USEDEFAULT)
HWND hwnd = CreateWindowEx(WS_EX_LEFT,TEXT("my_class"),
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
xPos,yPos,dx,dy,
NULL,
// parent window handle
NULL,
// window menu handle
GetModuleHandle(0), // program instance handle
NULL);
// creation parameters
err_if(!hwnd,"CreateWindowEx()");
// 43. Icon aus Shell32.dll holen
m_hIcon = ExtractIcon
(GetModuleHandle(0),TEXT("Shell32.dll"),43);
err_if(!m_hIcon,"kein Icon");
HICON hOld=(HICON)SetClassLong(hwnd,GCL_HICON,(LONG)m_hIcon);
// void show(HWND hwnd){...}
SetForegroundWindow(hwnd);
ShowWindow
(hwnd, SW_RESTORE);//SW_SHOWNORMAL
UpdateWindow
(hwnd);
// void main_loop() { ...}
while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{
err_if(-1==bRet,"GetMessage()");
// if((!IsWindow(m_msg.hwnd))
if(!TranslateAccelerator(m_msg.hwnd,m_hAccel,&m_msg))
{
if(!IsDialogMessage(m_msg.hwnd,&m_msg))
{
TranslateMessage(&m_msg);
DispatchMessage (&m_msg);
}
}
}
// hier kann aufgräumt werden
return (int) 0;
}
// ende WinMain
WIN_CLASS (mit Menu)
/////////////////////////////////////////////////
// cpp-Rahmen für Window-Applikation:
//
/////////////////////////////////////////////////
#define STRICT
//#define UNICODE
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>
//#include <math.h>
//#pragma warning(disable:4244)
//#pragma warning(disable:4189)
//#pragma warning(disable:4100)
#define err_if(e,errStr) if(e)if(IDOK!=MessageBox(0,TEXT(errStr),0,\
MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP|MB_SETFOREGROUND))exit(-1);
/////////////////////////////////////////////////
// Strukturen, Prototypen
/////////////////////////////////////////////////
typedef BOOL (* MENUPROC)(void);
LRESULT CALLBACK praeWndProc
(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
typedef struct _MENU_STRUCT { //für das Menue
LPCTSTR pText;
// Menu-Text
MENUPROC menuProc; // Funkt, bei Menu-Klick ausgeführt
WORD
key;
// für ACCEL-Tabelle
BYTE
fVirt;
// für ACCEL-Tabelle
WORD
id;
// ID's werden generiert
} MENU_STRUCT;
// (FVIRTKEY | FALT) or (FVIRTKEY | FALT | FSHIFT).
class WIN_CLASS
{
protected:
HICON m_hIcon;
// Icon der Applikation
HWND
m_hwnd;
// aktuelles Fenster
HACCEL m_hAccel;
// aktuelle Accel-Tabelle
MSG
m_msg;
// aktuelle Nachricht
MENU_STRUCT * m_pms; //für das aktuelle Menue
public:
#define
hwa_max
((int)50)
HWND
hwa[hwa_max];
// alle Fenster, Dialoge
WNDPROC m_old_wnd_proc; // für Sub-Classing (Menue)
WIN_CLASS() // Konstruktor
{
m_hwnd
= 0; // akt: "zeigt" auf Fensterdaten
m_hAccel = 0; // akt: Beschleunigungstasten-Tab
m_pms
= 0; //
memset(hwa,0,sizeof(hwa));
// 43. Icon aus Shell32.dll holen
m_hIcon = ExtractIcon
(GetModuleHandle(0),TEXT("Shell32.dll"),43);
err_if(!m_hIcon,"kein Icon");
}
~WIN_CLASS() // Destruktor
{
/*
if(m_hIcon) DestroyIcon(m_hIcon);
for(int i = 0; i < hwa_max; i++) {
if(hwa[i]) { // falls Fenster existiert:
MENU_STRUCT * pms = get_menu_tab(hwnd);
HACCEL hAccel = (HACCEL)(void*)pms->menuProc;
if(hAccel)DestroyAcceleratorTable(hAccel);
}
}
*/
}
//protected:
// setze hIcon in Window-Klassen-Daten
HICON set_icon(HWND hwnd, HICON hIcon)
{
if(!hIcon) return NULL;
HICON hOld = (HICON)
SetClassLong(hwnd, GCL_HICON,(LONG)hIcon );
return hOld;
}
// setze Zeiger pms in den Window-Daten
MENU_STRUCT * set_menu_tab(HWND hwnd, MENU_STRUCT pms[])
{
if(!pms) return NULL;
MENU_STRUCT *pOld = (MENU_STRUCT*)
SetWindowLong(hwnd,GWL_USERDATA,(LONG)pms);
return pOld;
}
// hole Zeiger pms aus den Window-Daten
MENU_STRUCT * get_menu_tab(HWND hwnd)
{
MENU_STRUCT *p = (MENU_STRUCT*)
GetWindowLong(hwnd,GWL_USERDATA);
return p;
}
// setze neuen Funktionszeiger in den Window-Daten
// Stichwort: Subclassing
WNDPROC set_wndproc(HWND hwnd, WNDPROC prae_wnd_proc)
{
if(!prae_wnd_proc) return NULL;
WNDPROC old_proc = (WNDPROC)
SetWindowLong(hwnd,GWL_WNDPROC,(LPARAM)(WNDPROC)prae_wnd_proc);
return old_proc;
}
public:
//////////////////////////////////////////////////////
// "Vorgeschaltete" CALLBACK-Funktion (Subclassing)
//////////////////////////////////////////////////////
LRESULT prae_wnd_proc
(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
// hinterlege die aktuelle Nachricht in der WIN-Instanz:
this->set_msg(hwnd,uMsg,wParam,lParam);
switch(uMsg)
{
case WM_CLOSE: {
if (GetParent(hwnd))break;
if(0 != this->get_hwnd_index(hwnd))break;
TCHAR buf[1024];
GetWindowText(hwnd,buf,sizeof(buf));
int id = MessageBox(hwnd,TEXT("Exit?"),
buf, MB_ICONQUESTION | MB_YESNO);
if(id == IDYES)
if( 0 == this->get_hwnd_index(hwnd))
DestroyWindow(hwnd);//sendet WM_DESTROY
return 0; }
case WM_DESTROY: {
PostQuitMessage(0);
break; }
case WM_COMMAND:{
if(HIWORD(wParam) > 1)break;
WORD id = LOWORD(wParam); //id=MENU-Item-Identifizierer
m_pms = this->get_menu_tab(hwnd); if(!m_pms) return 0;
int k = 0; // suche id in Menu-Tabelle
while( m_pms[++k].pText) { // Menu-Text
if( m_pms[k].id != id ) continue;
if(!m_pms[k].menuProc) break;
// Funktion ausführen
BOOL ok = m_pms[k].menuProc();
} //InvalidateRect(hwnd,NULL,TRUE);UpdateWindow(hwnd);
break;} // ende WM_COMMAND
case WM_ACTIVATE: {
if ( WA_INACTIVE == LOWORD(wParam) )
{
// becoming inactive
m_hwnd = 0;
} else {
// becoming active
m_hwnd = (GetWindowLong(hwnd,GWL_STYLE) & WS_CHILD)?
GetParent(hwnd):GetWindow(hwnd,GW_OWNER);
}
break; } // ende WM_ACTIVATE
} // ende switch
if(m_old_wnd_proc) // rufe Klassen-Callback-Funkt auf:
return CallWindowProc((WNDPROC)m_old_wnd_proc,hwnd,uMsg,wParam,lParam);
else return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
// gibt das aktuelle Fenster-Handle zurück:
HWND get_hwnd()
{
return m_msg.hwnd;
}
// hinterlegt die aktuelle Nachricht:
void set_msg(MSG msg)
{
m_msg.hwnd
= msg.hwnd;
m_msg.message=
m_msg.wParam =
m_msg.lParam =
m_msg.time
=
m_msg.pt
=
msg.message;
msg.wParam;
msg.lParam;
msg.time;
msg.pt;
}
// hinterlegt die aktuelle Nachricht:
void set_msg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
m_msg.hwnd
= hwnd;
m_msg.message= uMsg;
m_msg.wParam = wParam;
m_msg.lParam = lParam;
}
// typedef struct tagMSG {
//
HWND hwnd;UINT message;WPARAM wParam;LPARAM lParam;
//
DWORD time; POINT pt;
// } MSG
// gibt die aktuelle Nachricht zurück:
MSG get_msg()
{
return m_msg;
}
// zeige ein Fenster hwnd an:
void show(HWND hwnd)
{
SetForegroundWindow(hwnd);
ShowWindow
(hwnd, SW_RESTORE);//SW_SHOWNORMAL
UpdateWindow
(hwnd);
}
// get_hwnd_index() gibt den Index des aktuellen Fensters zurück
int get_hwnd_index(HWND hwnd)
{
if(!IsWindow(hwnd)) return 0;
for(int i = 0; i < hwa_max; i++) {
if(hwnd == hwa[i]) return i;
} return 0;
}
// set_text() schreibt Text in ein Fenster (Titelzeile)
void set_text(HWND hwnd, TCHAR * sz)
{
SetWindowText(hwnd, sz);
}
// set_menu():
// aus der vorhandenen "user-menu-struktur" wird
// ein Menu und die Accel-Tabelle zusammengebaut
// und gesetzt
BOOL set_menu(HWND hwnd, MENU_STRUCT menu_struc[])
{
//!!! menu_struc muss static sein !!!
err_if(!hwnd,"MENU_CLASS braucht hwnd"); if(!hwnd)return FALSE;
// hinterlege neue praeWndProc in hwnd-Daten:
m_old_wnd_proc = this->set_wndproc(hwnd, praeWndProc);
// hinterlege Menu-Tabellen-Zeiger in hwnd-Daten:
MENU_STRUCT *pOldMenu = this->set_menu_tab(hwnd,menu_struc);
err_if(pOldMenu,"pOldMenu");
// ermittle die Anzahl lenMenu von Menu-Items:
int lenMenu = -1;
while(menu_struc[++lenMenu].pText);
// Menu und Accel-Tab aus einer menu_struc erstellen:
HMENU hMenu1 = 0, hMenu = CreateMenu();
ACCEL
ac[200] = {0}; int lenAccel = 0;
WORD id = 10000; // idStart
for (int k = 0; k < lenMenu; k++)
{
// falls Funktion menu_struc[k].menuProc vorhanden ...
if((k>0)&&(menu_struc[k].menuProc)) {
id++; // diesen id-Identifizierer dem Menu-Item zuordnen
// gleichzeitig die Accelarator-Tabelle aufbauen:
WORD key = menu_struc[k].key; //menu_struc[k].key
if(key) // falls ein Accel-Key:
{
err_if(lenAccel>=200,"lenAccel>=200");
BYTE fVirt = menu_struc[k].fVirt;
ac[lenAccel].fVirt = (BYTE)(fVirt & ~0x80);//menu_struc[k].fVirt
ac[lenAccel].key
= key;
//menu_struc[k].key
ac[lenAccel].cmd
= id;
//id ab 10001 ...
lenAccel++;
}
// Menu fertig zusammen bauen:
menu_struc[k].id = id;
AppendMenu(hMenu1,MF_STRING,id,menu_struc[k].pText);
} else {
if(hMenu1)DestroyMenu(hMenu1); hMenu1 = CreateMenu();
AppendMenu(hMenu,MF_POPUP,(int)hMenu1,menu_struc[k].pText);
}
}
if(hMenu1)DestroyMenu(hMenu1); if(!hMenu) return FALSE;
HMENU hMenuOld = GetMenu(hwnd);
if ( hMenuOld ) { SetMenu(hwnd, NULL);
DestroyMenu(hMenuOld);
}
BOOL ok = SetMenu(hwnd,hMenu);
if(lenAccel > 0) {
ac[lenAccel-1].fVirt |= 0x80;//MS-Endekennung
m_hAccel = CreateAcceleratorTable(&ac[0],lenAccel);
err_if(!m_hAccel,"!m_hAccel");
menu_struc[0].menuProc = (MENUPROC)(void *)m_hAccel;
}
return ok;
}
// Beipiel um ein Fenster zu "machen"
// ist wnd_class_proc=NULL, so wird die
// interne CALLBACK-Funktion verwendet
HWND create_main_window(int xPos,int yPos,int dx,int dy,WNDPROC wnd_class_proc)
{
// existiert "my_class" bereits?
WNDCLASSEX tem = {0}; tem.cbSize = sizeof(WNDCLASSEX) ;
BOOL ok1 = GetClassInfoEx(GetModuleHandle(0),TEXT("my_class"),&tem);
if(!ok1) // "my_class" nur einmal anlegen:
{
WNDCLASSEX wndClass = {0};
if(!wnd_class_proc)
wnd_class_proc = DefWindowProc;
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.lpfnWndProc
= wnd_class_proc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 4;
wndClass.cbWndExtra
= 4;
wndClass.hInstance
= GetModuleHandle(0);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor
= LoadCursor(NULL, IDC_ARROW);
ATOM ok = RegisterClassEx(&wndClass);
err_if(!ok,"RegisterClassEx()"); if(!ok)return 0;
}
//int xPos=20, yPos=20, dx=500, dy=500; //(CW_USEDEFAULT)
HWND hwnd = CreateWindowEx(WS_EX_LEFT,TEXT("my_class"),
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
xPos,yPos,dx,dy,
NULL,
// parent window handle
NULL,
// window menu handle
GetModuleHandle(0), // program instance handle
NULL);
// creation parameters
if(hwnd) this->set_icon(hwnd, m_hIcon);
err_if(!hwnd,"CreateWindowEx()");
return hwnd;
}
// Haupt-Nachrichtenschleife:
void main_loop() { // hinterlege Nachricht in m_msg
while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{
err_if(-1==bRet,"GetMessage()");
// if((!IsWindow(m_msg.hwnd))
if(!TranslateAccelerator(m_msg.hwnd,m_hAccel,&m_msg))
{
if(!IsDialogMessage(m_msg.hwnd,&m_msg))
{
TranslateMessage(&m_msg);
DispatchMessage (&m_msg);
}
}
}
}
}; // ende class WIN_CLASS
/////////////////////////////////////////////////
// lege globale Instanz win an:
/////////////////////////////////////////////////
WIN_CLASS g = WIN_CLASS();
/////////////////////////////////////////////////
// CALLBACK-Funkt-Einsprung muss ausserhalb
// der Klasse erzeugt werden ...
/////////////////////////////////////////////////
LRESULT CALLBACK praeWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
return g.prae_wnd_proc(hwnd,uMsg,wParam,lParam );
};
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
BOOL on_help()
{ HWND hwnd = g.get_hwnd();
TCHAR * pInfo = TEXT("Dies ist von\n\n\t ...");
TCHAR * pTitle = TEXT("Info zur 3.Übung");
MessageBox(hwnd, pInfo, pTitle, MB_OK);
return TRUE;
}
BOOL on_menu1()
{
MSG m = g.get_msg();
TCHAR * pTitle = TEXT("on_menu1()");
TCHAR
Buf[1024];
wsprintf(Buf,
TEXT("LOWORD(wParam): id = %d"),LOWORD(m.wParam));
MessageBox(m.hwnd, Buf, pTitle, MB_OK);
return TRUE;
}
BOOL on_menu2()
{
MSG m = g.get_msg();
TCHAR * pTitle = TEXT("on_menu2()");
TCHAR
Buf[1024];
wsprintf(Buf,
TEXT("LOWORD(wParam): id = %d"),LOWORD(m.wParam));
MessageBox(m.hwnd, Buf, pTitle, MB_OK);
return TRUE;
}
BOOL on_paint4()
{
HWND hwnd = g.get_hwnd();
// PAINTSTRUCT ps;
// HDC hdc = BeginPaint(hwnd, &ps);
HDC hdc = GetDC(hwnd);
RECT rc; GetClientRect(hwnd, &rc) ;
DrawText(hdc,TEXT("Hallo, Win!"),-1,&rc,
DT_SINGLELINE|DT_CENTER|DT_VCENTER);
HPEN hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 20, 20, NULL);
LineTo(hdc, 200, 100);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
ReleaseDC(hwnd,hdc); // EndPaint(hwnd, &ps);
return TRUE;
}
BOOL on_paint3()
{
HWND hwnd = g.get_hwnd();
// PAINTSTRUCT ps;
// HDC hdc = BeginPaint(hwnd, &ps);
HDC hdc = GetDC(hwnd);
HPEN hPen = CreatePen(PS_SOLID, 5, RGB(0, 255, 0));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 120, 120, NULL);
LineTo(hdc,
120, 200);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
ReleaseDC(hwnd,hdc);
// EndPaint(hwnd, &ps);
return TRUE;
}
LRESULT CALLBACK WndProc
(HWND hwnd, UINT uMsg,WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY: { PostQuitMessage(0);
break; }
case WM_RBUTTONDOWN: {
//int xPos = (int)LOWORD(lParam);
break; }
case WM_KEYDOWN:{
switch (wParam) {
case VK_CLEAR:
case VK_NUMPAD5:
break; } // ende switch
break; } // ende WM_KEYDOWN
case WM_SIZE:{ // w = (int)LOWORD(lParam); h = (int)HIWORD(lParam);
break; }
case WM_PAINT:{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HPEN hPen = CreatePen(PS_SOLID, 5, RGB(0, 0, 255));
HPEN hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 120, 20, NULL);
LineTo(hdc,
20, 200);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hwnd, &ps);
break; }
default: return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
//
_tWinMain braucht TCHAR.H
INT WINAPI _tWinMain(HINSTANCE,HINSTANCE,PSTR,INT)
{
//g.hwa[0] = g.create_main_window(10,10,500,500, WndProc);
g.hwa[0] = g.create_main_window(100,100,200,300, NULL);
static //... static ist Pflicht!
MENU_STRUCT menu_struc0[] = {
{TEXT("Zeichne&Kurven"),
0 }, //... 0 für Popup
{TEXT("on_menu&1
F1"),on_menu1 , VK_F1,
FVIRTKEY},
{TEXT("on_menu&2
F2"),on_menu2 , VK_F2,
FVIRTKEY},
{TEXT("on_paint&4 Ctrl+F3"),on_paint4,VK_F3,FCONTROL|FVIRTKEY },
{TEXT("on_paint&3 Ctrl+F4"),on_paint3,VK_F4,FCONTROL|FVIRTKEY },
{TEXT("&?"),
0 }, //... 0 für Popup
{TEXT("on_help
?"),on_help,
'?',
FCONTROL},
{TEXT("on_help Alt+F5"),on_help, VK_F5, FALT|FVIRTKEY},
{0,0,0,0}}; // ... Endekriterium ist Pflicht!
g.set_menu(g.hwa[0], menu_struc0);
g.set_text(g.hwa[0], TEXT("Teste"));
g.show(
g.hwa[0]);
g.main_loop();
// hier kann aufgräumt werden
return (int) 0;
} // ende WinMain
4. SP2-Praktikum (SS 2005)
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 notepad.exe starten.
5. Per Button-Klick sind weitere *.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. Optional: Taschenrechner Ohne Ressourcen-Script
Hinweise
WinMain mit DialogBox()-Funktion
Es ist in einem neuen ( leeren ) Projekt ein einfacher Dialog zu erstellen ( z.B. 2 Buttons, Eingabe-Zeile, Menu, Icon ). Ist die IDD_DIALOG-Dialog-Resource (
resource.rc ) verfügbar, so kann mit der dlgProc-CALLBACK-Funktion ein Dialog gemaess
int ret = DialogBox( GetModuleHandle(NULL),
MAKEINTRESOURCE( IDD_DIALOG),
hwnd, (DLGPROC)dlgProc);
erzeugt werden. Das Windows-Hauptprogramm soll den DialogBox()-Aufruf (ohne Nachrichten-Schleife) enthalten. Die DialogBox() erzeugt implizit die whileSchleife eines (modalen) Hauptprogrammes. Die Dialog-Resource ( resource.rc ) soll den Identifizierer IDD_DIALOG haben. Ein IDD_DIALOG-Dialog und
die dlg-CALLBACK-Funktion dlgProc) sollen mit dem Ressourcen-Workshop erstellt werden.
//Hauptprogramm
int APIENTRY WinMain(
HINSTANCE hInstance,HINSTANCE hiPrev,PSTR pCmdMain,int iShowMain)
{
return DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG),
NULL, (DLGPROC)dlgProc);
}
dlgProc-CALLABCK
Bekanntlich senden MenuItem-Klicks und Button-Klicks Nachrichten
iMsg=WM_COMMAND mit LOWORD(wParam) = IDB_... , IDM_, usw. ...
case WM_COMMAND:
if(HIWORD(wParam)) break;
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 : {
TCHAR buf[256];
GetWindowText(hwnd,buf,sizeof(buf)/sizeof(TCHAR)) ;
int ret = MessageBox(hwnd,buf,"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: {
if(HIWORD(wParam)) break;
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 ResourcenWorkshop kann unmittelbar das Menu einfügen. Alternativ kann z.B. das Menu IDM_MENU ( zur Laufzeit ) unter case WM_INITDIALOG mit SetMenu()
geladen und angezeigt werden.
SetMenu(hwnd, LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDM_MENU)));
DialogBox mit Button's
Die DialogBox von Main soll einen Button IDB_... erhalten. Die Button-Beschriftung soll starte IDD_DIALOG1 sein. Ein Button-Klick von IDB_... soll einen
weiteren Dialog IDD_DIALOG1 anzeigen.
Starten von *.exe-Programmen
Als Beispiel wird beschrieben, wie das Notepad.exe-Programm gestartet werden kann. Am einfachsten ist die alte WinExec().Funktion.
UINT ui = WinExec("Notepad", SW_SHOW);
if(ui > 31) ...
Experimentieren und untersuchen Sie nützliche Anwendungen von
UINT ui = WinExec("cmd /K dir \r\n", SW_SHOW);
WinExec() wurde zu CreateProcess() erweitert, ist aufwendiger und wird empfohlen. Create.. braucht eine "saubere" Freigabe! Hier ein Muster, wenn
"BuildLog.htm" im gleichen Verzeichnis ist, wie unser entwickelter sp2aufxx.exe-File. Grob ausgedrückt entspricht dies etwa dem Aufruf von
WinExec("Notepad.exe FULLPATH\\BuildLog.htm", SW_SHOW)).
CHAR * programm = "Notepad.exe";
CHAR * filename = "BuildLog.htm";
CHAR drive[256]; CHAR dir[256]; CHAR fname[256];
CHAR ext[256]; CHAR path[512]; CHAR aufruf[512];
STARTUPINFO si; ZeroMemory(&si,sizeof(si));
GetStartupInfo(&si);
_splitpath(si.lpTitle, drive, dir, fname, ext);
_makepath(path, drive, dir,"","");
wsprintf(aufruf,"%s %s%s",programm,path,filename);
PROCESS_INFORMATION pi; ZeroMemory(&pi,sizeof(pi));
BOOL ok = CreateProcess (0,aufruf,
0,0,0,NORMAL_PRIORITY_CLASS,0,0,&si,&pi);
if(!ok){ //Process konnte nicht gestartet werden
err_if(!ok,"KEIN PROCESS");
} else {
//befreie, falls nicht mehr benötigt
CloseHandle(pi.hThread);
// WaitForSingleObject(pi.hProcess, INFINITE);
// der Process terminierte
DWORD dwExitCode; // wie wurde er beendet?
GetExitCodeProcess(pi.hProcess, &dwExitCode);
//befreie, falls nicht mehr benötigt:
CloseHandle(pipi.hProcess);
}
Wozu kann GetFullPathName(filename,sizeof(path),path,?); nützlich sein?
Taschenrechner mit Ressourcenscript
Es ist ein Prototyp für einen Hex-Taschenrechner zu gestalten ( mit Verbesserungen und Erweiterungen ). Um einem Control eine Nachricht zu schicken kann
anstelle von
HWND hCtl = GetDlgItem ( HWND hDlg, int idRes );
LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam);
kürzer auch verwendet werden:
LONG SendDlgItemMessage( HWND hDlg, int idRes, UINT iMsg, WPARAM wParam, LPARAM
lParam);
Für das Edit- und ComboBox-Control sollen die Macros ( wie z.B. Edit_SetText() ) aus WindosX.h verwendet werden.
Bei der Erstellung des Ressourcen-Scripts kann zunächst ein "leeres grosses Dialog-Rechteck" angelegt werden und in diesen rc-Quelltext wird der
untere rc-Quelltext hinein kopiert ( ID-Konstanten beachten ).
BEGIN //RESOURCE
COMBOBOX
IDC_COMBO1,5,5,115,125,CBS_DROPDOWN
| WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "0",48, 6,117,14,14,NOT WS_TABSTOP
PUSHBUTTON "1",49, 6, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "2",50,24, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "3",51,42, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "4",52, 6, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "5",53,24, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "6",54,42, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "7",55, 6, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "8",56,24, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "9",57,42, 64,14,14,NOT WS_TABSTOP
PUSHBUTTON "A",65,42, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "B",66,24, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "C",67, 6, 47,14,14,NOT WS_TABSTOP
PUSHBUTTON "D",68,42, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "E",69,24, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "F",70, 6, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "+",43,64, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "-",45,64, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "*",42,82, 81,14,14,NOT WS_TABSTOP
PUSHBUTTON "/",47,82, 99,14,14,NOT WS_TABSTOP
PUSHBUTTON "%",37,64, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON "=",61,24,117,31,14,NOT WS_TABSTOP
PUSHBUTTON "&&",38,82, 63,14,14,NOT WS_TABSTOP
PUSHBUTTON "|",124,64, 63,14,14,NOT WS_TABSTOP
PUSHBUTTON "^",94,64, 46,14,14,NOT WS_TABSTOP
PUSHBUTTON "<",60,82, 30,14,14,NOT WS_TABSTOP
PUSHBUTTON ">",62,82, 46,14,14,NOT WS_TABSTOP
PUSHBUTTON "M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP
PUSHBUTTON "M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP
PUSHBUTTON "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP
PUSHBUTTON "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP
PUSHBUTTON "BS",8,64,117,31,14,NOT WS_TABSTOP
PUSHBUTTON "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP
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:
CONTROL
CONTROL
CONTROL
CONTROL
EDITTEXT
"",IDC_STATIC,"Static",SS_BLACKRECT,98,30,6,101
"",IDC_STATIC,"Static",SS_BLACKRECT,5,21,116,6
"",IDC_STATIC,"Static",SS_BLACKRECT,58,29,6,101
"",IDC_STATIC,"Static",SS_BLACKRECT,7,132,116,6
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
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 '^' : return iFirstNum ^ iNum ;
case
case
case
case
}
'<'
'>'
'/'
'%'
:
:
:
:
return
return
return
return
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 der Weil der _hBut = CreateWindowEx()-Aufruf wird für jeden Button verwendet werden soll, ist eine "Schreinbvereinfachung" sinnvoll,
etwa
// mit
static my_button * pButtton[256]; //max 256 Button's
WM_CREATE : ... pButton[255] = new my_button(hwnd,255,"255", 200,100,80,80);
WM_DESTROY: ... if(pButton[255]) delete pButton[255];
Kontroll-Fragen:
1. Enthält die Funktion DialogBox() eine Hauptnachrichtenschleife?
2. Nennen Sie unterschiedliche Möglichkeiten, wie DialogBox() mit einem Menu versehen werden kann.
3. Wozu dient der ret-Parameter bei EndDialog(hwnd,ret)?
4. Welche Nachricht wird durch einen Button-Klick ausgelöst?
5. Wie heißt die Klasse, die Button's erstellt und die MS-CALLBACK-Funktion enthält?
6. Was ist zu tun, wenn alle Nachrichten ZUERST an eine eigene CALLBACK-Funktion geschickt werden sollen und erst
danach an die "vorhandene, unsichtbare" MS-CALLBACK-Funktion weiter gereicht werden sollen?
7. Was bewirkt der Aufruf: ShellExecute(hwnd,"explore",0,0,0,SW_SHOWNORMAL)?
8. Welches Programm übersetzt einen *.rc-File in einen *.res-File?
9. Welches Programm bindet *.res-Files in das *.exe-File ein?
10. Welche CALLBACK-Funktion gehört zu der eingebauten Klasse "#32770" und
welche Nachrichten (Beispiele angeben) verarbeitet dies CALLBACK-Funktion?
11. Wozu dienen die Aufrufe: WNDCLASSEX wc = { 0 }; GetClassInfoEx(hInst,"#32770",&wc);?
12. 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)) ....;
13. 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?
14. 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?
15. 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
dlg_class.h | Teil A | "Notepad-Dialog" editor.gif | Verwaltung der Fenster mit glob. Handle-Array HWND hwa[10] | Wie wird der Modale zum Modeless? | Wie sieht eine
Dialog-CALLBACK-Funktion aus? | Was ist nun für Modeless zu tun?
| Teil B: | Übliche Tastenkombinationen (Dialogfelder) | Müssen Identifizierer stets neu definiert werden? | Was ist eigentlich zu tun? | Wie kann nun ein Modeless-Dialog
erstellt werden? | Wie kann ohne Visualität ein Modeless-Dialog erstellt werden? | Wie kann ohne eigene User-CALLBACK-Funktion mit der default_dlg_callback_proc
getestet werden? | Wie kann die vorhandene default_dlg_callback_proc() erweitert werden? | Kontroll-Fragen:
↑
5. SP2-Praktikum (SS 2005)
Der Teil A ist Pflichtteil für Sehfähige und optional für Sehbehinderte. Der Teil B ist Pflichtteil für Sehbehinderte und optional für
Sehfähige.
↑
Teil A
Der Teil A ist Pflichtteil für Sehfähige und optional für Sehbehinderte. Diese Aufgabe besteht darin, mit Modless-Dialogen zu arbeiten.
Dialoge sind zu erstellen und die zugehörigen Dialog-CALLBACK-Funktionen sind zu schreiben. Falls sinnvoll sind gewohnte
Tastenkombinationen zu unterstützen. Im Einzelnen:
Ausgehend von einer eigenen Window-Applikation, die ein Menu hat, soll ein Standard-File-Open-Dialog hinzu gefügt werden. Der
Standard-File-Open-Dialog soll per Menu-Klick aufgerufen werden. Ein Standard-File-Open-Dialog wird mit GetOpenFileName(&ofn))
angezeigt. Hier ein Muster:
#include <commdlg.h>
// includes common dialog functionality
BOOL my_open_file_dialog(HWND hwnd, TCHAR buf[], DWORD nChar)
{
TCHAR * pTitle = "mein file open";
TCHAR * pFilt =
"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";
buf[0] = '\0' ;
OPENFILENAME ofn = { 0 } ; //ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize
= sizeof(OPENFILENAME);
ofn.hwndOwner
= hwnd ;
ofn.hInstance
= GetModuleHandle(0);
ofn.lpstrTitle
= pTitle ;
ofn.lpstrFile
= buf ;
ofn.nMaxFile
= nChar;
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 FALSE;
//Filename ist nun in (char*)ofn.lpstrFile;
return TRUE;
}
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.
Nun ist beieinem entspechenden Menu-Klick ein .txt-File-Name auszuwählen, die File-Text-Daten sind zu lesen und in den Heap zu laden (
new ...). Die File-Text-Daten sind dann an ein Edit-Control ("EDIT"-Fenster) zu schicken. Hier ist mehr oder minder geeigneter erweiterter
cpp-Quelltext ...
/*
Test für file_open_copy_to_heap:
BYTE *pFix = file_open_copy_to_heap(hwnd);
err_if(!pFix,"kein File");
char * p = (char *) pFix;
// Achtung! p kann geändert werden,
// aber pFix darf nicht geändertwerden.
// pFix wird später für delete gebraucht
MessageBox(0,p,0,MB_OK);
if(pFix) delete pFix;
*/
BYTE * file_open_copy_to_heap(HWND hwnd)
{
TCHAR * pTitle = "mein begin_open_dialog()";
TCHAR * pFilt = TEXT("C-Dateien (*.c;*.cpp;)\000*.c;*.cpp;\000 Alle Files (*.*)
\000 *.*; \000\000");
TCHAR szFileName[_MAX_PATH]; szFileName[0] = '\0';
OPENFILENAME ofn = { 0 } ; //ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize
= sizeof( OPENFILENAME );
ofn.hwndOwner
= hwnd ;
ofn.hInstance
= GetModuleHandle(0);
ofn.lpstrTitle
= pTitle ;
ofn.lpstrFile
= szFileName;
ofn.nMaxFile
= _MAX_PATH;
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 NULL;
//Filename ist nun in (char*)ofn.lpstrFile;
BOOL ok = (szFileName && *szFileName);
err_if(!ok,"FILE_STRUCT ohne Filenamen");
if(!ok) return 0;
TCHAR drive[32]; TCHAR dir[256];
TCHAR fname[256];TCHAR ext[32];
_splitpath(szFileName,drive,dir,fname, ext);
//_makepath(path, drive, dir,"","");
if(!drive[0]&&!dir[0]){
TCHAR szTemp[_MAX_PATH]; LPSTR pName;
if (!GetFullPathName(szFileName,_MAX_PATH,szTemp,&pName)) {
lstrcpyn( szTemp, szFileName,_MAX_PATH);
} lstrcpyn(szFileName,szTemp,_MAX_PATH);
} else {
lstrcpyn(szFileName,szFileName,_MAX_PATH);
}
SECURITY_ATTRIBUTES sa={0}; sa.nLength = sizeof(sa);
DWORD dwCreateFlag = OPEN_ALWAYS;
HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,
&sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0);
BOOL isErr=(hFile==INVALID_HANDLE_VALUE); err_if(isErr,"hFile"); if(isErr) return
0;
DWORD nZuLesen = GetFileSize(hFile,0); if(!nZuLesen) return 0;
BYTE *p = new BYTE[nZuLesen+2]; if(!p) return 0;
memset(p,0,nZuLesen+2);
//DWORD dwOld = SetFilePointer(hFile,0,NULL,FILE_CURRENT);
//DWORD dwNew = SetFilePointer(hFile,0,NULL,FILE_BEGIN);
DWORD nGelesen;
BOOL ok1 = ReadFile(hFile,p,nZuLesen,&nGelesen,0); err_if(!ok1,"read");
//SetFilePointer(hFile,dwOld,NULL,FILE_CURRENT);
HRESULT ok2 = CloseHandle(hFile); err_if(!ok2,"end");
return p;
}
↑
"Notepad-Dialog"
Nun ist ein eigener "Notepad-Dialog" als Modeless-Dialog zu schreiben. Für die Ressourcen bitte die angegebenen ID-entifizierer
verwenden:
Edit-Control
Erstellen Sie bitte das Ressourcen-Template und einen Find-Replace-Dialog, den sie selbst entwickeln und programmieren. Zunächst sollte
der Dialog als nodaler Dialog angezeigt werden. Hierzu ist in das Haupt-Menu ein Menu-Item einzufügen, das das Edit-Dialog-Template
anzeigt.
↑
Verwaltung der Fenster mit glob. Handle-Array HWND hwa[10]
Ist z.B. HWND hwa[20]; ein globaler Array, so kann mit hwa[0] = CreateWindowEx() ein Hauptfenster erzeugt werden.
WNDCLASSEX wndClass = {0};
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.lpfnWndProc
= WndProc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 4;
wndClass.cbWndExtra
= 4;
wndClass.hInstance
= GetModuleHandle(0);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor
= LoadCursor(NULL, IDC_ARROW);
ATOM Ok = RegisterClassEx(&wndClass);
err_if(!Ok,"RegisterClassEx()"); if(!Ok)return 0;
int xPos=20, yPos=20, dx=500, dy=500; //(CW_USEDEFAULT)
hwnd[0] = CreateWindowEx(WS_EX_LEFT,TEXT("my_class"),
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
xPos,yPos,dx,dy,
NULL,
// parent window handle
NULL,
// window menu handle
GetModuleHandle(0), // program instance handle
NULL);
// creation parameters
↑
Wie wird der Modale zum Modeless?
Anstelle von DialogBox() wird ein modaler Dialog einmal in WinMain() (sichtbar, später unsichtbar) erzeugt und je nach Bedarf unsichtbar
oder sichtbar geschalten.
// modal:
int ret = DialogBox(GetModuleHandle(0),
MAKEINTRESOURCE(IDD_DIALOG1),
hParent, (DLGPROC)myDlgProc1 );
beenden mit EndDialog(...)
// modless:
hwa[1] = CreateDialog(GetModuleHandle(0),
MAKEINTRESOURCE(IDD_DIALOG1),
hParent, (DLGPROC)myDlgProc1 );
// nicht Zerstören sondern
// show(hwa[1]) bzw. hide(hwa[1])
Hier sind 2 Funktionen für show() bzw. hide():
// für die SetWindowPos()-Funktion brauchbar:
#define SWP_ZONLY
(SWP_NOSIZE|SWP_NOMOVE |SWP_NOACTIVATE)
#define SWP_SIZEONLY (SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE)
#define SWP_MOVEONLY (SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE)
#define SWP_HIDEONLY
(SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_HIDEWINDOW)
#define SWP_SHOWONLY
(SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_SHOWWINDOW)
void show(HWND hwnd)// zeige ein hwnd-Fenster an:
{ SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_SHOWONLY);
SetActiveWindow(hwnd);
}
void hide(HWND hwnd) // hwnd-Fenster verbergen:
{ if(IsIconic(hwnd)) return;
SetWindowPos(hwnd,0,0,0,0,0,SWP_HIDEONLY);
if(hwa[0])SetActiveWindow(hwa[0]);
}
↑
Wie sieht eine Dialog-CALLBACK-Funktion aus?
Eine Dialog-CALLBACK-Funktion gibt mit return FALSE die Kontrolle an Windows. Eine Dialog-CALLBACK-Funktion verbietet mit
return TRUE die nachfolgende Kontrolle durch die MS-internen-Dialog-CALLBACK-Funktion. Ein typischer Aufbau ist:
BOOL CALLBACK dlg_proc_1(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE: {
// EndDialog() für modale ...
// hide() für modeless ...
break;}
//
// falls benötigt z.B.: WM_INITDIALOG, WM_LBUTTONDOWN,...
//
// WM_COMMAND wie bekannt IDOK, IDCANCEL, ...
case WM_COMMAND: {
switch (LOWORD(wParam))
{
case IDOK: { // kommt von WM_CLOSE
MessageBox(hwnd,TEXT("IDOK"),TEXT("WM_COMMAND"),MB_OK);
break;}
case psh1: { // kommt von PushButten psh1
break;}
} // ende switch (LOWORD(wParam))
break;} // ende WM_COMMAND
} // ende switch(uMsg)
return FALSE;
//////////////////////////////////////////
// Später einmal anstelle von return FALSE:
// Hier könnte eine allen Dialogen gemeinsame
// dlg-CALLBACK-Funktion aufgerufen werden:
// return default_dlg_callback_proc(hwnd,uMsg,wParam,lParam);
}
↑
Was ist nun für Modeless zu tun?
Sind HWND m_hDlg ein globales Handle für alle Modeless-Dialoge,
HACCEL m_hAccel ein globales Handle auf die aktuelle Accelerator-Tabelle und
MSG m_msg eine globale Struktur,
so werden durch main_loop() die Nachrichten verteilt: Zunächst (falls erfolgreich) mit TranslateAccelerator() andernfalls (falls erfolgreich)
mit IsDialogMessage() an die modeless Dialoge und, wenn das nichts war, mit DispatchMessage().
// Haupt-Nachrichtenschleife:
void main_loop() { // hinterlege Nachricht in m_msg
while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{
err_if(-1==bRet,"-1==GetMessage()");
//err_if(!m_msg.hwnd,"!m_msg.hwnd");
m_hDlg = (GetWindowLong(m_msg.hwnd,GWL_STYLE) & WS_CHILD)
?GetParent(m_msg.hwnd):m_msg.hwnd;//GetWindow(hwnd,GW_OWNER);
if(!IsWindow(
m_hDlg)
|| !TranslateAccelerator(m_hDlg, m_hAccel, &m_msg))
{
if (!IsWindow(
m_hDlg)
|| !IsDialogMessage(m_hDlg, &m_msg))
{
TranslateMessage(&m_msg);
DispatchMessage (&m_msg);
}
}
}
}
Ein Anfang für die CALLBACK-Funktion ist dlg_proc_edit_mit_find_repl():
BOOL CALLBACK dlg_proc_edit_mit_find_repl
( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
static int idxSelStart, idxSelEnd, nChar;
static char buf[256], *pBuf,*pFind;
static HWND hwnd_combo_find, hwnd_combo_repl, hwnd_edit;
switch ( iMsg ) {
case WM_INITDIALOG : {
hwnd_combo_find=...
hwnd_combo_repl=...
hwnd_edit=...;
break; }
case WM_CLOSE:
PostQuitMessage(0);
return TRUE;
case WM_SETCURSOR:
if ( hwnd_edit != (HWND) wParam ) break;
if ( pBuf ) { free(pBuf); pBuf = NULL;}
idxSelStart = idxSelEnd = Edit_LineIndex(hwnd_edit,-1);
break;
case WM_COMMAND: { //Buttons, Edit, Combo
switch ( LOWORD( wParam ) ) {
case IDCLOSE: SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), lParam );
return TRUE;
case 4902: //IDC_BUTTON_REPL
ComboBox_GetText( hwnd_combo_repl, buf, sizeof(buf));
if ( idxSelStart < idxSelEnd ) Edit_ReplaceSel(hwnd_edit, buf);
//falle in Find-Button
case 4901: //IDC_BUTTON_FIND
ComboBox_GetText(hwnd_combo_find, buf, sizeof(buf));
nChar = Edit_GetTextLength(hwnd_edit);
if ( pBuf ) { free(pBuf); pBuf = NULL;
} else {
pBuf = (char *) malloc((nChar+1)*sizeof(char));
err_if(!pBuf,"malloc");
memset(pBuf,0,(nChar+1)*sizeof(char));
}
nChar = Edit_GetText(hwnd_edit, pBuf, nChar);
pFind = strstr( pBuf + idxSelEnd, buf );
if (pFind) {
idxSelStart = pFind - pBuf;
idxSelEnd
= idxSelStart + strlen(buf);
} else {
MessageBox(hwnd,"Ende des\r\nEditor-Textes","Hinweis",MB_OK);
idxSelEnd = idxSelStart = 0;
}
SetFocus( hwnd_edit );
Edit_SetSel( hwnd_edit, idxSelStart, idxSelEnd);
Edit_ScrollCaret( hwnd_edit);
if (pBuf) { free(pBuf); pBuf=NULL;}
break;
}
break; } // ende WM_COMMAND
}
//ende switch ( iMsg )
return FALSE;
}
↑
Teil B:
Der Teil B ist Pflichtteil für Sehbehinderte und optional für Sehfähige.
↑
Übliche Tastenkombinationen (Dialogfelder)
Die Dialog-CALLBACK-Funktion #32770 wandelt die RETURN (ENTER-key-message) in WM_COMMAND mit wParam = IDOK um.
Die Dialog-CALLBACK-Funktion #32770 erlaubt es, mit der Tab-Taste bzw. der Shift+Tab-taste vorwärts/rückwärts durch die Controls
eines Dialoges (Auswahl-Optionen) zu bewegen. Übliche Tastenkombinationen (Dialogfelder) sind:
Esc
Return-Taste
Tab
Shift+Tab
Abbrechen! (Dialog, aktuellen Task)
Ausführen! (aktive Menu-Option oder Button-Schaltfläche)
Vorwärts/Rückwärts durch die Optionen bewegen
Strg+Tab
Vorwärts/Rückwärts durch Contol-Folge oder Registerkarten bewegen
Strg+Shift+Tab
Alt+Leertaste
Öffnet das Kontextmenü für das aktive Fenster
Alt oder F10 gehe zum Menu
Alt+F4 Aktives Element schließen oder aktives Programm beenden
Alt+unterstrichener Buchstabe
Menu-Befehl ausführen (Option auswählen)
F1
Hilfe anzeigen
F2
Ausgewähltes Element umbenennen
F3
Suchen, Weitersuchen (Wort,Datei,Ordner)
F4
Elemente in der aktiven Liste anzeigen
F5
Aktives Fenster aktualisieren
F6
Zwischen Bildschirmelementen in einem Fenster oder auf dem Desktop umschalten
F10
↑
Menüleiste im aktiven Fenster aktivieren
Müssen Identifizierer stets neu definiert werden?
In dlgs.h gibt es bereits zahlreiche Identifizierer, die benutzt werden können. Gehört zu jedem Dialog-Template eine eigene CALLBACKFunktion, so müssen die Identifizierer nur innerhalb eines Dialoges eindeutig sein. Die Identifizierer aus dlgs.h liegen zwischen 1024 und
1279.
#define ctlFirst 0x0400
#define ctlLast 0x04ff
Es
Es
Es
Es
↑
gibt
gibt
gibt
gibt
Pushbutton-Identifizierer psh1,psh2,...,pshHelp=psh15,psh16.
Edit-Control-Identifizierer edt1,edt2,...,edt16
ComboBox-Identifizierer cmb1,cmb2, ...,cmb16
ListBox-Identifizierer lst1,lst2, ...,lst16
Was ist eigentlich zu tun?
Beginnen Sie bitte ein neue Window-Projekt, das zunächst diesen Header-File dlg_class.h enthalten soll.
Fügen Sie dem Projekt einen leeren meine_aufgabe.cpp-File hinzu, in den zunächst #include "dlg_class.h" geschieben wird. dlg_class.h
enthält die bekannte Menü-Unterstützung und wurde um Dialoge erweitert.
Schauen Sie sich die folgende Funktion create_main_window() an, die ein Hauptfenster erzeugt und kopieren sie diesen in
meine_aufgabe.cpp.
HWND create_main_window(int xPos,int yPos, int dx,int dy, WNDPROC WndProc)
{
if(!WndProc) WndProc = default_wnd_callback_proc;
// existiert "my_class" bereits?
BOOL ok1 = g.is_class(TEXT("my_class"));
if (!ok1) // "my_class" nur einmal anlegen:
{
WNDCLASSEX wndClass = {0};
wndClass.cbSize
= sizeof( WNDCLASSEX ) ;
wndClass.style
= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.lpfnWndProc
= WndProc;
wndClass.lpszClassName = TEXT("my_class");
wndClass.cbClsExtra
= 4;
wndClass.cbWndExtra
= 4;
wndClass.hInstance
= GetModuleHandle(0);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor
= LoadCursor(NULL, IDC_ARROW);
ATOM Ok = RegisterClassEx(&wndClass);
err_if(!Ok,"RegisterClassEx()"); if(!Ok)return 0;
}
//int xPos=20, yPos=20, dx=500, dy=500; //(CW_USEDEFAULT)
HWND hwnd = CreateWindowEx(WS_EX_LEFT,TEXT("my_class"),
TEXT("Titelzeile"), // window caption
WS_OVERLAPPEDWINDOW, // window style
xPos,yPos,dx,dy,
NULL,
// parent window handle
NULL,
// window menu handle
GetModuleHandle(0), // program instance handle
NULL);
// creation parameters
if(hwnd) g.set_icon(hwnd);
err_if(!hwnd,"CreateWindowEx()");
#define GHWND_IDX 0 // Fenster 0 ist stets das Hauptfenster!
ghwnd(GHWND_IDX) = hwnd;
// Menü-Makros zur Vereinfachung der Schreibarbeit:
MENU_BEGIN(GHWND_IDX) //0-tes Fenster, Makro, d.h. Ende-';' verboten!
MENU_POPUP("&Fenster") //kein ;
MENU_ITEM_ALT("next_dlg
Alt+F3", show_next_dlg,VK_F3)//kein ;
MENU_ITEM_KEY("on_help
?", on_help,
'?')//kein ;
MENU_ITEM_VK_F("on_help
F5", on_help,
VK_F5)//kein ;
MENU_END_AND_SHOW(GHWND_IDX); // alternativ nur: MENU_END(GHWND_IDX);
return hwnd;
#undef GHWND_IDX
}
Das Hauptprogramm von meine_aufgabe.cpp könnte dann etwa so aussehen:
INT WINAPI WinMain(HINSTANCE,HINSTANCE,PSTR,INT)
{
// erstellt Hauptfenster ghwnd(0)
ghwnd(0) = create_main_window(100,100,200,300, NULL);
g.show(ghwnd(0));
g.main_loop();
// hier kann aufgräumt werden
return (int) 0;
} // ende WinMain
Dies sollte ein Fenster mit Menü ergeben, wobei die Menü-Funktion on_help() existiert und lediglich zum testen dient.
↑
Wie kann nun ein Modeless-Dialog erstellt werden?
Zunächst einige Erklärungen. Für Sehbehinderte ist das kontollierte Zeigen mit der Maus schwierig und ein Ressourcen-Workshop kaum
brauchbar. create_dlg3(hParent,dlgProg) soll deshalb ein Modeless-Dialog-Template als Befehlsfolge von g.dlg_xxx()-Funktionen erstellen.
Weitere Erklärungen. Für den Dialog 3 sei das Handle des Dialog-Fenster g.hwa[3]. Eine andere Schreibweise für g.hwa[3] mit dem
ghwnd()-Makro ist ghwnd(3). Anstelle von 3 wird das define GHWND_IDX verwendet. Der prinzipielle Template-Aufbau zwischen
dlg_begin() und dlg_end() ist:
g.dlg_begin(hParent);
g.dlg_rahmen(x_dlg_pos,y_dlg_pos,width_dialog,high_dialog,TEXT("DIALOG 3"));
...
...
ghwnd(GHWND_IDX) = g.dlg_end(dlgProg);
err_if(!ghwnd(GHWND_IDX),"g.dlg_end(???,???)")
Weitere Erklärungen. Hierbei erstellt dlg_end(dlgProc) den Dialog mit Hilfe der Windows-Funktion CreateDialogIndirect(), die ein im
Speicher zusammen gebasteltes Dialog-Template und die (verfügbare) CALLBACK-Funktion verwendet.
HWND dlg_end(DLGPROC dlgProc) // existiert bereits in dlg_class.h
{
if(!dlgProc) { m_ds.dlgProc = default_dlg_callback_proc;
} else
{ m_ds.dlgProc = dlgProc;
}
HWND hwnd = CreateDialogIndirect(GetModuleHandle(0),
(LPDLGTEMPLATE)m_ds.buf,m_ds.hParent,(DLGPROC)m_ds.dlgProc);
err_if(!hwnd,"dlg_end(): kein hwnd");
return hwnd;
}
Weitere Erklärungen. Der dlg_rahmen() sagt, wo (in Pixel: x_dlg_pos, y_dlg_pos) der Dialog erscheinen wird und wie breit und hoch (in
Pixel: width_dialog, high_dialog) der der Dialog sein soll und wie der Titelzeilen-Text lautet, hier TEXT("DIALOG 3"). x läuft von links
nach rechts und y von oben nach unten.
↑
Wie kann ohne Visualität ein Modeless-Dialog erstellt werden?
Weitere Erklärungen. Im Kopf sind geometrische Vorstellung mit Pixelwerten kaum machbar.
1. Einfacher ist es, als Maß für unterschiedliche Breiten von der Mindestbreite eines Buttons (WORD width =
40;) auszugehen
2. Einfacher ist es, als Maß für unterschiedliche von der Elementar-Höhe eines Button (WORD high = 14;)
auszugehen
3. Einfacher ist es, als Einteilung der Rechteck-Dialog-Fläche von der gewünschte Horizontal-Unterteilung der
gesamte dlg-Breite in nx-Teile auszugehen (z.B. WORD nx = 4;)
4. Einfacher ist es, als Einteilung der Rechteck-Dialog-Fläche von der gewünschte Vertikal-Unterteilung der
gesamte dlg-Höhe in ny-Teile auszugehen (z.B. WORD ny = 10; )
Dann kann z.B. die gesamte Dialog-Fläche mit
WORD width_dialog = nx * width; und
WORD high_dialog = ny * high; berechnet werden. x_dlg_pos, y_dlg_pos werden lediglich so gesetzt, dass mehrere Dialoge nicht überein
ander liegen.
Beispiel für das horizontale Positionieren. Ist nx = 4, so gibt es die horizontalen Positionen 0 (gang links), 1 (1. Viertels), 2 (mittig), 3 (3.
Viertels), 4 (ganz rechts). Die linke Hälfte kann mit den Zahlen (0,2,4) beschrieben werden. (0,2,4) wird gelesen: Teilfeld von 0 bis
einschliesslich 2 von insgesamt 4 Teilfeldern. Die linke Hälfte kann aber auch mit den Zahlen (0,1,2) beschrieben werden. (0,1,2) wird
gelesen: Teilfeld von 0 bis einschliesslich 1 von insgesamt 2 Teilfeldern. Entsprechendes gilt für die Vertikale. Dies verdeutlicht der Dialog
mit einer linken ListBox lst1, einer rechten ListBox lst2, und 2 mittigen Pushbuttons psh1, psh2:
nur für Erklärungen ...
g.dlg_begin(hParent);
g.dlg_rahmen(x_dlg_pos,y_dlg_pos,width_dialog,high_dialog,TEXT("DIALOG 3"));
g.dlg_list( 0,9,ny, 0,2,5, lst1); // linke ListBox lst1
g.dlg_button(3,3,ny, 2,2,5, TEXT("==>"),psh1); // Identifizierer psh1
g.dlg_list( 0,9,ny, 3,5,5, lst2); // rechte ListBox lst2
g.dlg_button(4,4,ny, 2,2,5, TEXT("<=="),psh2); // Identifizierer psh2
ghwnd(3) = g.dlg_end(NULL); err_if(!ghwnd(3),"g.dlg_end(???,???)")
g.dlg_end(dlgProg) wird (falls vorhanden) die eigene Dialog-CALLBACK-Funktion dlgProg übergeben, die am ende
default_dlg_callback_proc() aufrufen sollte. Gibt es (zunächst) keine eigene Dialog-CALLBACK-Funktion dlgProg, so wird
g.dlg_end(NULL) verwendet, d.h. es wird dann automatisch (nur) die default_dlg_callback_proc() verwendet. Dies ist zum vorherigen
Testen des Dialoges geeignet. Die folgende Funktion create_dlg3() kann hinter #include "dlg_class.h" kopiert werden.
void create_dlg3(HWND hParent, DLGPROC dlgProg)
{
// Durch kopieren z.B. des Dialoges 1 und erweitern
// wird nun der Dialog 3 erstellt:
#define GHWND_IDX 3
WORD nx
= 4; // !!! gewünschte Unterteilung der gesamte dlg-Breite in nx-Teile
WORD ny
= 10; // gewünschte Unterteilung der gesamte dlg-Höhe in ny-Teile
WORD high = 14; // Höhe eines Button als Maß
WORD width = 40; // !!! Mindestbreite eines Button als Maß
WORD width_dialog = nx * width; // 160 Pixel
WORD high_dialog = ny * high; // 140 Pixel
WORD x_dlg_pos = GHWND_IDX*high + 100;
WORD y_dlg_pos = GHWND_IDX*width;
g.dlg_begin(hParent);
g.dlg_rahmen(x_dlg_pos,y_dlg_pos,width_dialog,high_dialog,TEXT("DIALOG 3"));
g.dlg_list( 0,9,ny, 0,2,5, lst1);
g.dlg_button(3,3,ny, 2,2,5, TEXT("==>"),psh1);// psh1 aus winuser.h
g.dlg_list( 0,9,ny, 3,5,5, lst2);
g.dlg_button(4,4,ny, 2,2,5, TEXT("<=="),psh2);// psh2 aus winuser.h
ghwnd(GHWND_IDX) = // jetzt wird es spannend ...
// mit User-CALLBACK dlgProg:
// g.dlg_end(dlgProg); err_if(!ghwnd(GHWND_IDX),"g.dlg_end(???,???)")
// ohne User-CALLBACK:
g.dlg_end(NULL); err_if(!ghwnd(GHWND_IDX),"g.dlg_end(???,???)")
HWND hList1 = GetDlgItem(ghwnd(GHWND_IDX),lst1);
HWND hList2 = GetDlgItem(ghwnd(GHWND_IDX),lst2);
err_if(!hList1,"hList1"); err_if(!hList2,"hList2");
// Text einfügen in die ListBoxen:
ListBox_AddString(hList1, TEXT("links
ListBox_AddString(hList1, TEXT("links
ListBox_AddString(hList1, TEXT("links
ListBox_AddString(hList1, TEXT("links
ListBox_AddString(hList1, TEXT("links
ListBox_AddString(hList2,
ListBox_AddString(hList2,
ListBox_AddString(hList2,
ListBox_AddString(hList2,
ListBox_AddString(hList2,
TEXT("rechts
TEXT("rechts
TEXT("rechts
TEXT("rechts
TEXT("rechts
text
text
text
text
text
text
text
text
text
text
0"));
1"));
2"));
3"));
4"));
0"));
1"));
2"));
3"));
4"));
// Menü mit Macros bauen (Grossbuchstaben):
MENU_BEGIN(GHWND_IDX) //-tes Fenster, Makro, d.h. Ende-';' verboten!
MENU_POPUP("&Fenster")
//kein ;
MENU_ITEM_ALT("next_dlg
Alt+F3", show_next_dlg, VK_F3)//kein ;
MENU_ITEM_KEY("on_help
?", on_help,
'?')//kein ;
//MENU_ITEM_ALT("Button ==> ", on_psh1, VK_RIGHT)//kein ;
MENU_ITEM_VK_F("on_help
F6", on_help,
VK_F6)//kein ;
MENU_END(GHWND_IDX);
// g.show(ghwnd(GHWND_IDX));
#undef GHWND_IDX
}
Die Menü-Funktionen show_next_dlg(), on_help() sind in dlg_class.h enthalten. show_next_dlg() geht mit ALt+F3 zum nächsten Fenster
(Hauptfenster, Dialog) in der Index Reihenfolge ghwnd(0), ghwnd(1), ghwnd(2), ... wobei nur das fenster aktiviert wird, wenn das Handle
ghwnd(i) gültiges ist. Die Funktion on_psh1() gibt es noch nicht und das Menü-Item ist aukommentiert. Beispiele für Menü-Funktionen
sind:
BOOL show_dlg_3()
{
if(ghwnd(3)) g.show(ghwnd(3));
return TRUE;
}
BOOL hide_dlg_3()
{
if(ghwnd(3)) g.hide(ghwnd(3));
return TRUE;
}
BOOL on_menu1()
{
MSG m = g.get_msg();
TCHAR * pTitle = TEXT("on_menu1()");
TCHAR
Buf[1024];
wsprintf(Buf,
TEXT("LOWORD(wParam): id = %d"),LOWORD(m.wParam));
MessageBox(m.hwnd, Buf, pTitle, MB_OK);
return TRUE;
}
BOOL on_menu2()
{
MSG m = g.get_msg();
TCHAR * pTitle = TEXT("on_menu2()");
TCHAR
Buf[1024];
wsprintf(Buf,
TEXT("LOWORD(wParam): id = %d"),LOWORD(m.wParam));
MessageBox(m.hwnd, Buf, pTitle, MB_OK);
return TRUE;
}
Natürlich kann unter WM_COMMAND und LOWORD(wParam) im case psh1: hier irgend eine Menü-Funktion einfügen, die infolge des
PushButten psh1 ausgeführt wird.
↑
Wie kann ohne eigene User-CALLBACK-Funktion mit der default_dlg_callback_proc getestet werden?
Existiert noch keine selbstgeschrieben CALLBACK-Funktion, so kann an den entsprechenden Stellen NULL eingesetzt werden. Das
ghwnd(3)-Dialog-Template hat eine linke Listbox lsb1. Die Funktion create_dlg3(hParent, NULL) erzeugt durch g.dlg_end(NULL) den
Dialog. g.dlg_end()verwendet innen CreateDialogIndirect(). Dem ghwnd(3)-Dialog-Fenster kann ein Menü für on_psh1() hinzugefügt
werden (oben auskommentiert): Die Menu-Funktion on_psh1() holt mit HWND hList1 = GetDlgItem(hwnd,lst1); das Handle für die
ListBox, holt den Text der Zeile line_idx=2 mit ListBox_GetText(hList1,line_idx, buf) in den buf-fer. und gibt diesen mit der MessageBox()
aus.
BOOL on_psh1() // Menu-Funktion
{
HWND hwnd = ghwnd(3);
// Achtung! Hotkey-err, falls hwnd = g.get_ghwnd();
err_if(!hwnd,"on_psh1(): !ghwnd(3)");
HWND hList1 = GetDlgItem(hwnd,lst1);
err_if(!hList1,"on_psh1(): !hList1");
int max_lines = ListBox_GetCount(hList1);
int line_idx = 2; // [0],[1],[2],[3],..[max-1]
int n_char
= ListBox_GetTextLen(hList1,line_idx);
TCHAR buf[512]; buf[0] = 0;
if((n_char < 512) && (line_idx < max_lines))
ListBox_GetText(hList1,line_idx, buf);
MessageBox(hwnd,buf,TEXT("hList1 [2]"),MB_OK);
return TRUE;
}
In WinMain() kommt rein create_dlg3(ghwnd(0),NULL); g.show(ghwnd(3)); Nun sollte die Tab-Taste für die Controlls funktionieren. Auch
die Alt+F3-Taste sollte zyklisch die (Haupt-)Fenster weiterschalten.
↑
Wie kann die vorhandene default_dlg_callback_proc() erweitert werden?
Um auf bestimmte Ereigniss zu reagieren, müssen diese ausprogrammiert werden (CALLBAC-Funktion dlg_proc3). Als Beispiel seien in
einem ghwnd(3)-Dialog-Template die ListBox mit dem Identifizierer lst1 (aus dlgs.h) und ein Pushbutton mit dem Identifizierer psh1 (aus
dlgs.h) vorhanden. Das Handle auf die Listbox wird erhalten durch
HWND hList1 = GetDlgItem(ghwnd(3),lst1)
windowsx.h enthält Carsting-Makros für SendMessage, die einfacher zu benutzen sind. Es gibt z.B.
ListBox_GetCount(hList1);
ListBox_GetTextLen(hList1,line_idx);
ListBox_GetText(hList1,line_idx, buf);
Wichtig! Die folgende User-CALLBACK dlg_proc_3 ruft am Ende die default_dlg_callback_proc() auf, die allen Dialogen Gemeinsames
behandelt. CALLBACK dlg_proc3() kann als Muster für andere Dialog-CALLBACK-Funktionen dienen:
BOOL CALLBACK dlg_proc3(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
// nicht erforderlich: case WM_CLOSE: { ... break;}
// nicht erforderlich: case WM_DESTROY:{ ... break;}
//
// falls benötigt z.B.: WM_INITDIALOG, WM_LBUTTONDOWN,...
//
// WM_COMMAND ist nicht bei Menu-Funktionen,
// erforderlich, aber für zusätzliche
// (Identifizierer-)Aktionen, wie z.B.
// IDOK, IDCANCEL, usw.
case WM_COMMAND: {
switch (LOWORD(wParam))
{
case IDOK: { // kommt von WM_CLOSE
MessageBox(hwnd,TEXT("IDOK"),TEXT("WM_COMMAND"),MB_OK);
break;}
case psh1: { // kommt von PushButten psh1
//MessageBox(hwnd,TEXT("PushButten 1"),TEXT("WM_COMMAND"),MB_OK);
// ListBox-Handles von Dialog 3
HWND hList1 = GetDlgItem(ghwnd(3),lst1);err_if(!hList1,"!hList1");
int max_lines = ListBox_GetCount(hList1);
int line_idx = 2; // [0],[1],[2],[3],..[max-1]
int n_char
= ListBox_GetTextLen(hList1,line_idx);
TCHAR buf[512];
if((n_char < 512) && (line_idx < max_lines))
ListBox_GetText(hList1,line_idx, buf);
MessageBox(hwnd,buf,TEXT("hList1 [2]"),MB_OK);
break;}
} // ende switch (LOWORD(wParam))
break;} // ende WM_COMMAND
} // ende switch(uMsg)
//////////////////////////////////////////
// Hier ist die allen Dialogen gemeinsame
// dlg-CALLBACK-Funktion aufzurufen:
return default_dlg_callback_proc(hwnd,uMsg,wParam,lParam);
}
Hier 2 Beispiele (create_dlg1,create_dlg2), die kommentiert und ungetestet sind ...
void create_dlg1(HWND hParent, DLGPROC dlgProg)
{
#define GHWND_IDX 1 // Dialog 1 bitte
WORD nx = 4; // !!! gewünschte Unterteilung der gesamte dlg-Breite in nx-Teile
WORD ny = 10; // gewünschte Unterteilung der gesamte dlg-Höhe in ny-Teile
WORD high = 14; // Höhe eines Button als Maß
WORD width = 40; // !!! Mindestbreite eines Button als Maß
WORD high_menu
= high; // es soll ein Menu dazu
WORD high_dialog = ny * high + high_menu;
WORD width_dialog = nx * width;
WORD x_dlg_pos = GHWND_IDX*high + 100;
WORD y_dlg_pos = GHWND_IDX*width;
// Dialog 1 erstellen:
// wahrscheinlich fehlerhaft ....:
g.dlg_begin(hParent);
g.dlg_rahmen(x_dlg_pos,y_dlg_pos, width_dialog, high_dialog, TEXT("DIALOG1"));
g.dlg_editM( 0,7,ny, 0,nx,nx, TEXT("hallo edt1"), edt1);
g.dlg_button(7,8,ny, 0,nx,nx, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
ghwnd(GHWND_IDX) = // jetzt wird es spannend ...
g.dlg_end(dlg_proc_1); err_if(!ghwnd(GHWND_IDX),"DLG_END(???,???)")
// nun ist ghwnd(1) das globale Fenster-Handle!
// Verwende Fenster 1 (siehe define GHWND_IDX als 1)
// mit dem Makro ghwnd(1) oder
// gleichwertig mit dem globalen Handle g.hwa[1]
// manipuliere edit-control:
HWND hEdit = GetDlgItem(ghwnd(GHWND_IDX), edt1);
err_if(!hEdit,"hEdit");
Edit_LimitText(hEdit,2048); // begrenze die Zeichen-Anzahl
Edit_SetText(hEdit, TEXT("Edit-Init-Text")); // hinterlege Text
// Nun soll der Dialog ein Menü erhalten.
// Die Menü-Funktionen müssen existieren
MENU_BEGIN(GHWND_IDX) //1-tes Fenster, Makro, d.h. Ende-';' verboten!
MENU_POPUP("&Fenster")
//kein ;
MENU_ITEM_ALT("next_dlg
Alt+F3", show_next_dlg,VK_F3)//kein ;
MENU_ITEM("show_fenster_&0", show_fenster_0)//kein ;
MENU_ITEM("show_dlg_&1",
show_dlg_1)//kein ;
MENU_ITEM("show_dlg_&2",
show_dlg_2)//kein ;
MENU_POPUP("Zeichne&Kurven") //Makro, d.h. Ende-';' verboten!
MENU_ITEM_KEY("on_help
?", on_help,
'?')//kein ;
MENU_ITEM_VK_F("on_help
F6", on_help,
VK_F6)//kein ;
MENU_ITEM("on_menu1",
on_menu1) //Makro, d.h. ; verboten!
MENU_ITEM("on_menu&2 ", on_menu2) //kein ;
MENU_ITEM("on_paint&3", on_paint3) //kein ;
MENU_ITEM("on_paint&4", on_paint4) //kein ;
MENU_END(GHWND_IDX);
// g.show(ghwnd(GHWND_IDX));
#undef GHWND_IDX
}
// Dialog 2 erstellen:
// wahrscheinlich fehlerhaft ....:
void create_dlg2(HWND hParent, DLGPROC dlgProg)
{
// Durch kopieren Dialog 1 und erweitern
// wird nun der Dialog 2 erstellt:
#define GHWND_IDX 2
WORD nx = 4; // !!! gewünschte Unterteilung der gesamte dlg-Breite in nx-Teile
WORD ny = 10; // gewünschte Unterteilung der gesamte dlg-Höhe in ny-Teile
WORD high = 14; // Höhe eines Button als Maß
WORD width = 40; // !!! Mindestbreite eines Button als Maß
WORD high_dialog = ny * high;
WORD width_dialog = nx * width;
WORD x_dlg_pos = GHWND_IDX*high + 100;
WORD y_dlg_pos = GHWND_IDX*width;
g.dlg_begin(hParent);
g.dlg_rahmen(x_dlg_pos,y_dlg_pos,width_dialog,high_dialog,TEXT("DIALOG2"));
// 0,5,ny bedeutet von oben 0 herunter bis 5 von den ny-Teilen
// 0,nx,nx bedeutet die gesamte Breite (ebenso auch 0,1,1 oder 0,2,2 )
g.dlg_editM( 0,4,ny, 0,nx,nx, TEXT("hallo edt1"), edt1);
// 4,5,ny bedeutet von oben 4 herunter bis 5 von den ny=10-Teilen
// 0,nx,nx bedeutet die gesamte Breite (ebenso auch 0,1,1 oder 0,2,2 )
g.dlg_button(4,5,ny, 0,nx,nx, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
// 6,7,ny bedeutet von oben
// 0,1,2 bedeutet von links
g.dlg_static(5,6,ny, 0,1,2,
// 1,2,2 bedeutet von links
6 herunter bis 7 von den ny=10-Teilen
0 nach rechts bis 1 von den 2-horizontalen Teilen
TEXT("0,1,2 static-Text:"));//static-Text in Dialog
1 nach rechts bis 2 von den 2-horizontalen Teilen
g.dlg_button(5,6,ny, 1,2,2, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
g.dlg_static(6,7,ny, 0,1,2, TEXT("0,1,2 weiterer static-Text:"));//static-Text in
Dialog
g.dlg_button(6,7,ny, 1,2,2, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
// 7,7,ny ist eine Vereinfachung für einen Teil und bedeutet von oben 7 bis 8
// 0,2,4 ist eine Vereinfachung für einen Teil und bedeutet von 0 bis 2
g.dlg_edit(7,8,ny, 0,2,4, TEXT("Hallo edt14"), edt14);// edt14 aus winuser.h
// 2,2,4 ist eine Vereinfachung für einen Teil und bedeutet von 2 bis 3
g.dlg_button(7,8,ny, 2,2,4, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
// 3,3,4 ist eine Vereinfachung für einen Teil und bedeutet von 3 bis 4
g.dlg_button(7,8,ny, 3,3,4, TEXT("Beende"), IDCANCEL);// IDCANCEL aus winuser.h
g.dlg_combo(8,9,ny, 0,2,2, cmb1);// cmb1 aus winuser.h
ghwnd(GHWND_IDX) = // jetzt wird es spannend ...
g.dlg_end(dlg_proc_1);
err_if(!ghwnd(GHWND_IDX),"create_dlg2(): dlg_end(?)");
HWND hCombo1 = GetDlgItem(ghwnd(GHWND_IDX), cmb1);
err_if(!hCombo1,"create_dlg2(): hCombo1");
//ComboBox_LimitText(hCombo1, 256); // anzahl char
//ComboBox_Enable(hCombo1,FALSE);
//ComboBox_Enable(hCombo1,TRUE);
//if(!ComboBox_GetDroppedState(hCombo1))ComboBox_ShowDropdown(hCombo1,TRUE);
//???ComboBox_SetText(hCombo1,TEXT("cb-edit-cmb1"));
ComboBox_AddString(hCombo1,TEXT("cb-list [0]-ter Eintrag"));
ComboBox_AddString(hCombo1,TEXT("cb-list [1]-ter Eintrag"));
ComboBox_AddString(hCombo1,TEXT("cb-list [2]-ter Eintrag"));
//SetFocus(hCombo1);SetFocus(ghwnd(GHWND_IDX));
MENU_BEGIN(GHWND_IDX) //-tes Fenster, Makro, d.h. Ende-';' verboten!
MENU_POPUP("&Fenster")
//kein ;
MENU_ITEM_ALT("next_dlg
Alt+F3", show_next_dlg,VK_F3)//kein ;
MENU_ITEM_KEY("on_help
?", on_help,
'?')//kein ;
MENU_ITEM_VK_F("on_help
F6", on_help,
VK_F6)//kein ;
MENU_END(GHWND_IDX);
// g.show(ghwnd(GHWND_IDX));
#undef GHWND_IDX
}
↑
Kontroll-Fragen:
1. Welche Standard-Dialoge gibt es?
2. Wo auf dem Screen ist das "Taskbar-Icon" zu sehen?
3. Ein Fenster hwnd soll mittige zentriert werden. Was ist hier zu ändern?
RECT rc ;
GetWindowRect ( hwnd ,
& rc ) ;
rc.left = ( GetSystemMetrics ( SM_CXSCREEN ) - rc.right
rc.top
+ rc.left ) / 2 ;
= ( GetSystemMetrics ( SM_CYSCREEN ) - rc.bottom + rc.top
) / 2 ;
SetWindowPos(hwnd, NULL, rc.left, rc.top,0,0,SWP_NOSIZE|SWP_NOZORDER);
4. Wozu dient die Seek()-Funktion bei Files?
5. Es sei int i = 256; float f = 1.0; Diese beiden Zahlen sollen (binär) in einen File geschrieben werden. Das
"Holen" vom File soll byteweise erfolgen. Welche Bytes erhalten wir?
6. Erklären Sie bitte den Find-Replace-"Mechanismus" an Hand der CALLBACK-Funktion.
7. Wenn die folgenden Funktion verstanden und lauffähig sind, wozu können diese dann dienen?
int CDECL print_to(HWND hDst, HWND hSrc, LPTSTR pFormat, ...)
{ static TCHAR Buf[2048];
err_if(!hDst,"print_to(): 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);
}
int __cdecl wfprintf(HANDLE file, const TCHAR *fmt, ...)
{
//variable argument
static TCHAR tmpbuf[256];
int len, numwritten;
if(file == 0) return 0;
va_list argp;
va_start(argp, fmt);
len = wvsprintf(tmpbuf, fmt, argp) * sizeof(TCHAR);
va_end(argp);
WriteFile(file, tmpbuf, len, (LPDWORD)&numwritten, NULL);
return len;
}
UINT __stdcall HexErrorBox(TCHAR *fmt, ...)
{ static TCHAR tmpbuf[_MAX_PATH+256]; va_list argp;
va_start(argp, fmt);
wvsprintf(tmpbuf, fmt, argp);
va_end(argp);
return MessageBox(GetActiveWindow(),
tmpbuf, szAppName, MB_OK | MB_ICONEXCLAMATION);
}
8. Erklären Sie bitte die folgende Tabelle:
String | Data Type
| String Literal Function
--------|-----------------|-------------------------char
| "string"
| StringCbCopyExA
TCHAR
| TEXT("string")
| StringCbCopyEx
WCHAR
| L"string"
| StringCbCopyExW
--------|-----------------|--------------------------
9. Welche Nachrichten sendet GetParent(GetActiveWindow()); ?
10. Erklären sie bitte jede Funktion:
hwnd1 = GetActiveWindow();
hwnd2 = GetFocus();
hwnd3 = GetWindow(hwnd,GW_CHILD);
if(IsIconic(hwnd)) ...
if(IsChild(m_hParent,m_hDlg)) ...
if(IsWindowEnabled(hwnd))...
11. Erklären sie bitte jede Abfrage:
if(IsChild(hParent,hDlg)) ...
if(IsIconic(hwnd)) ...
if(IsWindowVisible(hwnd)) ...
if(IsWindowEnabled(hwnd))...
if((GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ...
12. Erklären sie bitte das folgende Statement:
m_hDlg = (GetWindowLong(hwnd,GWL_STYLE) & WS_CHILD)
?GetParent(hwnd):GetWindow(hwnd,GW_OWNER);
13. Wie heißen die EN_..., CBN_..., LBN_... Nachrichten?
14. Wieviele CB_...-Nachrichten gibt es?
15. Wieviele LB_...-Nachrichten gibt es?
16. Stellen sie bitte vergleichbare die define's von
17. CB_...--Nachrichten und LB-..-Nachrichten neben einander.
18. Welche Notify-Benachrichtigungen gibt es für das ComboBox-Control?
19. Nennen sie Gründe, warum die Prüfung auf String-Gleichheit aufwendig sein kann!
// gehört hwnd zu einer bestimmten Fenster-Class?
BOOL is_class(HWND hwnd, TCHAR *className)
{
TCHAR buf[512];
int anz = GetClassName(hwnd, buf, 512);
int diff= CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE
| NORM_IGNOREKANATYPE
| NORM_IGNOREWIDTH,buf,-1,className,-1);
//if(GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ...
return (diff == CSTR_EQUAL);
}
#ifndef _DLG_CLASS_
#define _DLG_CLASS_
/////////////////////////////////////////////////
// dlg_class.h schafft den Rahmen für Dialoge
/////////////////////////////////////////////////
#define STRICT
//#define UNICODE
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>
#include <math.h>
//#pragma warning(disable:4244)
//#pragma warning(disable:4189)
//#pragma warning(disable:4100)
#define err_if(e,errStr) if(e)if(IDOK!=MessageBox(0,TEXT(errStr),0,\
MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP|MB_SETFOREGROUND))exit(-1);
// i-tes Fenster-hwnd entspricht ghwnd(i)
#define ghwnd(num)
g.hwa[num]
// Menu-Macros (vereinfachen die Schreibarbeit...):
#define MENU_BEGIN(num) static MENU_STRUCT menu_name##num[] = {
#define MENU_POPUP(text)
{TEXT(text),0,0,0},
#define MENU_ITEM(text,
on_funkt)
{TEXT(text),(on_funkt)},
#define MENU_ITEM_KEY(text,
on_funkt,keyasc){TEXT(text),(on_funkt),(keyasc),FCONTROL},
#define MENU_ITEM_VK_F(text,on_funkt,key)
{TEXT(text),(on_funkt),(key),FVIRTKEY},
#define MENU_ITEM_CTRL(text,on_funkt,key)
{TEXT(text),(on_funkt),(key),FVIRTKEY|FCONTROL},
#define MENU_ITEM_ALT(text,on_funkt,key)
{TEXT(text),(on_funkt),(key),FVIRTKEY|FALT},
#define MENU_END(num)
{0,0,0,0}}; g.set_menu(g.hwa[num],menu_name##num);
#define MENU_END_AND_SHOW(num) {0,0,0,0}};
g.set_menu(g.hwa[num],menu_name##num);g.show(ghwnd(num));
/////////////////////////////////////////////////
// Strukturen, Prototypen
/////////////////////////////////////////////////
typedef BOOL (* MENUPROC)(void);
LRESULT CALLBACK default_wnd_callback_proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM
lParam);
BOOL
CALLBACK default_dlg_callback_proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM
lParam);
/////////////////////////////////////////////////
// Nützliche Strukturen:
/////////////////////////////////////////////////
typedef struct _MENU_STRUCT { //für das Menue
LPCTSTR pText;
// Menu-Text
MENUPROC menuProc; // Funkt, bei Menu-Klick ausgeführt
WORD
key;
// für ACCEL-Tabelle
WORD
fVirt;
// für ACCEL-Tabelle
WORD
id;
// ID's werden generiert
} MENU_STRUCT;
// (FVIRTKEY | FALT) or (FVIRTKEY | FALT | FSHIFT).
/////////////////////////////////////////////////
// WIN_CLASS:
/////////////////////////////////////////////////
class WIN_CLASS
{
protected:
HICON m_hIcon;
// Icon der Applikation
HWND
m_hParent; // Parent Fenster
HWND
m_hDlg; // aktuelles Fenster
HACCEL m_hAccel;
// aktuelle Accel-Tabelle
MSG
m_msg;
// aktuelle Nachricht
MENU_STRUCT * m_pms; //für das aktuelle Menue
public:
#define LEN_DLG_STRUCT
2048
typedef struct _DLG_STRUCT {//für das DlgTemplate
DLGPROC dlgProc; // Dialog CALLBACK-Funktion !!!
HWND
hParent; // Handle des Parent-fensters
int
idxBuf; // idx, wo weiter geschrieben wird
WORD buf[LEN_DLG_STRUCT]; // Speicher für das DlgTemplate-Aufbau
} DLG_STRUCT;
DLG_STRUCT m_ds;
// Array für alle (Haupt-) Fenster und Dialoge
// i-tes Fenster-hwnd entspricht dem Makro ghwnd(i)
// ghwnd(i) steht für (i)-tes-(g)lobales-(hwnd)
#define
hwa_max
((int)50)
HWND
hwa[hwa_max]; // hwa steht für (h)andle-(w)indow-(a)rray
WIN_CLASS() // Konstruktor
{
m_hDlg
= 0; // akt: für Modeless-Fensterdaten
m_pms
= 0; // akt: Zeiger auf die static-menü-Tabelle
m_hAccel = 0; // akt: Beschleunigungstasten-Tabelle aus m_pms
memset(hwa,0,sizeof(hwa));
// 43. Icon aus Shell32.dll holen
m_hIcon = ExtractIcon
(GetModuleHandle(0),TEXT("Shell32.dll"),43);
err_if(!m_hIcon,"kein Icon");
}
~WIN_CLASS() // Destruktor
{
/* sollte noch überlegt werden ...
if(m_hIcon) DestroyIcon(m_hIcon);
for(int i = 0; i < hwa_max; i++) {
if(hwa[i]) { // falls Fenster existiert:
MENU_STRUCT * pms = get_menu_tab(hwnd);
HACCEL hAccel = (HACCEL)(void*)pms->menuProc;
if(hAccel)DestroyAcceleratorTable(hAccel);
alle Fenster ghwa[i] zerstören ...
}
}
*/
}
protected:
// setze Zeiger pms in den Window-Daten
MENU_STRUCT * set_menu_tab(HWND hwnd, MENU_STRUCT pms[])
{
if(!pms) return NULL;//HMENU hMenu = GetMenu(hwnd);
m_hAccel = (HACCEL) pms->menuProc;
MENU_STRUCT *pOld = (MENU_STRUCT*)
SetWindowLong(hwnd,GWL_USERDATA,(LONG)pms);
return pOld;
}
public:
// hole Zeiger pms aus den Window-Daten
MENU_STRUCT * get_menu_tab(HWND hwnd)
{
MENU_STRUCT *pms = (MENU_STRUCT*)
GetWindowLong(hwnd,GWL_USERDATA);
if(!pms) m_hAccel = 0;
else
m_hAccel = (HACCEL) pms->menuProc;
return pms;
}
// setze hIcon in Window-Klassen-Daten
HICON set_icon(HWND hwnd)
{
if(!g.m_hIcon) return NULL;
HICON hOld = (HICON)
SetClassLong(hwnd, GCL_HICON,(LONG)g.m_hIcon);
return hOld;
}
// existiert className bereits?
BOOL is_class(TCHAR *className)
{
WNDCLASSEX tem = {0}; tem.cbSize = sizeof(WNDCLASSEX) ;
BOOL ok = GetClassInfoEx(GetModuleHandle(0),className,&tem);
return ok;
}
// gehört hwnd zu einer bestimmten Fnster-Class?
BOOL is_class(HWND hwnd, TCHAR *className)
{
TCHAR buf[512];
int anz = GetClassName(hwnd, buf, 512);
int diff= CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE
| NORM_IGNOREKANATYPE
| NORM_IGNOREWIDTH,buf,-1,className,-1);
//if(GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ...
return (diff == CSTR_EQUAL);
}
// gibt das aktuelle Fenster-Handle zurück:
HWND get_ghwnd()
{
return m_msg.hwnd;
}
// hinterlegt die aktuelle Nachricht:
void set_msg(MSG msg)
{
if(!msg.hwnd) return;
m_hDlg
=
m_msg.hwnd
= msg.hwnd;
m_msg.message= msg.message;
m_msg.wParam = msg.wParam;
m_msg.lParam = msg.lParam;
m_msg.time
= msg.time;
m_msg.pt
= msg.pt;
}
// get_msg() gibt die aktuelle m_msg-Nachricht zurück:
// typedef struct tagMSG {
//
HWND hwnd;UINT message;WPARAM wParam;LPARAM lParam;
//
DWORD time; POINT pt;
// } MSG
MSG get_msg()
{
return m_msg;
}
// get_anz_child() gibt die Anzahl der Childs zurück,
// die zu hwnd gehören: ... wurde noch nicht geprüft ...
int get_anz_child(HWND hwnd)
{
HWND hChild = GetWindow(hwnd,GW_CHILD);
if (!hChild) return 0;
int anz = 1;
for (;hChild;hChild = GetNextWindow(hChild,GW_HWNDNEXT))
{
anz++;
} return anz;
}
// get_hwnd_index() gibt den Index des aktuellen
// Fenster-Handle-Arrays hwa[i], hwa[i] entspricht ghwnd(i),
// zurück
int get_hwnd_index(HWND hwnd)
{
HWND hParent = GetParent(hwnd);
if(hParent)
if(is_class(hParent,TEXT("#32770"))) hwnd = hParent;
err_if(!IsWindow(hwnd),"get_hwnd_index(???)");
if(!IsWindow(hwnd)) return 0;
for(int i = 0; i < hwa_max; i++) {
if(hwnd == hwa[i]) return i;
} return 0;
}
// get_hwnd_next() gibt den Index des nächsten
// Fenster-Handle im Array hwa[i] zurück
int get_hwnd_next(HWND hwnd)
{
int i = get_hwnd_index(hwnd), i_akt = i;
while(++i < hwa_max) if(hwa[i]) return i;
i = -1;
while(++i < i_akt ) if(hwa[i]) return i;
return 0;
}
// für die SetWindowPos()-Funktion brauchbar:
#define SWP_ZONLY
(SWP_NOSIZE|SWP_NOMOVE |SWP_NOACTIVATE)
#define SWP_SIZEONLY (SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE)
#define SWP_MOVEONLY (SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE)
#define SWP_HIDEONLY
(SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_HIDEWINDOW)
#define SWP_SHOWONLY
(SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_SHOWWINDOW)
// zeige ein hwnd-Fenster an:
void show(HWND hwnd)
{
m_pms = get_menu_tab(hwnd);
SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_SHOWONLY);
SetActiveWindow(hwnd);
}
// hwnd-Fenster verbergen:
void hide(HWND hwnd)
{
if(IsIconic(hwnd)) return;
SetWindowPos(hwnd,0,0,0,0,0,SWP_HIDEONLY);
if(hwa[0])SetActiveWindow(hwa[0]);
}
// set_text() schreibt Text in ein Fenster (Titelzeile)
void set_text(HWND hwnd, TCHAR * sz)
{
SetWindowText(hwnd, sz);
}
//////////////////////////////////////////////////////
// "Nachgeschaltete CALLBACK"-Funktion (Subclassing)
//////////////////////////////////////////////////////
BOOL interne_dlg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_CLOSE: {
if(is_class(hwnd,TEXT("#32770"))) return FALSE;
TCHAR buf[256]; // Hauptfenster [0] beenden?
GetWindowText(hwnd,buf,256);
int ret = MessageBox(hwnd,TEXT("Exit?"),TEXT("Exit?"),
MB_ICONQUESTION|MB_YESNO);
if (IDNO == ret) {show(hwnd);return TRUE;} // nein!
DestroyWindow(hwnd); //SendMessage(hwnd,WM_DESTROY,0,0);
return TRUE;
break; }
case WM_DESTROY: {
PostQuitMessage(0);
break; }
case WM_COMMAND:{
if(HIWORD(wParam)==CBN_SETFOCUS)
return TRUE; //lParam hCombo
if(HIWORD(wParam) > 1) break;
if(is_class(hwnd,TEXT("#32770"))
&& (LOWORD(wParam)
== IDCANCEL))
{ // IDCANCEL kommt bei Dlg von WM_CLOSE
if((HIWORD(wParam) == BN_CLICKED) || lParam) {
hide(hwnd); return TRUE;
}
}
WORD id = LOWORD(wParam);//id=MENU-Item-Identifizierer
m_pms = get_menu_tab(hwnd); if(!m_pms) break;
//if((HIWORD(wParam)==1) && !lParam) { //..von Accel-Tab
// if(!m_hAccel) break;
//}
int k = 0; // suche id in Menu-Tabelle
while( m_pms[++k].pText) { // Menu-Text
if( m_pms[k].id != id ) continue;
err_if((ctlFirst<=id)&&(id<=ctlLast),"(ctlFirst<=id)&&(id<=ctlLast)");
if(!m_pms[k].menuProc) break;
// Funktion ausführen
BOOL ok = m_pms[k].menuProc();
} //InvalidateRect(hwnd,NULL,TRUE);UpdateWindow(hwnd);
break;} // ende WM_COMMAND
/* viel getestet, wird wohl alles nicht gebraucht ...
case WM_SETFOCUS: {
//m_pms = get_menu_tab(hwnd);
//SetFocus(hwnd);
break; }
case WM_KILLFOCUS: {
//????m_pms = get_menu_tab(hwnd);
break; }
case WM_ACTIVATE: {
//if(HIWORD(wParam)) break; // ist Minimized
if (WA_INACTIVE==LOWORD(wParam)) { // becoming inactive
m_pms = 0;
} else { // becoming active
m_pms = get_menu_tab(hwnd);
}
break; } // ende WM_ACTIVATE
*/
default: { break;}
} // ende switch
return FALSE;
}
// set_menu():
// aus der vorhandenen "user-menu-struktur" wird ein
// Menu und die Accel-Tabelle zusammengebaut und gesetzt
BOOL set_menu(HWND hwnd, MENU_STRUCT menu_struc[])
{
//!!! menu_struc muss static sein !!!
err_if(!hwnd,"set_menu: MENU braucht hwnd");
if(!hwnd)return FALSE;
MENU_STRUCT *pOldMenu = set_menu_tab(hwnd,menu_struc);
// ermittle die Anzahl lenMenu von Menu-Items:
int lenMenu = -1;
while(menu_struc[++lenMenu].pText);
// Menu und Accel-Tab aus einer menu_struc erstellen:
HMENU hMenu1 = 0, hMenu = CreateMenu();
ACCEL
ac[200] = {0}; int kk = 0, lenAccel = 0;
WORD id = 10000; // idStart
for (int k = 0; k < lenMenu; k++)
{
// falls Funktion menu_struc[k].menuProc vorhanden ...
if((k>0)&&(menu_struc[k].menuProc)) {
id++; // diesen id-Identifizierer dem Menu-Item zuordnen
// gleichzeitig die Accelarator-Tabelle aufbauen:
WORD key = menu_struc[k].key; //menu_struc[k].key
if(key) // falls ein Accel-Key:
{
err_if(lenAccel>=200,"set_menu: lenAccel>=200");
WORD fVirt = menu_struc[k].fVirt;
ac[lenAccel].fVirt = ((WORD)fVirt & ~0xff80);//menu_struc[k].fVirt
ac[lenAccel].key
= key;
//menu_struc[k].key
ac[lenAccel].cmd
= id;
//id ab 10001 ...
lenAccel++;
}
// Menu fertig zusammen bauen:
menu_struc[k].id = id;
AppendMenu(hMenu1,MF_STRING,id,menu_struc[k].pText);
} else {
if(k>0) AppendMenu(hMenu,MF_POPUP,(UINT)hMenu1,menu_struc[kk].pText);
if(hMenu1)DestroyMenu(hMenu1);
kk = k; hMenu1 = CreateMenu();
}
}
AppendMenu(hMenu,MF_POPUP,(UINT)hMenu1,menu_struc[kk].pText);
if(hMenu1) DestroyMenu(hMenu1); if(!hMenu) return FALSE;
HMENU hMenuOld = GetMenu(hwnd);
if ( hMenuOld ) {SetMenu(hwnd, NULL); DestroyMenu(hMenuOld);}
BOOL ok = SetMenu(hwnd,hMenu); DestroyMenu(hMenu);
if(lenAccel > 0) {
ac[lenAccel-1].fVirt |= 0x80;//MS-Endekennung
m_hAccel = CreateAcceleratorTable(&ac[0],lenAccel);
err_if(!m_hAccel,"!m_hAccel");
menu_struc[0].menuProc = (MENUPROC)(void *)m_hAccel;
}
m_pms = get_menu_tab(hwnd); err_if(!m_pms,"set_menu():m_pms");
return ok;
}
// Haupt-Nachrichtenschleife:
void main_loop() { // hinterlege Nachricht in m_msg
while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{
err_if(-1==bRet,"-1==GetMessage()");
//err_if(!m_msg.hwnd,"!m_msg.hwnd");
m_hDlg = (GetWindowLong(m_msg.hwnd,GWL_STYLE) & WS_CHILD)
?GetParent(m_msg.hwnd):m_msg.hwnd;//GetWindow(hwnd,GW_OWNER);
if(!IsWindow(
m_hDlg)
|| !TranslateAccelerator(m_hDlg, m_hAccel, &m_msg))
{
if (!IsWindow(
m_hDlg)
||
{
!IsDialogMessage(m_hDlg, &m_msg))
TranslateMessage(&m_msg);
DispatchMessage (&m_msg);
}
}
}
}
/////////////////////////////////////////////////
int nCopyAnsiToWideChar (LPWORD lpWCStr, TCHAR *lpAnsiIn)
{
#ifdef UNICODE
lstrcpy(lpWCStr, lpAnsiIn);
return (int) (1+lstrlen(lpAnsiIn));
#else
return MultiByteToWideChar(CP_ACP,0,lpAnsiIn,-1,lpWCStr,128);
#endif
}
BOOL dlg_begin(HWND hParent)
{
memset(&m_ds,0,sizeof(DLG_STRUCT));
m_ds.hParent = hParent; return TRUE;
}
HWND dlg_end(DLGPROC dlgProc)
{
if(!dlgProc) {
m_ds.dlgProc = default_dlg_callback_proc;
} else {
m_ds.dlgProc = dlgProc;
}
HWND hwnd = CreateDialogIndirect(GetModuleHandle(0),
(LPDLGTEMPLATE)m_ds.buf,m_ds.hParent,(DLGPROC)m_ds.dlgProc);
err_if(!hwnd,"dlg_end(): kein hwnd");
return hwnd;
}
void dlg_rahmen(WORD x, WORD y, WORD cx, WORD cy, TCHAR *szTitelStr)
{
PWORD p = m_ds.buf; //memset(p,0,sizeof(DLG_STRUCT));
TCHAR * font= TEXT("Times New Roman"); WORD FontSize = 9;
DWORD lStyle = WS_POPUP | WS_CAPTION | WS_SYSMENU| WS_CLIPSIBLINGS
| DS_SETFONT | DS_MODALFRAME;
DWORD lExStyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_MDICHILD
//| WS_EX_NOPARENTNOTIFY
;
*p++ = 1;
// DlgVer
*p++ = 0xFFFF; // Signature
*p++ = 0;
// LOWORD HelpID
*p++ = 0;
// HIWORD HelpID
*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);
//??? p += 1 + 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,TEXT("Courier New"));
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
void dlg_edit(WORD x, WORD y, WORD cx, WORD cy, TCHAR * szInitStr, WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle
= WS_VISIBLE|WS_CHILD|WS_TABSTOP|SS_LEFT|ES_AUTOHSCROLL;
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("EDIT"));
if(szInitStr)p +=nCopyAnsiToWideChar(p,szInitStr);
else
p +=nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
void dlg_editM(WORD x, WORD y, WORD cx, WORD cy, TCHAR * szInitStr, WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.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; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("EDIT"));
if(szInitStr)p += nCopyAnsiToWideChar(p,szInitStr);
else
p += nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
void dlg_list(WORD x, WORD y, WORD cx, WORD cy, WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle = WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_VSCROLL|WS_BORDER
|LBS_HASSTRINGS|LBS_NOTIFY;
//LBS_WANTKEYBOARDINPUT
//LBS_MULTIPLESEL or the LBS_EXTENDEDSEL
DWORD lExStyle = WS_EX_CLIENTEDGE;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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, TEXT("ListBox"));
p += nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
void dlg_button(WORD x,WORD y,WORD cx, WORD cy, TCHAR * szStr,WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle = WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP;
DWORD lExStyle = 0;//WS_EX_CLIENTEDGE;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("BUTTON"));
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,TEXT("?"));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
/////////////////////////////////////////////////
void dlg_static(WORD x, WORD y, WORD cx, WORD cy, TCHAR * szStr)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle = WS_CHILD | WS_VISIBLE | SS_LEFT;
DWORD lExStyle = 0;//WS_EX_CLIENTEDGE;
WORD idRes = 0xffff;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("STATIC"));
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
/////////////////////////////////////////////////
void dlg_black(WORD x, WORD y, WORD cx, WORD cy)
{// schwarzes Rechteck
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle = WS_CHILD | WS_VISIBLE |SS_BLACKRECT| SS_LEFT;
//| SS_CENTER;
DWORD lExStyle = WS_EX_CLIENTEDGE;
WORD idRes = 0xffff;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("STATIC"));
p += nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
/////////////////////////////////////////////////
/////////////////////////////////////////////////
int dlg_but_check(WORD x, WORD y, WORD cx, WORD cy, TCHAR * szStr, WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.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; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("BUTTON"));
if(szStr)p += nCopyAnsiToWideChar(p,szStr);
else
p += nCopyAnsiToWideChar(p,TEXT("?"));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
return TRUE;
}
/////////////////////////////////////////////////
void dlg_combo(WORD x, WORD y, WORD cx, WORD cy, WORD idRes)
{
PWORD p = &m_ds.buf[m_ds.idxBuf]; m_ds.buf[8]++;
DWORD lStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |WS_VSCROLL
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS
| CBS_HASSTRINGS | CBS_AUTOHSCROLL
| CBS_DROPDOWNLIST| CBS_DROPDOWN;
DWORD lExStyle = WS_EX_CLIENTEDGE;
//??? |WS_EX_NOPARENTNOTIFY|WS_EX_CONTROLPARENT|WS_EX_TOPMOST;
*p++ = 0; // LOWORD (lHelpID)
*p++ = 0; // 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,TEXT("COMBOBOX"));
p += nCopyAnsiToWideChar(p,TEXT(""));
*p++ = 0; // Advance pointer over nExtraStuff WORD.
ULONG ul=(ULONG)p;ul+=3;ul>>=2;ul<<=2;p=(LPWORD)ul; //Align
m_ds.idxBuf = p - m_ds.buf;
err_if(LEN_DLG_STRUCT - m_ds.idxBuf < 256,"LEN_DLG_STRUCT zu klein");
}
// innere Position der Dialog-Breite bei nr:
int get_x(WORD nr, WORD nr_max)
{ err_if(!nr_max,"Anzahl nx der horizontalen Teile?");
if (nr > nr_max) nr = nr_max;
WORD d = 3, dlg_width = m_ds.buf[11];
WORD xPos = (dlg_width-d)*nr/nr_max + d;
return xPos;
}
// innere Position der Dialog-Höhe bei nr:
int get_y(WORD nr, WORD nr_max)
{ err_if(!nr_max,"Anzahl ny der vertikalen Teile?");
if (nr > nr_max) nr = nr_max;
WORD d = 3, dlg_high = m_ds.buf[12];
WORD yPos = (dlg_high-d)*nr/nr_max + d;
return yPos;
}
// innere Dialog-Breite von nr bis nr_end:
int get_cx(WORD nr, WORD nr_end, WORD nr_max)
{ err_if(!nr_max,"Anzahl nx der horizontalen Teile?");
if (nr
> nr_max) nr
= nr_max;
if (nr_end > nr_max) nr_end = nr_max;
if (nr_end <= nr ) nr_end = nr + 1;
WORD d = 3, dlg_width = m_ds.buf[11];
WORD cx = (dlg_width-d)*(nr_end-nr)/nr_max-d;
return cx;
}
// innere Dialog-Höhe von nr bis nr_end:
int get_cy(WORD nr, WORD nr_end, WORD nr_max)
{ err_if(!nr_max,"Anzahl ny der vertikalen Teile?");
if (nr
> nr_max) nr
= nr_max;
if (nr_end > nr_max) nr_end = nr_max;
if (nr_end <= nr ) nr_end = nr + 1;
WORD d = 3, dlg_high = m_ds.buf[12];
WORD cy = (dlg_high)*(nr_end-nr)/nr_max-d;
return cy;
}
void dlg_button(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, TCHAR * szStr,WORD idRes)
{ dlg_button(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny), szStr,idRes);
}
void dlg_edit(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, TCHAR * szInitStr, WORD idRes)
{ dlg_edit(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny), szInitStr,idRes);
}
void dlg_editM(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, TCHAR * szInitStr, WORD idRes)
{ dlg_editM(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny), szInitStr,idRes);
}
void dlg_list(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, WORD idRes)
{ dlg_list(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny),idRes);
}
void dlg_static(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, TCHAR * szStr) {
dlg_static(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny),szStr);
}
void dlg_black(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx) {
dlg_black(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),get_cy(iy,jy,ny));
}
void dlg_combo(WORD iy,WORD jy,WORD ny,
WORD ix,WORD jx,WORD nx, WORD idRes)
{
WORD cy = 8*get_cy(iy,iy+1,ny); // droped-bereich!!!
dlg_combo(get_x(ix,nx),get_y(iy,ny),
get_cx(ix,jx,nx),cy,idRes);
}
BOOL show_next_dlg()
{ HWND
hwnd = get_ghwnd(); // hole das globale-aktuelle hwnd
int idx_next = get_hwnd_next(hwnd); // hole nächstes globales hwnd
g.show(ghwnd(idx_next)); // mache dieses Fenster sichtbar
return TRUE;
}
} g = WIN_CLASS(); // ende class WIN_CLASS
/////////////////////////////////////////////////
// default-CALLBACK-Funktionen:
/////////////////////////////////////////////////
LRESULT CALLBACK default_wnd_callback_proc
(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if(g.interne_dlg_proc(hwnd,uMsg,wParam,lParam)) return 0;
return CallWindowProc(DefWindowProc,hwnd,uMsg,wParam,lParam);
}
BOOL CALLBACK default_dlg_callback_proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM
lParam)
{
return g.interne_dlg_proc(hwnd,uMsg,wParam,lParam);
}
// gehe zum nächsten Fenster g.hwnd[]
BOOL show_next_dlg()
{ HWND
hwnd = g.get_ghwnd(); // hole das globale-aktuelle hwnd
int idx_next = g.get_hwnd_next(hwnd); // hole nächstes globales hwnd
g.show(ghwnd(idx_next)); // mache dieses Fenster sichtbar
return TRUE;
}
// lediglich zum Testen
BOOL on_help()
{ HWND hwnd = g.get_ghwnd();
TCHAR * pInfo = TEXT("Dies ist Programm von\n\n\t VORNAME NACHMANE\n\nWeiterte
Infos sind ...");
TCHAR * pTitle = TEXT("Info zur 3.Übung");
MessageBox(hwnd, pInfo, pTitle, MB_OK);
return TRUE;
}
////////////////////////////////////////////////////////////////
#endif
auf_06.exe(grobe Vorstufe) einige cpp-"brocken"
6. SP2-Praktikum (SS 2005)
Teil A
Der Teil A ist Pflichtteil für Sehfähige und optional für Sehbehinderte. Diese Aufgabe besteht darin, mit MDI-Applikationen zu arbeiten. Es ist eine MDI-Applikation zu erstellen, die
es ermöglicht, Quelltexte (hilfreich) zusammem zu erstellen ("hablautomatische Quellcode-Generierung"). Z.B. sollen (zahlreiche!) HTML-Konstrukte (oder Konstrukte einer anderen
Sprache, XML-, ...,usw. ) an der Cursor-Stelle (z.B. mit Hilfe eines Kontext-Menus) einfügbar sein. Die zugehörigen Dialog-CALLBACK-Funktionen sind zu schreiben. Im Einzelnen:
Was ist MDI?
Ein "Single Document Interface" (SDI, z.B. Notepad) kann zu einer Zeit ein Dokument händeln. Ein "Multiple Document Interface" (MDI, z.B. Word, Dev.Studio, usw.) kann
gleichzeitig mehrere Dokumente bedienen. Auch gibt es MTI-Anwendungen ( Multiple Top-Level Interface).
MDI ist eine Windows-Applications, die zum "standard user interface" wurde. Bei MDI können auf der (Client Area)-Bildschirmfläche innerhalb des Haupt-Fensters (Frame Fenster,
Rahmen-Fenster) mehrere Child-Fenster sein. Alle Child-Fenster werden an der Client Area geklippt. Child-Fenster werden auf der Client Area minimiert. Child-Fenster können mit
Strg+F4 geschlossen werden. Zwischen den Child-Fenstern kann mit Strg+Tab navigiert werden. Für diese (Sytem-)Tasten-Nachrichten wird die Hauptnachrichtenschleife um
TranslateMDISysAccel() erweitert. Eine MDI-Applikation hat 3 Fensterarten:
-
Die Schritte um ein Frame-Fenster zu erzeugen sind:
WNDCLASSEX-Struktur füllen, Frame-Fenster-Klasse registrieren (RegisterClassEx)
Frame-Fenster erzeugen mit CreateWindowEx
Haupt-Message-Loop um TranslateMDISysAccel erweitern
Haupt-CALLBACK-Funktion gibt Nachrichten DefFrameProc weiter (nicht DefWindowProc).
Fenster können horizontal/vertikal die Client-Fläche des Frame-Window unterteilen.
Eine MDI-Apllikation besteht aus einem Haupt-Fensters (Rahmen-Fenster bildet die Client Area), einem unsichtbaren Client Fenster (Klassen-Name "MDICLIENT") MDI-CildFenstern, die sich auf der Client Area befinden und durch die "MDICLIENT"-Klasse mit eingebauter CALLBACK-Funktion, kontrolliert werden. Typisches Aussehen:
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
MENU-Identifizierer:
IDM_APP_EXIT ...
IDM_EDIT_NEW_TEXT ...
IDM_EDIT_CLOSE_TEXT ...
IDM_WINDOW_CASCADE ...
IDM_WINDOW_TILE_VERTIKAL ...
IDM_WINDOW_TILE_HORIZONTAL ...
IDM_WINDOW_ARRANGE ...
IDM_WINDOW_SHOWMINIMIZE ...
IDM_WINDOW_SHOWDEFAULT ...
IDM_WINDOW_SHOWMAXIMIZE ...
IDM_WINDOW_CLOSEALL ...
winuser.h-MDI-Nachrichten
Aussehen etwa:
winuser.h:
#define WM_MDICREATE 0x0220
#define WM_MDIDESTROY 0x0221
#define WM_MDIACTIVATE 0x0222
#define WM_MDIRESTORE 0x0223
#define WM_MDINEXT 0x0224
#define WM_MDIMAXIMIZE 0x0225
#define WM_MDITILE 0x0226
#define WM_MDICASCADE 0x0227
#define WM_MDIICONARRANGE 0x0228
#define WM_MDIGETACTIVE 0x0229
#define WM_MDISETMENU 0x0230
#define WM_ENTERSIZEMOVE 0x0231
#define WM_EXITSIZEMOVE 0x0232
#define WM_DROPFILES 0x0233
#define WM_MDIREFRESHMENU 0x0234
MDI-Struktur (Übersicht):
Sichtbares Frame Fenster
(MDI-Haupt-Fensters,
Rahmen-Fenster, Client Area, "Workspace")
Haupt-CALLBAC ruft am Ende
immer DefFrameProc() auf
|
Unsichtbares Client Fenster (Klassen-Name "MDICLIENT")
kontrolliert die MDI-Cild-Fenstern der Client Area,
hClient wird für DefFrameProc() benötigt
|
|
|
|
|
|
MDI Child 1
MDI Child 2
MDI Child 3
WS_CHILD
WS_VISIBLE
WS_CLIPCHILDREN
WS_CHILD
WS_VISIBLE
WS_CLIPCHILDREN
WS_CHILD
WS_VISIBLE
WS_CLIPCHILDREN
// Anlegen eines Child-Fensters
// Methode a:
MDICREATESTRUCT mc;
mc.szClass = myChildClass;
mc.szTitle = TEXT("Hello");
mc.hOwner = hInst;
mc.x = CW_USEDEFAULT;
mc.y = CW_USEDEFAULT;
mc.cx = CW_USEDEFAULT;
mc.cy = CW_USEDEFAULT;
mc.style = 0;
mc.lParam = 0;
HWND hChild =
(HWND)::SendMessage(m_hClient,WM_MDICREATE,0,
(LPARAM)(LPMDICREATESTRUCT) &mc);
MDI Child 4
WS_CHILD
WS_CHILD
WS_VISIBLE
WS_VISIBLE
WS_CLIPCHILDREN WS_CLIPCHILDREN
// Anlegen eines Child-Fensters
// nach der neueren Methode b:
HWND hChild = ::CreateMDIWindow(
myChildClass,TEXT("Hello"),
WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
m_hClient,hInst,NULL);
//::BringWindowToTop(hChild);
-------------------------------------------------hwnd das Handle innerhalb einer
Child-CALLBACK-Funktion. Es gilt:
static HWND m_hClient = ::GetParent(hwnd);
static HWND m_hFrame = ::GetParent(m_hClient);
Child-CALLBACK-Funktion reicht weiter:
return DefMDIChildProc(hwnd,m_hClient,uMsg,wParam,lParam);
Menu erstellen
Erstellen Sie mit dem Ressourcen-Workshop ein Menu, das die folgenden Identifizierer verwendet:
IDM_APP_EXIT
IDM_EDIT_NEW_TEXT
IDM_EDIT_CLOSE_TEXT
IDM_WINDOW_CASCADE
IDM_WINDOW_TILE_VERTIKAL
IDM_WINDOW_TILE_HORIZONTAL
IDM_WINDOW_ARRANGE
IDM_WINDOW_SHOWMINIMIZE
IDM_WINDOW_SHOWDEFAULT
IDM_WINDOW_SHOWMAXIMIZE
IDM_WINDOW_CLOSEALL
IDM_ENUM_WINDOW_DATEN
MDI Child n
Der Menu-Aufbau kann etwa wie folgt sein:
// soll später auf m_hMenu[0] geladen werden
"&Datei":
"Neues &Text-Fenster",
IDM_EDIT_NEW_TEXT)
"Programm &beenden",
IDM_APP_EXIT)
"Fenster &Daten",
IDM_ENUM_WINDOW_DATEN)
// soll später auf m_hMenu[1] geladen werden
"&Datei":
"Neues &Text-Fenster",
IDM_EDIT_NEW_TEXT
"Fenster &schließen",
IDM_EDIT_CLOSE_TEXT
"Fenster &Daten",
IDM_ENUM_WINDOW_DATEN
"Programm &beenden",
IDM_APP_EXIT
"&Fenster":
"Überla&ppend",
"&Vertikal",
"&Horizontal",
"&Minimieren",
"&Nomale Größe",
"Ma&ximieren",
"&Symbole Anordnen",
"&Alle Fenster schließen",
IDM_WINDOW_CASCADE
IDM_WINDOW_TILE_VERTIKAL
IDM_WINDOW_TILE_HORIZONTAL
IDM_WINDOW_SHOWMINIMIZE
IDM_WINDOW_SHOWDEFAULT
IDM_WINDOW_SHOWMAXIMIZE
IDM_WINDOW_ARRANGE
IDM_WINDOW_CLOSEALL
Ein Menu's wird geladen mit
m_hMenu[0] = LoadMenu(m_hInst, MAKEINTRESOURCE(IDR_MENU0));
//zunächst weglassen:
m_hAccel = LoadAccelerators(m_hInst,MAKEINTRESOURCE(IDR_ACCEL));
Welche Klassen RegisterClassEx() werden verwendet?
Es ist günstig, für das Frame-fenster den globalen Beichner m_hwnd[0] zu verwenden.
Als globale Bezeichner bieten sich an:
//globale Konstanten:
#define myAppName
#define myFrameClass
#define myEditClass
#define myShellDll
#define myClientClass
TEXT("my_mdi_demo")
TEXT("my_mdi_frame")
TEXT("my_mdi_edit_class")
TEXT("Shell32.dll")
TEXT("MY_MDI_CLIENT")
//globale Konstanten:
#define FIRST_CHILD_IDX
50000 // wird später klar ...
#define
MAX_ANZ_HWND
((int)30)
HWND
m_hwnd[ MAX_ANZ_HWND]; // [0] ist das hauptfenster bzw. MDI-Frame
HMENU
m_hMenu[MAX_ANZ_HWND]; // [] für menu's
HACCEL
m_hAccel;
// aktuelle Accel-Tabelle
HWND
m_hClient;
// mdi-Client-fenster
HWND
m_hDlg;
// aktueller Dialog
MSG
m_msg;
// aktuelle Nachricht
HINSTANCE m_hInst;
// = GetModuleHandle(0);
void create_mdi_classen()
{
ATOM atom; WNDCLASSEX wc;
// aus TEXT("MDICLIENT") mach myClientClass
wc.cbSize = sizeof(WNDCLASSEX) ;
BOOL ok = GetClassInfoEx(m_hInst,TEXT("MDICLIENT"),&wc);
wc.hInstance
= m_hInst;
wc.hbrBackground =(HBRUSH) GetStockObject(BLACK_BRUSH);
wc.lpszClassName = myClientClass;
atom = RegisterClassEx(&wc);
// Fensterklasse für das Rahmenfenster anlegen:
memset(&wc,0,sizeof(wc));
wc.cbSize
= sizeof(wc);
wc.style
= CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc
= mdi_default_frame_proc;
wc.cbClsExtra
= sizeof(HANDLE);
wc.cbWndExtra
= sizeof(HANDLE);
wc.hInstance
= m_hInst;
wc.hIcon
= ExtractIcon(m_hInst,myShellDll,43);
wc.hCursor
= LoadCursor(0,IDC_ARROW);
wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = myFrameClass;
atom = RegisterClassEx(&wc);
// Fensterklasse für das Edit-Window
memset(&wc,0,sizeof(wc));
wc.cbSize
= sizeof(wc);
wc.style
= CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc
= mdi_default_child_proc;
wc.lpszClassName = myEditClass;
wc.cbClsExtra
= 4;
wc.cbWndExtra
= 4;
wc.hInstance
= m_hInst;
wc.hCursor
= LoadCursor(0,IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hIcon
= ExtractIcon(m_hInst,myShellDll,114);
//wc.lpszMenuName = NULL;
atom = RegisterClassEx(&wc);
}
Wie wird ein MDI-FrameWindow m_hwnd[0] erzeugt?
int WINAPI WinMain(HINSTANCE,HINSTANCE hInst,PSTR,int)
{
m_hInst = hInst;
create_mdi_classen();
// FrameWindow als Rahmenfenster [0] anlegen
int xPos=0; int yPos=0; int dx=0; int dy=0;
if((xPos<0)||(yPos<0)||(dx<=0)||(dy<=0)) {
xPos = yPos = 0;
if(dx<1) dx = GetSystemMetrics(SM_CXSCREEN);
if(dy<1) dy = GetSystemMetrics(SM_CYSCREEN);
} else {
xPos = yPos = dx = dy = CW_USEDEFAULT;
}
// Rahmenfenster anlegen
m_hwnd[0] = CreateWindowEx(WS_EX_DLGMODALFRAME,
myFrameClass, myAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
xPos,yPos,dx,dy,NULL,m_hMenu[0],m_hInst,0);
// m_hClient wurde unter WM_CREATE angelegt
m_hClient = GetWindow(m_hwnd[0], GW_CHILD);
ShowWindow(m_hwnd[0], SW_SHOW);
UpdateWindow(m_hwnd[0]);
// hier werden später weitere m_hwnd[1],[2],[3]
// Edit-Fenster als MDI-Child's erzeugt, die
// beim Start gleich angezeigt werden sollen.
main_loop();
// hier Aufräumen: ...
return m_msg.wParam;
}
Damit TranslateMDISysAccel(m_hClient, &m_msg)) die die Nachricht an die Client-Klasse schicken kann, muss die Nachrichten-Schleife erweitert werden.
// Haupt-Nachrichtenschleife:
void main_loop() { // hinterlege Nachricht in m_msg
while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{
err_if(-1==bRet,"-1==GetMessage()");
//err_if(!m_msg.hwnd,"!m_msg.hwnd");
m_hDlg = (GetWindowLong(m_msg.hwnd,GWL_STYLE) & WS_CHILD)
?GetParent(m_msg.hwnd):m_msg.hwnd;//GetWindow(hwnd,GW_OWNER);
if(!IsWindow(
m_hDlg)
|| !TranslateAccelerator(m_hDlg, m_hAccel, &m_msg))
{
if(!IsWindow(
m_hClient)
|| !TranslateMDISysAccel(m_hClient, &m_msg))
{
if (!IsWindow(
m_hDlg)
|| !IsDialogMessage(m_hDlg, &m_msg))
{
TranslateMessage(&m_msg);
DispatchMessage (&m_msg);
}
}
}
}
}
Wie können Edit-Fenster als MDI-Child's angelegt werden?
Existiert create_mdi_edit_window(), so können etwa gemäß m_hwnd[1] = create_mdi_edit_window(TEXT("[1]")); Edit-Fenster als MDI-Child erzeugt werden.
HWND create_mdi_edit_window(TCHAR *pTitel)
{
int xPos=0;int yPos=0; int dx=0;int dy=0;
// FrameWindow als Childfenster [1] anlegen
if((xPos<0)||(yPos<0)||(dx<=0)||(dy<=0)) {
xPos = yPos = dx = dy = CW_USEDEFAULT;
}
HWND hChild = ::CreateMDIWindow(
myEditClass, // class
pTitel, // window caption
WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,
xPos,yPos,dx,dy, m_hClient,m_hInst,NULL);
//::BringWindowToTop(hChild);
// zusätzlich ein "EDIT" ins Child-Fenster
WNDCLASSEX wc; memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
GetClassInfoEx(GetModuleHandle(0),TEXT("EDIT"),&wc);
RECT rc; GetClientRect(hChild, &rc ) ;
//WS_EX_CLIENTEDGE
HWND hEdit = CreateWindowEx(0,TEXT("EDIT"),0,
WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL
|ES_WANTRETURN|ES_MULTILINE
|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
rc.left,rc.top,rc.right,rc.bottom,
hChild,(HMENU)hChild,m_hInst,0);
err_if(!hEdit,"kein hEdit");
SendMessage(hEdit,WM_SETFONT,
(WPARAM)GetStockObject(ANSI_FIXED_FONT),TRUE);
SetFocus(hEdit); return hChild;
}
Wie sieht die Frame-CALLBACK-Funktion aus?
Es ist günstig, die gemeinsame Hauptarbeit von mdi_default_frame_proc() durchführen zu lassen. Die eigene myFrameProc() ruft am Ende die mdi_default_frame_proc() auf etwa
gemäß:
LRESULT CALLBACK myFrameProc
(HWND hwnd, UINT uMsg,
{
switch(uMsg)
WPARAM wParam, LPARAM lParam)
{
case WM_CREATE: {
return 0;}
case WM_COMMAND:{
/*
switch(LOWORD(wParam))
{
// case IDM_...: { ... break; }
// case IDM_...: { ... break; }
default:{
break; }
} // switch(LOWORD(wParam))
*/
break; } // ende von WM_COMMAND
} // ende von switch(uMsg)
return mdi_default_frame_proc(..);
}
Die mdi_default_frame_proc() behandelt beinahe alle MDI-Nachrichten. Bei Comiler-fehlern kann unwichtiges zunächst auskommentiert werden:
LRESULT CALLBACK mdi_default_frame_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
switch(uMsg)
{
case WM_CREATE: {
// Client-Fenster erzeugen
CLIENTCREATESTRUCT clientcreate;
clientcreate.hWindowMenu = GetSubMenu(m_hMenu[0],0);
clientcreate.idFirstChild = FIRST_CHILD_IDX;
m_hClient = CreateWindowEx(0,myClientClass,NULL,
MDIS_ALLCHILDSTYLES|WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
0,0,0,0,hwnd,(HMENU)1,m_hInst,
(PSTR) &clientcreate);
return 0; }
case WM_COMMAND: {
switch(LOWORD(wParam))
{
case IDM_EDIT_NEW_TEXT: {
// erstes/nächstes HELLO-Fenster
create_mdi_edit_window(TEXT("Edit für temporäre Nutzung"));
return 0; }
case IDM_ENUM_WINDOW_DATEN: {
EnumChildWindows(NULL,EnumCallBack,0);
EnumChildWindows(NULL,EnumCallBack,(LPARAM)hwnd);
//EnumChildWindows(m_hClient,EnumCallBack,0);
//EnumChildWindows(m_hClient,EnumCallBack,(LPARAM)hwnd);
return 0; }
case IDM_EDIT_CLOSE_TEXT: {// aktives Dokumentenfenster schließen
HWND hChild =(HWND)
SendMessage(m_hClient,WM_MDIGETACTIVE,0,0);
if(SendMessage(hChild, WM_QUERYENDSESSION,0,0))
SendMessage(m_hClient, WM_MDIDESTROY,(WPARAM) hChild, 0);
return 0; }
case IDM_WINDOW_SHOWDEFAULT: {
HWND hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0);
ShowWindow(hChild,SW_SHOWDEFAULT);
return 0; }
case IDM_WINDOW_SHOWMINIMIZE: {
HWND hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0);
ShowWindow(hChild,SW_SHOWMINIMIZED);
return 0; }
case IDM_WINDOW_SHOWMAXIMIZE: {
HWND hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0);
if(IsWindow(hChild))
SendMessage(m_hClient,(UINT)WM_MDIMAXIMIZE,(WPARAM)hChild,0);
return 0; }
case IDM_APP_EXIT: {
// Programm beenden
SendMessage(hwnd, WM_CLOSE,0,0);
return 0;}
// Nachrichten zum Anordnen der Dokumentenfenster
case IDM_WINDOW_TILE_VERTIKAL: {
//
SendMessage(m_hClient, WM_MDITILE,0,0);
//
oder:
WORD nWindows =
TileWindows(m_hClient,MDITILE_VERTICAL,0,0,0);
return 0;}
case IDM_WINDOW_TILE_HORIZONTAL: {
WORD nWindows =
TileWindows(m_hClient,MDITILE_HORIZONTAL,0,0,0);
return 0;}
case IDM_WINDOW_CASCADE: {
SendMessage(m_hClient,WM_MDICASCADE,0,0);
return 0;}
case IDM_WINDOW_ARRANGE:{
// SendMessage(m_hClient, WM_MDIICONARRANGE,0,0);
// oder:
UINT height = ArrangeIconicWindows(m_hClient);
return 0;}
case IDM_WINDOW_CLOSEALL:{
// Schließen aller Dokumentenfenster
EnumChildWindows(m_hClient, EnumCloseProc, 0);
return 0;}
default: {
// Weitergabe ans aktive Dokumentenfenster
HWND hChild =(HWND) SendMessage(m_hClient, WM_MDIGETACTIVE,0,0);
if(IsWindow(hChild))
SendMessage(hChild, WM_COMMAND, wParam, lParam);
break; }
// ...und danach an DefFrameProc
}
break; } // ende WM_COMMAND
case WM_QUERYENDSESSION:
case WM_CLOSE:{
// alle Dokumentenfenster schließen
SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
if(NULL != GetWindow(m_hClient, GW_CHILD)) return 0;
break; } // i.e., call DefFrameProc
case WM_DESTROY: PostQuitMessage(0); return 0;
}
// Weitergabe an DefFrameProc(ersetzt DefWindowProc)
return DefFrameProc(hwnd, m_hClient, uMsg, wParam, lParam);
}
Wie sieht die Child-CALLBACK-Funktion aus?
Es ist günstig, die gemeinsame Aarbeit von mdi_default_child_proc() durchführen zu lassen. Die eigene myFrameProc() ruft am Ende die mdi_default_child_proc() auf etwa gemäß:
LRESULT CALLBACK myChildProc
(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE: {
// HWND hwnd_Client = GetParent(hwnd); // m_hClient
// HWND hwnd_Frame = GetParent(hwnd_Client); //[0]
return 0;}
case WM_PAINT: { // Fenster neu zeichnen
break; }
case WM_COMMAND:{
/*
switch(LOWORD(wParam))
{
// case IDM_...: { ... break; }
// case IDM_...: { ... break; }
default:{
break; }
} // switch(LOWORD(wParam))
*/
break; } // ende von WM_COMMAND
} // ende von switch(uMsg)
return mdi_default_child_proc(..);
}
Die mdi_default_child_proc() behandelt u.a. bei WM_SIZE das Anpassen des "EDIT" an das umgebende Fenster, setzt bei WM_SETFOCUS den Cursor ins "EDIT". Bei Comilerfehlern kann unwichtiges zunächst auskommentiert werden:
LRESULT CALLBACK mdi_default_child_proc(HWND hwnd, UINT uMsg,
lParam)
{
switch(uMsg)
{
case WM_SETFOCUS: {
HWND hEdit = GetWindow(hwnd,GW_CHILD);
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) break;
if(!is_hwnd_class(hwnd, myEditClass)) break;
SetFocus(hEdit);
return 0;}
WPARAM wParam, LPARAM
case WM_SIZE: {
//LONG child_nr = GetWindowLong(hwnd,GWL_ID);
err_if(m_hClient!=GetParent(hwnd),"m_hClient!=GetParent(hwnd)");
err_if(m_hwnd[0]!=GetParent(GetParent(hwnd)),"m_hwnd[0]!=GetParent(GetParent(hwnd))");
// "EDIT"-Child-Grösse bei WM_SIZE anpassen:
HWND hEdit = GetWindow(hwnd,GW_CHILD);
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) break;
if(!is_hwnd_class(hwnd, myEditClass))
break;
RECT rc; GetClientRect(hwnd, &rc);
SetWindowPos(hEdit,HWND_BOTTOM,
rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
break;}
case WM_MDIACTIVATE: {
// Eingabefokus wechselt: Menü setzen
if((LPARAM)hwnd == lParam) {
HWND hClient = GetParent(hwnd);
HWND hFrame = GetParent(hClient);
SendMessage(m_hClient,WM_MDISETMENU,
(WPARAM) m_hMenu[1],(LPARAM)GetSubMenu(m_hMenu[1],1));
} else {
// Eingabefokus wechselt,d.h. m_hMenu[0] setzen
SendMessage(m_hClient, WM_MDISETMENU,
(WPARAM) m_hMenu[0],(LPARAM) GetSubMenu(m_hMenu[0],0));
}
DrawMenuBar(m_hwnd[0]);
break; }
case WM_QUERYENDSESSION:
case WM_CLOSE: {
TCHAR child_titel[512]; // Cild-Fenster beenden?
memset(child_titel, 0, sizeof(child_titel));
GetWindowText(hwnd,child_titel, 512);
/*
// Nummer i des Child-Fensters (nur ein Test!)
LONG i = GetWindowLong(hwnd,GWL_ID)-(LONG)FIRST_CHILD_IDX;
TCHAR
child_num [128];
memset(child_num,0,sizeof(child_num));
wsprintf(child_num,TEXT("Child-Fenster = %li schließen"),i);
int ret = MessageBox(hwnd, child_num, child_titel,
MB_ICONQUESTION|MB_OKCANCEL);
if (IDOK != ret) return 0; // bleib!
*/
int ret = MessageBox(hwnd, TEXT("Child-Fenster schließen?"), child_titel,
MB_ICONQUESTION|MB_OKCANCEL);
if (IDOK != ret) return 0; // bleib!
// sonst zerstören mit DefMDIChildProc
break; }
// Weitergabe an DefMDIChildProc(ersetzt DefWindowProc)
return DefMDIChildProc(hwnd,uMsg,wParam,lParam);
}
Gibt es hilfreiche Funktionen?
is_hwnd_class() prüft, ob ein hwnd zu einer bestimmten Klasse ehört.
// gehört hwnd zu einer bestimmten Fnster-Class? BOOL is_hwnd_class(HWND hwnd, TCHAR *className) { TCHAR buf[512]; int anz = GetClassName(hwnd, buf, 512); int
diff= CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,buf,-1,className,-1);
//if(GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ... return (diff == CSTR_EQUAL); }
Mit Hilfe der EnumChildWindows(..,EnumCallBack,...)-Funktion wird der EnumCloseProc() - Funktionszeiger hinterlegt. Es werden alle ChildWindows durchlaufen und jedesmal
wird EnumCloseProc() aufgerufen. Antwortet EnumCloseProc() mit TRUE, so wird das Durchlaufen fortgesetzt.
BOOL CALLBACK EnumCloseProc(HWND hwnd, LPARAM lParam)
{
// falls Client-Fenster? - nicht abbauen:
if(GetWindow(hwnd, GW_OWNER)) return TRUE;
// Nachricht an das Client-Fenster: Dokument zurück auf Originalgröße
SendMessage(GetParent(hwnd), WM_MDIRESTORE,(WPARAM) hwnd, 0);
// Nachricht an das Dokumentenfenster: Schließen OK?
if(!SendMessage(hwnd,WM_QUERYENDSESSION,0,0))return TRUE;
// OK. Nachricht an das Client-Fenster: Dokumentenfenster abbauen
SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM) hwnd, 0);
return TRUE;
}
Wie können ALLE fenster durchlaufen werden?
Folgend bedeutet NULL "system-zugehörig", d.h. alle. Mit Hilfe der EnumChildWindows(NULL,EnumCallBack,...)-Funktion wird der EnumCallBack() - Funktionszeiger hinterlegt.
Es werden alle ChildWindows durchlaufen und jedesmal wird EnumCallBack() aufgerufen. Antwortet EnumCallBack() mit TRUE, so wird das Durchlaufen fortgesetzt. Es ergibt sich
etwa die folgende Anzeige:
// dies ist verbesserungsfähig ...
BOOL CALLBACK EnumCallBack(HWND nhWnd, LPARAM Param )
{
static int Nummer;// zum Zählen der Fenster
#define NCHAR 1024
TCHAR buf[ NCHAR]; buf[0]='\0';
TCHAR BUF[6*NCHAR], * p = BUF;
HWND hParent = (HWND) Param;
HWND hEdit = GetWindow(m_hwnd[2],GW_CHILD);
//SendMessage(hEdit,WM_SETFONT,(WPARAM)GetStockObject(ANSI_FIXED_FONT),TRUE);
if(Param <= 0) { Nummer = 0; return FALSE; }
if(NCHAR < GetWindowTextLength(nhWnd)) return FALSE;
if(Nummer <= 0){ // Überschrift
p += wsprintf(p,TEXT("\r\n win |
hwnd
| Titel"));
p += wsprintf(p,TEXT("\r\n=====|==========|=========="));
}
GetWindowText( nhWnd, buf,NCHAR);
if ( buf[0] != '\0' ) {
int nMax = GetWindowTextLength(hEdit);
if( ( p - BUF ) > nMax - 2*NCHAR) {//err("BUF[] zu klein");
SendMessage(hEdit,EM_LIMITTEXT,(WPARAM)6*NCHAR,0L);
}
p += wsprintf(p,TEXT("\r\n %03i | %08x | %s"),
Nummer++, nhWnd, buf);
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)BUF);
// anstelle von
// while (HIWORD(SendMessage(hEdit,EM_SCROLL,SB_PAGEUP,0L)));
// kann :
SendMessage(hEdit, WM_VSCROLL, (WPARAM)SB_TOP,0L);
SendMessage(hEdit, WM_HSCROLL, (WPARAM)SB_PAGELEFT,0L);
} return TRUE;
#undef NCHAR
}
Wie geht es weiter?
Wenn die MDI-Applikation bis hierher stabil funktioniert, so ist nun diese zu erweitern. Die MDI-Applikation soll es ermöglichen, Quelltexte "hablautomatische zu Generieren". Z.B.
sollen (zahlreiche!) HTML-Konstrukte (oder Konstrukte einer anderen Sprache, XML-, ...,usw. ) an der Cursor-Stelle (z.B. mit Hilfe eines Kontext-Menus) einfügbar sein. Die
zugehörigen CALLBACK-Funktionen sind zu schreiben.
Teil B
Der Teil B ist Pflichtteil für Sehbehinderte optional für alle anderen. Diese Aufgabe besteht darin, mit MDI-Applikationen zu arbeiten. Es ist eine MDI-Applikation zu erstellen, die es
ermöglicht, Quelltexte (hilfreich) zusammem zu erstellen ("hablautomatische Quellcode-Generierung"). Z.B. sollen (zahlreiche!) HTML-Konstrukte (oder Konstrukte einer anderen
Sprache, XML-, ...,usw. ) an der Cursor-Stelle (z.B. mit Hilfe eines Kontext-Menus) einfügbar sein. Im Einzelnen: Es sollte ein Projekt angelegt werden, das einen Header-File
vorgegebenen "auf_06.h" und einen selbst zu schreibenden "auf_06.cpp" enthalten soll. Der Aufbau von "auf_06.cpp" ist etwa:
#define STRICT
#include "auf_06.h"
// hier kommen die eigenen #define IDM_...
// hier kommt die Menü-erzeugende Funktion: create_all_menu() ...
// hier kommt die eigene myChildProc()- CALLBACK-Funktion ...
// hier kommt WinMain() ...
Hinweise zur Menü-erzeugende Funktion: create_all_menu()
Mit den Macros (alles Grusbuchstaben, sind bereits in auf_06.h enthalten) MDI_MENU_BEGIN(idx), MDI_MENU_POPUP(text), MDI_MENU_ITEM(text,idRes),
MDI_MENU_END() können Menüs zusammen gebaut werden, etwa gemäß:
void create_all_menu()
{
// Hinterlege Menu bei m_hMenu[0]:
MDI_MENU_BEGIN(0) // kein;
MDI_MENU_POPUP("&Datei")// kein;
MDI_MENU_ITEM("Neues &Text-Fenster",
IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Programm &beenden",
IDM_APP_EXIT) // kein;
MDI_MENU_END() // kein;
err_if(!IsMenu(m_hMenu[0]), "!IsMenu(m_hMenu[0]");
// Hinterlege Menu bei m_hMenu[1]:
MDI_MENU_BEGIN(1) // kein;
MDI_MENU_POPUP("&Datei") // kein;
MDI_MENU_ITEM("Neues &Text-Fenster",
IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Ö&ffnen ...",
IDM_FILE_OPEN) // kein;
MDI_MENU_ITEM("S&peichern ...",
IDM_FILE_SAVE) // kein;
MDI_MENU_ITEM("Speichern &unter ...",
IDM_FILE_SAVE_AS) // kein;
MDI_MENU_ITEM("alle Fenster Daten",
IDM_ENUM_ALL_WINDOW_DATEN) // kein;
MDI_MENU_ITEM("mdi-client-Fenster &Daten",IDM_ENUM_CHILD_WINDOW_DATEN) // kein;
MDI_MENU_ITEM("Programm &beenden",
IDM_APP_EXIT) // kein;
MDI_MENU_POPUP("&Bearbeiten") // kein;
MDI_MENU_ITEM("&Rückgängig
Ctrl+Z",
IDM_EDIT_UNDO) // kein;
MDI_MENU_ITEM("Alles &Markieren",
IDM_EDIT_SELECT_ALL) // kein;
MDI_MENU_ITEM("&Ausschneider Ctrl+X",
IDM_EDIT_CUT) // kein;
MDI_MENU_ITEM("&Kopieren
Ctrl+C",
IDM_EDIT_COPY) // kein;
MDI_MENU_ITEM("Ein&fügen
Ctrl+V",
IDM_EDIT_PASTE) // kein;
MDI_MENU_ITEM("&Löschen
Del",
IDM_EDIT_CLEAR) // kein;
MDI_MENU_POPUP("&Fenster") // kein;
MDI_MENU_ITEM("&finde markierten Text", IDM_FIND_MARKIERTEN_TEXT) // kein;
MDI_MENU_ITEM("Überla&ppend",
IDM_WINDOW_CASCADE) // kein;
MDI_MENU_ITEM("&Vertikal",
IDM_WINDOW_TILE_VERTIKAL) // kein;
MDI_MENU_ITEM("&Horizontal",
IDM_WINDOW_TILE_HORIZONTAL) // kein;
MDI_MENU_ITEM("&Minimieren",
IDM_WINDOW_SHOWMINIMIZE) // kein;
MDI_MENU_ITEM("&Nomale Größe",
IDM_WINDOW_SHOWDEFAULT) // kein;
MDI_MENU_ITEM("Ma&ximieren",
IDM_WINDOW_SHOWMAXIMIZE) // kein;
MDI_MENU_ITEM("Symbole anordnen",
IDM_WINDOW_ARRANGE) // kein;
MDI_MENU_ITEM("Fenster &schließen",
IDM_EDIT_CLOSE_TEXT) // kein;
MDI_MENU_ITEM("&Alle Fenster schließen", IDM_WINDOW_CLOSEALL) // kein;
MDI_MENU_END() // kein;
err_if(!IsMenu(m_hMenu[1]),"!IsMenu(m_hMenu[1]");
}
// MDI_MENU_POPUP("&Tags") // kein; // MDI_MENU_ITEM("do xhtml-Grundgerüst", IDM_DO_GRUNDGERUEST) // kein; // MDI_MENU_ITEM("do <&p>..<//p>",
IDM_DO_P_TAG) // kein; // MDI_MENU_ITEM("do c&ode-Tag <pre>..<//pre>", IDM_DO_PRE_TAG) // kein; // MDI_MENU_ITEM("do &center-Tag
<div>..<//div>",IDM_DO_CENTER_TAG) // kein; // MDI_MENU_ITEM("do &bild-Tag <img ...//>", IDM_DO_IMG_TAG) // kein;
Es ist eine CALLBACK-myChildProc() zu schreiben, die Tags an der aktuellen Caret-Position einfügt. Ein markierter Bereich wird eingerahmt, etwa bei einem pre-Tag wird <pre> vor
den markierter Bereich geschrieben und </pre> nach dem den markierter Bereich. Sind die globalen Variablen m_pPrae und m_pPost gesetzt, so erledigt dies
SendMessage(hwnd,WM_COMMAND,IDM_ERSETZE_PRAE_POST,0); IDM_ERSETZE_PRAE_POST existiert schon in "auf_06.h".
Hinweise zur eigene myChildProc()- CALLBACK-Funktion
myChildProc() soll (bei unklarer Lage) am Ende die eingebaute mdi_default_child_proc()-Funktion aufrufen, die einige Ereignisse behandelt (siehe "auf_06.h").
LRESULT CALLBACK myChildProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE: {
// HWND hwnd_Client = GetParent(hwnd); // m_hClient
// HWND hwnd_Frame = GetParent(hwnd_Client); //[0]
return 0;}
case WM_COMMAND:{
switch(LOWORD(wParam))
{
case IDM_DO_P_TAG: {
m_pPrae = "<p>\r\n";
m_pPost = "<\\p>\r\n";
SendMessage(hwnd,WM_COMMAND,IDM_ERSETZE_PRAE_POST,0);
return 0; }
case IDM_DO_PRE_TAG: {
m_pPrae = "\r\n<pre class=\'box\'>";
m_pPost = "\r\n</pre>\r\n";
SendMessage(hwnd,WM_COMMAND,IDM_ERSETZE_PRAE_POST,0);
return 0; }
case IDM_DO_CENTER_TAG: {
m_pPrae = "\r\n<div style=\'text-align:center;\'>\r\n";
m_pPost = "\r\n</div>\r\n";
SendMessage(hwnd,WM_COMMAND,IDM_ERSETZE_PRAE_POST,0);
return 0; }
case IDM_DO_IMG_TAG: {
m_pPrae = "\r\n<img src=\'--1 a_logo.gif\' alt=\'--1 a_logo.gif\' />\r\n";
m_pPost = "";
SendMessage(hwnd,WM_COMMAND,IDM_ERSETZE_PRAE_POST,0);
return 0; }
} // switch(LOWORD(wParam))
break; } // ende von WM_COMMAND
} // ende von switch(uMsg)
return mdi_default_child_proc(hwnd,uMsg,wParam,lParam);
}
Bitte beachten Sie, dass die Identifizierer, wie z.B. IDM_DO_PRE_TAG selbst definiert werden müssen (unmittelbar nach #include "auf-06.h"). Dies kann etwa erfolgen, gemäß:
// eigene Identifizierer zwischen 1000 und 1999 wählen:
#define IDM_DO_P_TAG
1001
#define IDM_DO_PRE_TAG
1002
#define IDM_DO_CENTER_TAG
1003
#define IDM_DO_IMG_TAG
1004
// in "auf_06.h" gibt es bereits (bitte
#define IDM_FILE_OPEN
#define IDM_FILE_SAVE
#define IDM_FILE_SAVE_AS
#define IDM_APP_EXIT
#define IDM_EDIT_NEW_TEXT
#define IDM_EDIT_CLOSE_TEXT
#define IDM_WINDOW_CASCADE
#define IDM_WINDOW_TILE_VERTIKAL
#define IDM_WINDOW_TILE_HORIZONTAL
#define IDM_WINDOW_ARRANGE
#define IDM_WINDOW_SHOWMINIMIZE
#define IDM_WINDOW_SHOWDEFAULT
#define IDM_WINDOW_SHOWMAXIMIZE
#define IDM_WINDOW_CLOSEALL
#define IDM_ENUM_CHILD_WINDOW_DATEN
anschauen):
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
#define
#define
#define
#define
#define
#define
#define
#define
#define
IDM_ENUM_ALL_WINDOW_DATEN
IDM_EDIT_UNDO
IDM_EDIT_CUT
IDM_EDIT_COPY
IDM_EDIT_PASTE
IDM_EDIT_CLEAR
IDM_EDIT_SELECT_ALL
IDM_FIND_MARKIERTEN_TEXT
IDM_ERSETZE_PRAE_POST
4016
4017
4018
4019
4020
4021
4022
4024
4025
Hinweise zur WinMain()-Aufbau
Das folgende Hauptprogramm erstellt das Menü, die notwendigen Klassen, das Frame-Fenster (m_hwnd[0]), intern das Client-Fenster und 2 Child-Fenster (m_hwnd[1],m_hwnd[2]).
int WINAPI WinMain(HINSTANCE, HINSTANCE hInst, PSTR, int)
{
m_hInst = GetModuleHandle(0);
create_all_menu();
// ist zu modifizieren
create_mdi_classen(); // aus "auf_06.h"
// FrameWindow-Rahmenfenster m_hwnd[0] anlegen
int xPos = 0;
int yPos = 0;
int dx = GetSystemMetrics(SM_CXSCREEN);
int dy = GetSystemMetrics(SM_CYSCREEN);
// Rahmenfenster anlegen
m_hwnd[0] = CreateWindow(
myFrameClass, myAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
xPos,yPos,dx,dy,NULL,m_hMenu[0],m_hInst,0);
// m_hClient wurde unter WM_CREATE angelegt
m_hClient = GetWindow(m_hwnd[0], GW_CHILD);
err_if(!m_hClient,"m_hClient");
ShowWindow(m_hwnd[0], SW_SHOW);
UpdateWindow(m_hwnd[0]);
// m_hwnd[1] ist ein Child-Fenster
m_hwnd[1] = create_mdi_edit_window(TEXT("[1]"));
// m_hwnd[2] ist ein weiteres Child-Fenster
m_hwnd[2] = create_mdi_edit_window(TEXT("[2]"));
// Hauptnachrichtenschleife aus "auf_06.h"
main_loop();
int i; // Aufräumen: (Menüs, ...)
// freigeben:myClientClass,myFrameClass,myEditClass
// DestroyIcon(m_hIconOld);
// Klassen ...
for(i=0;i < MAX_ANZ_HWND;i++) { DestroyMenu(m_hMenu[i]); }
for(i=0;i < MAX_ANZ_HWND;i++) { DestroyWindow(m_hwnd[i]);}
return m_msg.wParam;
}
Kontroll-Fragen:
1. Welche "eingebauten Hot-Key-Nachrichten" verschickt TranslateMDISysAccel()? Nennen sie "MDI-Hot-Key"-Tastenkombinationen.
2. Wenn MSG m_msg; eine globale Variable ist und m_msg immer die aktuelle Nachricht enthält, wie kann dann auf das aktuelle Handle hwnd zugegriffen
werden?
3. Wie kann für hEdit (möglichst einfach) ein "FIXED_FONT" gesetzt werden?
4. Untersuchen sie bitte die interne Nummerierung der Childs:
// Schreibe []-Nummer in die Titelzeile (nur ein Test!)
TCHAR child_titel[512];
LONG li = GetWindowLong(hChild,GWL_ID)-(FIRST_CHILD_IDX);
wsprintf(child_titel,TEXT("[%li] %s"), li, myEditTitel);
SetWindowText(hChild, child_titel);
"\ "\r\n\r\n"\ "\r\n\r\n"\ "\r\n"\ "\r\n\r\n\r\n" , "\r\n\r\n"\ "\r\n\r\n"\ "\r\n\r\n"\ "\r\n\r\n\r\n" } }; //globale Definitionen und Konstanten: #define myAppName TEXT("my_mdi_demo")
#define myFrameClass TEXT("my_mdi_frame") #define myEditClass TEXT("my_mdi_edit_class") #define myShellDll TEXT("Shell32.dll") #define myClientClass
TEXT("MY_MDI_CLIENT") // Menu-Macros #define MDI_MENU_BEGIN(idx) {HMENU hPopup=0;int num=(idx);CHAR *pPopup=("");m_hMenu[(num)]=CreateMenu(); #define
MDI_MENU_POPUP(text) if(hPopup)AppendMenuA(m_hMenu[num],MF_POPUP,(UINT)hPopup,pPopup);hPopup=CreatePopupMenu();pPopup=(text); #define
MDI_MENU_ITEM(text,idRes) AppendMenuA(hPopup,MF_STRING,((UINT)idRes),(text)); //#define MDI_MENU_ITEMV(pText,idRes)
AppendMenuA(hPopup,MF_STRING,((UINT)idRes),(pText)); #define MDI_MENU_END() AppendMenuA(m_hMenu[num],MF_POPUP,(UINT)hPopup,pPopup);} // Macro für
Fehler-Anzeige #define err_if(e,errStr) if(e)if(IDOK!=MessageBox(0,TEXT(errStr),0,\ MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP|MB_SETFOREGROUND))exit(-1);
//Prototypen: //LRESULT CALLBACK mdi_default_frame_proc(HWND,UINT,WPARAM,LPARAM); //LRESULT CALLBACK
mdi_default_edit_proc(HWND,UINT,WPARAM,LPARAM); HWND create_mdi_edit_window(TCHAR *pTitel); //...LRESULT CALLBACK
myChildProc(HWND,UINT,WPARAM,LPARAM); //...BOOL CALLBACK EnumCloseProc(HWND,LPARAM); //...BOOL CALLBACK EnumCallBack(HWND,LPARAM);
/////////////////////////////////////////////////////////////// //globale Konstanten: /////////////////////////////////////////////////////////////// #define FIRST_CHILD_IDX 50000 #define MAX_ANZ_HWND
((int)50) HWND m_hwnd[ MAX_ANZ_HWND]; // [0] ist das hauptfenster bzw. MDI-Frame #define MAX_ANZ_MENU ((int)10) HMENU m_hMenu[MAX_ANZ_MENU]; // [] für
menu's HACCEL m_hAccel; // aktuelle Accel-Tabelle HWND m_hClient; // mdi-Client-fenster HWND m_hDlg; // aktueller Dialog MSG m_msg; // aktuelle Nachricht HINSTANCE
m_hInst; // = GetModuleHandle(0); #define MAX_BUF 256 CHAR m_buf[MAX_BUF], *m_pSrc, *m_pDst, *m_pPrae, *m_pPost, *m_pFind;
/////////////////////////////////////////////////////////////// // Haupt-Nachrichtenschleife: void main_loop() { // hinterlege Nachricht in m_msg while (BOOL bRet = GetMessage(&m_msg,NULL,0,0))
{ err_if(-1==bRet,"-1==GetMessage()"); //err_if(!m_msg.hwnd,"!m_msg.hwnd"); m_hDlg = (GetWindowLong(m_msg.hwnd,GWL_STYLE) & WS_CHILD)
?GetParent(m_msg.hwnd):m_msg.hwnd;//GetWindow(hwnd,GW_OWNER); if(!IsWindow( m_hDlg) || !TranslateAccelerator(m_hDlg, m_hAccel, &m_msg)) { if(!IsWindow(
m_hClient) || !TranslateMDISysAccel(m_hClient, &m_msg)) { if (!IsWindow( m_hDlg) || !IsDialogMessage(m_hDlg, &m_msg)) { TranslateMessage(&m_msg);DispatchMessage
(&m_msg);} } } } } // gehört hwnd zu einer bestimmten Fnster-Class? BOOL is_hwnd_class(HWND hwnd, TCHAR *className) { TCHAR buf[512]; int anz = GetClassName(hwnd,
buf, 512); int diff= CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,buf,-1,className,-1);
//if(GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ... return (diff == CSTR_EQUAL); } BOOL file_save_from_edit(HWND hEdit) {
if(!is_hwnd_class(hEdit,TEXT("Edit"))) return FALSE; TCHAR szFileName[_MAX_PATH]; szFileName[0] = '\0'; GetWindowText(GetParent(hEdit),szFileName,_MAX_PATH-2);
SECURITY_ATTRIBUTES sa={0}; sa.nLength = sizeof(sa); DWORD dwCreateFlag = OPEN_ALWAYS; HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0); BOOL isErr=(hFile==INVALID_HANDLE_VALUE);
err_if(isErr,"hFile"); if(isErr) return FALSE; DWORD nZuSchreiben = Edit_GetTextLength(hEdit); TCHAR *p = new TCHAR[nZuSchreiben+2]; if(!p) return FALSE;
memset(p,0,nZuSchreiben+2); Edit_GetText(hEdit,p,nZuSchreiben); DWORD nGeschrieben; BOOL ok1 = WriteFile(hFile,p,nZuSchreiben,&nGeschrieben,0);err_if(!ok1,"write");
HRESULT ok2 = CloseHandle(hFile); err_if(!ok2,"end"); if(p) delete [] p; return TRUE; } BOOL file_save_as_from_edit(HWND hEdit) { if(!is_hwnd_class(hEdit,TEXT("Edit")))
return FALSE; TCHAR szFileName[_MAX_PATH]; szFileName[0] = '\0'; OPENFILENAME ofn = { 0 }; ofn.lStructSize = sizeof( OPENFILENAME ); ofn.hwndOwner = hEdit;
ofn.hInstance = GetModuleHandle(0); ofn.lpstrTitle = TEXT("Speichern unter ..."); ofn.lpstrFile = szFileName; ofn.nMaxFile = _MAX_PATH; ofn.lpstrFilter = TEXT("Text-Dateien
(*.txt;)\000 *.txt;\000")\ TEXT("Alle Files (*.*)\000*.*\000"); ofn.Flags = OFN_OVERWRITEPROMPT ; if (!GetSaveFileName(&ofn)) return FALSE; SECURITY_ATTRIBUTES
sa={0}; sa.nLength = sizeof(sa); DWORD dwCreateFlag = OPEN_ALWAYS; HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0); BOOL isErr=(hFile==INVALID_HANDLE_VALUE);
err_if(isErr,"hFile"); if(isErr) return FALSE; DWORD nZuSchreiben = 1+Edit_GetTextLength(hEdit); TCHAR *p = new TCHAR[nZuSchreiben+2]; if(!p) return FALSE;
memset(p,0,nZuSchreiben+2); Edit_GetText(hEdit,p,nZuSchreiben); DWORD nGeschrieben; BOOL ok1 = WriteFile(hFile,p,nZuSchreiben,&nGeschrieben,0);err_if(!ok1,"write");
HRESULT ok2 = CloseHandle(hFile); err_if(!ok2,"end"); if(p) delete [] p; return TRUE; } // File-Open-Standard-Dialog BOOL file_open_to_edit(HWND hEdit) {
if(!is_hwnd_class(hEdit,TEXT("Edit"))) return FALSE; TCHAR szFileName[_MAX_PATH]; szFileName[0] = '\0'; OPENFILENAME ofn = { 0 }; ofn.lStructSize = sizeof(
OPENFILENAME ); ofn.hwndOwner = hEdit ; ofn.hInstance = GetModuleHandle(0); ofn.lpstrFile = szFileName; ofn.nMaxFile = _MAX_PATH; ofn.lpstrDefExt = TEXT("*");
ofn.nFilterIndex = 1L ; ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; ofn.lpstrTitle = TEXT("Öffnen"); ofn.lpstrFilter = TEXT("C-Dateien
(*.c;*.cpp;*.h;*.rc;)\000 *.c;*.cpp;*.h;*.rc;\000")\ TEXT("Text-Dateien (*.txt;)\000 *.txt;\000")\ TEXT("Alle Files (*.*)\000 *.*;\000\000"); if (!GetOpenFileName(&ofn)) return
FALSE; //Filename ist nun in (char*)ofn.lpstrFile; BOOL ok = (szFileName && *szFileName); err_if(!ok,"FILE_STRUCT ohne Filenamen"); if(!ok) return FALSE; TCHAR drive[32];
TCHAR dir[256]; TCHAR fname[256];TCHAR ext[32]; #ifdef UNICODE _wsplitpath(szFileName,drive,dir,fname, ext); #else _splitpath(szFileName,drive,dir,fname, ext); #endif
//_makepath(path, drive, dir,"",""); if(!drive[0]&&!dir[0]){ TCHAR szTemp[_MAX_PATH]; LPTSTR pName; if (!GetFullPathName(szFileName,_MAX_PATH,szTemp,&pName)) {
lstrcpyn( szTemp, szFileName,_MAX_PATH); } lstrcpyn(szFileName,szTemp,_MAX_PATH); } else { lstrcpyn(szFileName,szFileName,_MAX_PATH); }
SECURITY_ATTRIBUTES sa={0}; sa.nLength = sizeof(sa); DWORD dwCreateFlag = OPEN_ALWAYS; HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0); BOOL isErr=(hFile==INVALID_HANDLE_VALUE);
err_if(isErr,"hFile"); if(isErr) return FALSE; DWORD nZuLesen = 1+GetFileSize(hFile,0); if(!nZuLesen) return FALSE; TCHAR *p = new TCHAR[nZuLesen+4]; if(!p) return
FALSE; memset(p,0,nZuLesen+4); //DWORD dwOld = SetFilePointer(hFile,0,NULL,FILE_CURRENT); //DWORD dwNew = SetFilePointer(hFile,0,NULL,FILE_BEGIN); DWORD
nGelesen; BOOL ok1 = ReadFile(hFile,p,nZuLesen,&nGelesen,0);err_if(!ok1,"read"); //SetFilePointer(hFile,dwOld,NULL,FILE_CURRENT); HRESULT ok2 = CloseHandle(hFile);
err_if(!ok2,"end"); Edit_SetText(hEdit,p); SetWindowText(GetParent(hEdit),szFileName); if(p) delete [] p; return TRUE; } BOOL CALLBACK EnumCallBack(HWND nhWnd,
LPARAM lParam) { //#define hwnd m_hwnd[MAX_ANZ_HWND-1] static HWND hwnd; TCHAR buffer [1024]; TCHAR classname[ 512]; TCHAR titel [ 512]; int nSrc = 512;
HWND hEdit = NULL; if(!IsWindow(nhWnd)) return TRUE; int Nummer = *(int*)lParam; if(*(int*)lParam == 0) { // Überschrift *(int*)lParam = 1; //if(hwnd)
SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM)hwnd, 0); hwnd = create_mdi_edit_window(TEXT("fenster-anzeige")); err_if(!hwnd,"EnumCallBack: kein
Zielfenster"); memset(buffer,0,nSrc); wsprintf(buffer,TEXT("\r\n nr | hwnd | Class | Titel") \ TEXT("\r\n====|==========|====================|==========\r\n")); hEdit =
GetWindow(hwnd,GW_CHILD); if(!IsWindow(hEdit)) return FALSE; SetWindowText(hEdit,TEXT("")); SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buffer);
SetFocus(hEdit); } memset(titel, 0, nSrc); memset(classname,0, nSrc); memset(buffer, 0,2*nSrc); int nMax = GetWindowTextLength(nhWnd); if (nMax>0)
GetWindowText(nhWnd,titel,nSrc-2); int anz = GetClassName(nhWnd,classname,nSrc-2); wsprintf(buffer,TEXT("%03i | %08x | %18s | %s \r\n"), (*(int*)lParam)1,nhWnd,classname,titel); (*(int*)lParam)++; hEdit = GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("Edit"))) return FALSE;
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buffer); SetFocus(hEdit); return TRUE; //#undef hwnd } // Enum-CALLBACK-Funktionen BOOL CALLBACK
EnumCloseProc(HWND hwnd, LPARAM lParam) { // falls Client-Fenster? - nicht abbauen: if(GetWindow(hwnd, GW_OWNER)) return TRUE; // Nachricht an das Client-Fenster:
Dokument zurück auf Originalgröße SendMessage(GetParent(hwnd), WM_MDIRESTORE,(WPARAM) hwnd, 0); // Nachricht an das Dokumentenfenster: Schließen OK?
if(!SendMessage(hwnd,WM_QUERYENDSESSION,0,0)) return TRUE; // OK. Nachricht an das Client-Fenster: Dokumentenfenster abbauen
SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM) hwnd, 0); return TRUE; } BOOL CALLBACK EnumAllMinimize(HWND hwnd, LPARAM lParam) {
if(is_hwnd_class(hwnd,myEditClass)) { ShowWindow(hwnd,SW_SHOWMINIMIZED); } return TRUE; } BOOL CALLBACK EnumAllMaximize(HWND hwnd, LPARAM lParam) {
if(is_hwnd_class(hwnd,myEditClass)) { ShowWindow(hwnd,SW_SHOWMAXIMIZED); } return TRUE; } BOOL CALLBACK EnumAllDefault(HWND hwnd, LPARAM lParam) {
if(is_hwnd_class(hwnd,myEditClass)) { ShowWindow(hwnd,SW_NORMAL); } return TRUE; } LRESULT CALLBACK mdi_default_frame_proc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) { // static HWND m_hClient; HWND hChild; switch(uMsg) { case WM_CREATE: { // Client-Fenster erzeugen CLIENTCREATESTRUCT
clientcreate; clientcreate.hWindowMenu = GetSubMenu(m_hMenu[0],0); clientcreate.idFirstChild = FIRST_CHILD_IDX; m_hClient = CreateWindowEx(0,myClientClass,NULL,
MDIS_ALLCHILDSTYLES|WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE, 0,0,0,0,hwnd,(HMENU)1,m_hInst, (PSTR) &clientcreate);return 0; } case WM_COMMAND: { //ok:
if(FIRST_CHILD_IDX <= LOWORD(wParam)) break; //ok: HWND hChild = (HWND)SendMessage(m_hClient,WM_MDIGETACTIVE,0,0); //ok: if(hChild)
SendMessage(hChild,WM_COMMAND,wParam,lParam); switch(LOWORD(wParam)) { case IDM_EDIT_NEXT: { // HWND hChild =(HWND)
SendMessage(m_hClient,WM_MDIGETACTIVE,0,0); PostMessage(hChild,WM_SYSCOMMAND,SC_NEXTWINDOW,0); return 0; } case IDM_EDIT_NEW_TEXT: { //
erstes/nächstes HELLO-Fenster create_mdi_edit_window(TEXT("Edit für temporäre Nutzung")); return 0; } case IDM_EDIT_CLOSE_TEXT: { // aktives Dokumentenfenster schließen
HWND hChild =(HWND) SendMessage(m_hClient,WM_MDIGETACTIVE,0,0); if(SendMessage(hChild, WM_QUERYENDSESSION,0,0)) SendMessage(m_hClient,
WM_MDIDESTROY,(WPARAM) hChild, 0); return 0; } case IDM_WINDOW_SHOWDEFAULT: { HWND hChild =(HWND) SendMessage(m_hClient,
WM_MDIGETACTIVE,0,0); ShowWindow(hChild,SW_SHOWDEFAULT); return 0; } case IDM_WINDOW_SHOWMINIMIZE: { HWND hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0); ShowWindow(hChild,SW_SHOWMINIMIZED); return 0; } case IDM_WINDOW_SHOWMAXIMIZE: { hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0); if(IsWindow(hChild)) SendMessage(m_hClient,(UINT)WM_MDIMAXIMIZE,(WPARAM)hChild,0); return 0; } case
IDM_WINDOW_ALL_DEFAULT:{ EnumChildWindows(m_hClient,EnumAllDefault,0); return 0; } case IDM_WINDOW_CLOSE_TEXT: { // hChild =(HWND)
SendMessage(m_hClient, WM_MDIGETACTIVE,0,0); if(SendMessage(hChild,WM_QUERYENDSESSION,0,0)) SendMessage(m_hClient,WM_MDIDESTROY,(WPARAM)
hChild, 0); return 0; } case IDM_APP_EXIT: { // Programm beenden SendMessage(hwnd, WM_CLOSE,0,0); return 0;} // Nachrichten zum Anordnen der Dokumentenfenster case
IDM_WINDOW_TILE_VERTIKAL: { // SendMessage(m_hClient, WM_MDITILE,0,0); // oder: WORD nWindows = TileWindows(m_hClient,MDITILE_VERTICAL,0,0,0); return
0;} case IDM_WINDOW_TILE_HORIZONTAL: { WORD nWindows = TileWindows(m_hClient,MDITILE_HORIZONTAL,0,0,0); return 0;} case IDM_WINDOW_CASCADE: {
SendMessage(m_hClient,WM_MDICASCADE,0,0); return 0;} case IDM_WINDOW_ARRANGE:{ // SendMessage(m_hClient, WM_MDIICONARRANGE,0,0); // oder: UINT
height = ArrangeIconicWindows(m_hClient); return 0;} case IDM_WINDOW_ALL_MINIMIZE: { EnumChildWindows(m_hClient,EnumAllMinimize,0); return 0;} case
IDM_WINDOW_ALL_MAXIMIZE: { EnumChildWindows(m_hClient,EnumAllMaximize,0); return 0;} case IDM_WINDOW_CLOSEALL:{ // Schließen aller Dokumentenfenster
EnumChildWindows(m_hClient, EnumCloseProc, 0); return 0;} case IDM_ENUM_CHILD_WINDOW_DATEN: { static LPARAM num; num = 0;
EnumChildWindows(m_hClient,EnumCallBack,(LPARAM)&num);break; } case IDM_ENUM_ALL_WINDOW_DATEN: { static LPARAM num; num = 0;
EnumWindows(EnumCallBack,(LPARAM)&num);break; } default: { // Weitergabe ans aktive Dokumentenfenster hChild =(HWND) SendMessage(m_hClient,
WM_MDIGETACTIVE,0,0); if(IsWindow(hChild)) SendMessage(hChild, WM_COMMAND, wParam, lParam); break; } // ...und danach an DefFrameProc } break; } // ende
WM_COMMAND case WM_QUERYENDSESSION: case WM_CLOSE:{ // alle Dokumentenfenster schließen SendMessage(hwnd, WM_COMMAND,
IDM_WINDOW_CLOSEALL, 0); if(NULL != GetWindow(m_hClient, GW_CHILD)) return 0; break; } // i.e., call DefFrameProc case WM_DESTROY: PostQuitMessage(0); return
0; } // ende switch(uMsg) // Weitergabe an DefFrameProc(ersetzt DefWindowProc) return DefFrameProc(hwnd, m_hClient, uMsg, wParam, lParam); } BOOL
ersetze_prae_post(HWND hwnd, LPSTR m_pPrae, LPSTR m_pPost) { /* #ifdef UNICODE #define StrLenght wcslen #else // kein UNICODE #define StrLenght strlen #endif */ int
idxSel1, idxSel2; HWND hEdit = GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("EDIT"))) return FALSE; if(!is_hwnd_class(hwnd, myEditClass)) return FALSE;
CHAR ch; // Wieviele Buchstaben enthält hEdit? // 4 mehr allokieren: int nSrc = 4 + Edit_GetTextLength(hEdit); int nPrae = strlen(m_pPrae); int nPost = strlen(m_pPost); // falls
m_pSrc allokiert ist, erst freigeben if (m_pSrc) { free(m_pSrc); m_pSrc=0; } // allokiere für Src von hEdit: m_pSrc = (CHAR*)malloc((nSrc)*sizeof(CHAR)); err_if(!m_pSrc,"m_pSrc
= new ?"); // falls m_pDst allokiert ist, erst freigeben: if (m_pDst) { free(m_pDst); m_pDst=0;} // allokiere für Dst (zusammen gesetzter text): int nDst = nSrc + nPrae + nPost; m_pDst =
(CHAR*) malloc((nDst)*sizeof(CHAR)); err_if(!m_pDst,"m_pDst = new ?"); // alle Speicher auf 0 setzen: memset(m_pSrc,0,(nSrc)*sizeof(CHAR));
memset(m_pDst,0,(nDst)*sizeof(CHAR)); memset(m_buf,0,MAX_BUF*sizeof(CHAR)); // hole hEdit-Text nach m_pSrc // int nSrc1 = Edit_GetText(hEdit,m_pSrc,nSrc); int nSrc1 =
GetWindowTextA(hEdit,m_pSrc,nSrc); // Ist was Markiert? DWORD hilo = SendMessage(hEdit,(UINT)EM_GETSEL, (WPARAM)&idxSel1,(LPARAM)&idxSel2);int nSel = idxSel2
- idxSel1; // anfangs-string ins Ziel: ch = m_pSrc[idxSel1]; m_pSrc[idxSel1]=(CHAR)0; strcat(m_pDst,m_pSrc); m_pSrc[idxSel1]=ch; // m_pPrae ins Ziel: if(nPrae > 0)
strcat(m_pDst,m_pPrae); ch=m_pSrc[idxSel2]; m_pSrc[idxSel2]=(CHAR)0; strcat(m_buf,&m_pSrc[idxSel1]);m_pSrc[idxSel2]=ch; // tue markierten-text ins Ziel:
strcat(m_pDst,m_buf); // m_pPost ins Ziel: if(nPost > 0) strcat(m_pDst,m_pPost); // rest von m_pSrc ins Ziel: strcat(m_pDst,&m_pSrc[idxSel2]);// hinterlege im Editor:
//Edit_SetText(hEdit,m_pDst); SetWindowTextA(hEdit,m_pDst); SetFocus(hEdit); Edit_SetSel(hEdit,idxSel1,idxSel1); Edit_ScrollCaret(hEdit); // allokierten Speicher freigeben: if
(m_pSrc) { free(m_pSrc); m_pSrc=0; } if (m_pDst) { free(m_pDst); m_pDst=0; } return TRUE; } LRESULT CALLBACK mdi_default_edit_proc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) { int idxSel1, idxSel2; switch(uMsg) { case WM_SETFOCUS: { HWND hEdit = GetWindow(hwnd,GW_CHILD);
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) break; if(!is_hwnd_class(hwnd, myEditClass)) break; SetFocus(hEdit); return 0;} case WM_SIZE: { //LONG child_nr =
GetWindowLong(hwnd,GWL_ID); err_if(m_hClient!=GetParent(hwnd),"m_hClient!=GetParent(hwnd)");
err_if(m_hwnd[0]!=GetParent(GetParent(hwnd)),"m_hwnd[0]!=GetParent(GetParent(hwnd))"); // "EDIT"-Child-Grösse bei WM_SIZE anpassen: HWND hEdit =
GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("EDIT"))) break; if(!is_hwnd_class(hwnd, myEditClass)) break; // Move und Repaint:
MoveWindow(hEdit,0,0,LOWORD(lParam),HIWORD(lParam),TRUE); return 0; // alternativ zu Move und Repaint: // RECT rc; GetClientRect(hwnd, &rc);//
SetWindowPos(hEdit,HWND_BOTTOM, // rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top, // SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); // return 0; break;} case
WM_MDIACTIVATE: { // falls Focusverlust ... HWND hChildNew = (HWND)wParam; if (!hChildNew && IsZoomed(hwnd)) {
SendMessage(m_hClient,WM_MDIRESTORE,(WPARAM)hwnd,0L); break; } // Eingabefokus wechselt: Menü setzen if((LPARAM)hwnd == lParam) { HWND hClient =
GetParent(hwnd); HWND hFrame = GetParent(hClient); SendMessage(m_hClient,WM_MDISETMENU, (WPARAM) m_hMenu[1],(LPARAM)GetSubMenu(m_hMenu[1],1)); } else
{ // Eingabefokus wechselt,d.h. m_hMenu[0] setzen SendMessage(m_hClient, WM_MDISETMENU, (WPARAM) m_hMenu[0],(LPARAM) GetSubMenu(m_hMenu[0],0)); }
DrawMenuBar(m_hwnd[0]); break; } case WM_QUERYENDSESSION: case WM_CLOSE: { if(m_hwnd[MAX_ANZ_HWND-1]==hwnd) { //temporäres Fenster sofort zumachen
m_hwnd[MAX_ANZ_HWND-1]=0; break; } TCHAR child_titel[512]; // Cild-Fenster beenden? memset(child_titel, 0, sizeof(child_titel)); GetWindowText(hwnd,child_titel, 512); int
ret = MessageBox(hwnd, TEXT("Child-Fenster schließen?"), child_titel, MB_ICONQUESTION|MB_OKCANCEL); if (IDOK != ret) return 0; // bleib! // sonst zerstören mit
DefMDIChildProc break; } //case WM_CREATE: { // HWND hwnd_Client = GetParent(hwnd); // m_hClient // HWND hwnd_Frame = GetParent(hwnd_Client); //[0] //return 0;} //case
WM_PAINT: { break; } // Fenster neu zeichnen //case WM_DESTROY: { return 0;} /* /////////////////////////////////////// // Child case WM_CONTEXTMENU: { //Notification-Nachricht //
kommt bei // WM_RBUTTONUP mit(HWND)lParam // WM_NCRBUTTONUP mit(HWND)lParam // shift+F10, mit lParam=-1: Anzeige bei aktuellen Selection (d.h. auch Cursor) //
VK_APPS (5D, Numpad-Mitte) err_if(1,"WM_CONTEXTMENU child"); break; } */ case WM_COMMAND:{ HWND hEdit = GetWindow(hwnd,GW_CHILD); if
(lParam==(LPARAM)hEdit) { if((HIWORD(wParam)==EN_ERRSPACE || HIWORD(wParam)==EN_MAXTEXT)) MessageBox(hwnd,TEXT("Kapazitätsgrenze!"),
0,MB_OK|MB_ICONSTOP); return 0; } else switch(LOWORD(wParam)) { case IDM_FILE_OPEN:{ //hChild = (HWND)SendMessage(m_hClient,WM_MDIGETACTIVE,0,0);
//HWND hEdit = GetWindow(hChild,GW_CHILD); HWND hEdit = GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("Edit"))) break; if(file_open_to_edit(hEdit))
return 0; break; } case IDM_FILE_SAVE:{ //MessageBox (hwnd,TEXT("behandelt in vorherigen Übungen ..."), myAppName,MB_OK|MB_ICONSTOP); HWND hEdit =
GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("Edit"))) break; if(file_save_from_edit(hEdit)) return 0; break; } case IDM_FILE_SAVE_AS_FROM_EDIT:{ HWND
hEdit = GetWindow(hwnd,GW_CHILD); if(!is_hwnd_class(hEdit,TEXT("Edit"))) break; if(file_save_as_from_edit(hEdit)) return 0; break; } case IDM_EDIT_UNDO:
SendMessage(hEdit, WM_UNDO,0,0); return 0; case IDM_EDIT_CUT: SendMessage(hEdit, WM_CUT,0,0); return 0; case IDM_EDIT_COPY: SendMessage(hEdit, WM_COPY,0,0);
return 0; case IDM_EDIT_PASTE: SendMessage(hEdit, WM_PASTE,0,0); return 0; case IDM_EDIT_CLEAR: SendMessage(hEdit, WM_CLEAR,0,0); return 0; case
IDM_EDIT_SELECT_ALL:SendMessage(hEdit, EM_SETSEL,0,-1); return 0; case IDM_FIND_MARKIERTEN_TEXT: { HWND hEdit = GetWindow(hwnd,GW_CHILD);
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) break; if(!is_hwnd_class(hwnd, myEditClass)) break; // hole die selektierten Text-Positionen: DWORD hilo =
SendMessage(hEdit,(UINT)EM_GETSEL, (WPARAM)&idxSel1,(LPARAM)&idxSel2);int nSel = idxSel2 - idxSel1; if(nSel <=0 ) break; // Wieviele Buchstaben enthält hEdit? int nSrc
= Edit_GetTextLength(hEdit); err_if(nSrc<=0,"nSrc<=0"); // falls m_pSrc bereits allokiert ist, // dann erst freigeben: if (m_pSrc) {free(m_pSrc); m_pSrc = 0;} m_pSrc =
(CHAR*)malloc((nSrc+10)*sizeof(CHAR)); memset(m_pSrc,0,(nSrc+10)*sizeof(CHAR)); err_if(!m_pSrc,"m_pSrc = new ?"); // hole hEdit-Text nach m_pSrc-Heap: //nSrc =
Edit_GetText(hEdit,m_pSrc,nSrc); nSrc = GetWindowTextA(hEdit,m_pSrc,nSrc); //memset(buf,0,MAX_BUF*sizeof(TCHAR)); // hole selektierten text in buf for(int i=0; i <nSel;i++)
{ m_buf[i] = m_pSrc[idxSel1 + i]; err_if((i+2)>=MAX_BUF,"buf zu klein"); } m_buf[i] = (TCHAR)0; // suche das nächste Auftreten: m_pFind = strstr(m_pSrc + idxSel2,m_buf); if
(m_pFind) { idxSel1 = m_pFind - m_pSrc; idxSel2 = idxSel1 + strlen(m_buf); } else { MessageBox(hwnd,TEXT("Ende des\r\nEditor-Textes"),TEXT("Hinweis"),MB_OK); idxSel2 =
idxSel1 = 0; // gleich weiter vom Anfang her: m_pFind = strstr(m_pSrc,m_buf); idxSel1 = m_pFind - m_pSrc; idxSel2 = idxSel1 + strlen(m_buf); Edit_SetSel(hEdit,idxSel1,idxSel2); }
SetFocus( hEdit ); Edit_SetSel(hEdit,idxSel1,idxSel2); Edit_ScrollCaret(hEdit); if (m_pSrc) {free(m_pSrc);m_pSrc = 0;} break; } default:{ break; } } // switch(LOWORD(wParam))
break; } // ende von WM_COMMAND } // ende von switch(uMsg) // Weitergabe an DefMDIChildProc(ersetzt DefWindowProc) return
DefMDIChildProc(hwnd,uMsg,wParam,lParam); } LRESULT CALLBACK myChildProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case
WM_CREATE: { // HWND hwnd_Client = GetParent(hwnd); // m_hClient // HWND hwnd_Frame = GetParent(hwnd_Client); //[0] return 0;} case WM_COMMAND:{ int i, id =
LOWORD(wParam); if((idIDM_ERSETZE_PRAE_POST_LAST)) break; for(i = 0; i <sizeof(m_pPraePost)/sizeof(m_pPraePost[0]); i++) { if(id
==(i+IDM_ERSETZE_PRAE_POST_FIRST)) { if(ersetze_prae_post(hwnd,m_pPraePost[i][1],m_pPraePost[i][2]))return 0; break; } } break; } // ende von WM_COMMAND } // ende
von switch(uMsg) return mdi_default_edit_proc(hwnd,uMsg,wParam,lParam); #undef MAX_BUF } void destroy_mdi_classen() { UnregisterClass(myClientClass,m_hInst);
UnregisterClass(myFrameClass,m_hInst); UnregisterClass(myEditClass,m_hInst); } void create_mdi_classen() { ATOM atom; WNDCLASSEX wc; // aus TEXT("MDICLIENT") mach
myClientClass wc.cbSize = sizeof(wc); BOOL ok = GetClassInfoEx(m_hInst,TEXT("MDICLIENT"),&wc);wc.hInstance = m_hInst; wc.hbrBackground =(HBRUSH)
GetStockObject(BLACK_BRUSH); wc.lpszClassName = myClientClass; atom = RegisterClassEx(&wc);// Fensterklasse für das Rahmenfenster anlegen:
memset(&wc,0,sizeof(wc));wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = mdi_default_frame_proc; wc.cbClsExtra = sizeof(HANDLE);
wc.cbWndExtra = sizeof(HANDLE); wc.hInstance = m_hInst; wc.hIcon = ExtractIcon(m_hInst,myShellDll,43); wc.hCursor = LoadCursor(0,IDC_ARROW); wc.hbrBackground
=(HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = myFrameClass; atom = RegisterClassEx(&wc);// Fensterklasse für das EditWindow memset(&wc,0,sizeof(wc));wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = myChildProc;//mdi_default_edit_proc;
wc.lpszClassName = myEditClass; wc.cbClsExtra = 4; wc.cbWndExtra = 4; wc.hInstance = m_hInst; wc.hCursor = LoadCursor(0,IDC_ARROW); wc.hbrBackground =
(HBRUSH)GetStockObject(WHITE_BRUSH); wc.hIcon = ExtractIcon(m_hInst,myShellDll,2); //wc.lpszMenuName = NULL; atom = RegisterClassEx(&wc);} HWND
create_mdi_edit_window(TCHAR *pTitel) { int xPos=0;int yPos=0; int dx=0;int dy=0; // FrameWindow als Childfenster [1] anlegen if((xPos<0)||(yPos<0)||(dx<=0)||(dy<=0)) { xPos =
yPos = dx = dy = CW_USEDEFAULT; } HWND hChild = ::CreateMDIWindow( myEditClass, // class pTitel, // window caption
WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE, xPos,yPos,dx,dy, m_hClient,m_hInst,NULL); //::BringWindowToTop(hChild); // zusätzlich ein "EDIT" ins Child-Fenster
WNDCLASSEX wc; memset(&wc,0,sizeof(wc));wc.cbSize = sizeof(WNDCLASSEX); GetClassInfoEx(GetModuleHandle(0),TEXT("EDIT"),&wc);RECT rc; GetClientRect(hChild,
&rc ); //WS_EX_CLIENTEDGE|WS_EX_CONTROLPARENT //HWND hEdit = CreateWindowEx(WS_EX_CLIENTEDGE|WS_EX_CONTROLPARENT,TEXT("EDIT"),0,
HWND hEdit = CreateWindow(TEXT("EDIT"),0, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL |ES_WANTRETURN|ES_MULTILINE
|ES_AUTOHSCROLL|ES_AUTOVSCROLL, rc.left,rc.top,rc.right,rc.bottom, hChild,(HMENU)hChild,m_hInst,0); err_if(!hEdit,"kein hEdit"); SendMessage(hEdit,WM_SETFONT,
(WPARAM)GetStockObject(ANSI_FIXED_FONT),TRUE); SetFocus(hEdit); return hChild; } /* void create_all_menu() { // Hinterlege Menu bei m_hMenu[0]:
MDI_MENU_BEGIN(0) // kein; MDI_MENU_POPUP("&Datei")// kein; MDI_MENU_ITEM("Neues &Text-Fenster", IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Programm &beenden", IDM_APP_EXIT) // kein; MDI_MENU_END() // kein; err_if(!IsMenu(m_hMenu[0]), "!IsMenu(m_hMenu[0]"); // Hinterlege Menu bei
m_hMenu[1]: MDI_MENU_BEGIN(1) // kein; MDI_MENU_POPUP("&Datei") // kein; MDI_MENU_ITEM("Neues &Text-Fenster", IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Ö&ffnen ...", IDM_FILE_OPEN) // kein; MDI_MENU_ITEM("S&peichern ...", IDM_FILE_SAVE) // kein; MDI_MENU_ITEM("Speichern &unter ...",
IDM_FILE_SAVE_AS_FROM_EDIT) // kein; MDI_MENU_ITEM("alle Fenster Daten", IDM_ENUM_ALL_WINDOW_DATEN) // kein; MDI_MENU_ITEM("mdi-client-Fenster
&Daten",IDM_ENUM_CHILD_WINDOW_DATEN) // kein; MDI_MENU_ITEM("Programm &beenden", IDM_APP_EXIT) // kein; MDI_MENU_POPUP("&Bearbeiten") // kein;
MDI_MENU_ITEM("&Rückgängig Ctrl+Z", IDM_EDIT_UNDO) // kein; MDI_MENU_ITEM("Alles &Markieren", IDM_EDIT_SELECT_ALL) // kein;
MDI_MENU_ITEM("&Ausschneider Ctrl+X", IDM_EDIT_CUT) // kein; MDI_MENU_ITEM("&Kopieren Ctrl+C", IDM_EDIT_COPY) // kein; MDI_MENU_ITEM("Ein&fügen
Ctrl+V", IDM_EDIT_PASTE) // kein; MDI_MENU_ITEM("&Löschen Del", IDM_EDIT_CLEAR) // kein; MDI_MENU_POPUP("&Fenster") // kein; MDI_MENU_ITEM("&finde
markierten Text", IDM_FIND_MARKIERTEN_TEXT) // kein; MDI_MENU_ITEM("Überla&ppend", IDM_WINDOW_CASCADE) // kein; MDI_MENU_ITEM("&Vertikal",
IDM_WINDOW_TILE_VERTIKAL) // kein; MDI_MENU_ITEM("&Horizontal", IDM_WINDOW_TILE_HORIZONTAL) // kein; MDI_MENU_ITEM("&Minimieren",
IDM_WINDOW_SHOWMINIMIZE) // kein; MDI_MENU_ITEM("&Nomale Größe", IDM_WINDOW_SHOWDEFAULT) // kein; MDI_MENU_ITEM("Ma&ximieren",
IDM_WINDOW_SHOWMAXIMIZE) // kein; MDI_MENU_ITEM("Symbole anordnen", IDM_WINDOW_ARRANGE) // kein; MDI_MENU_ITEM("Fenster &schließen",
IDM_EDIT_CLOSE_TEXT) // kein; MDI_MENU_ITEM("&Alle Fenster schließen", IDM_WINDOW_CLOSEALL) // kein; // MDI_MENU_POPUP("&Tags") // kein; //
MDI_MENU_ITEM("do xhtml-Grundgerüst", IDM_DO_GRUNDGERUEST) // kein; // MDI_MENU_ITEM("do <&p>..", IDM_DO_P_TAG) // kein; // MDI_MENU_ITEM("do
c&ode-Tag
..", IDM_DO_PRE_TAG) // kein;
//
MDI_MENU_ITEM("do ¢er-Tag
..",IDM_DO_CENTER_TAG) // kein;
//
MDI_MENU_ITEM("do &bild-Tag
",
IDM_DO_IMG_TAG) // kein;
MDI_MENU_END() // kein;
err_if(!IsMenu(m_hMenu[1]),"!IsMenu(m_hMenu[1]");
}*/
void create_all_menu()
{
// Hinterlege Menu bei m_hMenu[0]:
MDI_MENU_BEGIN(0) // kein;
MDI_MENU_POPUP("&Datei")// kein;
MDI_MENU_ITEM("Neues &Text-Fenster", IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Programm &beenden", IDM_APP_EXIT) // kein;
MDI_MENU_END() // kein;
err_if(!IsMenu(m_hMenu[0]), "!IsMenu(m_hMenu[0]");
// Hinterlege Menu bei m_hMenu[1]:
MDI_MENU_BEGIN(1) // kein;
MDI_MENU_POPUP("&Datei") // kein;
MDI_MENU_ITEM("Neues &Text-Fenster", IDM_EDIT_NEW_TEXT) // kein;
MDI_MENU_ITEM("Ö&ffnen ...",
IDM_FILE_OPEN) // kein;
MDI_MENU_ITEM("S&peichern ...",
IDM_FILE_SAVE) // kein;
MDI_MENU_ITEM("Speichern &unter ...",
IDM_FILE_SAVE_AS_FROM_EDIT) // kein;
MDI_MENU_ITEM("alle Fenster Daten",
IDM_ENUM_ALL_WINDOW_DATEN) // kein;
MDI_MENU_ITEM("mdi-client-Fenster &Daten",IDM_ENUM_CHILD_WINDOW_DATEN) // kein;
MDI_MENU_ITEM("Programm &beenden", IDM_APP_EXIT) // kein;
MDI_MENU_POPUP("&Bearbeiten") // kein;
MDI_MENU_ITEM("&Nächstes Fenster\t Ctrl+tab/Ctrl+F6", IDM_EDIT_NEXT) // kein;
MDI_MENU_ITEM("&Rückgängig \t Ctrl+Z",
IDM_EDIT_UNDO) // kein;
MDI_MENU_ITEM("Alles &markieren", IDM_EDIT_SELECT_ALL) // kein;
MDI_MENU_ITEM("&Ausschneiden \t Ctrl+X",
IDM_EDIT_CUT) // kein;
MDI_MENU_ITEM("&Kopieren \t Ctrl+C",
IDM_EDIT_COPY) // kein;
MDI_MENU_ITEM("Ein&fügen \t Ctrl+V",
IDM_EDIT_PASTE) // kein;
MDI_MENU_ITEM("&Löschen \t Del",
IDM_EDIT_CLEAR) // kein;
MDI_MENU_POPUP("&Fenster") // kein;
MDI_MENU_ITEM("&Finde markierten Text",
IDM_FIND_MARKIERTEN_TEXT) // kein;
MDI_MENU_ITEM("Fenster &Vertikal teilen", IDM_WINDOW_TILE_VERTIKAL) // kein;
MDI_MENU_ITEM("Fenster &Horizontal teilen",IDM_WINDOW_TILE_HORIZONTAL) // kein;
MDI_MENU_ITEM("Fenster überla&ppend", IDM_WINDOW_CASCADE) // kein;
MDI_MENU_ITEM("Fenster &Minimieren", IDM_WINDOW_SHOWMINIMIZE) // kein;
MDI_MENU_ITEM("Fenster &Normale Größe", IDM_WINDOW_SHOWDEFAULT) // kein;
MDI_MENU_ITEM("Fenster M&aximieren", IDM_WINDOW_SHOWMAXIMIZE) // kein;
MDI_MENU_ITEM("Fenster &schließen", IDM_WINDOW_CLOSE_TEXT) // kein;
MDI_MENU_ITEM("Alle Fenster minimieren", IDM_WINDOW_ALL_MINIMIZE) // kein;
MDI_MENU_ITEM("Alle Fenster normal",
IDM_WINDOW_ALL_DEFAULT) // kein;
MDI_MENU_ITEM("Alle Fenster maximieren", IDM_WINDOW_ALL_MAXIMIZE) // kein;
MDI_MENU_ITEM("Alle Symbole anordnen",
IDM_WINDOW_ARRANGE) // kein;
MDI_MENU_ITEM("&Alle Fenster schließen", IDM_WINDOW_CLOSEALL) // kein;
MDI_MENU_POPUP("&Tags") // kein;
for(UINT i=0;i= PACKVERSION(4,71))
{
//Proceed.
} else {
// Use an alternate approach for older DLL versions.
}
*/
/*
char buf[256]; memset(buf,0,256);
wsprintf(buf,TEXT("WinMain-Adr: %08x, func-Adr:
%08x"),(WPARAM)WinMain,(WPARAM)main_loop);
err_if(1,buf);
*/
int WINAPI WinMain(HINSTANCE, HINSTANCE hInst, PSTR, int)
{
//versionstest();
m_hInst = GetModuleHandle(0);
create_all_menu();
create_mdi_classen();
// FrameWindow als Rahmenfenster [0] anlegen
int xPos=0; int yPos=0; int dx=0; int dy=0;
if((xPos<0)||(yPos<0)||(dx<=0)||(dy<=0)) {
xPos = yPos = 0;
if(dx<1) dx = GetSystemMetrics(SM_CXSCREEN);
if(dy<1) dy = GetSystemMetrics(SM_CYSCREEN);
} else {
xPos = yPos = dx = dy = CW_USEDEFAULT;
}
// Rahmenfenster anlegen
m_hwnd[0] = CreateWindow(
myFrameClass, myAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
xPos,yPos,dx,dy,NULL,m_hMenu[0],m_hInst,0);
// m_hClient wurde unter WM_CREATE angelegt
m_hClient = GetWindow(m_hwnd[0], GW_CHILD);
err_if(!m_hClient,"m_hClient");
ShowWindow(m_hwnd[0], SW_SHOW);
UpdateWindow(m_hwnd[0]);
// m_hwnd[1] ist ein Child-Fenster
m_hwnd[1] = create_mdi_edit_window(TEXT("[1]"));
// m_hwnd[2] ist ein weiteres Child-Fenster
m_hwnd[2] = create_mdi_edit_window(TEXT("[2]"));
// Hauptnachrichtenschleife
main_loop();
int i; // Aufräumen: (Menüs, ...)
// DestroyIcon(m_hIconOld);
if (m_pSrc) { free(m_pSrc); }
if (m_pDst) { free(m_pDst); }
for(i=0;i <MAX_ANZ_MENU;i++) { DestroyMenu(m_hMenu[i]); }
for(i=0;i <MAX_ANZ_HWND;i++) { DestroyWindow(m_hwnd[i]);}
destroy_mdi_classen();// freigeben:myClientClass,myFrameClass,myEditClass
return m_msg.wParam;
}
-->
Hier einige "Brocken" zur Aufgabe 6
ACHTUNG!
return FALSE meint break;
return TRUE meint return 0;
//globale Konstanten:
#define FIRST_CHILD_IDX
50000
#define
HWND
#define
HMENU
MAX_ANZ_HWND
((int)30)
m_hwnd[ MAX_ANZ_HWND]; // [0] ist das hauptfenster bzw. MDI-Frame
MAX_ANZ_MENU
((int)10)
m_hMenu[MAX_ANZ_MENU]; // [] für menu's
HACCEL
HWND
HWND
MSG
HINSTANCE
m_hAccel;
m_hClient;
m_hDlg;
m_msg;
m_hInst;
//
//
//
//
//
aktuelle Accel-Tabelle
mdi-Client-fenster
aktueller Dialog
aktuelle Nachricht
= GetModuleHandle(0);
#define
MAX_BUF
1024
CHAR m_buf[MAX_BUF], *m_pSrc, *m_pDst,*m_pPrae,*m_pPost,*m_pFind;
int m_idxSel1, m_idxSel2;
// gehört hwnd zu einer bestimmten Fnster-Class?
BOOL is_hwnd_class(HWND hwnd, TCHAR *className)
{
TCHAR buf[512];
int anz = GetClassName(hwnd, buf, 512);
int diff= CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE
| NORM_IGNOREKANATYPE
| NORM_IGNOREWIDTH,buf,-1,className,-1);
//if(GetWindowLong(hwnd,GWL_STYLE)&DS_MODALFRAME) ...
return (diff == CSTR_EQUAL);
}
// oft benötigte hwnd's:
HWND get_aktiv_child(void)
{
HWND hChild = (HWND)SendMessage(m_hClient,WM_MDIGETACTIVE,0,0);
return hChild;
}
HWND get_aktiv_edit(void)
{
HWND hChild = get_aktiv_child();
HWND hEdit = GetWindow(hChild,GW_CHILD);
return hEdit;
}
BOOL IDM_FILE_SAVE_AS(void)
{
HWND hwnd = get_aktiv_edit();
TCHAR szFileName[_MAX_PATH];
szFileName[0] = '\0';
OPENFILENAME ofn = { 0 };
ofn.lStructSize
= sizeof( OPENFILENAME );
ofn.hwndOwner
= hwnd ;
ofn.hInstance
= GetModuleHandle(0);
ofn.lpstrTitle
= TEXT("Speichern unter ...");
ofn.lpstrFile
= szFileName;
ofn.nMaxFile
= _MAX_PATH;
ofn.lpstrFilter
= TEXT("Text-Dateien (*.txt;)\000 *.txt;\000")\
TEXT("Alle Files (*.*)\000*.*\000");
ofn.Flags
= OFN_OVERWRITEPROMPT ;
if (!GetSaveFileName(&ofn))
return FALSE;
SECURITY_ATTRIBUTES sa={0}; sa.nLength = sizeof(sa);
DWORD dwCreateFlag = OPEN_ALWAYS;
HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,
&sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0);
BOOL isErr=(hFile==INVALID_HANDLE_VALUE); err_if(isErr,"hFile"); if(isErr) return
FALSE;
DWORD nZuSchreiben = Edit_GetTextLength(hwnd);
CHAR *p = new CHAR[nZuSchreiben+2]; if(!p) return FALSE;
memset(p,0,nZuSchreiben+2);
Edit_GetText(hwnd,p,nZuSchreiben);
DWORD nGeschrieben;
BOOL ok1 = WriteFile(hFile,p,nZuSchreiben,&nGeschrieben,0); err_if(!ok1,"write");
HRESULT ok2 = CloseHandle(hFile); err_if(!ok2,"end");
if(p) delete [] p;
// Edit_SetText(hwnd,p); if(p) delete [] p;
// Edit_SetText(hwnd,p); if(p) delete [] p;
return TRUE;
}
// File-Open-Standard-Dialog
BOOL IDM_FILE_OPEN(void)
{
HWND hwnd = get_aktiv_edit();
TCHAR szFileName[_MAX_PATH];
szFileName[0] = '\0';
OPENFILENAME ofn = { 0 };
ofn.lStructSize
= sizeof( OPENFILENAME );
ofn.hwndOwner
= hwnd ;
ofn.hInstance
= GetModuleHandle(0);
ofn.lpstrFile
= szFileName;
ofn.nMaxFile
= _MAX_PATH;
ofn.lpstrDefExt
= "*" ;
ofn.nFilterIndex = 1L ;
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.lpstrTitle
= TEXT("Öffnen");
ofn.lpstrFilter
= TEXT("C-Dateien (*.c;*.cpp;*.h;*.rc;)\000
*.c;*.cpp;*.h;*.rc;\000")\
TEXT("Text-Dateien (*.txt;)\000 *.txt;\000")\
TEXT("Alle Files (*.*)\000 *.*;\000\000");
if (!GetOpenFileName(&ofn)) return FALSE;
//Filename ist nun in (char*)ofn.lpstrFile;
BOOL ok = (szFileName && *szFileName);
err_if(!ok,"FILE_STRUCT ohne Filenamen"); if(!ok) return FALSE;
TCHAR drive[32]; TCHAR dir[256];
TCHAR fname[256];TCHAR ext[32];
_splitpath(szFileName,drive,dir,fname, ext);
//_makepath(path, drive, dir,"","");
if(!drive[0]&&!dir[0]){
TCHAR szTemp[_MAX_PATH]; LPSTR pName;
if (!GetFullPathName(szFileName,_MAX_PATH,szTemp,&pName)) {
lstrcpyn( szTemp, szFileName,_MAX_PATH);
} lstrcpyn(szFileName,szTemp,_MAX_PATH);
} else {
lstrcpyn(szFileName,szFileName,_MAX_PATH);
}
SECURITY_ATTRIBUTES sa={0}; sa.nLength = sizeof(sa);
DWORD dwCreateFlag = OPEN_ALWAYS;
HANDLE hFile = CreateFile(szFileName,
GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,
&sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL,0);
BOOL isErr=(hFile==INVALID_HANDLE_VALUE); err_if(isErr,"hFile"); if(isErr) return
FALSE;
DWORD nZuLesen = GetFileSize(hFile,0); if(!nZuLesen) return FALSE;
CHAR *p = new CHAR[nZuLesen+2]; if(!p) return FALSE;
memset(p,0,nZuLesen+2);
//DWORD dwOld = SetFilePointer(hFile,0,NULL,FILE_CURRENT);
//DWORD dwNew = SetFilePointer(hFile,0,NULL,FILE_BEGIN);
DWORD nGelesen;
BOOL ok1 = ReadFile(hFile,p,nZuLesen,&nGelesen,0); err_if(!ok1,"read");
//SetFilePointer(hFile,dwOld,NULL,FILE_CURRENT);
HRESULT ok2 = CloseHandle(hFile); err_if(!ok2,"end");
Edit_SetText(hwnd,p); if(p) delete [] p;
return TRUE;
}
BOOL CALLBACK EnumCloseProc(HWND hwnd, LPARAM lParam)
{
// falls Client-Fenster? - nicht abbauen:
if(GetWindow(hwnd,GW_OWNER)) return TRUE;
// Nachricht an das Client-Fenster: Dokument zurück auf Originalgröße
SendMessage(GetParent(hwnd),WM_MDIRESTORE,(WPARAM) hwnd, 0);
// Nachricht an das Dokumentenfenster: Schließen OK?
if(!SendMessage(hwnd,WM_QUERYENDSESSION,0,0)) return TRUE;
// OK. Nachricht an das Client-Fenster: Dokumentenfenster abbauen
SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM)hwnd, 0);
return TRUE;
}
//////////////////////////////////////////////////
// für mdi_frame_proc:
//////////////////////////////////////////////////
BOOL IDM_EDIT_NEW_TEXT(void)
{ // erstes/nächstes NEUES Edit-Fenster
create_mdi_edit_window(TEXT("Edit für temporäre Nutzung"));
return FALSE;
}
BOOL IDM_WINDOW_CLOSE_TEXT(void)
{ // aktives Dokumentenfenster schließen
HWND hChild = get_aktiv_child();
if(SendMessage(hChild,WM_QUERYENDSESSION,0,0))
SendMessage(m_hClient,WM_MDIDESTROY,(WPARAM) hChild, 0);
return FALSE;
}
BOOL IDM_WINDOW_SHOWDEFAULT(void)
{
HWND hChild = get_aktiv_child();
ShowWindow(hChild,SW_SHOWDEFAULT);
return FALSE;
}
BOOL IDM_WINDOW_SHOWMINIMIZE(void)
{
HWND hChild = get_aktiv_child(); if(!hChild) return TRUE;
ShowWindow(hChild,SW_SHOWMINIMIZED);
SendMessage(hChild,WM_SYSCOMMAND,SC_NEXTWINDOW,0);
return FALSE;
}
BOOL IDM_WINDOW_SHOWMAXIMIZE(void)
{
HWND hChild = get_aktiv_child();
if(IsWindow(hChild))
SendMessage(m_hClient,(UINT)WM_MDIMAXIMIZE,(WPARAM)hChild,0);
return FALSE;
}
BOOL CALLBACK EnumAllMinimize(HWND hwnd, LPARAM lParam)
{
if(is_hwnd_class(hwnd,myEditClass)) {
ShowWindow(hwnd,SW_SHOWMINIMIZED);
} return TRUE;
}
BOOL CALLBACK EnumAllDefault(HWND hwnd, LPARAM lParam)
{
if(is_hwnd_class(hwnd,myEditClass)) {
ShowWindow(hwnd,SW_NORMAL);
} return TRUE;
}
BOOL CALLBACK EnumAllMaximize(HWND hwnd, LPARAM lParam)
{
if(is_hwnd_class(hwnd,myEditClass)) {
ShowWindow(hwnd,SW_SHOWMAXIMIZED);
} return TRUE;
}
BOOL IDM_WINDOW_ALL_MINIMIZE(void)
{
EnumChildWindows(m_hClient,EnumAllMinimize,0);
return FALSE;
}
BOOL IDM_WINDOW_ALL_DEFAULT(void)
{
EnumChildWindows(m_hClient,EnumAllDefault,0);
return FALSE;
}
BOOL IDM_WINDOW_ALL_MAXIMIZE(void)
{
EnumChildWindows(m_hClient,EnumAllMaximize,0);
return FALSE;
}
BOOL IDM_APP_EXIT(void)
{ HWND hwnd = m_msg.hwnd;
SendMessage(hwnd,WM_CLOSE,0,0);
return FALSE;
}
BOOL IDM_WINDOW_TILE_VERTIKAL(void)
{ // Nachrichten zum Anordnen der Dokumentenfenster
//
SendMessage(m_hClient,WM_MDITILE,0,0);
//
oder:
WORD nWindows =
TileWindows(m_hClient,MDITILE_VERTICAL,0,0,0);
return FALSE;
}
BOOL IDM_WINDOW_TILE_HORIZONTAL(void)
{ WORD nWindows =
TileWindows(m_hClient,MDITILE_HORIZONTAL,0,0,0);
return FALSE;
}
BOOL IDM_WINDOW_CASCADE(void)
{ SendMessage(m_hClient,WM_MDICASCADE,0,0);
return FALSE;
}
BOOL IDM_WINDOW_ARRANGE(void)
{ // SendMessage(m_hClient,WM_MDIICONARRANGE,0,0);
// oder:
UINT height = ArrangeIconicWindows(m_hClient);
return FALSE;
}
BOOL IDM_WINDOW_CLOSEALL(void)
{ // Schließen aller Dokumentenfenster
EnumChildWindows(m_hClient, EnumCloseProc, 0);
return FALSE;
}
BOOL IDM_ENUM_CHILD_WINDOW_DATEN(void)
{ static LPARAM num; num = 0;
EnumChildWindows(m_hClient,EnumCallBack,(LPARAM)&num);
return TRUE;
}
BOOL IDM_ENUM_ALL_WINDOW_DATEN(void)
{ static LPARAM num; num = 0;
EnumWindows(EnumCallBack,(LPARAM)&num);
return TRUE;
}
BOOL IDM_EDIT_NEXT(void)
{
HWND hChild = get_aktiv_child();
PostMessage(hChild,WM_SYSCOMMAND,SC_NEXTWINDOW,0);
return TRUE;
}
//////////////////////////////////////////////////
// für mdi_frame_proc:
//////////////////////////////////////////////////
BOOL IDM_EDIT_SELECT_ALL(void)
{
HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,EM_SETSEL,0,-1); return FALSE;
}
BOOL IDM_EDIT_PASTE(void)
{ HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,WM_PASTE,0,0); return FALSE;
}
BOOL IDM_EDIT_CLEAR(void)
{ HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,WM_CLEAR,0,0); return FALSE;
}
BOOL IDM_EDIT_COPY(void)
{ HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,WM_COPY,0,0); return FALSE;
}
BOOL IDM_EDIT_CUT(void)
{ HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,WM_CUT,0,0); return FALSE;
}
BOOL IDM_EDIT_UNDO(void)
{ HWND hEdit = get_aktiv_edit();
SendMessage(hEdit,WM_UNDO,0,0); return FALSE;
}
BOOL IDM_FIND_MARKIERTEN_TEXT(void)
{
HWND hwnd = get_aktiv_child();
HWND hEdit = get_aktiv_edit();
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) return TRUE;
if(!is_hwnd_class(hwnd, myEditClass)) return TRUE;
// hole die selektierten Text-Positionen:
DWORD hilo = SendMessage(hEdit,(UINT)EM_GETSEL,
(WPARAM)&m_idxSel1,(LPARAM)&m_idxSel2);
int nSel = m_idxSel2 - m_idxSel1;
if(nSel <=0 ) return TRUE;
// Wieviele Buchstaben enthält hEdit?
int nSrc = Edit_GetTextLength(hEdit);
err_if(nSrc<=0,"nSrc<=0");
// falls m_pSrc bereits allokiert ist,
// dann erst freigeben:
if (m_pSrc) {free(m_pSrc); m_pSrc = 0;}
m_pSrc = (CHAR*)malloc((nSrc+10)*sizeof(CHAR));
memset(m_pSrc,0,(nSrc+10)*sizeof(CHAR));
err_if(!m_pSrc,"m_pSrc = new ?");
// hole hEdit-Text nach m_pSrc-Heap:
nSrc = Edit_GetText(hEdit,m_pSrc,nSrc);
//memset(buf,0,MAX_BUF*sizeof(CHAR));
// hole selektierten text in buf
for(int i=0; i < nSel;i++) {
if((i+2) >= MAX_BUF) break;
m_buf[i] = m_pSrc[m_idxSel1 + i];
} m_buf[i] = (CHAR)0;
// suche das nächste Auftreten:
m_pFind = strstr(m_pSrc + m_idxSel2,m_buf);
if (m_pFind) {
m_idxSel1 = m_pFind - m_pSrc;
m_idxSel2 = m_idxSel1 + strlen(m_buf);
} else {
MessageBox(hwnd,"Ende des\r\nEditor-Textes","Hinweis",MB_OK);
m_idxSel2 = m_idxSel1 = 0;
// gleich weiter vom Anfang her:
m_pFind = strstr(m_pSrc,m_buf);
m_idxSel1 = m_pFind - m_pSrc;
m_idxSel2
= m_idxSel1 + strlen(m_buf);
Edit_SetSel(hEdit,m_idxSel1,m_idxSel2);
}
SetFocus( hEdit );
Edit_SetSel(hEdit,m_idxSel1,m_idxSel2);
Edit_ScrollCaret(hEdit);
if (m_pSrc) {free(m_pSrc);m_pSrc = 0;}
return TRUE;
}
BOOL IDM_ERSETZE_PRAE_POST(void)
{ HWND hwnd = get_aktiv_child();
HWND hEdit = get_aktiv_edit();
if(!is_hwnd_class(hEdit,TEXT("EDIT"))) return TRUE;
if(!is_hwnd_class(hwnd, myEditClass)) return TRUE;
CHAR ch;
// Wieviele Buchstaben enthält hEdit?
// 4 mehr allokieren:
int nSrc = 4 + Edit_GetTextLength(hEdit);
int nPrae = strlen(m_pPrae);
int nPost = strlen(m_pPost);
// falls m_pSrc allokiert ist, erst freigeben
if (m_pSrc) { free(m_pSrc); m_pSrc=0; }
// allokiere für Src von hEdit:
m_pSrc = (CHAR*)malloc((nSrc)*sizeof(CHAR));
err_if(!m_pSrc,"m_pSrc = new ?");
// falls m_pDst allokiert ist, erst freigeben:
if (m_pDst) { free(m_pDst); m_pDst=0;}
// allokiere für Dst (zusammen gesetzter text):
int nDst = nSrc + nPrae + nPost;
m_pDst = (CHAR*) malloc((nDst)*sizeof(CHAR));
err_if(!m_pDst,"m_pDst = new ?");
// alle Speicher auf 0 setzen:
memset(m_pSrc,0,(nSrc)*sizeof(CHAR));
memset(m_pDst,0,(nDst)*sizeof(CHAR));
memset(m_buf,0,MAX_BUF*sizeof(CHAR));
// hole hEdit-Text nach m_pSrc
int nSrc1 = Edit_GetText(hEdit,m_pSrc,nSrc);
// Ist was Markiert?
DWORD hilo = SendMessage(hEdit,(UINT)EM_GETSEL,
(WPARAM)&m_idxSel1,(LPARAM)&m_idxSel2);
int nSel = m_idxSel2 - m_idxSel1;
// anfangs-string ins Ziel:
ch = m_pSrc[m_idxSel1];
m_pSrc[m_idxSel1]=(CHAR)0;
strcat(m_pDst,m_pSrc);
m_pSrc[m_idxSel1]=ch;
// m_pPrae ins Ziel:
if(nPrae > 0) strcat(m_pDst,m_pPrae);
ch=m_pSrc[m_idxSel2];
m_pSrc[m_idxSel2]=(CHAR)0;
strcat(m_buf,&m_pSrc[m_idxSel1]);m_pSrc[m_idxSel2]=ch;
// tue markierten-text ins Ziel:
strcat(m_pDst,m_buf);
// m_pPost ins Ziel:
if(nPost > 0) strcat(m_pDst,m_pPost);
// rest von m_pSrc ins Ziel:
strcat(m_pDst,&m_pSrc[m_idxSel2]);
// hinterlege im Editor:
Edit_SetText(hEdit,m_pDst);
SetFocus(hEdit);
Edit_SetSel(hEdit,m_idxSel1,m_idxSel1);
Edit_ScrollCaret(hEdit);
// allokierten Speicher freigeben:
if (m_pSrc) { free(m_pSrc); m_pSrc=0; }
if (m_pDst) { free(m_pDst); m_pDst=0; }
return FALSE;
}
///////////////////////////////////////////
// einige Tags
///////////////////////////////////////////
BOOL IDM_DO_P_TAG(void)
{
HWND hwnd = m_msg.hwnd;
m_pPrae = "<p>\r\n";
m_pPost = "<\\p>\r\n";
SendMessage(hwnd,WM_COMMAND,(WPARAM)IDM_ERSETZE_PRAE_POST,0);
return FALSE;
}
BOOL IDM_DO_PRE_TAG(void)
{
HWND hwnd = m_msg.hwnd;
m_pPrae = "\r\n<pre class=\'box\'>";
m_pPost = "\r\n</pre>\r\n";
SendMessage(hwnd,WM_COMMAND,(WPARAM)IDM_ERSETZE_PRAE_POST,0);
return FALSE;
}
BOOL IDM_DO_CENTER_TAG(void)
{
HWND hwnd = m_msg.hwnd;
m_pPrae = "\r\n<div style=\'text-align:center;\'>\r\n";
m_pPost = "\r\n</div>\r\n";
SendMessage(hwnd,WM_COMMAND,(WPARAM)IDM_ERSETZE_PRAE_POST,0);
return FALSE;
}
BOOL IDM_DO_IMG_TAG(void)
{
HWND hwnd = m_msg.hwnd;
m_pPrae = "\r\n<img src=\'--1 a_logo.gif\' alt=\'--1 a_logo.gif\' />\r\n";
m_pPost = "";
SendMessage(hwnd,WM_COMMAND,(WPARAM)IDM_ERSETZE_PRAE_POST,0);
return FALSE;
}
BOOL IDM_DO_GRUNDGERUEST(void)
{
HWND hwnd = m_msg.hwnd;
m_pPrae = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "\
"\r\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"\
"\r\n<html>\r\n<head>\r\n<title><!--[1] hier den Titel der html-Page einfügen -->"\
"\r\n</title>\r\n<script type=\'text/javascript\'>/*<![CDATA[*/
\r\n/*]]>*/</script>"\
"\r\n\r\n<style type=\'text/css\'>\r\nbody {display:block;"\
"\r\n background:#f8f8f8; color:#000000;"\
"\r\n margin:2px 2px 2px 8px; padding:0;"\
"\r\n width:expression(document.documentElement.clientWidth - 12);/* MS */"\
"\r\n /* background-image:url(\"bg_menu0.gif\"); */"\
"\r\n background-image:url(\"bg_menu0.gif\"); \r\n}\r\n"\
"\r\na { display:block; font-size:10pt; font-weight:bold;line-height:92%; "\
"\r\n color:#000000;text-decoration:none; text-align:center;"\
"\r\n border-width: 4px; border-color: #e3e3e3;"\
"\r\n border-style: outset; background:#e3e3e3;"\
"\r\n}\r\n\r\ntd {padding-left:4pt;padding-right:4pt;}"\
"\r\ntfoot {font-size:90%;line-height:92%;background:#f8f8f8;color:#000000;}"\
"\r\nthead {font-size: 110%;font-weight:bold; text-align:center;"\
"\r\n background:#999999; color:#FFFFFF;\r\n}"\
"\r\n.box{ background:#fdfdff;padding:0.2em 0.2em 0.2em 0.7em;border:1px solid
#ddddee;}"\
"\r\n.center{text-align:center}"\
"\r\n.grau1i{background:#999999;color:#FFFFFF;"\
"\r\n font-weight:bold;padding-left:4pt;padding-right:4pt;\r\n}"\
"\r\n.grau3 {background:#f8f8f8;color:#000000;}
"\
"\r\n.big {display:inline;font-size:130%;}"\
"\r\n.fett {display:inline;font-weight:bold;}"\
"\r\n.lolu {display:inline;font-weight:bold;border:1px solid #cccccc;"\
"\r\n border-left:none; padding-left:4pt;"\
"\r\n border-right:none;padding-right:4pt;\r\n}"\
"\r\n</style>"\
"\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"
/>"\
"\r\n</head>\r\n<body>\r\n";
m_pPost =
"\r\n<!--[2] hier Pagegestaltung einfügen -->\r\n"\
"\r\n<!--[3] hier Pagegestaltung einfügen -->\r\n"\
"\r\n<!--[4] hier Pagegestaltung einfügen -->\r\n"\
"\r\n</body>\r\n</html>\r\n";
SendMessage(hwnd,WM_COMMAND,(WPARAM)IDM_ERSETZE_PRAE_POST,0);
return FALSE;
}
void create_mdi_classen()
{
ATOM atom; WNDCLASSEX wc;
// aus TEXT("MDICLIENT") mach myClientClass
wc.cbSize = sizeof(wc);
BOOL ok = GetClassInfoEx(m_hInst,TEXT("MDICLIENT"),&wc);
wc.hInstance
= m_hInst;
wc.hbrBackground =(HBRUSH) GetStockObject(BLACK_BRUSH);
wc.lpszClassName = myClientClass;
atom = RegisterClassEx(&wc);
// Fensterklasse für das Rahmenfenster anlegen:
memset(&wc,0,sizeof(wc));
wc.cbSize
= sizeof(wc);
wc.style
= CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc
= mdi_default_frame_proc;
wc.cbClsExtra
= sizeof(HANDLE);
wc.cbWndExtra
= sizeof(HANDLE);
wc.hInstance
= m_hInst;
wc.hIcon
= ExtractIcon(m_hInst,myShellDll,43);
wc.hCursor
= LoadCursor(0,IDC_ARROW);
wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = myFrameClass;
atom = RegisterClassEx(&wc);
// Fensterklasse für das Edit-Window
memset(&wc,0,sizeof(wc));
wc.cbSize
= sizeof(wc);
wc.style
= CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc
= myChildProc;//mdi_default_child_proc;
wc.lpszClassName = myEditClass;
wc.cbClsExtra
= 4;
wc.cbWndExtra
= 4;
wc.hInstance
= m_hInst;
wc.hCursor
= LoadCursor(0,IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hIcon
= ExtractIcon(m_hInst,myShellDll,2);
//wc.lpszMenuName = NULL;
atom = RegisterClassEx(&wc);
}
BOOL CALLBACK EnumCallBack(HWND nhWnd, LPARAM lParam)
{
//#define
hwnd
m_hwnd[MAX_ANZ_HWND-1]
static HWND hwnd;
CHAR buffer
[1024];
CHAR classname[ 512];
CHAR titel
[ 512];
int nSrc
=
512;
HWND hEdit = NULL; if(!IsWindow(nhWnd)) return TRUE;
int
Nummer = *(int*)lParam;
if(*(int*)lParam == 0) { // Überschrift
*(int*)lParam = 1;
//if(hwnd) SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM)hwnd, 0);
hwnd = create_mdi_edit_window(TEXT("fenster-anzeige"));
err_if(!hwnd,"EnumCallBack: kein Zielfenster");
memset(buffer,0,nSrc);
wsprintf(buffer,TEXT("\r\n nr |
hwnd
|
Class
|
Titel") \
TEXT("\r\n====|==========|====================|==========\r\n"));
hEdit = GetWindow(hwnd,GW_CHILD);
if(!IsWindow(hEdit)) return FALSE;
SetWindowText(hEdit,TEXT(""));
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buffer);
SetFocus(hEdit);
}
memset(titel,
0, nSrc);
memset(classname,0, nSrc);
memset(buffer,
0,2*nSrc);
int nMax = GetWindowTextLength(nhWnd);
if (nMax>0) GetWindowText(nhWnd,titel,nSrc-2);
int anz = GetClassName(nhWnd,classname,nSrc-2);
wsprintf(buffer,TEXT("%03i | %08x | %18s | %s \r\n"),
(*(int*)lParam)-1,nhWnd,classname,titel);
(*(int*)lParam)++;
hEdit = GetWindow(hwnd,GW_CHILD);if(!IsWindow(hEdit)) return FALSE;
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buffer);
SetFocus(hEdit); return TRUE;
//#undef hwnd
}
HWND create_mdi_edit_window(TCHAR *pTitel)
{
int xPos=0;int yPos=0; int dx=0;int dy=0;
// FrameWindow als Childfenster [1] anlegen
if((xPos<0)||(yPos<0)||(dx<=0)||(dy<=0)) {
xPos = yPos = dx = dy = CW_USEDEFAULT;
}
HWND hChild = ::CreateMDIWindow(
myEditClass, // class
pTitel, // window caption
WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,
xPos,yPos,dx,dy, m_hClient,m_hInst,NULL);
//::BringWindowToTop(hChild);
// zusätzlich ein "EDIT" ins Child-Fenster
WNDCLASSEX wc; memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
GetClassInfoEx(GetModuleHandle(0),TEXT("EDIT"),&wc);
RECT rc; GetClientRect(hChild, &rc );
//WS_EX_CLIENTEDGE|WS_EX_CONTROLPARENT
//HWND hEdit =
CreateWindowEx(WS_EX_CLIENTEDGE|WS_EX_CONTROLPARENT,TEXT("EDIT"),0,
HWND hEdit = CreateWindow(TEXT("EDIT"),0,
WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL
|ES_WANTRETURN|ES_MULTILINE
|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
rc.left,rc.top,rc.right,rc.bottom,
hChild,(HMENU)hChild,m_hInst,0);
err_if(!hEdit,"kein hEdit");
SendMessage(hEdit,WM_SETFONT,
(WPARAM)GetStockObject(ANSI_FIXED_FONT),TRUE);
SetFocus(hEdit); return hChild;
}
void versionstest(void)
{
DWORD dwVersion = GetVersion();
DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
err_if(dwWindowsMajorVersion<5,"leider zu alte Windows-Version ...");
/*
DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
DWORD dwBuild = 0;
if (dwVersion < 0x80000000)
// Windows NT
dwBuild = (DWORD)(HIWORD(dwVersion));
else if (dwWindowsMajorVersion < 4)
// Win32s
dwBuild = (DWORD)(HIWORD(dwVersion) & ~0x8000);
else dwBuild = 0;
// Windows Me/98/95
*/
}
int WINAPI WinMain(HINSTANCE, HINSTANCE hInst, PSTR, int)
{
m_hInst = GetModuleHandle(0);
versionstest();
create_all_menu();
create_mdi_classen();
// FrameWindow als Rahmenfenster [0] anlegen
int xPos=0; int yPos=0;
dx = GetSystemMetrics(SM_CXSCREEN);
dy = GetSystemMetrics(SM_CYSCREEN);
// Rahmenfenster anlegen
m_hwnd[0] = CreateWindow(
myFrameClass, myAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
xPos,yPos,dx,dy,NULL,m_hMenu[0],m_hInst,0);
// m_hClient wurde unter WM_CREATE angelegt
m_hClient = GetWindow(m_hwnd[0], GW_CHILD);
err_if(!m_hClient,"m_hClient");
ShowWindow(m_hwnd[0], SW_SHOW);
UpdateWindow(m_hwnd[0]);
m_hwnd[1] = create_mdi_edit_window(TEXT("[1]"));
m_hwnd[2] = create_mdi_edit_window(TEXT("[2]"));
// Hauptnachrichtenschleife
main_loop();
int i; // Aufräumen: (Menüs, ...)
// freigeben:UnregisterClass: myClientClass,myFrameClass,myEditClass
// DestroyIcon(m_hIconOld);
// Klassen ...
for(i=0;i<MAX_ANZ_MENU;i++) { DestroyMenu(m_hMenu[i]); }
for(i=0;i<MAX_ANZ_HWND;i++) { DestroyWindow(m_hwnd[i]);}
return m_msg.wParam;
}
7. SP2-Praktikum (SS 2005)
Diese Aufgabe besteht darin, das Erstellen von DLL's zu üben und eine "kleine brauchbaren" Windows-Anwendung (nach freiem Ermessen mit *.dll, *.lib, Dokumentation) zu entwickeln und zu testen.
Hinweise
In der Entwicklungsumgebung sind 2 Projekte anzulegen. Zunächt ein Projet für das Erstellen einer Dll, dann ein Projet für eine Console-Applikation.
●
1.Projekt: sp2_dll ( Windows-DLL, beginnend mit einem leeren Projekt )
●
2.Projekt: sp2_app ( Console-Applikation, beginnend mit einem leeren Projekt )
In das Projekt sp2_dll ( 1.Projekt ) sind zunächst die beiden Files sp2_dll.h, sp2_dll.cpp einzufügen. Die Übersetzung soll die Files sp2_dll.dll und sp2_dll.lib erstellen (Bitte nachschauen). Später soll die
Anwendung ( 2. Projekt: sp2_app als Console-Applikation) die erstellten DLL-Files ( sp2_dll.dll und sp2_dll.lib ) nutzen.
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
Beim Programmieren von neuen Applikationen wird nicht nur die *.dll benötigt, sondern auch die zugehörige *.lib. Hier kommt ein einführendes Beispiel, das als erste Grundlage zum Erstellen der DLL
und der LIB verwendet werden soll. Zunächst sind die sp2_dll.dll und die sp2_dll.lib zu erstellen. Im Header-File sp2_dll.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: sp2_dll.h
#ifndef sp2_dll_H
#define sp2_dll_H
///////////////////
#include <windows.h>
#ifdef _DLLBUILD_
#define DLL_API
#else
#define DLL_API
#endif
__declspec( dllexport )
File: sp2_dll.cpp
#define _DLLBUILD_
#include "sp2_dll.h"
///////////////////////////////////
// einige DLL-Test-Beispiele
///////////////////////////////////
DLL_API HINSTANCE hInst = 0;
DLL_API HINSTANCE GetDllInstance() { return hInst; }
__declspec( dllimport )
///////////////////////////////////
// Funktions-Prototyp:
///////////////////////////////////
DLL_API int sp2_dllFunc( int i );
DLL_API HINSTANCE GetDllInstance(void);
///////////////////////////////////
// Referenz:
///////////////////////////////////
extern DLL_API
int sp2_dllInt;
///////////////////////////////////
// C++-Klasse:
//
ohne tiefen Copy-Konstruktor!
DLL_API
DLL_API
DLL_API
DLL_API
void func();
int i = 10;
int j;
int n;
///////////////////////////////////
// Konstruktor der Klasse
///////////////////////////////////
sp2_dllClass::sp2_dllClass() {
return;
}
///////////////////////////////////
// SHARED-Variablen in der DLL
///////////////////////////////////
#pragma data_seg("SHARED")
///////////////////////////////////
class DLL_API sp2_dllClass {
public:
sp2_dllClass(void); //Konstruktor
};
///////////////////////////////////
#endif //sp2_dll_H
///////////////////////////////////
//exportierte Variable
DLL_API int sp2_dllInt = 1;
//exportierte Funktion.
DLL_API int sp2_dllFunc(int i) {
char buf[256];
int j = i + sp2_dllInt;
sp2_dllInt += 10;
wsprintf( buf, "i + sp2_dllInt = %d", j );
MessageBox(0,buf,0,MB_OK);
return j;
}
#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")
///////////////////////////////////
// DllMain ist Pflicht
///////////////////////////////////
BOOL WINAPI DllMain( HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH:
break;
}
hInst = hinstDLL;
return TRUE;
}
Applikation-Erstellung
Das 1.Projekt: sp2_app enthält die Windows-Applikation. Weil der sp2_app.exe-File die Dll zunächst im eigenen Direktory sucht, so ist es günstig die Linker-Ausgabe in das Debug-Verzeichnis des DLLProjektes umzuleiten. Dort befinden sich bereits sp2_dll.dll und sp2_dll.lib. Dem Linker muss noch die benötigte LIB ( sp2_dll.lib ) mitgeteilt werden. Dies kann erfolgen mit:
#include "..\\sp2_dll\\sp2_dll.h"
#pragma comment(lib, "..\\sp2_dll\\debug\\sp2_dll.lib")
Ein Test ist:
#undef _DLLBUILD_
#include "..\\sp2_dll\\sp2_dll.h"
#pragma comment(lib, "..\\sp2_dll\\debug\\sp2_dll.lib")
void main() {
ZUNÄCHST MIT DEM DEBUGGER ANSEHEN!
Wie kann die sp2_dll.dll erreicht werden?
// Ein Test ist:
///////////////////
// hier folgt myApp.cpp
// Teste z.B.
HINSTANCE hInstDll = GetDllInstance();
HINSTANCE hInst
= GetModuleHandle(0);//=hInstance
int i1 = sp2_dllInt;
// i1 = ???
int i2 = sp2_dllFunc(i1); // i2 = ???
int i3 = sp2_dllInt;
// 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);
}
Kontroll-Fragen:
1. Wozu gibt es DLL's?
2. Wie unterscheiden sich .dll's von .exe?
3. Funktioniert hInstance = GetModuleHandle(0) auch bei DLL's?
4. Was kann eine DLL enthalten?
5. Wozu kann eine DLL nicht verwendet werden?
6. Wie unterscheidet sich das implizite und expliziete Laden einer DLL?
7. Was hat der Linker mit DLL'S zu tun?
Beispiel:
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
Beim Programmieren von neuen Applikationen wird nicht nur die *.dll benötigt, sondern auch die zugehörige *.lib. Hier kommt ein einführendes Beispiel, das als erste Grundlage zum Erstellen der DLL
und der LIB verwendet werden soll. Zunächst sind die sp2_dll.dll und die sp2_dll.lib zu erstellen. Im Header-File sp2_dll.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: sp2_dll.h
File: sp2_dll.cpp
#ifndef sp2_dll_H
#define sp2_dll_H
///////////////////
#include <windows.h>
#ifdef _DLLBUILD_
#define DLL_API
#else
#define DLL_API
#endif
__declspec( dllexport )
#define _DLLBUILD_
#include "sp2_dll.h"
///////////////////////////////////
// einige DLL-Test-Beispiele
///////////////////////////////////
DLL_API HINSTANCE hInst = 0;
DLL_API HINSTANCE GetDllInstance() { return hInst; }
__declspec( dllimport )
///////////////////////////////////
// Funktions-Prototyp:
///////////////////////////////////
DLL_API int sp2_dllFunc( int i );
DLL_API HINSTANCE GetDllInstance(void);
///////////////////////////////////
// Referenz:
///////////////////////////////////
extern DLL_API
int sp2_dllInt;
///////////////////////////////////
// C++-Klasse:
//
ohne tiefen Copy-Konstruktor!
///////////////////////////////////
class DLL_API sp2_dllClass {
public:
sp2_dllClass(void); //Konstruktor
};
///////////////////////////////////
#endif //sp2_dll_H
///////////////////////////////////
DLL_API
DLL_API
DLL_API
DLL_API
void func();
int i = 10;
int j;
int n;
///////////////////////////////////
// Konstruktor der Klasse
///////////////////////////////////
sp2_dllClass::sp2_dllClass() {
return;
}
///////////////////////////////////
// SHARED-Variablen in der DLL
///////////////////////////////////
#pragma data_seg("SHARED")
//exportierte Variable
DLL_API int sp2_dllInt = 1;
//exportierte Funktion.
DLL_API int sp2_dllFunc(int i) {
char buf[256];
int j = i + sp2_dllInt;
sp2_dllInt += 10;
wsprintf( buf, "i + sp2_dllInt = %d", j );
MessageBox(0,buf,0,MB_OK);
return j;
}
#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")
///////////////////////////////////
// DllMain ist Pflicht
///////////////////////////////////
BOOL WINAPI DllMain( HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH:
break;
}
hInst = hinstDLL;
return TRUE;
}
Applikation-Erstellung
Das 1.Projekt: sp2_app enthält die Windows-Applikation. Weil der sp2_app.exe-File die Dll zunächst im eigenen Direktory sucht, so ist es günstig die Linker-Ausgabe in das Debug-Verzeichnis des DLLProjektes umzuleiten. Dort befinden sich bereits sp2_dll.dll und sp2_dll.lib. Dem Linker muss noch die benötigte LIB ( sp2_dll.lib ) mitgeteilt werden. Dies kann erfolgen mit:
#include "..\\sp2_dll\\sp2_dll.h"
#pragma comment(lib, "..\\sp2_dll\\debug\\sp2_dll.lib")
Ein Test ist:
#undef _DLLBUILD_
#include "..\\sp2_dll\\sp2_dll.h"
#pragma comment(lib, "..\\sp2_dll\\debug\\sp2_dll.lib")
void main() {
ZUNÄCHST MIT DEM DEBUGGER ANSEHEN!
Wie kann die sp2_dll.dll erreicht werden?
// Ein Test ist:
///////////////////
// hier folgt myApp.cpp
// Teste z.B.
HINSTANCE hInstDll = GetDllInstance();
HINSTANCE hInst
= GetModuleHandle(0);//=hInstance
int i1 = sp2_dllInt;
// i1 = ???
int i2 = sp2_dllFunc(i1); // i2 = ???
int i3 = sp2_dllInt;
// i3 = ???
}
SP2-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 BetriebssystemFunktionalität eingeführt. Der Schwerpunkt liegt auf praktischen Anwendungsaspekten. Wegen des Stoff-Umfanges
kann nur eine spezielle Auswahl behandelt werden.
Kognitive Ziele
Verstehen von Sachverhalten bedeutet, dass wir ( innerhalb eines stillschweigend vorausgesetzten Kontext ) in
Begriffen, Schlüssen, Urteilen denken und Erkenntnisse in Zusammenhänge einordnen können.
●
Beschreibungen antworten auf Wie - Fragen,
●
Erklärungen antworten auf Warum - Fragen.
Praktische Ziele
Im engeren Sinne wird als Grunglage ein aktuelles Betriebssystem ( Windows ) und aktuelle Programmierwerkzeuge
verwendet ( Entwicklungsumgebung, Debbuger, Ressourcen-Erstellung, Nachrichtenverfolgung, usw. ).
Danke
Ich möchte mich
●
bei meiner Frau für das Verständnis,
●
bei den Kollegen für interessante Diskussionen,
●
bei meinen Diplomanden für die geleistete Arbeit,
●
bei den Tutoren für den aufopfernden Einsatz und
●
bei den Studenten für zahlreiche Fragen
bedanken.
Ron Kritzfeld:
Der Pragmatiker entscheidet Fälle
nicht nach Grundsätzen,
sondern fallweise.
In dem Wort "Systemprogrammierung" steckt "System" und "Programmierung". Diese Begriffe werden unten
behandelt.
Was ist ein Programm?
Das Wort Programm kommt aus dem griechischen und bedeutet "schriftliche Bekanntmachung, Tagesordnung". Das
Programmieren möchte ein bestimmtes Verhalten entwickeln, aufschreiben und festlegen um damit Abläufe zu
unterstützen, steuern, regeln. Ein Programm kann bedeuten:
●
Vorhaben
●
ökonomisches Sortiment, Warenangebot
●
Vorstellungs-, Aufführungs-, Vortrags-, Konzertfolge oder Spielfolge ( Theater,
Fernsehen )
●
Angebot an Sendungen ( Gesamtheit der Sendungen des Tages, Rundfunk, Fernsehen )
●
Darlegung von Zielen und Grundsätzen ( politische Partei, Staatsführung )
●
Vorgesehenen Ablauf für eine Reihe von Darbietungen
●
Folge von Tätigkeiten; Arbeitsplan für ein Vorhaben
●
Zeit- od. Terminplan, festlegen der Abfolge von Vorgängen
●
Detailplanung der einzelnen technischen Arbeitsschritte für die Ausführung ( durch
ausführende Einheiten )
●
Folge von Anweisungen an den Computer, mit denen bestimmte Aufgaben von
physikalisch-technischen Einheiten ausgeführt werden ( Realisierung mit Algorithmen,
Programmiersprache, Hardware, Sensoren, Aktoren )
Beispiel: Im Raum von Ressourcen und Wissen entwickelt der Programmatiker ( z.B. Prof. ) ein Vorlesungsprogramm
für eine Veranstaltung. Art und Umfang der Durchführung hängen auch von der Programmatik ( Zielsetzung,
Zielvorstellung ) und der programmatischen ( zielsetzend, richtungsweisend, auf dem Programm beruhenden )
Mitarbeit der Studierenden ab, die zum programmgemäßen ( planmäßig, so wie es geplant ist ) Gelingen beitragen.
allg. Programmiermodell
Das Erstellen einer Schrittfolge ( programmieren ) erfolgt auf einer abstrakten, formalen Ebene (
Projektabwicklungen, militärische Planungen, Arbeitsvorbereitungen, volkswirtschaftliche Verflechtungs- und
Vorgehensmodelle, Software/Hardware-Entwicklungszyklen, Entwicklungsmodelle, usw. ).
Das erstellte Programm garantiert noch nicht die Fehlerfreiheit ( Verwendbarkeit, Ausführung ). In komplexen
Ausführungssystemen ( Organisationen, Computersysteme, Netze, usw. ) können vorausschauenden Beurteilungen
schwierig sein ( Funktionstests, Laufzeitverhalten, Skalierung, Fehlerfreiheit, zusichernde Garantien, Verfeinerungen,
usw. ). Für ein allgemeines, abstraktes Programmier-Modell gibt es unterschiedliche Ansätze. Ein universelles Modell
soll auch für nicht technische Systeme brauchbar sein. Das folgende Modell kann komplexe Prozesse beschreiben und
ist einem Computer-System nachgebildet. Es besteht aus den Komponenten: Memory, Prozessor, Receptor, Effektor,
Enviroment.
Memory
Prozessor
Wandler
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
wandelt um:
<==
Rececptor(
Sensor )
Memory
Prozessor
Wandler
==>
Effektor(
Aktor )
Enviroment
Übertragungsmedium:
Weiterleitung
von
Signalfolgen
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-BindTheorie zur Rolle der Familie bei der Entstehung von Schizophrenie.
Die zunehmende Bevölkerung führte zu Umweltschutz, Grenzen des Wachstums, Populationen, Ökologie,
Biozönosen, Nahrungsbeziehungen zwischen den Arten, usw. Die Biologie und Evolutionstheorie führten zu
verwobenen ( grossen ) Systemen. Die Ökologie ( zu griechisch oikos: Haus und lógos: Lehre ) beschreibt Systeme
undderen Wechselbeziehungen zwischen den Organismen der unbelebten/belebten Umwelt und dem Stoff- und
Energiehaushalt Es wird zwischen der unbelebten Umwelt ( abiotische Faktoren wie Klima, Boden ) und der belebte
Umwelt ( biotische Faktoren ) unterschieden.
●
Die Aut-Ökologie behandelt Beziehungen zwischen Individuum und Umwelt Die DemÖkologie ( Populationsökologie ) behandelt Beziehungen zwischen
Wechselbeziehungen artgleicher Individuen
●
Die Syn-Ökologie behandelt Wechselbeziehungen verschiedener Populationen
Biozönosen kennzeichnet die Gesamtheit aller Lebewesen eines bestimmten
Lebensraums.
●
Die System-Ökologie behandelt Ökosysteme untereinander
●
Die Human-Ökologie behandelt Wechselwirkungen zwischen dem Menschen und
seiner natürlichen und technischen Umwelt
Syllogistik [griechisch] die, Logik: von Aristoteles begründete Lehre vom Schluss als Kernstück der traditionellen
Logik. Aus der Verbindung von zwei Vordersätzen (Prämissen) geht dabei der Schlusssatz (Konklusion) als logische
Folgerung hervor. Die Syllogistik stellt in der modernen Logik einen Teil der prädikatenlogischen Schlüsse dar (
Prädikat lateinisch: auszeichnende Bewertung ).
In der Mathematik ist der von D.Hilbert begründete ( nur aus Axiomen gewonne ) Formalismus als mathematisch
erweisbare Widerspruchsfreiheit gescheitert ( Gegenposition zum Intuitionismus ). K.Gödel hat 1931 den
Unvollständigkeitssatz bewiesen:
Eine mathematische Theorie,
die die Arithmetik umfasst,
und die widerspruchsfrei ist,
kann nicht alle in ihr
wahren Aussagen
beweisen.
Intuitionismus [lateinisch] der, als mathematische Grundlagenforschung die von L.Kronecker, H.Poincaré, H.L.
Lebesgue u.a. vertretene Lehre, dass die Gesamtheit der natürlichen Zahlen intuitiv und unableitbar gegeben sei und
dass sich die Gesamtheit der reellen Zahlen (Kontinuum) arithmetisch nicht bilden lasse. Einen intuitionistischen
Neuaufbau der Mathematik versuchten seit 1907 L.E.J. Brouwer, H.Weyl, A.Heyting u.a. mit der Forderung der
effektiven Konstruktion zur Definition mathematischer Objekte und unter Einschränkung des Tertium non datur (
lateinisch: ein Drittes gibt es nicht; Satzes vom ausgeschlossenen Dritten; ein Axiom, das besagt, dass eine Aussage
gilt oder nicht gilt; eine dritte Möglichkeit besteht nicht ) auf endliche Mengen.
In der Informatik werden in der Systemanalyse Methoden zur Einteilung und Untersuchung von Arbeitsgebieten und
Arbeitsabläufe entwickelt ( Automatisierung, Phase der Softwaretechnik, usw. ).
Aristoteles:
Das Ganze ist mehr als die Summe der Teile.
Im allgemeinen Sinne ist ein System eine Sammlung von Komponenten, die zusammenwirken. Das System enthält
den ganzheitlichen Zusammenhang von Dingen, Vorgängen, Teilen, ( z.B. ökologische Wechselwirkungen in der
Natur; vom Menschen hergestelltes soziologisch-politisches System ) und entspricht einem geordneten,
zusammenwirkendem Ganzen.
Ein System besteht aus wechselwirkenden Komponenten.
Die Wechselwirkungen werden durch Relationen ( Funktionen, Methoden ) ausgedrückt. Die Komponenten (
Elemente, Bausteine, Teile ) haben Eigenschaften, die als Merkmale und Methoden gekennzeichnet werden können.
Ein System besteht aus einer Menge von Elementen, welche Eigenschaften besitzen und durch Relationen miteinander
verknüpft sind.
Ein System ist ein Gebilde ( Gefüge, Komplex, Zusammenstellung ) von bestimmten Objekten ( Komponenten,
Bestandteile, Gegenstände ) zwischen denen Beziehungen ( Verbindungen, Kopplungen ) mit bestimmten
Eigenschaften bestehen. Ein System ist ein Gefüge von Objekten und Beziehungen mit bestimmten Eigenschaften.
Der System - Begriff wird in vielfältiger Weise verwendet. Z.B. sind Programmen, Verfahren, Daten und Methoden
zur Informationsverarbeitung in einem.
In der Informatik wird der System - Begriff in vielfältiger Weise benutzt.
●
Ein Hardware-System besteht z.B. Mikroprozessoren, elektronischen Bausteinen,
elektronischen Geräten, weiteren Schaltungen, physikalischen Sensoren und Aktoren
●
Ein Computer besteht aus System-Software, Betriebssystem, Firmware, Middleware,
Software-Komponenten, Anwendungssoftware, Hardware-System, Speicher-System,
Ein- und Ausgabegeräten, Peripherie, usw.
●
Eingabegeräten ( Tastatur, Maus, Laufwerk ),
●
Ausgabegeräten ( Bildschirm, Laufwerk ) und
●
Peripheriegeräten ( Drucker, Modem )
●
Datenbanksystem ( Anwendungsprogramm zum Erfassen, Suchen, Sortieren und
Verwalten größerer Datenmengen, Daten-, Adressen- und Artikelverwaltung,
Buchhaltungssysteme, Rechnungssystem, SQL-Abfragen, Recherchen, Suchmaschinen
)
●
CIM ( englisch computer integrated manufacturing, rechnerintegrierte Fertigung )
enthält für die Konstruktion und Fertigung mit Hilfe eines Rechners CAD ( ComputerAided-Design ) und CAM ( Computer-Aided-Manufacturing )
Nach DIN 19226 gilt:
Ein System ist eine abgegrenzte Anordnung von aufeinander einwirkenden Gebilden.
Solche Gebilde können sowohl Gegenstände als auch Denkmethoden und deren
Ergebnisse ( z.B. Organisationsformen, mathematische Methoden,
Programmiersprachen) sein. Diese Anordnung wird durch eine Hüllfläche von ihrer
Umgebung abgegrenzt oder abgegrenzt gedacht. Durch die Hüllfläche werden
Verbindungen des Systems mit seiner Umgebung geschnitten. Die mit diesen
Verbindungen übertragenen Eigenschaften und Zustände sind die Größen, deren
Beziehungen untereinander das dem System eigentümliche Verhalten beschreibt.
Durch zweckmäßiges Zusammenfügen und Unterteilen von solchen Systemen
können größere und kleinere Systeme entstehen.
Objektbezogene Systembezeichnungen:
Systeme können nach Prinzipien eingeteilt und unterschieden werden:
abstrakt:
lat. abstrahere
formal äußere Form ( nicht Inhalt )
verbal mündlich
konkret:
gegenständlich
konzipiert lat. concipere
real lat., zu res "Sache"
Etwas auführlicher:
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 ).
abstrakt:
formal Formal meint die äußere Form ( nicht den Inhalt ) und kann ohne Entsprechung in der
Wirklichkeit sein, der Form genügend, nur äußerlich, nicht in Wirklichkeit, Axiome
werden in Zeichen des Operationssystems ausgedrückt
verbal mündlich, mit Worten, mit Hilfe der Sprache
gegenständlich, dinglich, fassbar, wirklich, tatsächlich, anschaulich, sinnlich
wahrnehmbar;
Gegensatz: abstrakt.
konkret:
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 ( MitarbeiterAbteilungsleiter, 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 ).
Eine Schnittstelle (engl. Interface) ist eine Beschreibung von Attributen, Methoden und Ereignissen. Bei SoftwareSchnittstellen besteht der Unterschied zur Klasse (Class) darin, dass die Methoden keine Implementierung enthalten,
d.h. nur die äußeren Form vorgeben. Eine Schnittstelle entspricht einer abstrakten Klasse. Eine Software-Schnittstelle
kann nicht instanziiert, sondern nur als äußerer Rahmen einer Klasse verwendet werden. Dort muss die Schnittstelle
implementiert werden (Deklarieren aller Attribute, Ereignisse, Implementieren der Methoden).
Albert Einstein:
Fortschritt lebt vom Austausch des Wissen.
Software-Ergonomie
Die Schnittstelle zwischen dem Menschen und dem Computer ( Mensch-Maschine-Schnittstelle, Man-MachineInterface 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 MenschComputer-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. SoftwareErgonomie 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.
Die externe Führungsgrösse übermittelt einen gewünschten Soll-Wert xk. Der Regler vergleicht Soll- und Ist-Wert,
ermittelt die Abweichung, sucht eine optimale Handlungsstrategie und legt die Stellgrösse y fest, die über das
Stellorgan wirkt und zum gewünschten Ergebnis führen soll. Der Fühler misst den ist-Wert x und meldet diesen an
den Regler.
Eine Blackbox [ englisch schwarzer Kasten ] ist ein grafisches Box-Symbol für Systemkomponenten, wobei der
innere Aufbau des Kasten nicht bekannt, aber die äusseren Reaktionen aus Eingangssignale gemessen, untersucht und
beschrieben werden können. Wird eine Blackbox unterteilt, so ergeben sich für die inneren Komponenten äussere
Reaktionen ( innere Untersuchungen ). Jede Verfeinerung erhöht die Gesamtkomplexität aller möglichen
Wechselwirkungen.
Kybernetik bezeichnet heute oft interdisziplinäre Foschungsaktivitäten ( z.B. Aufbau von neuralen Netze in Medizin
Psychologie, Informatik ) und weniger ein abgetrenntes, eigenständiges Forschungsgebiet.
Beispiel: menschlicher Körper
Im menschlichen Körper koordiniert z.B. das Nervensystem ( Gehirn ) die
Verarbeitung der Informationen. Natürliche Prozesse ( 2.Hauptsatz der
Thermodynamik ) streben einen Zustand der Unordnung oder des Chaos an. Die
Auswahl einer bestimmten Botschaft hängt von der Vielfalt der Wahlfreiheit einer
Aktion ab ( Entropie ist das Maß der Wahrscheinlichkeit, mehr Chaos führt zur
Erhöhung der Entropie ). In diesem Bild kann Leben nur materiell und als Maschine
beschrieben werden. Es gibt keine Gefühle, Willen, Geist. Ein zielgerichtetes
Verhalten von Menschen bedingt zur Aufrechterhaltung von der Ordnung impizite
Steuerungsmechanismen.
Vielfach können Eigenschaften und Verhaltensweisen von realer Systeme aus unterschiedlichen
Wissenschaftbereichen fachübergreifend aus einer zusammenfassenden Modellvorstellung behandelt und verstanden
werden. Bescheibende Modell-Identität entstehen durch Reduktion von Komplexität ( Selektion von Komponenten )
und der Erfassung und Behandlung von Wechselwirkungen zwischen den Komponenten.
Wissenschaftliche Untersuchung ( Kybernetik ) umfassen Psychologie, künstlicher Intelligenz, Servomechanismen,
Wirtschaft, Neurophysiologie, Systemsteuerung und sozialen Systemen
Um die Gleichartigkeit von ähnlichen Erscheinungen in ganz unterschiedlichen Bereichen eines abstrakten
kybernetischen Systems zu finden, werden vorrangig die Aufnahme, Übertragung, Rückkopplung von Informationen
betrachtet. Zu ihren Hauptmethoden zählen Analogie- und Modellverfahren ( z.B. Blackboxmethode ). Zentrale
Begriffe sind System, Information, Steuerung und Regelung.
Hauptdisziplinen sind:
●
Steuerungstheorie und Regelungstheorie
●
Systemtheorie
●
Informationstheorie und Automatentheorie
●
Zuverlässigkeitstheorie
●
Algorithmenheorie und Spieltheorie
●
künstliche Intelligenz
Beispiele
Die spezielle Kybernetik behandelt die Theorie und Konstruktion von lernenden ( sich selbst organisierenden )
Automaten und sich selbst reproduzierenden Maschinen ( lernende Automaten ).
Die angewandte Kybernetik versucht empirischer Sachverhalte im kybernetischen Zusammenhang zu erklären ( in
Technik, Ökonomie, Biologie, Bionik, Ökologie, Medizin, Soziologie, Pädagogik, Psychologie, Linguistik ).
Die politische Kybernetik ( Talcott Parsons, David Eastons, Gabriel A.Almonds und Karl W.Deutschs ) als
politikwissenschaftliches Theorie- und Analysekonzept untersucht wechselseitige Rückkopplungen und
Steuerungsprozesse ( Umweltproblematik, Globalisierung der Wirtschaft, Bevölkerungswachstum, Migration )
innerhalb eines politischen Systems ( Beziehungsgeflechten ) ( Wie und dem Warum, Theorien des politischen
Handelns, politischer Entscheidung und Planung ).
Für Niklas Luhmann (1927-1998) ist ein soziales System ein reales System, das durch beobachtung das soziale
System selbst bestimmt ( selbstreferentielle Systeme ). Der Mensch gehört zu seiner Umwelt und beide sind Teil des
sozialen System. In diesem Sinne sind rigide Ideologien ( als geschlossenes System ohne Austausches mit ihrer
Umwelt ) kein Teil eines sozialen System. Nach Luhmann ( Theorie der Gesellschaft ) besitzt die moderne
Gesellschaft kein Zentrum ( weder in Politik, noch in Moral oder Wirtschaft ), das alle anderen Gesellschaftsbereiche
erklären kann. Eine Gesellschaftstheorie kann nicht auf einige Bereiche eingeschränkt werden ( wie z.B. Religion,
Wirtschaft, Recht ). Jedes System arbeitet spezifisch:
●
Das Wirtschaftssystem funktioniert über das Medium Geld ( Gewinnoptimierung )
●
Das Rechtssystem über erlassene Gesetze ( Machtmonopol des Staates )
●
Die Menschen als psychische Systeme über Bewusstsein
●
Die Religionssysteme über einen bekennenden Glauben
Humberto R.Maturana und Francesco J.Varela versuchen die biologische Systemtheorie ( Neurophysiologie ) in den
Sozialwissenschaften anzuwenden.
Was ist eine normal? (Normen)
Im Alltag verhalten sich die Menschen i.a. "funktional-normal". Der Einzelne versucht seine Verhaltensweisen ( mit
seiner kognitiven Kompetenzen ) zu bewerten um sich "angepasst und normal" zu verhalten. Normal ist, was häufig
vorkommt ( z.B. Alkohol ). Normal ist, was "im gesellschaftlichen Funktionieren" dem eigenen, wünschenswerten
Ideal entspricht. Normal ist, was als gesellschaftliche Idealnormen erkennbar wird ( z.B. Schönheitsideale ).
Schulische Leistungskriterien und Anforderungen zeigen die vielen Unterschiede auf von Erzieher, Eltern, Lehrer,
Ausbilder ( individuelle Normvorstellungen, Bezugsnormen des Lehrenden, Erwartungsnormen der Gesellschaft,
Bedürfnissen und Zielsetzungen des Einzelnen, Idealnormen und das durchschnittliche Verhalten ).
Was ist eine Norm?
Allgemein beruhen die Wechselwirkungen von System-Komponenten auf Vereinbarungen. Damit z.B. im
Fertigungsbau ( Maschinenbau ) unterschiedliche Hersteller Schrauben fertigen können, müssen Durchmesser und
Gewindeart ( und vieles mehr ) "genormt" sein. Die Einhaltung der Norm "garantiert" die Verwendbarkeit. Im
Informations- und Medienzeitalter braucht auch die Kommunikation zahlreiche vereinbarungen ( einheitliche
Buchstaben, Schrift, Sprache, usw. ). Ein Austausch von Informationen ist nur auf der Grundlage von Vereinbarungen
möglich. Z.B. macht die Unterhaltung von 2 Betrunkenen ( in unterschiedlichen Sprachen ) wenig Sinn.
Genormt wird nur, was in einem Gefüge verwendet und genutzt werden kann. Standards und Normen kennzeichnen
einen gewissen Abschluss von Erfahrungen. Neue Erfindungen und inovative Entwicklungen erweitern den möglichen
Gestaltungsraum, ( Erweitern und Ergänzen von bestehenden Normen ). Normen für technische Komponenten und
Geräte orientieren sich an sachlichen Bezügen. Die meisten nationalen und internationalen Normungsinstitutionen
wurden im im 20.Jahrhundert gegründet und dienem dem Zweck die Austauschbarkeit von Komponenten und
Erfahrungen zu fördern. Durch Normen wird der Warenverkehr vereinfacht ( bei "Normenchaos" erschwert ).
Normung ist mit Rationalisierung der industriellen Massenproduktion und Vereinfachung des Warenverkehrs
verknüpft und eine Vorbedingung freie eine frei Wirtschaft ( Globalisierung ). Das Deutsche Institut für Normung (
DIN ) erklärt ( definiert ) den Begriff Normung gemäss:
Nach DIN 820-1 ist Normung die planmäßige, durch interessierte Kreise
gemeinschaftlich durchgeführte Vereinheitlichung von materiellen und immateriellen
Gegenständen zum Nutzen der Allgemeinheit; sie darf nicht zu einem
wirtschaftlichen Sondervorteil Einzelner führen.
Normung fördert vor allem die Rationalisierung, Regelung,
Kommunikationsverbesserung und Qualitätssicherung in Wirtschaft, Technik,
Wissenschaft und Verwaltung; sie soll überdies der Sicherheit des Menschen, dem
Schutz der Umwelt und der Qualitätsverbesserung in allen Lebensbereichen dienen.
Zur Effizienzsteigerung und Kostensenkung durch Normung kommt es etwa durch
die Austauschbarkeit oder Vereinbarkeit genormter Produkte, die Verringerung der
Typenvielfalt, die Erleichterung der Lagerhaltung und des Warenverkehrs.
Normen sind darüber hinaus als Beschreibung technischer Sachverhalte für
Gesetzgebung und Rechtsverkehr von Bedeutung.
DIN-Normen enthalten in der Hauptsache Angaben, Anweisungen oder Anforderungen für die Herstellung, Wartung
oder Handhabung von Gegenständen, Geräten oder Anlagen, den Ablauf oder die Ausführung von Vorgängen oder
Dienstleistungen, die Qualität oder Qualitätsprüfung, -sicherung oder -verbesserung technischer Produkte, die
Sicherheit oder Gesundheit des Menschen oder den Schutz der Umwelt.
Einheiten
Für die Objektivierung von vergleichenden Messungen sind Basis-Einheiten definiert. In Industrienationen ist das
Internationale bzw. das SI-Einheitensystem ( Système international ) verbindlich. Durch das "Gesetz über Einheiten
im Meßwesen" vom 2.7.1969 und der Ausführungsverordnung vom 26.6.1970 wurde das SI-Einheitensystem in der
BRD verbindlich eingeführt. Außer seinen 6 Basiseinheiten ( Meter, Kilogramm, Sekunde, Ampere, Kelvin, Mol,
candela m, kg, s, A, K mol, und cd werden auch die abgeleiteten Einheiten N, Pa, J, W und Pa s benutzt.
Masse
1 t = 1000 kg
Zeit
1 h = 60 min = 3600 s
Temperaturdifferenz
1 °C = 1 K
Volumen 1 l = 103 m3
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
Kurzname:
Exa
Peta
Tera
Giga
Mega
Kilo
Hekto
Deka
Wert:
1018
1015
1012
109
106
103
102
101
Abkürzung:
d
c
m
µ
n
p
f
a
Kurzname:
Dezi
Zenti
Milli
Mikro
Nano
Piko
Femto
Atto
Wert:
10-1
10-2
10-3
10-6
10-9
10-12
10-15
10-18
Bezeichnungen Kilo
Mega
Giga
Nibble Byte Word
DWord
Anz.Leitungen:
10
20
30
4
8
16
32
Anz.Bitmuster:
210
220
230
24
28
216
232
1 073 741 824
16
256 65 536 4 294 967 296
Anz.Adressen: 1 024 1 048 576
Beispiel: Nach DIN 1314 wird der Druck p meist in der Einheit bar angegeben und zählt vom Nullpunkt aus.
Druckdifferenzen werden durch die Formelzeichen, nicht aber durch die Einheit gekennzeichnet. Dies gilt besonders
für die Manometerablesung bzw. atmosphärischen Druckdifferenzen.
Nationale Normungsinstitutionen
1917 wurde in Deutschland der Normalienausschuß für den Allgemeinen Maschinenbau gegründet
1926 in Deutscher Normenausschuß e.V. ( DNA ) umbenannt wurde.
1936 wurden die Normen staatlich verbindlich.
1975 erfolgte eine Umbenennung in DIN = Deutsches Institut für Normung e.V. und die Anerkennung als nationale
Normungsinstitution der Bundesrepublik Deutschland
1990 übernahm das DIN die gesamtdeutsche Normung. DIN hat die Rechtsform eines eingetragenen, gemeinnützigen
Vereins mit Sitz in Berlin. Mitglieder ( etwa 6000 ) können Firmen, Verbände, interessierte Körperschaften, Behörden
und Organisationen aber keine Einzelpersonen sein. Die Normungsarbeit wird in 4600 Arbeitsausschüssen von etwa
28 500 Fachleuten ( ehrenamtliche Mitarbeiter von Herstellern, Handel, Handwerk, Verbraucher, Behörden,
Wissenschaftseinrichtungen ) geleistet und von 1000 hauptamtlichen Mitarbeitern koordiniert. DIN finanziert sich zu
etwa 60% aus dem eigenen Beuth-Verlag ( Normen, Normentwürfe und DIN-Taschenbücher ). Die eigene
Normungsarbeit ist in DIN 820-4) festgelegt und ausgerichtet an Freiwilligkeit, Öffentlichkeit, Beteiligung aller
interessierten Kreise, Konsens, Einheitlichkeit und Widerspruchsfreiheit, Ausrichtung am Stand der Technik, an den
wirtschaftlichen Gegebenheiten und am allgemeinen Nutzen sowie Internationalität.
Internationale Normungsinstitutionen
1906 Genf: International Electrotechnical Commission ( IEC )
1926 Genf: International Federation of the National Standardizing Associations ( ISA )
1947 International Organization for Standardization ( ISO, ersetzte die ISA ). Die ISO besteht aus etwa 120
nationalen Normungsinstitutionen. Die Internationale Fernmelde-Union ( IFU ) ist für Telekommunikation zuständig.
1961 Brüssel: das Europäische Komitee für Normung ( CEN, Comité Européen de Normalisation; nicht staatliche,
gemeinnützige Vereinigung; Deutsches Mitglied ist das DIN )
1961 Brüssel: Europäische Komitee für elektrotechnische Normung ( CENELEC, Comité Européen de Normalisation
Electrotechnique; nicht staatliche, gemeinnützige Vereinigung; Deutsche Mitglieder sind die DKE = Deutsche
Elektrotechnische Kommission und der VDE = Verband Deutscher Elektrotechniker )
1982 Zusammenschluss von CEN und CENELEC zur Gemeinsamen Europäischen Normungsinstitution.
CEN/CENELEC-Mitglieder übernehmen ( soweit möglich ) die europäischen Normen ( EN ) als nationale Normen.
Im Bereich der Telekommunikation sorgt das Europäische Institut für Telekommunikationsnormen ( ETSI, Institut
Européen des Normes de Télécommunication, etwa 12000 europäische Normen ) in enger Zusammenarbeit mit
CEN/CENELEC für europaweite Normen.
DFÜ-Normen schafft die CCITT ( ComitConsultatif International Télégraphique et Téléphonique, Genf, nationalen
Behörden, privaten Firmen sowie nationalen und internationalen wissenschaftlichen Organisationen ) ständiges Organ
der internationalen Fernmeldeunion ( Abkürzung ITU ). Das CCITT ist 1993 in der ITU aufgegangen.
Beispiele für Normen
X.400
An international message-handling standard for connecting e-mail networks and for connecting users
to e-mail networks. X.400 is published by the International Telegraph and Telephone Consultative
Committee ( CCITT standards body, now called the International Telecommunications Union (ITU).
The X.400 Application Programming Interface Association XAPIA defines programming interfaces
to X.400. MAPI applications are fully interoperable with X.400 messaging applications.
X.435
Electronic Data Interchange (EDI): A standard for integrating data with various native formats into
a, which has been defined by the International Telegraph and Telephone Consultative Committee
standards body, now called the International Telecommunications Union (ITU), and is implemented
in the X.435 message-handling standard. X.435 is an international message-handling standard that is
published by the International Telegraph and Telephone Consultative Committee CCITT standards
body, now called the International Telecommunications Union (ITU), and that implements the
Electronic Data Interchange (EDI) standard for integrating data with various native formats into a
message.
X.400
Schicker, Pietro, "Message Handling Systems, X.400", Message Handling Systems and Distributed
Applications, E. Stefferud, O-j. Jacobsen, and P. Schicker, eds., North-Holland, 1989, pp. 3-41.
X.500
An international message-handling standard for directory services, published by the International
Telegraph and Telephone Consultative Committee CCITT standards body, now called the Internal
Telecommunications Union (ITU).
X.509
An international message-handling standard for message authentication and encryption. X.509 is
published by the International Telegraph and Telephone Consultative Committee CCITT standards
body, now called the Internal Telecommunications Union (ITU).
XAPIA
The X.400 Application Programming Interface Association, the standards-setting body for
programming interfaces to X.400 components. XAPIA also defines the Common Messaging Calls
inteface component.
US-ASCII
Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986.
ISO-646
International Standard--Information Processing--ISO 7-bit coded character set for information
interchange, ISO 646:1983.
ISO-2022
International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code
extension techniques, ISO 2022:1986.
ISO-8859
Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet
No. 1, ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No.
3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet,
ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet,
ISO 8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5,
ISO 8859-9, 1990.
ISO 9241-10
Grundsätze der Dialoggestaltung
ISO/DIS 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 E-Mail-Nachricht fest,z.b. die Codierung von Sender- und Empfaengeradresse.
RFC1521
MIME(Multipurpose Internet Mail Extensions)Part One: Definiert ein Schema fuer die
Unterbringung verschiedenartigster Daten innerhalb des Hauptteils einer E-Mail-Nachricht.
Beispilesweise von Grafiken oder ausfuehrbaren Dateien. Gilt nicht fuer E-Mail ,sondern natuerlich
auch fuer das Web.
RFC1522
MIME(Multipurpose Internet Mail Extensions)Part Two: Der zweite Teil der MIME-Definition.
Definiert den Kodierungsmechanismus fuer Zeichen,die ueber den 7-Bit-Us_ASCII-Zeichensatz
hinausgehen,in den Kopffeldern von E-Mail-Nachrichten.
RFC 2617
Digest Access Authentication
GIF
Graphics Interchange Format (Version 89a), Compuserve, Inc., Columbus, Ohio, 1990.
MPEG
Video Coding Draft Standard ISO 11172 CD, ISO IEC/TJC1/SC2/WG11 (Motion Picture Experts
Group), May, 1991.
PCM
CCITT, Fascicle III.4 - Recommendation G.711, Geneva, 1972, "Pulse Code Modulation (PCM) of
Voice Frequencies".
POSTSCRIPT Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, 1985.
POSTSCRIPT2 Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, Second Edition,
1990.
ATK
Borenstein, Nathaniel S., Multimedia Applications Development with the Andrew Toolkit, PrenticeHall, 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/
Teil 8)
EWG von 1990 ( DIN 66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter
EG ( 90/270/ ) 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 ).
...
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 DDS-DC 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 DATA-D3-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 (QSIGCTLR), 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 (QSIGCTMO), 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 Ondemand Inter-PINX 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 - AIT1 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 InterExchange 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 InterExchange 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 InterExchange 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 InterExchange 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 - VXA1 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
Data Interchange on 12,7 mm - 384- Track Magnetic Tape Cartridges - Ultrium-1 Format (June
2001)
ECMA-320
ECMA-321
Data Interchange on 12,7 mm - 448-Track Magnetic Tape Cartridges - SDLT1 Format (June 2001)
Streaming Lossless Data Compression Algorithm (SLDC) (June 2001)
ECMA-322
Data Interchange on 130 mm Magneto-Optical Disk Cartridges - Capacity: 9,1 Gbytes per
Cartridge (June 2001)
ECMA-323
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 - AIT3 Format (December 2001)
ECMA-330
120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVDRAM) (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
Mehrbenutzer-Betriebssystem für General Electric ( Mainframe GE645 ) Trotz Nicht-Einsatzes von
MULTICS ( techn. Mängel ) Weiter-Entwicklung durch Thompson ( "Space Travel", 2 Benutzer)
Verballhornung durch Brian Kernighan "UNICS"
1969, Betriebssystem UNICS, ab 1970: Unix ( Assembler ). Gleichzeitig: Thompson u. Ritchie entwickeln
Sprache A (BCPL-* basiert), verbesserte Version B, Weiterentw. zu C.
1973, Unix erstes BS größtenteils in einer Hochsprache ( kaum 1000 Zeilen Maschinencode, portierbar ),
Keine Vermarktung von Unix wg. US-Kartell-Bestimmungen
1975, BSD-UNIX: Abkürzung für Berkeley Software Distribution-UNIX. Bezeichnung für eine UNIXVariante ( entwickelt an der Berkeley-Universität in Kalifornien, Abgabe an Universitäten zum
Selbstkostenpreis )
1980, Xenix ( Microsoft, ab Mitte 80er: Santa Cruz Operation, etwa bis 1990 )
1981 IBM bringt den ersten PC ( mit MS-DOS ) heraus: 8088-CPU, 4.77 MHz, 64 KByte Speicher, 5.25"Diskettenlaufwerk. Microsoft entwickelt dazu eine erste Version des Betriebssystems MS-DOS. Hayes bringt
ein Modem mit 1200 Bit/s heraus. Herwig Feichtinger, heute bei Shamrock, gründet mit "mc" eine der ersten
Computer-Zeitschriften. Novell stellt ein Netzwerk vor, mit dem mehrere Computer auf eine gemeinsame
Festplatte zugreifen können. Hewlett-Packet konstruiert den ersten 32-Bit-Mikroprozessor.
1981 MS-DOS ( Microsoft-Disc Operating System, angelehtn an CP/M 80 für 160 KByte Disketten entwickelt,
Version 1.25 ( ab 1982 ) benutzt zweiseitige Disketten ( 320 KByte Kapazität );
ab 1983 MS-DOS 2.11 mit FAT-Festplatten und User-Hardware-Anpassungen durch Treiber ( in der
CONFIG.SYS );
ab 1984 MS-DOS 3.2 mit HD-Disketten ( 5.25 Zoll, 720 KByte) und die Einbindung in Netzwerke. ab 1984
MS-DOS 3.3 konnten Platten mit mehr als 32 MByte verwaltet werden;
ab 1988 gab es das fehlerbehaftete MS-DOS 4.X mit DOS-Shell, Festplatten bis 2 GByte, EMS-Speicher nach
dem LIM-Standard;
ab 1991 erschien MS-DOS 5.0 mit HMA und UMA ab 1993 MS-DOS 6.X mit Zusatzprogrammen, wie
Online-Komprimierer Doublespace, einem Virenschutz- und einem Backup-Programm, Memmaker-SpeicherOptimierer, ab 6.22 als Drivespace; )
1983 Apple bringt mit "Lisa" erstmals einen per Maus bedienbaren Computer mit grafischer Oberfläche heraus.
Wegen des hohen Preises von rund 75.000 Dollar wird er ein Flop. Microsoft kündigt Windows 1.0 an, es
wird erst 1985 verfügbar. Sony kündigt die 3,5"-Diskette an. IBM und Microsoft entwickeln zusammen das
Betriebssystem OS/2. Novell bringt die Netware-Software heraus. Microcom erfindet ein fehlerkorrigierendes
Modem-Protokoll (MNP).
1984 POSIX ( Portable Operating System Interface for UNIX ). Schnittstellen-Standard der IEEE, der von allen
UNIX-Derivaten benutzt wird, dementsprechend auch von Programmen, die unter UNIX laufen
beziehungsweise Übergänge zu UNIX-Rechnern herstellen.
1988 Normung zu ANSI-C ( Komitee X3J11 ).
1991 Linux 0.02 ( Linus Torvalds entwickelt einen Kern, FIN )
1985 1985, MS präsentiert Windows 1.01;
1987, Windows 2;
1987, OS/2 von IBM / MS, zeichenorientiert
1988, OS/2 von IBM/MS mit grafischer Oberfläche
1990, Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet
die Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste
kommerzielle Internet-Provider den Dienst auf. Unter Federführung der Bundespost entsteht der TreiberStandard 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
Help
Potenzen von 2
Nat. Zahlen i
(Schritt 1)
Brüche
(Schritt 0.1)
Nat. Zahlen i
(Schritt 1/8)
Brüche 1/i
(Schritt 1)
Lucas
Nat.Zahlen i
(Basis=phi)
Fibonacci
Anzeigen
Nat. Zahlen i
(Schritt 2)
Nat. Zahlen
1/i
(Basis=phi)
Anzeigen
Darstellung von Zahlen in einer Basis b:
Start
i: 1
Basis
b: 2
End
i: 16
Schritt: i
nmax: 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
nmin: -2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
0
0
0
0
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Zahlendarstellungen (zurück)
Zur Darstellung einer Zahl w betrachten wir das Beispiel w = 432.1 = 4 102 + 3
101 + 2 100 + 1 10-1. Das Zehnersystem hat die Basis b = 10. Es gibt 10 Ziffer
0,1,2,3,4,5,6,7,8,9. Eine von diesen Ziffern wird mit ai bezeichnet. Für jede
Ziffer gilt 0 <= ai < b. Mit den Ziffern ai wird eine Zahl w in des Basis b
repräsentiert durch:
w = anmax*bnmax + anmax-1*bnmax-1 + ... + anmin+1*bnmin+1 + anmin*bnmin mit natürlichen 0
<= ai < b
Abkürzende Schreibweise für natürliche Zahlen w (mit nmin=0): w = (akak-1...a0)b
Achtung! Fehlerhaften Eingaben werden nicht geprüft.
=====================
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
abs
atexit
atof
atoi
atol
bsearch
Abort current process returning error code
Return absolute value of integer parameter
Specifies a function to be executed at exit
Convert string to double
Convert string to integer
Convert string to long
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
strncat
strncmp
strncpy
strpbrk
strrchr
strspn
strstr
strtok
strxfrm
Return string length
Append substring to string
Compare some characters of two strings
Copy characters from one string to another
Scan string for specified characters
Find last occurrence of character in string
Get length of substring composed of given characters
Find substring
Sequentially truncate string if delimiter is found
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
GlobalAllocPtr(flags, cb)
\
(GlobalLock(GlobalAlloc((flags), (cb))))
GlobalReAllocPtr(lp, cbNew, flags)
\
(GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) ,
(cbNew), (flags))))
#define
GlobalFreePtr(lp)
\
(GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))
/****** GDI Macro APIs *******************************************************/
#define
DeletePen(hpen)
DeleteObject((HGDIOBJ)(HPEN)(hpen))
#define
SelectPen(hdc, hpen)
((HPEN)SelectObject((hdc),
(HGDIOBJ)(HPEN)(hpen)))
#define
GetStockPen(i)
((HPEN)GetStockObject(i))
#define
DeleteBrush(hbr)
DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
#define
SelectBrush(hdc, hbr)
((HBRUSH)SelectObject((hdc),
(HGDIOBJ)(HBRUSH)(hbr)))
#define
GetStockBrush(i)
((HBRUSH)GetStockObject(i))
#define
DeleteRgn(hrgn)
DeleteObject((HGDIOBJ)(HRGN)(hrgn))
#define
CopyRgn(hrgnDst, hrgnSrc)
RGN_COPY)
#define
IntersectRgn(hrgnResult, hrgnA, hrgnB)
hrgnB, RGN_AND)
#define
SubtractRgn(hrgnResult, hrgnA, hrgnB)
hrgnB, RGN_DIFF)
#define
UnionRgn(hrgnResult, hrgnA, hrgnB)
hrgnB, RGN_OR)
#define
XorRgn(hrgnResult, hrgnA, hrgnB)
hrgnB, RGN_XOR)
CombineRgn(hrgnDst, hrgnSrc, 0,
CombineRgn(hrgnResult, hrgnA,
CombineRgn(hrgnResult, hrgnA,
CombineRgn(hrgnResult, hrgnA,
CombineRgn(hrgnResult, hrgnA,
#define
DeletePalette(hpal)
DeleteObject((HGDIOBJ)(HPALETTE)(hpal))
#define
#define
DeleteFont(hfont)
SelectFont(hdc, hfont)
DeleteObject((HGDIOBJ)(HFONT)(hfont))
((HFONT)SelectObject((hdc),
(HGDIOBJ)(HFONT)(hfont)))
#define
GetStockFont(i)
((HFONT)GetStockObject(i))
#define
DeleteBitmap(hbm)
#define
SelectBitmap(hdc, hbm)
(HGDIOBJ)(HBITMAP)(hbm)))
#define
DeleteObject((HGDIOBJ)(HBITMAP)(hbm))
((HBITMAP)SelectObject((hdc),
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),
GetDlgCtrlID(hwnd)
0L))
#define
SubclassWindow(hwnd, lpfn)
\
((WNDPROC)SetWindowLong((hwnd), GWL_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))
#define
IsMinimized(hwnd)
IsIconic(hwnd)
#define
#define
== 0L)
IsMaximized(hwnd)
IsRestored(hwnd)
IsZoomed(hwnd)
((GetWindowStyle(hwnd) & (WS_MINIMIZE | WS_MAXIMIZE))
#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
#define
SubclassDialog(hwndDlg, lpfn) \
((DLGPROC)SetWindowLong(hwndDlg, DWL_DLGPROC, (LPARAM)(DLGPROC)(lpfn)))
SetDlgMsgResult(hwnd, msg, result) (( \
(msg) == WM_CTLCOLORMSGBOX
|| \
(msg) == WM_CTLCOLOREDIT
|| \
(msg) == WM_CTLCOLORLISTBOX
|| \
(msg) == WM_CTLCOLORBTN
|| \
(msg) == WM_CTLCOLORDLG
|| \
(msg) == WM_CTLCOLORSCROLLBAR
|| \
(msg) == WM_CTLCOLORSTATIC
|| \
(msg) == WM_COMPAREITEM
|| \
(msg) == WM_VKEYTOITEM
|| \
(msg) == WM_CHARTOITEM
|| \
(msg) == WM_QUERYDRAGICON
|| \
(msg) == WM_INITDIALOG
\
) ? (BOOL)(result) : (SetWindowLong((hwnd), DWL_MSGRESULT,
(LPARAM)(LRESULT)(result)), TRUE))
#define
DefDlgProcEx(hwnd, msg, wParam, lParam, pfRecursion) \
(*(pfRecursion) = TRUE, DefDlgProc(hwnd, msg, wParam, lParam))
#define
CheckDefDlgRecursion(pfRecursion) \
if (*(pfRecursion)) { *(pfRecursion) = FALSE; return FALSE; }
/****** Message crackers ****************************************************/
#define HANDLE_MSG(hwnd, message, fn)
\
case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
/* void Cls_OnCompacting(HWND hwnd, UINT compactRatio) */
#define HANDLE_WM_COMPACTING(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam)), 0L)
#define FORWARD_WM_COMPACTING(hwnd, compactRatio, fn) \
(void)(fn)((hwnd), WM_COMPACTING, (WPARAM)(UINT)(compactRatio), 0L)
/* void Cls_OnWinIniChange(HWND hwnd, LPCTSTR lpszSectionName) */
#define HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_WININICHANGE(hwnd, lpszSectionName, fn) \
(void)(fn)((hwnd), WM_WININICHANGE, 0L, (LPARAM)(LPCTSTR)(lpszSectionName))
/* void Cls_OnSysColorChange(HWND hwnd) */
#define HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_SYSCOLORCHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_SYSCOLORCHANGE, 0L, 0L)
/* BOOL Cls_OnQueryNewPalette(HWND hwnd) */
#define HANDLE_WM_QUERYNEWPALETTE(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYNEWPALETTE(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYNEWPALETTE, 0L, 0L)
/* void Cls_OnPaletteIsChanging(HWND hwnd, HWND hwndPaletteChange) */
#define HANDLE_WM_PALETTEISCHANGING(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_PALETTEISCHANGING(hwnd, hwndPaletteChange, fn) \
(void)(fn)((hwnd), WM_PALETTEISCHANGING, (WPARAM)(HWND)(hwndPaletteChange), 0L)
/* void Cls_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange) */
#define HANDLE_WM_PALETTECHANGED(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_PALETTECHANGED(hwnd, hwndPaletteChange, fn) \
(void)(fn)((hwnd), WM_PALETTECHANGED, (WPARAM)(HWND)(hwndPaletteChange), 0L)
/* void Cls_OnFontChange(HWND hwnd) */
#define HANDLE_WM_FONTCHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_FONTCHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_FONTCHANGE, 0L, 0L)
/* void Cls_OnSpoolerStatus(HWND hwnd, UINT status, int cJobInQueue) */
#define HANDLE_WM_SPOOLERSTATUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SPOOLERSTATUS(hwnd, status, cJobInQueue, fn) \
(void)(fn)((hwnd), WM_SPOOLERSTATUS, (WPARAM)(status), MAKELPARAM((cJobInQueue),
0))
/* void Cls_OnDevModeChange(HWND hwnd, LPCTSTR lpszDeviceName) */
#define HANDLE_WM_DEVMODECHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_DEVMODECHANGE(hwnd, lpszDeviceName, fn) \
(void)(fn)((hwnd), WM_DEVMODECHANGE, 0L, (LPARAM)(LPCTSTR)(lpszDeviceName))
/* void Cls_OnTimeChange(HWND hwnd) */
#define HANDLE_WM_TIMECHANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_TIMECHANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_TIMECHANGE, 0L, 0L)
/* void Cls_OnPower(HWND hwnd, int code) */
#define HANDLE_WM_POWER(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam)), 0L)
#define FORWARD_WM_POWER(hwnd, code, fn) \
(void)(fn)((hwnd), WM_POWER, (WPARAM)(int)(code), 0L)
/* BOOL Cls_OnQueryEndSession(HWND hwnd) */
#define HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYENDSESSION(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYENDSESSION, 0L, 0L)
/* void Cls_OnEndSession(HWND hwnd, BOOL fEnding) */
#define HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_ENDSESSION(hwnd, fEnding, fn) \
(void)(fn)((hwnd), WM_ENDSESSION, (WPARAM)(BOOL)(fEnding), 0L)
/* void Cls_OnQuit(HWND hwnd, int exitCode) */
#define HANDLE_WM_QUIT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam)), 0L)
#define FORWARD_WM_QUIT(hwnd, exitCode, fn) \
(void)(fn)((hwnd), WM_QUIT, (WPARAM)(exitCode), 0L)
/* This message is in Windows 3.1 only */
/* void Cls_OnSystemError(HWND hwnd, int errCode) */
#define HANDLE_WM_SYSTEMERROR(hwnd, wParam, lParam, fn) 0L
#define FORWARD_WM_SYSTEMERROR(hwnd, errCode, fn) 0L
/* BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */
#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
#define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_CREATE, 0L,
(LPARAM)(LPCREATESTRUCT)(lpCreateStruct))
/* BOOL Cls_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct) */
#define HANDLE_WM_NCCREATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPCREATESTRUCT)(lParam))
#define FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_NCCREATE, 0L,
(LPARAM)(LPCREATESTRUCT)(lpCreateStruct))
/* void Cls_OnDestroy(HWND hwnd) */
#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DESTROY(hwnd, fn) \
(void)(fn)((hwnd), WM_DESTROY, 0L, 0L)
/* void Cls_OnNCDestroy(HWND hwnd) */
#define HANDLE_WM_NCDESTROY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_NCDESTROY(hwnd, fn) \
(void)(fn)((hwnd), WM_NCDESTROY, 0L, 0L)
/* void Cls_OnShowWindow(HWND hwnd, BOOL fShow, UINT status) */
#define HANDLE_WM_SHOWWINDOW(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam), (UINT)(lParam)), 0L)
#define FORWARD_WM_SHOWWINDOW(hwnd, fShow, status, fn) \
(void)(fn)((hwnd), WM_SHOWWINDOW, (WPARAM)(BOOL)(fShow), (LPARAM)(UINT)(status))
/* void Cls_OnSetRedraw(HWND hwnd, BOOL fRedraw) */
#define HANDLE_WM_SETREDRAW(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_SETREDRAW(hwnd, fRedraw, fn) \
(void)(fn)((hwnd), WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L)
/* void Cls_OnEnable(HWND hwnd, BOOL fEnable) */
#define HANDLE_WM_ENABLE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam)), 0L)
#define FORWARD_WM_ENABLE(hwnd, fEnable, fn) \
(void)(fn)((hwnd), WM_ENABLE, (WPARAM)(BOOL)(fEnable), 0L)
/* void Cls_OnSetText(HWND hwnd, LPCTSTR lpszText) */
#define HANDLE_WM_SETTEXT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPCTSTR)(lParam)), 0L)
#define FORWARD_WM_SETTEXT(hwnd, lpszText, fn) \
(void)(fn)((hwnd), WM_SETTEXT, 0L, (LPARAM)(LPCTSTR)(lpszText))
/* INT Cls_OnGetText(HWND hwnd, int cchTextMax, LPTSTR lpszText) */
#define HANDLE_WM_GETTEXT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (int)(wParam), (LPTSTR)(lParam))
#define FORWARD_WM_GETTEXT(hwnd, cchTextMax, lpszText, fn) \
(int)(DWORD)(fn)((hwnd), WM_GETTEXT, (WPARAM)(int)(cchTextMax),
(LPARAM)(LPTSTR)(lpszText))
/* INT Cls_OnGetTextLength(HWND hwnd) */
#define HANDLE_WM_GETTEXTLENGTH(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)(hwnd)
#define FORWARD_WM_GETTEXTLENGTH(hwnd, fn) \
(int)(DWORD)(fn)((hwnd), WM_GETTEXTLENGTH, 0L, 0L)
/* BOOL Cls_OnWindowPosChanging(HWND hwnd, LPWINDOWPOS lpwpos) */
#define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
#define FORWARD_WM_WINDOWPOSCHANGING(hwnd, lpwpos, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_WINDOWPOSCHANGING, 0L,
(LPARAM)(LPWINDOWPOS)(lpwpos))
/* void Cls_OnWindowPosChanged(HWND hwnd, const LPWINDOWPOS lpwpos) */
#define HANDLE_WM_WINDOWPOSCHANGED(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const LPWINDOWPOS)(lParam)), 0L)
#define FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, fn) \
(void)(fn)((hwnd), WM_WINDOWPOSCHANGED, 0L, (LPARAM)(const LPWINDOWPOS)(lpwpos))
/* void Cls_OnMove(HWND hwnd, int x, int y) */
#define HANDLE_WM_MOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_MOVE(hwnd, x, y, fn) \
(void)(fn)((hwnd), WM_MOVE, 0L, MAKELPARAM((x), (y)))
/* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy) */
#define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam),
(int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_SIZE(hwnd, state, cx, cy, fn) \
(void)(fn)((hwnd), WM_SIZE, (WPARAM)(UINT)(state), MAKELPARAM((cx), (cy)))
/* void Cls_OnClose(HWND hwnd) */
#define HANDLE_WM_CLOSE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CLOSE(hwnd, fn) \
(void)(fn)((hwnd), WM_CLOSE, 0L, 0L)
/* BOOL Cls_OnQueryOpen(HWND hwnd) */
#define HANDLE_WM_QUERYOPEN(hwnd, wParam, lParam, fn) \
MAKELRESULT((BOOL)(fn)(hwnd), 0L)
#define FORWARD_WM_QUERYOPEN(hwnd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_QUERYOPEN, 0L, 0L)
/* void Cls_OnGetMinMaxInfo(HWND hwnd, LPMINMAXINFO lpMinMaxInfo) */
#define HANDLE_WM_GETMINMAXINFO(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (LPMINMAXINFO)(lParam)), 0L)
#define FORWARD_WM_GETMINMAXINFO(hwnd, lpMinMaxInfo, fn) \
(void)(fn)((hwnd), WM_GETMINMAXINFO, 0L, (LPARAM)(LPMINMAXINFO)(lpMinMaxInfo))
/* void Cls_OnPaint(HWND hwnd) */
#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_PAINT(hwnd, fn) \
(void)(fn)((hwnd), WM_PAINT, 0L, 0L)
/* BOOL Cls_OnEraseBkgnd(HWND hwnd, HDC hdc) */
#define HANDLE_WM_ERASEBKGND(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
#define FORWARD_WM_ERASEBKGND(hwnd, hdc, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_ERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
/* BOOL Cls_OnIconEraseBkgnd(HWND hwnd, HDC hdc) */
#define HANDLE_WM_ICONERASEBKGND(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
#define FORWARD_WM_ICONERASEBKGND(hwnd, hdc, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_ICONERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
/* void Cls_OnNCPaint(HWND hwnd, HRGN hrgn) */
#define HANDLE_WM_NCPAINT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HRGN)(wParam)), 0L)
#define FORWARD_WM_NCPAINT(hwnd, hrgn, fn) \
(void)(fn)((hwnd), WM_NCPAINT, (WPARAM)(HRGN)(hrgn), 0L)
/* UINT Cls_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS * lpcsp)
*/
#define HANDLE_WM_NCCALCSIZE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(0), (NCCALCSIZE_PARAMS *)(lParam))
#define FORWARD_WM_NCCALCSIZE(hwnd, fCalcValidRects, lpcsp, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_NCCALCSIZE, 0L, (LPARAM)(NCCALCSIZE_PARAMS
*)(lpcsp))
/* UINT Cls_OnNCHitTest(HWND hwnd, int x, int y) */
#define HANDLE_WM_NCHITTEST(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (int)(short)LOWORD(lParam),
(int)(short)HIWORD(lParam))
#define FORWARD_WM_NCHITTEST(hwnd, x, y, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_NCHITTEST, 0L, MAKELPARAM((x), (y)))
/* HICON Cls_OnQueryDragIcon(HWND hwnd) */
#define HANDLE_WM_QUERYDRAGICON(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd)
#define FORWARD_WM_QUERYDRAGICON(hwnd, fn) \
(HICON)(UINT)(DWORD)(fn)((hwnd), WM_QUERYDRAGICON, 0L, 0L)
#ifdef _INC_SHELLAPI
/* void Cls_OnDropFiles(HWND hwnd, HDROP hdrop) */
#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HDROP)(wParam)), 0L)
#define FORWARD_WM_DROPFILES(hwnd, hdrop, fn) \
(void)(fn)((hwnd), WM_DROPFILES, (WPARAM)(HDROP)(hdrop), 0L)
#endif /* _INC_SHELLAPI */
/* void Cls_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized) */
#define HANDLE_WM_ACTIVATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (BOOL)HIWORD(wParam)), 0L)
#define FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, fn) \
(void)(fn)((hwnd), WM_ACTIVATE, MAKEWPARAM((state), (fMinimized)),
(LPARAM)(HWND)(hwndActDeact))
/* void Cls_OnActivateApp(HWND hwnd, BOOL fActivate, DWORD dwThreadId) */
#define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
#define FORWARD_WM_ACTIVATEAPP(hwnd, fActivate, dwThreadId, fn) \
(void)(fn)((hwnd), WM_ACTIVATEAPP, (WPARAM)(BOOL)(fActivate),
(LPARAM)(dwThreadId))
/* BOOL Cls_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized)
*/
#define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), 0L, 0L)
#define FORWARD_WM_NCACTIVATE(hwnd, fActive, hwndActDeact, fMinimized, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_NCACTIVATE, (WPARAM)(BOOL)(fActive), 0L)
/* void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus) */
#define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_SETFOCUS(hwnd, hwndOldFocus, fn) \
(void)(fn)((hwnd), WM_SETFOCUS, (WPARAM)(HWND)(hwndOldFocus), 0L)
/* void Cls_OnKillFocus(HWND hwnd, HWND hwndNewFocus) */
#define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_KILLFOCUS(hwnd, hwndNewFocus, fn) \
(void)(fn)((hwnd), WM_KILLFOCUS, (WPARAM)(HWND)(hwndNewFocus), 0L)
/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_KEYDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam),
(UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_KEYDOWN(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_KEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat),
(flags)))
/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_KEYUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam),
(UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_KEYUP(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_KEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat), (flags)))
/* void Cls_OnChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_CHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_CHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
/* void Cls_OnDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_DEADCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_DEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat),0))
/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_SYSKEYDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), TRUE, (int)(short)LOWORD(lParam),
(UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSKEYDOWN(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_SYSKEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat),
(flags)))
/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags) */
#define HANDLE_WM_SYSKEYUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), FALSE, (int)(short)LOWORD(lParam),
(UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSKEYUP(hwnd, vk, cRepeat, flags, fn) \
(void)(fn)((hwnd), WM_SYSKEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((cRepeat),
(flags)))
/* void Cls_OnSysChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SYSCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_SYSCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0))
/* void Cls_OnSysDeadChar(HWND hwnd, TCHAR ch, int cRepeat) */
#define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
#define FORWARD_WM_SYSDEADCHAR(hwnd, ch, cRepeat, fn) \
(void)(fn)((hwnd), WM_SYSDEADCHAR, (WPARAM)(TCHAR)(ch), MAKELPARAM((cRepeat), 0))
/* void Cls_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags) */
#define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_MOUSEMOVE(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_MOUSEMOVE, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags) */
#define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_LBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_LBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_RBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_RBUTTONDBLCLK : WM_RBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnRButtonUp(HWND hwnd, int x, int y, UINT flags) */
#define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_RBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_RBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_MBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_MBUTTONDBLCLK : WM_MBUTTONDOWN,
(WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
*/
#define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnMButtonUp(HWND hwnd, int x, int y, UINT flags) */
#define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_MBUTTONUP(hwnd, x, y, keyFlags, fn) \
(void)(fn)((hwnd), WM_MBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
/* void Cls_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMOUSEMOVE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCMOUSEMOVE(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCMOUSEMOVE, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x),
(y)))
/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCLBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCLBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCLButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCLBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCLBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCLBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x),
(y)))
/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCRBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCRBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCRBUTTONDBLCLK : WM_NCRBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCRBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCRButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCRBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCRBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCRBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x),
(y)) )
/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCMBUTTONDOWN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCMBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), (fDoubleClick) ? WM_NCMBUTTONDBLCLK : WM_NCMBUTTONDOWN,
(WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest) */
#define HANDLE_WM_NCMBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
/* void Cls_OnNCMButtonUp(HWND hwnd, int x, int y, UINT codeHitTest) */
#define HANDLE_WM_NCMBUTTONUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam),
(UINT)(wParam)), 0L)
#define FORWARD_WM_NCMBUTTONUP(hwnd, x, y, codeHitTest, fn) \
(void)(fn)((hwnd), WM_NCMBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x),
(y)) )
/* int Cls_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg)
*/
#define HANDLE_WM_MOUSEACTIVATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam),
(UINT)HIWORD(lParam))
#define FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg, fn) \
(int)(DWORD)(fn)((hwnd), WM_MOUSEACTIVATE, (WPARAM)(HWND)(hwndTopLevel),
MAKELPARAM((codeHitTest), (msg)))
/* void Cls_OnCancelMode(HWND hwnd) */
#define HANDLE_WM_CANCELMODE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CANCELMODE(hwnd, fn) \
(void)(fn)((hwnd), WM_CANCELMODE, 0L, 0L)
/* void Cls_OnTimer(HWND hwnd, UINT id) */
#define HANDLE_WM_TIMER(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam)), 0L)
#define FORWARD_WM_TIMER(hwnd, id, fn) \
(void)(fn)((hwnd), WM_TIMER, (WPARAM)(UINT)(id), 0L)
/* void Cls_OnInitMenu(HWND hwnd, HMENU hMenu) */
#define HANDLE_WM_INITMENU(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HMENU)(wParam)), 0L)
#define FORWARD_WM_INITMENU(hwnd, hMenu, fn) \
(void)(fn)((hwnd), WM_INITMENU, (WPARAM)(HMENU)(hMenu), 0L)
/* void Cls_OnInitMenuPopup(HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu) */
#define HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HMENU)(wParam), (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)), 0L)
#define FORWARD_WM_INITMENUPOPUP(hwnd, hMenu, item, fSystemMenu, fn) \
(void)(fn)((hwnd), WM_INITMENUPOPUP, (WPARAM)(HMENU)(hMenu),
MAKELPARAM((item),(fSystemMenu)))
/* void Cls_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT
flags) */
#define HANDLE_WM_MENUSELECT(hwnd, wParam, lParam, fn)
\
((fn)((hwnd), (HMENU)(lParam), \
(int)(LOWORD(wParam)),
\
(HIWORD(wParam) & MF_POPUP) ? GetSubMenu((HMENU)lParam, LOWORD(wParam)) : 0L, \
(UINT)(((short)HIWORD(wParam) == -1) ? 0xFFFFFFFF : HIWORD(wParam))), 0L)
#define FORWARD_WM_MENUSELECT(hwnd, hmenu, item, hmenuPopup, flags, fn) \
(void)(fn)((hwnd), WM_MENUSELECT, MAKEWPARAM((item), (flags)),
(LPARAM)(HMENU)((hmenu) ? (hmenu) : (hmenuPopup)))
/* DWORD Cls_OnMenuChar(HWND hwnd, UINT ch, UINT flags, HMENU hmenu) */
#define HANDLE_WM_MENUCHAR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(LOWORD(wParam)), (UINT)HIWORD(wParam),
(HMENU)(lParam))
#define FORWARD_WM_MENUCHAR(hwnd, ch, flags, hmenu, fn) \
(DWORD)(fn)((hwnd), WM_MENUCHAR, MAKEWPARAM(flags, (WORD)(ch)),
(LPARAM)(HMENU)(hmenu))
/* void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) */
#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
(void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)),
(LPARAM)(HWND)(hwndCtl))
/* void Cls_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */
#define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)),
(int)(short)HIWORD(wParam)), 0L)
#define FORWARD_WM_HSCROLL(hwnd, hwndCtl, code, pos, fn) \
(void)(fn)((hwnd), WM_HSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)),
(LPARAM)(UINT)(hwndCtl))
/* void Cls_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos) */
#define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)),
(int)(short)HIWORD(wParam)), 0L)
#define FORWARD_WM_VSCROLL(hwnd, hwndCtl, code, pos, fn) \
(void)(fn)((hwnd), WM_VSCROLL, MAKEWPARAM((UINT)(int)(code),(UINT)(int)(pos)),
(LPARAM)(HWND)(hwndCtl))
/* void Cls_OnCut(HWND hwnd) */
#define HANDLE_WM_CUT(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CUT(hwnd, fn) \
(void)(fn)((hwnd), WM_CUT, 0L, 0L)
/* void Cls_OnCopy(HWND hwnd) */
#define HANDLE_WM_COPY(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_COPY(hwnd, fn) \
(void)(fn)((hwnd), WM_COPY, 0L, 0L)
/* void Cls_OnPaste(HWND hwnd) */
#define HANDLE_WM_PASTE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_PASTE(hwnd, fn) \
(void)(fn)((hwnd), WM_PASTE, 0L, 0L)
/* void Cls_OnClear(HWND hwnd) */
#define HANDLE_WM_CLEAR(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CLEAR(hwnd, fn) \
(void)(fn)((hwnd), WM_CLEAR, 0L, 0L)
/* void Cls_OnUndo(HWND hwnd) */
#define HANDLE_WM_UNDO(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_UNDO(hwnd, fn) \
(void)(fn)((hwnd), WM_UNDO, 0L, 0L)
/* HANDLE Cls_OnRenderFormat(HWND hwnd, UINT fmt) */
#define HANDLE_WM_RENDERFORMAT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HANDLE)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_RENDERFORMAT(hwnd, fmt, fn) \
(HANDLE)(UINT)(DWORD)(fn)((hwnd), WM_RENDERFORMAT, (WPARAM)(UINT)(fmt), 0L)
/* void Cls_OnRenderAllFormats(HWND hwnd) */
#define HANDLE_WM_RENDERALLFORMATS(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_RENDERALLFORMATS(hwnd, fn) \
(void)(fn)((hwnd), WM_RENDERALLFORMATS, 0L, 0L)
/* void Cls_OnDestroyClipboard(HWND hwnd) */
#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DESTROYCLIPBOARD(hwnd, fn) \
(void)(fn)((hwnd), WM_DESTROYCLIPBOARD, 0L, 0L)
/* void Cls_OnDrawClipboard(HWND hwnd) */
#define HANDLE_WM_DRAWCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_DRAWCLIPBOARD(hwnd, fn) \
(void)(fn)((hwnd), WM_DRAWCLIPBOARD, 0L, 0L)
/* void Cls_OnPaintClipboard(HWND hwnd, HWND hwndCBViewer, const LPPAINTSTRUCT
lpPaintStruct) */
#define HANDLE_WM_PAINTCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (const
LPPAINTSTRUCT)GlobalLock((HGLOBAL)(lParam))), GlobalUnlock((HGLOBAL)(lParam)), 0L)
#define FORWARD_WM_PAINTCLIPBOARD(hwnd, hwndCBViewer, lpPaintStruct, fn) \
(void)(fn)((hwnd), WM_PAINTCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer),
(LPARAM)(LPPAINTSTRUCT)(lpPaintStruct))
/* void Cls_OnSizeClipboard(HWND hwnd, HWND hwndCBViewer, const LPRECT lprc) */
#define HANDLE_WM_SIZECLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (const LPRECT)GlobalLock((HGLOBAL)(lParam))),
GlobalUnlock((HGLOBAL)(lParam)), 0L)
#define FORWARD_WM_SIZECLIPBOARD(hwnd, hwndCBViewer, lprc, fn) \
(void)(fn)((hwnd), WM_SIZECLIPBOARD, (WPARAM)(HWND)(hwndCBViewer),
(LPARAM)(LPRECT)(lprc))
/* void Cls_OnVScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */
#define HANDLE_WM_VSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)),
0L)
#define FORWARD_WM_VSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
(void)(fn)((hwnd), WM_VSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer),
MAKELPARAM((code), (pos)))
/* void Cls_OnHScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos) */
#define HANDLE_WM_HSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (int)(short)HIWORD(lParam)),
0L)
#define FORWARD_WM_HSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
(void)(fn)((hwnd), WM_HSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer),
MAKELPARAM((code), (pos)))
/* void Cls_OnAskCBFormatName(HWND hwnd, int cchMax, LPTSTR rgchName) */
#define HANDLE_WM_ASKCBFORMATNAME(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam), (LPTSTR)(lParam)), 0L)
#define FORWARD_WM_ASKCBFORMATNAME(hwnd, cchMax, rgchName, fn) \
(void)(fn)((hwnd), WM_ASKCBFORMATNAME, (WPARAM)(int)(cchMax), (LPARAM)(rgchName))
/* void Cls_OnChangeCBChain(HWND hwnd, HWND hwndRemove, HWND hwndNext) */
#define HANDLE_WM_CHANGECBCHAIN(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (HWND)(lParam)), 0L)
#define FORWARD_WM_CHANGECBCHAIN(hwnd, hwndRemove, hwndNext, fn) \
(void)(fn)((hwnd), WM_CHANGECBCHAIN, (WPARAM)(HWND)(hwndRemove),
(LPARAM)(HWND)(hwndNext))
/* BOOL Cls_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg) */
#define HANDLE_WM_SETCURSOR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam),
(UINT)HIWORD(lParam))
#define FORWARD_WM_SETCURSOR(hwnd, hwndCursor, codeHitTest, msg, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_SETCURSOR, (WPARAM)(HWND)(hwndCursor),
MAKELPARAM((codeHitTest), (msg)))
/* void Cls_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) */
#define HANDLE_WM_SYSCOMMAND(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (int)(short)LOWORD(lParam),
(int)(short)HIWORD(lParam)), 0L)
#define FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, fn) \
(void)(fn)((hwnd), WM_SYSCOMMAND, (WPARAM)(UINT)(cmd), MAKELPARAM((x), (y)))
/* HWND Cls_MDICreate(HWND hwnd, const LPMDICREATESTRUCT lpmcs) */
#define HANDLE_WM_MDICREATE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (LPMDICREATESTRUCT)(lParam))
#define FORWARD_WM_MDICREATE(hwnd, lpmcs, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDICREATE, 0L,
(LPARAM)(LPMDICREATESTRUCT)(lpmcs))
/* void Cls_MDIDestroy(HWND hwnd, HWND hwndDestroy) */
#define HANDLE_WM_MDIDESTROY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIDESTROY(hwnd, hwndDestroy, fn) \
(void)(fn)((hwnd), WM_MDIDESTROY, (WPARAM)(hwndDestroy), 0L)
/* NOTE: Usable only by MDI client windows */
/* void Cls_MDIActivate(HWND hwnd, BOOL fActive, HWND hwndActivate, HWND
hwndDeactivate) */
#define HANDLE_WM_MDIACTIVATE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (BOOL)(lParam == (LPARAM)hwnd), (HWND)(lParam), (HWND)(wParam)),
0L)
#define FORWARD_WM_MDIACTIVATE(hwnd, fActive, hwndActivate, hwndDeactivate, fn) \
(void)(fn)(hwnd, WM_MDIACTIVATE, (WPARAM)(hwndDeactivate),
(LPARAM)(hwndActivate))
/* void Cls_MDIRestore(HWND hwnd, HWND hwndRestore) */
#define HANDLE_WM_MDIRESTORE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIRESTORE(hwnd, hwndRestore, fn) \
(void)(fn)((hwnd), WM_MDIRESTORE, (WPARAM)(hwndRestore), 0L)
/* HWND Cls_MDINext(HWND hwnd, HWND hwndCur, BOOL fPrev) */
#define HANDLE_WM_MDINEXT(hwnd, wParam, lParam, fn) \
(LRESULT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)lParam)
#define FORWARD_WM_MDINEXT(hwnd, hwndCur, fPrev, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDINEXT, (WPARAM)(hwndCur), (LPARAM)(fPrev))
/* void Cls_MDIMaximize(HWND hwnd, HWND hwndMaximize) */
#define HANDLE_WM_MDIMAXIMIZE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam)), 0L)
#define FORWARD_WM_MDIMAXIMIZE(hwnd, hwndMaximize, fn) \
(void)(fn)((hwnd), WM_MDIMAXIMIZE, (WPARAM)(hwndMaximize), 0L)
/* BOOL Cls_MDITile(HWND hwnd, UINT cmd) */
#define HANDLE_WM_MDITILE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_MDITILE(hwnd, cmd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_MDITILE, (WPARAM)(cmd), 0L)
/* BOOL Cls_MDICascade(HWND hwnd, UINT cmd) */
#define HANDLE_WM_MDICASCADE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
#define FORWARD_WM_MDICASCADE(hwnd, cmd, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_MDICASCADE, (WPARAM)(cmd), 0L)
/* void Cls_MDIIconArrange(HWND hwnd) */
#define HANDLE_WM_MDIICONARRANGE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_MDIICONARRANGE(hwnd, fn) \
(void)(fn)((hwnd), WM_MDIICONARRANGE, 0L, 0L)
/* HWND Cls_MDIGetActive(HWND hwnd) */
#define HANDLE_WM_MDIGETACTIVE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd)
#define FORWARD_WM_MDIGETACTIVE(hwnd, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDIGETACTIVE, 0L, 0L)
/* HMENU Cls_MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU
hmenuWindow) */
#define HANDLE_WM_MDISETMENU(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(wParam), (HMENU)(wParam),
(HMENU)(lParam))
#define FORWARD_WM_MDISETMENU(hwnd, fRefresh, hmenuFrame, hmenuWindow, fn) \
(HMENU)(UINT)(DWORD)(fn)((hwnd), WM_MDISETMENU, (WPARAM)((fRefresh) ?
(hmenuFrame) : 0), (LPARAM)(hmenuWindow))
/* void Cls_OnChildActivate(HWND hwnd) */
#define HANDLE_WM_CHILDACTIVATE(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_CHILDACTIVATE(hwnd, fn) \
(void)(fn)((hwnd), WM_CHILDACTIVATE, 0L, 0L)
/* BOOL Cls_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) */
#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)
#define FORWARD_WM_INITDIALOG(hwnd, hwndFocus, lParam, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_INITDIALOG, (WPARAM)(HWND)(hwndFocus), (lParam))
/* HWND Cls_OnNextDlgCtl(HWND hwnd, HWND hwndSetFocus, BOOL fNext) */
#define HANDLE_WM_NEXTDLGCTL(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)(lParam))
#define FORWARD_WM_NEXTDLGCTL(hwnd, hwndSetFocus, fNext, fn) \
(HWND)(UINT)(DWORD)(fn)((hwnd), WM_NEXTDLGCTL, (WPARAM)(HWND)(hwndSetFocus),
(LPARAM)(fNext))
/* void Cls_OnParentNotify(HWND hwnd, UINT msg, HWND hwndChild, int idChild) */
#define HANDLE_WM_PARENTNOTIFY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_PARENTNOTIFY(hwnd, msg, hwndChild, idChild, fn) \
(void)(fn)((hwnd), WM_PARENTNOTIFY, MAKEWPARAM(msg, idChild),
(LPARAM)(hwndChild))
/* void Cls_OnEnterIdle(HWND hwnd, UINT source, HWND hwndSource) */
#define HANDLE_WM_ENTERIDLE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (HWND)(lParam)), 0L)
#define FORWARD_WM_ENTERIDLE(hwnd, source, hwndSource, fn) \
(void)(fn)((hwnd), WM_ENTERIDLE, (WPARAM)(UINT)(source),
(LPARAM)(HWND)(hwndSource))
/* UINT Cls_OnGetDlgCode(HWND hwnd, LPMSG lpmsg) */
#define HANDLE_WM_GETDLGCODE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(fn)(hwnd, (LPMSG)(lParam))
#define FORWARD_WM_GETDLGCODE(hwnd, lpmsg, fn) \
(UINT)(DWORD)(fn)((hwnd), WM_GETDLGCODE, (lpmsg ? lpmsg->wParam : 0),
(LPARAM)(LPMSG)(lpmsg))
/* HBRUSH Cls_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type) */
#define HANDLE_WM_CTLCOLORMSGBOX(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_MSGBOX)
#define FORWARD_WM_CTLCOLORMSGBOX(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORMSGBOX, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLOREDIT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_EDIT)
#define FORWARD_WM_CTLCOLOREDIT(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLOREDIT, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORLISTBOX(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_LISTBOX)
#define FORWARD_WM_CTLCOLORLISTBOX(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORLISTBOX, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORBTN(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_BTN)
#define FORWARD_WM_CTLCOLORBTN(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORBTN, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORDLG(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_DLG)
#define FORWARD_WM_CTLCOLORDLG(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORDLG, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORSCROLLBAR(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_SCROLLBAR)
#define FORWARD_WM_CTLCOLORSCROLLBAR(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSCROLLBAR, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
#define HANDLE_WM_CTLCOLORSTATIC(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)(lParam),
CTLCOLOR_STATIC)
#define FORWARD_WM_CTLCOLORSTATIC(hwnd, hdc, hwndChild, fn) \
(HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLORSTATIC, (WPARAM)(HDC)(hdc),
(LPARAM)(HWND)(hwndChild))
/* void Cls_OnSetFont(HWND hwndCtl, HFONT hfont, BOOL fRedraw) */
#define HANDLE_WM_SETFONT(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HFONT)(wParam), (BOOL)(lParam)), 0L)
#define FORWARD_WM_SETFONT(hwnd, hfont, fRedraw, fn) \
(void)(fn)((hwnd), WM_SETFONT, (WPARAM)(HFONT)(hfont), (LPARAM)(BOOL)(fRedraw))
/* HFONT Cls_OnGetFont(HWND hwnd) */
#define HANDLE_WM_GETFONT(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(UINT)(HFONT)(fn)(hwnd)
#define FORWARD_WM_GETFONT(hwnd, fn) \
(HFONT)(UINT)(DWORD)(fn)((hwnd), WM_GETFONT, 0L, 0L)
/* void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem) */
#define HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const DRAWITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_DRAWITEM(hwnd, lpDrawItem, fn) \
(void)(fn)((hwnd), WM_DRAWITEM, (WPARAM)(((const DRAWITEMSTRUCT *)lpDrawItem)>CtlID), (LPARAM)(const DRAWITEMSTRUCT *)(lpDrawItem))
/* void Cls_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * lpMeasureItem) */
#define HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (MEASUREITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_MEASUREITEM(hwnd, lpMeasureItem, fn) \
(void)(fn)((hwnd), WM_MEASUREITEM, (WPARAM)(((MEASUREITEMSTRUCT *)lpMeasureItem)>CtlID), (LPARAM)(MEASUREITEMSTRUCT *)(lpMeasureItem))
/* void Cls_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT * lpDeleteItem) */
#define HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (const DELETEITEMSTRUCT *)(lParam)), 0L)
#define FORWARD_WM_DELETEITEM(hwnd, lpDeleteItem, fn) \
(void)(fn)((hwnd), WM_DELETEITEM, (WPARAM)(((const DELETEITEMSTRUCT
*)(lpDeleteItem))->CtlID), (LPARAM)(const DELETEITEMSTRUCT *)(lpDeleteItem))
/* int Cls_OnCompareItem(HWND hwnd, const COMPAREITEMSTRUCT * lpCompareItem) */
#define HANDLE_WM_COMPAREITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (const COMPAREITEMSTRUCT *)(lParam))
#define FORWARD_WM_COMPAREITEM(hwnd, lpCompareItem, fn) \
(int)(DWORD)(fn)((hwnd), WM_COMPAREITEM, (WPARAM)(((const COMPAREITEMSTRUCT
*)(lpCompareItem))->CtlID), (LPARAM)(const COMPAREITEMSTRUCT *)(lpCompareItem))
/* int Cls_OnVkeyToItem(HWND hwnd, UINT vk, HWND hwndListbox, int iCaret) */
#define HANDLE_WM_VKEYTOITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam),
(int)(short)HIWORD(wParam))
#define FORWARD_WM_VKEYTOITEM(hwnd, vk, hwndListBox, iCaret, fn) \
(int)(DWORD)(fn)((hwnd), WM_VKEYTOITEM, MAKEWPARAM((vk), (iCaret)),
(LPARAM)(hwndListBox))
/* int Cls_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret) */
#define HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)LOWORD(wParam), (HWND)(lParam),
(int)(short)HIWORD(wParam))
#define FORWARD_WM_CHARTOITEM(hwnd, ch, hwndListBox, iCaret, fn) \
(int)(DWORD)(fn)((hwnd), WM_CHARTOITEM, MAKEWPARAM((UINT)(ch), (UINT)(iCaret)),
(LPARAM)(hwndListBox))
/* void Cls_OnQueueSync(HWND hwnd) */
#define HANDLE_WM_QUEUESYNC(hwnd, wParam, lParam, fn) \
((fn)(hwnd), 0L)
#define FORWARD_WM_QUEUESYNC(hwnd, fn) \
(void)(fn)((hwnd), WM_QUEUESYNC, 0L, 0L)
#if (WINVER >= 0x030a)
/* void Cls_OnCommNotify(HWND hwnd, int cid, UINT flags) */
#define HANDLE_WM_COMMNOTIFY(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (int)(wParam), (UINT)LOWORD(lParam)), 0L)
#define FORWARD_WM_COMMNOTIFY(hwnd, cid, flags, fn) \
(void)(fn)((hwnd), WM_COMMNOTIFY, (WPARAM)(cid), MAKELPARAM((flags), 0))
#endif
/* void Cls_OnDisplayChange(HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT
cyScreen) */
#define HANDLE_WM_DISPLAYCHANGE(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (UINT)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(wParam)), 0L)
#define FORWARD_WM_DISPLAYCHANGE(hwnd, bitsPerPixel, cxScreen, cyScreen, fn) \
(void)(fn)((hwnd), WM_DISPLAYCHANGE, (WPARAM)(UINT)(bitsPerPixel),
(LPARAM)MAKELPARAM((UINT)(cxScreen), (UINT)(cyScreen)))
/* BOOL Cls_OnDeviceChange(HWND hwnd, UINT uEvent, DWORD dwEventData) */
#define HANDLE_WM_DEVICECHANGE(hwnd, wParam, lParam, fn) \
(LRESULT)(DWORD)(BOOL)(fn)((hwnd), (UINT)(wParam), (DWORD)(wParam))
#define FORWARD_WM_DEVICECHANGE(hwnd, uEvent, dwEventData, fn) \
(BOOL)(DWORD)(fn)((hwnd), WM_DEVICECHANGE, (WPARAM)(UINT)(uEvent),
(LPARAM)(DWORD)(dwEventData))
/* void Cls_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos) */
#define HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, fn) \
((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
#define FORWARD_WM_CONTEXTMENU(hwnd, hwndContext, xPos, yPos, fn) \
(void)(fn)((hwnd), WM_CONTEXTMENU, (WPARAM)(HWND)(hwndContext),
MAKELPARAM((UINT)(xPos), (UINT)(yPos)))
/****** Static control message APIs ******************************************/
#define Static_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define Static_GetText(hwndCtl, lpch, cchMax)
(cchMax))
#define Static_GetTextLength(hwndCtl)
#define Static_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch),
#define Static_SetIcon(hwndCtl, hIcon)
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_SETICON, (WPARAM)(HICON)(hIcon), 0L))
#define Static_GetIcon(hwndCtl, hIcon)
((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_GETICON, 0L, 0L))
/****** Button control message APIs ******************************************/
#define Button_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define Button_GetText(hwndCtl, lpch, cchMax)
(cchMax))
#define Button_GetTextLength(hwndCtl)
#define Button_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch),
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
#define Button_GetCheck(hwndCtl)
BM_GETCHECK, 0L, 0L))
#define Button_SetCheck(hwndCtl, check)
BM_SETCHECK, (WPARAM)(int)(check), 0L))
((int)(DWORD)SendMessage((hwndCtl),
#define Button_GetState(hwndCtl)
BM_GETSTATE, 0L, 0L))
#define Button_SetState(hwndCtl, state)
BM_SETSTATE, (WPARAM)(int)(state), 0L))
((int)(DWORD)SendMessage((hwndCtl),
((void)SendMessage((hwndCtl),
((UINT)(DWORD)SendMessage((hwndCtl),
#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)
(cchMax))
#define Edit_GetTextLength(hwndCtl)
#define Edit_SetText(hwndCtl, lpsz)
GetWindowText((hwndCtl), (lpch),
GetWindowTextLength(hwndCtl)
SetWindowText((hwndCtl), (lpsz))
#define Edit_LimitText(hwndCtl, cchMax)
EM_LIMITTEXT, (WPARAM)(cchMax), 0L))
((void)SendMessage((hwndCtl),
#define Edit_GetLineCount(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl),
EM_GETLINECOUNT, 0L, 0L))
#define Edit_GetLine(hwndCtl, line, lpch, cchMax) ((*((int *)(lpch)) = (cchMax)),
((int)(DWORD)SendMessage((hwndCtl), EM_GETLINE, (WPARAM)(int)(line),
(LPARAM)(LPTSTR)(lpch))))
#define Edit_GetRect(hwndCtl, lprc)
((void)SendMessage((hwndCtl),
EM_GETRECT, 0L, (LPARAM)(RECT *)(lprc)))
#define Edit_SetRect(hwndCtl, lprc)
((void)SendMessage((hwndCtl),
EM_SETRECT, 0L, (LPARAM)(const RECT *)(lprc)))
#define Edit_SetRectNoPaint(hwndCtl, lprc)
((void)SendMessage((hwndCtl),
EM_SETRECTNP, 0L, (LPARAM)(const RECT *)(lprc)))
#define Edit_GetSel(hwndCtl)
((DWORD)SendMessage((hwndCtl),
EM_GETSEL, 0L, 0L))
#define Edit_SetSel(hwndCtl, ichStart, ichEnd) ((void)SendMessage((hwndCtl),
EM_SETSEL, (ichStart), (ichEnd)))
#define Edit_ReplaceSel(hwndCtl, lpszReplace)
((void)SendMessage((hwndCtl),
EM_REPLACESEL, 0L, (LPARAM)(LPCTSTR)(lpszReplace)))
#define Edit_GetModify(hwndCtl)
EM_GETMODIFY, 0L, 0L))
#define Edit_SetModify(hwndCtl, fModified)
EM_SETMODIFY, (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)
((int)(DWORD)SendMessage((hwndCtl),
((void)SendMessage((hwndCtl),
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),
((int)(DWORD)SendMessage((hwndCtl),
#define Edit_Scroll(hwndCtl, dv, dh)
EM_LINESCROLL, (WPARAM)(dh), (LPARAM)(dv)))
((void)SendMessage((hwndCtl),
#define Edit_CanUndo(hwndCtl)
EM_CANUNDO, 0L, 0L))
#define Edit_Undo(hwndCtl)
EM_UNDO, 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),
((BOOL)(DWORD)SendMessage((hwndCtl),
((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)
((HLOCAL)(UINT)(DWORD)SendMessage((hwndCtl), EM_GETHANDLE, 0L, 0L))
#define Edit_SetHandle(hwndCtl, h)
((void)SendMessage((hwndCtl),
EM_SETHANDLE, (WPARAM)(UINT)(HLOCAL)(h), 0L))
#if (WINVER >= 0x030a)
#define Edit_GetFirstVisibleLine(hwndCtl)
EM_GETFIRSTVISIBLELINE, 0L, 0L))
((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)
(pos), (fRedraw))
#define ScrollBar_GetPos(hwndCtl)
SetScrollPos((hwndCtl), SB_CTL,
GetScrollPos((hwndCtl), SB_CTL)
#define ScrollBar_SetRange(hwndCtl, posMin, posMax, fRedraw)
SetScrollRange((hwndCtl), SB_CTL, (posMin), (posMax), (fRedraw))
#define ScrollBar_GetRange(hwndCtl, lpposMin, lpposMax)
GetScrollRange((hwndCtl), SB_CTL, (lpposMin), (lpposMax))
/****** ListBox control message APIs *****************************************/
#define ListBox_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl),
(fEnable))
#define ListBox_GetCount(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETCOUNT, 0L, 0L))
#define ListBox_ResetContent(hwndCtl)
((BOOL)(DWORD)SendMessage((hwndCtl), LB_RESETCONTENT, 0L, 0L))
#define ListBox_AddString(hwndCtl, lpsz)
((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz)))
#define ListBox_InsertString(hwndCtl, index, lpsz)
((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index),
(LPARAM)(LPCTSTR)(lpsz)))
#define ListBox_AddItemData(hwndCtl, data)
((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0L, (LPARAM)(data)))
#define ListBox_InsertItemData(hwndCtl, index, data)
((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index),
(LPARAM)(data)))
#define ListBox_DeleteString(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_DELETESTRING, (WPARAM)(int)(index), 0L))
#define ListBox_GetTextLen(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXTLEN, (WPARAM)(int)(index), 0L))
#define ListBox_GetText(hwndCtl, index, lpszBuffer)
((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXT, (WPARAM)(int)(index),
(LPARAM)(LPCTSTR)(lpszBuffer)))
#define ListBox_GetItemData(hwndCtl, index)
((LRESULT)(DWORD)SendMessage((hwndCtl), LB_GETITEMDATA, (WPARAM)(int)(index), 0L))
#define ListBox_SetItemData(hwndCtl, index, data)
((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMDATA, (WPARAM)(int)(index),
(LPARAM)(data)))
#if (WINVER >= 0x030a)
#define ListBox_FindString(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_FindItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(data)))
#define ListBox_SetSel(hwndCtl, fSelect, index)
((int)(DWORD)SendMessage((hwndCtl), LB_SETSEL, (WPARAM)(BOOL)(fSelect),
(LPARAM)(index)))
#define ListBox_SelItemRange(hwndCtl, fSelect, first, last)
((int)(DWORD)SendMessage((hwndCtl), LB_SELITEMRANGE, (WPARAM)(BOOL)(fSelect),
MAKELPARAM((first), (last))))
#define ListBox_GetCurSel(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETCURSEL, 0L, 0L))
#define ListBox_SetCurSel(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_SETCURSEL, (WPARAM)(int)(index), 0L))
#define ListBox_SelectString(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_SelectItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(data)))
#define ListBox_GetSel(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_GETSEL, (WPARAM)(int)(index), 0L))
#define ListBox_GetSelCount(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETSELCOUNT, 0L, 0L))
#define ListBox_GetTopIndex(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETTOPINDEX, 0L, 0L))
#define ListBox_GetSelItems(hwndCtl, cItems, lpItems)
((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems),
(LPARAM)(int *)(lpItems)))
#define ListBox_SetTopIndex(hwndCtl, indexTop)
((int)(DWORD)SendMessage((hwndCtl), LB_SETTOPINDEX, (WPARAM)(int)(indexTop), 0L))
#define ListBox_SetColumnWidth(hwndCtl, cxColumn)
((void)SendMessage((hwndCtl),
LB_SETCOLUMNWIDTH, (WPARAM)(int)(cxColumn), 0L))
#define ListBox_GetHorizontalExtent(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETHORIZONTALEXTENT, 0L, 0L))
#define ListBox_SetHorizontalExtent(hwndCtl, cxExtent)
((void)SendMessage((hwndCtl), LB_SETHORIZONTALEXTENT, (WPARAM)(int)(cxExtent), 0L))
#define ListBox_SetTabStops(hwndCtl, cTabs, lpTabs)
((BOOL)(DWORD)SendMessage((hwndCtl), LB_SETTABSTOPS, (WPARAM)(int)(cTabs),
(LPARAM)(int *)(lpTabs)))
#define ListBox_GetItemRect(hwndCtl, index, lprc)
((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMRECT, (WPARAM)(int)(index),
(LPARAM)(RECT *)(lprc)))
#define ListBox_SetCaretIndex(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_SETCARETINDEX, (WPARAM)(int)(index), 0L))
#define ListBox_GetCaretIndex(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), LB_GETCARETINDEX, 0L, 0L))
#define ListBox_FindStringExact(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ListBox_SetItemHeight(hwndCtl, index, cy)
((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMHEIGHT, (WPARAM)(int)(index),
MAKELPARAM((cy), 0)))
#define ListBox_GetItemHeight(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMHEIGHT, (WPARAM)(int)(index), 0L))
#endif /* WINVER >= 0x030a */
#define ListBox_Dir(hwndCtl, attrs, lpszFileSpec)
((int)(DWORD)SendMessage((hwndCtl), LB_DIR, (WPARAM)(UINT)(attrs),
(LPARAM)(LPCTSTR)(lpszFileSpec)))
/****** ComboBox control message APIs ****************************************/
#define ComboBox_Enable(hwndCtl, fEnable)
EnableWindow((hwndCtl), (fEnable))
#define ComboBox_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch),
(cchMax))
#define ComboBox_GetTextLength(hwndCtl)
GetWindowTextLength(hwndCtl)
#define ComboBox_SetText(hwndCtl, lpsz)
SetWindowText((hwndCtl), (lpsz))
#define ComboBox_LimitText(hwndCtl, cchLimit)
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),
#define ComboBox_AddString(hwndCtl, lpsz)
((int)(DWORD)SendMessage((hwndCtl),
((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, index)
((LRESULT)(DWORD)SendMessage((hwndCtl), CB_GETITEMDATA, (WPARAM)(int)(index), 0L))
#define ComboBox_SetItemData(hwndCtl, index, data)
((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMDATA, (WPARAM)(int)(index),
(LPARAM)(data)))
#define ComboBox_FindString(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ComboBox_FindItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(data)))
#define ComboBox_GetCurSel(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), CB_GETCURSEL, 0L, 0L))
#define ComboBox_SetCurSel(hwndCtl, index)
((int)(DWORD)SendMessage((hwndCtl), CB_SETCURSEL, (WPARAM)(int)(index), 0L))
#define ComboBox_SelectString(hwndCtl, indexStart, lpszSelect)
((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszSelect)))
#define ComboBox_SelectItemData(hwndCtl, indexStart, data)
((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart),
(LPARAM)(data)))
#define ComboBox_Dir(hwndCtl, attrs, lpszFileSpec)
((int)(DWORD)SendMessage((hwndCtl), CB_DIR, (WPARAM)(UINT)(attrs),
(LPARAM)(LPCTSTR)(lpszFileSpec)))
#define ComboBox_ShowDropdown(hwndCtl, fShow)
((BOOL)(DWORD)SendMessage((hwndCtl), CB_SHOWDROPDOWN, (WPARAM)(BOOL)(fShow), 0L))
#if (WINVER >= 0x030a)
#define ComboBox_FindStringExact(hwndCtl, indexStart, lpszFind)
((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart),
(LPARAM)(LPCTSTR)(lpszFind)))
#define ComboBox_GetDroppedState(hwndCtl)
((BOOL)(DWORD)SendMessage((hwndCtl), CB_GETDROPPEDSTATE, 0L, 0L))
#define ComboBox_GetDroppedControlRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl),
CB_GETDROPPEDCONTROLRECT, 0L, (LPARAM)(RECT *)(lprc)))
#define ComboBox_GetItemHeight(hwndCtl)
((int)(DWORD)SendMessage((hwndCtl), CB_GETITEMHEIGHT, 0L, 0L))
#define ComboBox_SetItemHeight(hwndCtl, index, cyItem)
((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMHEIGHT, (WPARAM)(int)(index),
(LPARAM)(int)cyItem))
#define ComboBox_GetExtendedUI(hwndCtl)
((UINT)(DWORD)SendMessage((hwndCtl), CB_GETEXTENDEDUI, 0L, 0L))
#define ComboBox_SetExtendedUI(hwndCtl, flags)
((int)(DWORD)SendMessage((hwndCtl), CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L))
#endif /* WINVER >= 0x030a */
/****** Alternate porting layer macros ****************************************/
/* USER MESSAGES: */
#define GET_WPARAM(wp, lp)
#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)
GET_WM_COMMAND_HWND(wp, lp)
GET_WM_COMMAND_CMD(wp, lp)
GET_WM_COMMAND_MPS(id, hwnd, cmd)
LOWORD(wp)
(HWND)(lp)
HIWORD(wp)
\
(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)
(TCHAR)LOWORD(wp)
(HMENU)(lp)
(BOOL)HIWORD(wp)
#define
#define
#define
#define
#define
#define
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
LOWORD(wp)
HIWORD(wp)
(HWND)(lp)
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)
#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
_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
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
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
_fstrnicmp
_fstrnset
_fstrpbrk
_fstrrchr
_fstrrev
_fstrset
_fstrspn
_fstrstr
_fstrtok
_fstrupr
_nfree
_nmalloc
_nmsize
_nrealloc
_nstrdup
hmemcpy
_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 */
=============================================
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
//
if fCalcValidRects:
//
lprc[1] = rcWindowOld
//
lprc[2] = rcClientOld
// On return:
//
rgrc[0] = rcClientNew
//
if fCalcValidRects:
//
rgrc[1] = rcValidDst
//
rgrc[2] = rcValidSrc
= New window rectangle
= Old window rectangle
= Old client rectangle
= New client rect
= Destination valid rectangle
= 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.
//
//
//
//
//
//
if
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
((!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);
}
| Nachrichten | Application-Message-Queue | System-Message-Queue ||./img/system_message_queu.gif ||./img/keyboard_lparam.gif ||./img/keyboard_prinzip.gif | Tabelle der Nachrichten-Prefixe | Message Cracker - Macros | Portabilität | Win32 | Win16 | Tastatur - Nachrichten | Tasten - Scan - Code | Tabelle der WM - Tastatur - Nachrichten ||./img/key1.gif | Virtual - Tasten - Code | Tabelle der Virtual - Tasten Codes | Tasten - Zustand - Flags | Wie kann eine gedrücke SHIFT - Taste abgefragt werden? | Wie kann eine Berechnung abgebrochen werden? | Wie kann eine gedrückte CTRL - Taste
( VK_CONTROL ) per Programm simuliert werden? | Wie kann die CAPS - LOCK - Taste
( VK_CAPITAL ) invertiert werden? | Wie kann ein "floating-pop-up-menu"
nach der Anzeige sichtbar bleiben? | lParam - Tastenflags | Maus - Nachrichten | WM_MOUSE - Nachrichten | Nachrichtenverfolgung
↑
Nachrichten
Windows ist ein Nachrichten - gesteuertes System. Die Behandlung von Nachrichten ist ein zentraler Bestandteil des Betriebssystems. Es gibt eine Maus (mit
zugehörigem einer System-Message-Queue). Es gibt eine tastatur (mit zugehörigem einer System-Message-Queue). Zu jeder Applikation wird eine ApplikationMessage-Queue eingerichtet, in die jene Nachrichten (standardisiert) gestellt werden, die zu dieser Applikation gehören. Beispiel für den Nachrichten-Fluß bei einer
Tasten-Nachricht:
KEYBOARD
(Ereignis)
↑
KeyboardDeviceDriver
holt ScanCode
vom
Keyboard
und
stellt
diesen in
SYSTEMMESSAGEQUEUE
(gerätespezifisch)
Windows
bringt
die gerätespezifische
Nachricht auf
standardisierte
MSG-Form
(WM_...),
stellt diese in
APPLICATIONMESSAGEQUEUE
(ThreadMessage-Queue)
(MSG: WM_...)
Dispatch
Message
(&msg)
APPLICATIONNACHRICHTENSchleife
ruft die
CALLBACKFunktion auf,
die zu
msg.hWin
gehört
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 uMsg ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
} MSG ;
MSG msg ;
Keyboard-Prinzip:
Beispiel lParam bei uMsg = WM_KEYDOWN:
WM_KEYDOWN: lParam :
↑
Tabelle der Nachrichten-Prefixe
Prefix
Message category
Prefix
Message category
Prefix
Message category
ABM
Application desktop toolbar
HDM
Header control
SB
Status bar window
BM
Button control
HKM
Hot key control
ABM
Application desktop toolbar
CB
Combo box control
IPM
IP address control
SBM
Scroll bar control
CBEM
Extended combo box control
LB
List box control
STM
Static control
CDM
Common dialog box
LVM
List view control
TB
Toolbar
DBT
Device
MCM
Month calendar control
TBM
Trackbar
DL
Drag list box
ABM
Application desktop toolbar
TCM
Tab control
DM
Default push button control
PBM
Progress bar
TTM
Tooltip control
DTM
Date and time picker control
PGM
Pager control
TVM
Tree-view control
EM
Edit control
PSM
Property sheet
UDM
Up-down control
RB
Rebar control
WM
General window
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.
MSG msg;
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, uMsg, fn)
\
case (uMsg): return HANDLE_##uMsg((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, uMsg, wParam, lParam ) Nachricht.
Mit dem HANDLE_MSG - Macro hat eine CALLBACK - Funktion etwa den folgenden Aufbau:
LRESULT CALLBACK myCallbackProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
HANDLE_MSG( hWnd, WM_CHAR, myOnChar);
HANDLE_MSG( ... );
...
default:
return myOrgProc( hWnd, uMsg, 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, uMsg, 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 uMsg, WPARAM wParam, LPARAM lParam) {
return CallWindowProc( lpOrgProc, hWnd, uMsg, 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äß erfolgen durch
WNDPROC lpOrgProc = NULL;
lpOrgProc = Sumy_classWindow( hWnd, myCallbackProc));
...
↑
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 ( uMsg, 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 uMsg ist die
Tasten - Nachricht eindeutig identifizierbar. Mit wParam, lParam können die Tasten unterschieden werden.
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
switch ( uMsg ) {
...
case WM_CHAR : {
switch ( LOWORD(wParam) ) {
case ‘\b’ : Rücktaste; break;
case ‘\t’ : Tabulatortaste; break;
case ‘\n’ : LF-Taste; break;
default : //normales Zeichen bearbeiten
}
}
...
}
return DefWindowProc( hWnd, uMsg, 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
WM_KILLFOCUS
wParam, lParam enthalten ...
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
// handle of window losing focus
hwndLoseFocus = (HWND) wParam;
// handle of window receiving focus
hwndGetFocus = (HWND) wParam;
WM_KEYDOWN nVirtKey = (int) wParam; // virtual-key code
WM_KEYUP
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
↑
TastenNachricht
WM_SYSKEYDOWN nVirtKey = (int) wParam; // virtual-key code
WM_SYSKEYUP
lKeyData = lParam; // key data
Virtual - Tasten - Code
Je Taste werden mehr als eine Nachricht generiert. Wird z.B. der Klein - Buchstabe a auf der Tastatur gedrückt, so wird die CALLBACK - Funktion mehrfach
aufgerufen, d.h. es werden die folgenden 3 Nachrichten generiert:
●
WM_KEYDOWN ( virtuelle Taste, wie z.B.
F1-Taste = VK_F1, Pfeil-DOWN-Taste = VK_DOWN,
PAGE-DOWN-Taste = VK_NEXT, PAGE-UP-Taste = VK_PRIOR,
HOME-Taste = VK_HOME, END-Taste = VK_END )
●
WM_CHAR ( wParam enthält ASCII von a, wie z.B. für a-Taste = '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 uMsg, WPARAM wParam, LPARAM lParam ) {
switch ( uMsg ) {
...
case WM_KEYDOWN : {
switch ( 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 ( uMsg ) {
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
= 0x2E VK_HELP
= 0x2F
VK_0
..VK_9
= 0x30 VK_A
...0x39 ..VK_Z
= 0x41
VK_LWIN
..0x5A
= 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_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_DELETE
VK_ADD
VK_RMENU
= 0x6B VK_SEPARATOR = 0x6C
= 0xA5
VK_PROCESSKEY
= 0xE5
WINVER<=0x0400
VK_ATTN
= 0xF6 VK_CRSEL
= 0xF7 VK_EXSEL
= 0xF8 VK_EREOF
VK_NONAME
= 0xFC VK_PA1
= 0xFD VK_OEM_CLEAR = 0xFE
= 0xF9 VK_PLAY
=
0xFA
VK_ZOOM
=
0xFB
Z.B. wird durch die Alt - Taste die wParam = VK_MENU - Nachricht generiert.
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() Funktionen benutzt.
↑
Tasten - Zustand - Flags
Der aktuelle Zustand aller Tasten wird in einem Buffer protokolliert. Auch die Applikation kann diese Einträge lesen/schreiben, wobei zwischen synchron/asynchron
unterschieden wird. Wird eine neue Tasten - Nachricht in den Applikations - Nachrichten - Warteschlange ( Applikations - Buffer ) eingetragen, so ändert sich der
asynchron Keyboard - Zustand. Der synchron Keyboard - Zustand entspricht dem momentanen Zustand der Tastatur.
↑
Wie kann eine gedrücke SHIFT - Taste abgefragt werden?
if ( GetKeyState ( VK_SHIFT ) & 0x80000000L ) {
// SHIFT - Taste gedrückt
}
GetKeyState() ( imGegensatz zu GetAsyncKeyState ) liefert den Zustand ohne Verzögerung zurück. Durch GetKeyState ( VK_LBUTTON ) wird z.B. der aktuelle
Zustand der linken Maustaste abgefragt.
↑
Wie kann eine Berechnung abgebrochen werden?
Dauert z.B. eine Berechnung zu lange und soll diese Berechnung durch
●
die Escape - Taste oder
●
die linke Maus - Taste
abgebrochen werden, so kann dies mit der ( asynchronen ) GetAsyncKeyState() - Funktion
if ( ( GetAsyncKeyState ( VK_LBUTTON ) < 0 ) // linke Maus - Taste down
|| ( GetAsyncKeyState ( VK_ESCAPE ) < 0 ) // Escape Taste
) {
// ... z.B. exit ( -1 ); oder
// ... SendMessage ( hWnd, WM_CLOSE, 0, 0 )
}
erfolgen. Um den Zustand von mehreren Tasten zu untersuchen, wie z.B. die
●
Shift - Taste ( VK_SHIFT, VK_LSHIFT, VK_RSHIFT ),
●
Ctrl - Taste ( VK_CONTROL, VK_LCONTROL, VK_RCONTROL ),
●
Alt - Taste ( VK_MENU, VK_LMENU, VK_RMENU )
können alle 256 Virtual Keys in einen Buffer buf kopiert werden. Die Funktionen GetKeyboardState(), SetKeyboardState(), GetAsyncKeyState(), GetKeyState(),
MapVirtualKey() werden benutzt. Es kann dann z.B. zwischen linken und rechten SHIFT - Tasten unterschieden werden. Die GetKeyboardState( buf ) - Funktion
kopiert alle 256 Virtual Keys in einen Buffer buf. Eine Taste ist gerade gedrückt, wenn das 7. Bit gesetzt ist ( sonst 0 ). Der Gedrückt/Losgelassen - Zustand hat
gewechselt, wenn das 0. Bit gleich 1 ist ( tggled ). Normalerweise ist eine Taste nicht gedrückt, dann ist das 0. Bit gleich 1.
↑
Wie kann eine gedrückte CTRL - Taste
( VK_CONTROL ) per Programm simuliert werden?
BYTE buf[256];
GetKeyboardState( buf ); // hole VK_ - Keys
buf[VK_CONTROL] |= 0x80;
// setze "gedrückt" bei VK_CONTROL - Taste
SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
↑ Wie kann die CAPS - LOCK - Taste
( VK_CAPITAL ) invertiert werden?
BYTE buf[256];
GetKeyboardState( buf );
if ( buf[VK_CAPITAL] & 1 ) buf[VK_CAPITAL] &= 0xFE;
else
buf[VK_CAPITAL] |= 0x01;
SetKeyboardState( buf );
VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() Funktionen benutzt.
↑ Wie kann ein "floating-pop-up-menu"
nach der Anzeige sichtbar bleiben?
case WM_RBUTTONDOWN: {
BYTE buf[256];
GetKeyboardState( buf ); // hole VK_ - Keys
buf[VK_RBUTTON] = 0x00; // setze "losgelassen" bei VK_RBUTTON - Maus - Taste
SetKeyboardState( buf ); // schreibe VK_ - Keys zurück
... create - pop - up - Menu ...
... call TrackPopUp
...
break; }
↑
lParam - Tastenflags
TranslateMessage() benutzt die Funktion ToAsciiEx() um den virtuellen Key - Code ( z.B. für die WM_KEYDOWN - Nachricht ) zu erzeugen. Eine Nachricht enthält
in LOWORD( lParam ) die Anzahl von automatischen Tasten - Wiederholungen. Durch diesen Anschlag - Wiederholungs - Zähler werden Überflutungen von
Nachrichten vermieden.
In HIWORD( lParam ) sind interessante Tasten - Flags, die im folgenden erklärt werden. Eine Nachricht enthält in HIWORD( lParam ) interessante Tasten - Flags, die
im folgenden erklärt werden.
Bit HIWORD( lParam ) - Bit
15
1 if the key is up;
0 if the key is down.
Bit HIWORD( lParam ) - Bit
14
1 if the key was previously up;
0 if the key was previously down.
Bit HIWORD( lParam ) - Bit
Bit HIWORD( lParam ) - Bit
13 1 if the ALT key is down.
12 1 if Windows displays a menu.
11 1 if Windows displays a dialog box.
7 generally 0.
↑
10 Not used.
6..0
9 Not used.
8
1 if the key is extended;
0 if it is not.
hardware-scan code
( 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 ( uMsg, 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 uMsg ist die
Maus - Nachricht eindeutig identifizierbar. Typische uMsg 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 uMsg, WPARAM wParam, LPARAM lParam ) {
static int xPos,yPos;
switch ( uMsg ) {
...
case WM_LBUTTONDOWN :
xPos = (int) LOWORD(lparam); // 16 BIT
yPos = (int) HIWORD(lparam); // pt = MAKEPOINT(lparam); // 32 BIT, pt vom
Typ Point
break;
...
}
...
return DefWindowProc( hWnd, uMsg, 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
Nachricht
wParam, lParam enthalten ...
WM_CAPTURECHANGED
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
nHittest see WM_NCHITTEST
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.
↑
Nachrichtenverfolgung
Um die Folge von Nachrichten zu untersuchen, soll die folgende Funktion schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam) die Folge der
Nachrichten anzeigen. Der Header-File enthält die #define's für die Nachrichten, die in einen Array der Art { "WM_DESTROY", WM_DESTROY}// 0x0002 hinterlegt
werden. Steht der Aufruf schreibe_nachrichten(uMsg,wParam,lParam) in einer CALLBACK-Funktion, so durchläuft for(int i = 0;i < n; i++) {...} alle Array-Einträgt
und gibt den gefundenen aus.
Das stdout_to()-Macro ermöglicht (mit Hilfe der freopen()-Funktion), die Standard-Ausgabe der printf's (einer Console-Applikation) in den aktuellen Quelltext-File
(__FILE__) umzuleiten. Die Benutzung von stdout_to erfolgt etwa gemäss:
stdout_to(__FILE__);
printf("\n // ...");
printf("\n // ...");
stdout_to("CON");
Die folgende Funktion schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam) wird in der CALLBACK-Funktion aufgerufen. In
schreibe_nachrichten() wird beijeder ankommenden Nachricht die Nachrichten-Tabelle msgdesc[] durchlaufen und bei Übereinstimmung wird der Name der aktuellen
uMsg-Nachricht (und auch wParam,lParam) ausgegeben.
void schreibe_nachrichten(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
#undef stdout_to
#define stdout_to(f) if((freopen(f,"at", stdout))==NULL)\
{fprintf(stderr,"\nredir-err\n");exit(-1);}
typedef struct { LPTSTR psz; UINT uMsg;} MSGDESC;
static MSGDESC msgdesc[] =
{
{ "WM_NULL",
WM_NULL},
// 0x0000
{ "WM_CREATE",
WM_CREATE},
// 0x0001
{ "WM_DESTROY", WM_DESTROY},
// 0x0002
{ "WM_MOVE",
WM_MOVE},
// 0x0003
{ "WM_SIZE",
WM_SIZE},
// 0x0005
{ "WM_ACTIVATE", WM_ACTIVATE},
// 0x0006
{ "WM_SETFOCUS", WM_SETFOCUS},
// 0x0007
...
};
static UINT j; if(j == 0) stdout_to(__FILE__);
UINT len = sizeof(msgdesc)/sizeof(msgdesc[0]);
for(int i = 0; i < len; i++) {
if(uMsg == msgdesc[i].uMsg) {
printf("\n// %03u %04x %s", j++, i, msgdesc[i].psz);
if(uMsg == WM_COMMAND)
printf(" wPar=0x%08x lPar=0x%08x",wParam,lParam);
}
}
}
Es gibt Werkzeuge, die eine fortgeschrittene Verfolgung der Nachrichten erlauben (z.B. spy++).
=============================================
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 | Lebensdauer von Objekten | Gegenüberstellung | Klassen - Objekte | Fenster - Objekte || ./img/virtual_heap.gif | Beispiel CreateWindow(), DestroyWindow() ||
./img/object1.gif || ./img/object2.gif | GDI - Objekte | Device Kontext | Funktionen zum Zeichnen MoveToEx(), LineTo(), Polyline() | Rectangle(), MoveToEx(), LineTo(),
MoveToEx(), LineTo(), Ellipse(), RoundRect() | Funktionen zum Schreiben TextOut() | Beispiel: DrawText()
↑
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
Destroyer function
User Objects
Creator function
Destroyer function
Accelerator CreateAcceleratorTable
table
DestroyAcceleratorTable Cursor
LoadCursor, GetCursor,
CreateCursor SetCursor
DestroyCursor
DDE
conversation
DdeDisconnect,
DdeDisconnectList
Applications cannot
delete this object.
DdeConnect, DdeConnectList,
DdeQueryNextServer,
DdeReconnect
Desktop
GetThreadDesktop
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.
↑
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
( System bei shared )
Programm, Block
bis zur Freigabe
( System bei shared )
32 Byte
Resourcen
RC-Compiler
( Linker, Lader )
Programm, Block
(System bei stock)
Programm
(System bei stock)
ca. 32 Byte
GDI Objekte
USER-Funktionen
( Linker mit *.lib, Lader )
System
( Programm )
Programm, Block
bis zur Freigabe
( System bei stock )
ca. 30-50 Byte
User Objekte
Linker
Programm, Block
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.
C-Run-time
strcat, wcscat
strcpy, wcscpy
strerror
String Manipulation
Win32
C-Run-time
Win32
C-Run-time
lstrcat
strchr, wcschr
none
strcmp, wcscmp
lstrcpy
strcspn, wcscspn none
_strdup, _wcsdup
FormatMessage _strerror
FormatMessage _stricmp, _wcsicmp
Win32
lstrcmp
none
lstrcmpi
strlen, wcslen
lstrlen
strncmp, wcsncmp none
FillMemory,
_strnset, _wcsnset
ZeroMemory
CharLower,
strncat, wcsncat
none
CharLowerBuffer
strncpy, wcsncpy none
_strnicmp, _wcsnicmp none
_strlwr, _wcslwr
strpbrk, wcspbrk none
strrchr, wcsrchr
none
_strrev, _wcsrev
none
_strset, _wcsset
FillMemory,
ZeroMemory
strspn, wcsspn
none
strstr, wcsstr
none
strtok, wcstok
none
_strupr, _wcsupr
CharUpper,
CharUpperBuffer
Buffer Manipulation
C-Run-time Win32 C-Run-time
Win32
C-Run-time Win32 C-Run-time
Win32
_memccpy none memchr
none
memcmp none
memcpy
CopyMemory
FillMemory,
_swab
none
_memicmp none memmove MoveMemory memset
ZeroMemory
C-Runtime
isalnum
__iscsym
islower
isupper
Win32
IsCharAlphaNumeric
none
IsCharLower,
GetStringTypeW
(Unicode)
IsCharUpper,
GetStringTypeW
(Unicode)
Character Classification
C-RunC-Run-time
Win32
time
IsCharAlpha,
isalpha
GetStringTypeW
__isascii
(Unicode)
__iscsymf
none
isdigit
isprint
none
ispunct
isxdigit
none,
GetStringTypeW
(Unicode)
__toascii
Win32
none
none,
GetStringTypeW
(Unicode)
none,
GetStringTypeW
(Unicode)
none
C-Runtime
Win32
iscntrl
none,
GetStringTypeW
(Unicode)
isgraph
none
isspace
none,
GetStringTypeW
(Unicode)
tolower
CharLower
_tolower
none
toupper
CharUpper
_toupper
none
Directory Control
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
_chdir
SetCurrentDirectory _chdrive
SetCurrentDirectory _getcwd
GetCurrentDirectory _getdrive GetCurrentDirectory
_mkdir
CreateDirectory
_rmdir
RemoveDirectory _searchenv SearchPath
File Handling
C-Run-time Win32 C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
_access
none
_chmod
SetFileAttributes _chsize
SetEndOfFile
_filelength
GetFileSize
_fstat
See Note 5 _fullpath GetFullPathName _get_osfhandle none
_isatty
GetFileType
_locking
LockFileEx _makepath none
_mktemp
GetTempFileName _open_osfhandle none
remove
DeleteFile rename
MoveFile
_setmode
none
_splitpath
none
_stat
none
_umask
none
_unlink
DeleteFile
Creating Text Output Routines
C-Run-time
Win32
C-Run-time
Win32
_displaycursor*
SetConsoleCursorInfo
_gettextcolor* GetConsoleScreenBufferInfo
_gettextcursor*
GetConsoleCursorInfo
_gettextposition* GetConsoleScreenBufferInfo
_gettextwindow* GetConsoleWindowInfo _outtext*
WriteConsole
_scrolltextwindow* ScrollConsoleScreenBuffer _settextcolor*
SetConsoleTextAttribute
_settextcursor*
SetConsoleCursorInfo
_settextposition* SetConsoleCursorPosition
_settextwindow* SetConsoleWindowInfo
_wrapon*
SetConsoleMode
C-Run-time
Win32
clearerr
none
feof
none
_fgetchar none
Stream Routines
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
fclose
CloseHandle
_fcloseall none
_fdopen
none
ferror
none
fflush
FlushFileBuffers fgetc
none
fgetpos
none
fgets
none
_fileno
none
_flushall
none
fopen
CreateFile
fprintf
none
_fputchar
none
fputs
none
fread
ReadFile
fscanf
none
fseek
SetFilePointer
fwrite
(check return value)
none
_getw
none
puts
none
scanf
none
sprintf
none
tmpnam
none
_vsnprintf
SetFilePointer
fsetpos
SetFilePointer
fputc
none
freopen
SetStdHandle
(std handles)
_fsopen
CreateFile
WriteFile
getc
none
getchar
none
none
none
none
none
none
wvsprintf
putc
rewind
setvbuf
_tempnam
vfprintf
none
SetFilePointer
none
GetTempFileName
none
ftell
gets
putchar
_rmtmp
_snprintf
tmpfile
vprintf
none
printf
none
_putw
none
setbuf
wsprintf
sscanf
GetTempFileName ungetc
none
vsprintf
Low-Level I/O
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
C-Run-time
Win32
_close
_lclose, CloseHandle _commit
FlushFileBuffers _creat
_lcreat, CreateFile
_dup
DuplicateHandle
_dup2
none
_eof
none
_lseek
_llseek, SetFilePointer _open
_lopen, CreateFile
SetFilePointer
_write
_lread
_read
_lread, ReadFile
_sopen
CreateFile
_tell
(check return value)
Console and Port I/O Routines
C-Run-time
Win32
C-Run-time
Win32
C-Run-time Win32 C-Run-time
Win32
_cgets
none
_cprintf
none
_cputs
none _cscanf
none
_getch
ReadConsoleInput _getche
ReadConsoleInput _inp
none _inpw
none
_kbhit
PeekConsoleInput _outp
none
_outpw
none _putch
WriteConsoleInput
_ungetch none
Memory Allocation
C-RunWin32
C-Run-time
Win32
time
_alloca
none
_bfreeseg* none
_bheapseg* none
calloc
GlobalAlloc
_expand
none
free
GlobalFree _freect*
GlobalMemoryStatus _halloc*
GlobalAlloc
_heapadd
none
_heapchk none
_heapmin none
_heapset
none
_heapwalk
none
_hfree*
GlobalFree malloc
GlobalAlloc
_memavl
GlobalMemoryStatus
_memmax
GlobalMemoryStatus _msize*
GlobalSize realloc
GlobalReAlloc
_set_new_handler none
_set_hnew_handler* none
_stackavail* none
C-Run-time
C-Run-time
abort
none
_c_exit
none
Win32
Win32
C-Run-time
Win32
Process and Environment Control Routines
C-Run-time
Win32
C-Run-time
Win32
assert
none
atexit
none
_exec functions none
exit
ExitProcess
C-Run-time Win32
_cexit
none
_exit
ExitProcess
getenv
GetEnvironmentVariable _getpid
GetCurrentProcessId
longjmp
perror
FormatMessage
_putenv
SetEnvironmentVariable raise
signal
SetConsoleCtrlHandler _spawn functions CreateProcess
system
(ctrl-c only)
↑
Klassen - Objekte
↑
Fenster - Objekte
none
_onexit
RaiseException setjmp
none
none
CreateProcess
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:
TCHAR buf[256]; TCHAR pStr[5000]; TCHAR * 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, TEXT("%s\n") , buf );
} else { p += wsprintf( p, TEXT("\t%s\n"), buf ); }
} MessageBox( hWnd, pStr, TEXT("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 uMsg = 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 uMsg, WPARAM wParam, LPARAM lParam ) {
static int cxClient, cyClient ; POINT pt [NUM] ;
switch ( uMsg ) {
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 , uMsg, 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 uMsg, WPARAM wParam, LPARAM lParam ) {
static int cxClient, cyClient ; HDC hDC ; PAINTSTRUCT ps ;
switch ( uMsg ) {
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 , uMsg, wParam, lParam ) ;
}
↑
Funktionen zum Schreiben TextOut()
Die TextOut() - Funktion wird in der CALLBACK - FUnktion unter uMsg = 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(
TextOut(
TextOut(
TextOut(
TextOut(
TextOut(
EndPaint
break;
↑
hDC, 50,
hDC, 50,
hDC, 50,
hDC, 50,
hDC, 50,
hDC, 50,
( hWnd ,
175,
200,
225,
250,
275,
300,
& ps
"4.Zeile",
"5.Zeile",
"6.Zeile",
"7.Zeile",
"8.Zeile",
"9.Zeile",
) ;
7
7
7
7
7
7
);
);
);
);
);
);
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_CALCRECT,
DT_END_ELLIPSIS oder DT_PATH_ELLIPSIS,
DT_CENTER,
DT_EXPANDTABS,
DT_EDITCONTROL,
DT_EXTERNALLEADING,
DT_INTERNAL,
DT_NOPREFIX,
DT_TABSTOP,
DT_WORD_ELLIPSIS
DT_LEFT,
DT_RIGHT,
DT_TOP,
DT_MODIFYSTRING,
DT_RTLREADING,
DT_VCENTER,
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 | *.RC-Syntax | Vordefinierte Resourcen - Typen | MAKEINTRESOURCE() - Macro | Resourcen - Itentifizierer | Benutzerdefinierte Resourcen - Macros | Resource-Funktionen | Cursor - Resource | Icon - Resource |
String - Table - Resource | Menu - Resourcen | System - Menu | Beschleunigungs - Tasten | LoadMenuIndirect || ./img/menu_indirect.gif | CREATE_DLG_INDIRECT || ./img/dlg_indirect.gif | Ressourcen von dll's MDICLIENT
↑
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)entifiziereeinen_(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_ Dialog-resource Help context
HIDD_SPELL_CHECK
0x20001 to 0x26FF
IDB_
Bitmap resource
IDB_COMPANY_LOGO
1 to 0x6FFF
IDC_
Cursor resource
IDC_PENCIL
1 to 0x6FFF
IDI_
Icon resource
IDI_NOTEPAD
1 to 0x6FFF
ID_ _
Command from menu item or toolbar ID_TOOLS_SPELLING
0x8000 to 0xDFFF
HID_
Command Help context
HID_TOOLS_SPELLING
0x18000 to 0x1DFFF
IDP_
Message-box prompt
IDP_INVALID_PARTNO
8 to 0xDFFF
HIDP_ Message-box Help context
HIDP_INVALID_PARTNO 0x30008 to 0x3DFFF
IDS_
IDS_COPYRIGHT
String resource
1 to 0x7FFF
IDC_
↑
Control within dialog box
IDC_RECALC
8 to 0xDFFF
Benutzerdefinierte Resourcen - Macros
Damit die unterschiedliche Syntax und Bezeichner im *.RC, *.H und *.CPP Files bei den Übersetzungen unterschieden werden können, gibt es vordefinierte Konstanten ( z.B.
RC_INVODED ). Durch
#ifdef RC_INVODED
#define ID(x) x
#else
#define ID(x) MAKEINTRESOURCE(x)
#endif
wird während der Resourcen - Übersetzung anstelle von ID(x) das Macro MAKEINTRESOURCE(x) verwendet und sonst die Zahl x direkt. Für die Erstellung eines *.RC - Resourcen Files ( ASCII ) "von Hand" können die folgenden Macros hilfreich sein. Durch solche Macros kann eine einheitliche, übersichtliche Gestaltung des *.RC - Files erreicht werden. Im C/C++
- Programm wird eine Resource durch einen Idetifizierer ( idRes = ID_ ... ) angesprochen.
#define ICON_NAME(idRes, pFileName) idRes ICON DISCARDABLE pFileName
#define 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_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
#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
↑
Resource-Funktionen
Resourcen werden mit Load...()-Funktionen verfügbar. Diese Load...()-Funktionen benötigen die Instance hInstance des usführenden Programmes. Zur Vermeidung von globalen Variablen
hInstance wird oft hInstance = GetModuleHandle(0) verwendet. Auch bei DLL's funktioniert die folgende Funktion:
HINSTANCE GetMyHinstance(VOID)
{ MEMORY_BASIC_INFORMATION mbi;
VirtualQuery((PVOID)GetMyHinstance, &mbi, sizeof(mbi));
return ((HINSTANCE)mbi.AllocationBase);
}
↑
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 XORverknüpft. Der Hotspot gibt innerhalb der Maske die Pixel - Position an, welche z.B. die Spitze des Pfeils symbolisiert. Die Erstellung eines Maus - Cursor - Bitmap durch den Benutzer ist
nur dann erforderlich, wenn die verfügbaren Maus - Cursor - Bitmaps nicht ausreichen.
↑
Icon - Resource
Ist ein Icon in dem File "c:\\pfad\\...\\myName.ico" enthalten, so kann dieses Icon gemäß
IDI_MYICON ICON DISCARDABLE "c:\\pfad\\...\\myName.ico"
in den *.RC - ASCII - File aufgenommen werden. Im C/C++ - Programm wird dieses Icon z.B. durch
wndclass.hIcon = LoadIcon( GetModuleHandle(0), IDI_MYICON );
geladen.
↑
String - Table - Resource
Tabellen von Strings werden für Fehler - Meldungen, statische Anzeigetexte und Ausgaben benutzt. Das C/C++ - Programm läd bei Bedarf diese Strings. Wird eine Applikation in eine
andere Landes - Sprachen übersetzt, so muß nur die Stringtabellen auswechselt werden. Bei C/C++ wird ein String "..." automatisch mit einem zusätzlichem \0 - Zeichen abgeschlossen.
●
Ein *.RC - String wird nicht automatisch mit einem \0 abgeschlossen.
●
Sonderzeichen innerhalb eines *.RC - Strings müssen oktal eingegeben werden ( ein "für" wird zu "f\374r" ).
Im *.RC sieht eine STRINGTABLE etwa wie folgt aus:
STRINGTABLE DISCARDABLE BEGIN
IDS_STRING1, "Error in Runtime 1"
....
IDS_STRING16, "Wert = %d"
END
Eine Tabelle sollte maximal 16 Strings enthalten. Die Strings aus der Resourcen - String - Tabelle werden dann gemäß
CHAR buf[256];
LoadString( GetModuleHandle(0), IDS_STRING1, buf, sizeof(buf) )
geladen. hInstance = GetModuleHandle(0) entspricht der Anfangsadresse des ausgeführten Programmes. Der WinMain( ) - Aufruf übergibt den Parameter hInstance an das Programm.
hInstance wird in unterschiedlichen Funktionen benötigt. Deshable kann hInstance ( anstelle des Aufrufes GetModuleHandle(0) ) auch in einer globale Variablen gespeichert werden.
Alternativ kann hInstance auch beim WM_CREATE - Ereignis ( infolge von CreateWindow ) durch
my_hInstance = ( LPCREATESTRUCT ) lParam -> hInstance erhalten werden.
Eine vereinfachte Funktion Load_String( int idRes ) gibt den Zeiger auf den geladenen String zurück.
LPSTR Load_String( int idRes ) {
static char buf[256];
if ( LoadString( GetModuleHandle(0), idRes, buf, sizeof(buf) ) < 0 )
return NULL;
else
return ( LPSTR ) buf;
}
Sollen drei Resourcen - Strings geladenen, aneinander gefügt und angezeigt werden, so kann dies z.B. gemäß
CHAR buf[1024]; LPSTR pp = &buf[0];
pp += sprintf( pp, Load_String( IDS_STRING1 ) );
pp += sprintf( pp, Load_String( IDS_STRING2 ) );
pp += sprintf( pp, Load_String( IDS_STRING3 ) );
MessageBox( hWnd, buf, "3 Strings", MB_OK );
erfolgen. Sollen drei Strings gleichzeitig, nebeneinander benutzt werden ( nrStr = 0, 1, 2 ), so kann eine erweitert Funktion Load_String_into() geschrieben werden.
LPSTR Load_String_into( int nrStr, int idRes ) {
static CHAR buf[3][256];
LoadString( GetModuleHandle( NULL ), idRes, buf[nrStr], 256 );
return ( LPSTR ) buf[nrStr];
}
// Die drei static Buffer können mehrfach geladen und
// p0, p1, p2 können unabhängig voneinander benutzt werden.
LPSTR p0 = Load_String_into( 0, IDS_STRING0 );
LPSTR p1 = Load_String_into( 1, IDS_STRING1 );
LPSTR p2 = Load_String_into( 2, IDS_STRING2 );
geladen werden. Mit (NULL!=FindResource(GetModuleHandle(0),MAKEINTRESOURCE((idRes>>4)+1),RT_STRING)) kann geprüft werden, ob die String-Ressource im 16-Block
existiert.
Die Zeichenanzahl (Länge von Stringressourcen) wird benötigt, wenn vor dem LoadString-Aufruf hinreichend Buffer-Speicher zur Verfügung stehen soll.
UINT GetResourceStringLen(UINT uID)
{
HGLOBAL
hGlobal; LPWSTR
pwstr;
HRSRC
hrsrc;
UINT
uLen = 0, x;
HINSTANCE hInst = GetModuleHandle(0);
// String-Ressourcen sind in 16er Gruppen gepackt.
// Hier finden wir das Segment,
// in dem sich der gesuchte String befindet:
if(NULL == (hrsrc = FindResource(hInst,MAKEINTRESOURCE((uID/16)+1),RT_STRING)))
return(0);
if(NULL == (hGlobal = LoadResource(hInst,hrsrc)))
return(0);
if(NULL != (pwstr = (LPWSTR)LockResource(hGlobal))) {
// Die 16 (UNICODE-)Strings sind nacheinander und nicht
// null-terminiert gespeichert. Im ersten Character steht die Länge
// des Strings.
for(x = (uID % 16) + 1; x; --x) {
uLen = *pwstr;
pwstr += (uLen + 1);
} UnlockResource(hGlobal);
} FreeResource(hGlobal);
// uLen++; wegen abschliessendem \0-Zeichen
return(uLen);
}
↑
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
typedef struct {
WORD versionNumber; // 0
WORD offset;
// 0
} MENUITEMTEMPLATEHEADER;
Jedes Popup/Item
MENUITEMTEMPLATE
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!
//CALLBACK-Pseudocode:
case WM_COMMAND:{if(HIWORD(wParam))break;
for( int k=0; (pMenu+k)->_txt; k++) {
if( LOWORD(wParam) == (pMenu+k)->_id ) {
menu_fn_aktiv = (pMenu+k)->_fn;
if
( menu_fn_aktiv ) {
return menu_fn_aktiv(hwnd);
}
}
} // for
break; } //ende WM_COMMAND
Alternative mit AppendMenu()
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;
if(p2) *p2 = MF_END;
*p++ = MF_POPUP;
p += nCopyAnsiToWideChar(p,
TEXT(pMenu[k]._txt));
} else { p2 = p;
*p++ = 0;
*p++ = pMenu[k]._id;
p += nCopyAnsiToWideChar(p,
TEXT(pMenu[k]._txt));
}
}
if(p1) *p1 = MF_POPUP|MF_END;
if(p2) *p2 = MF_END;
HMENU hMenu = LoadMenuIndirect(buf);
SetMenu(hwnd, hMenu);
return hMenu;
}
HMENU
set_menu(HWND hwnd,menu_struct * pMenu)
{ HMENU hMenu=CreateMenu(), hPopup = NULL;
LPSTR pSave=NULL; int j,k=0;
if((!hwnd)||(!pMenu))return NULL;
while(pMenu[k]._txt)
{
hPopup = CreateMenu();
for(j=k+1; pMenu[j]._id; j++){
AppendMenu(hPopup,MF_STRING,
pMenu[j]._id,
pMenu[j]._txt);
}
AppendMenu(hMenu,MF_POPUP,
(UINT_PTR)hPopup,pMenu[k]._txt);
k = j;
}
if(!hMenu)DestroyMenu(hMenu);
SetMenu(hwnd,hMenu);return hMenu;
}
↑
CREATE_DLG_INDIRECT
Ein DLGTEMPLATE kann auch ohne Ressourcen ( ohne *.RC, *.RES ) im C/C++-Programm "bitweise zusammengebastelt" werden und dann durch die Funktion CreateDialogIndirect()
aufgerufen werden. Bei solchen Ressourcen ( im Speicher ) ist das Alignment ( WORD- bzw. DWORD-weise ) wesentlich. Dies bedeutet z.B., dass ein LPSTR-Strings lpAnsiIn
WORDweise in p geschrieben werden muss und das Stringende durch 0x0000 gekennzeichnet ist.
int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn)
{ int nChar = 0;
do {
*p++ = (WORD) *lpAnsiIn;
nChar++;
} while (*lpAnsiIn++);
return nChar;
}
Aufbau der CDLGTEMPLATE-Struktur für CreateDialogIndirect()
[Resource header (type = 5)]
struct DialogBoxHeader {
DWORD lStyle;
DWORD lExtendedStyle;
WORD NumberOfItems;
WORD x,y,cx,cy;
[Name or Ordinal] MenuName;
[Name or Ordinal] ClassName;
WCHAR szCaption[];
WORD
wPointSize; //nur bei DS_SETFONT
WCHAR szFontName[];//nur bei DS_SETFONT
};
Jedes Control beginnt an DWORD-Grenze
struct ControlData {
DWORD lStyle;//WS_CHILD,WS_VISIBLE...
DWORD lExtendedStyle;
WORD
x,y,cx,cy;
WORD
wId;
[Name or Ordinal] ClassId;
[Name or Ordinal] Text;
WORD
nExtraStuff; // soll 0x0000 sein
};
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:
/////////////////////////////////////////////
typedef struct _DLG_STRUCT {
HWND hwnd;
// wird später eingesetzt
LPSTR pKlasse;
// z.B. "BUTTON"
LPSTR pText; // wird in das Ctrl geschrieben
WORD x,y,cx,cy; // Position
} DLG_STRUCT;
///////////////////////////////////////////
// Beispiel für Aufruf:
///////////////////////////////////////////
static
DLG_STRUCT dlg1[] = {
//
x, y, cx, cy
{0,"DIALOG", "dlg-Titel", 50, 50,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,"", 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");
//////////////////
// so sieht es aus
//////////////////
///////////////////////////////////////////
// class CREATE_DLG_INDIRECT
///////////////////////////////////////////
class CREATE_DLG_INDIRECT
{
int nCopyAnsiToWideChar(LPWORD p, LPSTR lpAnsiIn)
{ int nChar = 0;
do {
*p++ = (WORD)*lpAnsiIn;
nChar++;
} while (*lpAnsiIn++);
return nChar;
}
#define es_ist(str) (CSTR_EQUAL==CompareString(\
LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,(str),-1,pD->pKlasse,-1))
public:
CREATE_DLG_INDIRECT( HWND hwnd, DLG_STRUCT * pDlg, DLGPROC dlgProc)
{
DWORD lStyle, lExtStyle; DLG_STRUCT * pD;
WORD pDlgStruct[4000] = {0}, *p = pDlgStruct;
int
i, nCtrl=0; // = NumberOfItems !!!
if(!pDlg)return;
while((*pDlg[nCtrl].pKlasse)
&&( pDlg[nCtrl].cx)
&&( pDlg[nCtrl].cy)) nCtrl++;
nCtrl--; // = NumberOfItems !!!
if(nCtrl<1) return;
// Dialog: /////////////////////////////////////////////
pD = pDlg+0; //pD zeigt auf den 0-ten DLG_STRUCT-Eintrag
if(!es_ist("DIALOG"))return;
lStyle = WS_CAPTION|WS_SYSMENU|WS_VISIBLE
| DS_SETFOREGROUND|DS_MODALFRAME|DS_SETFONT;
lExtStyle = WS_EX_DLGMODALFRAME;//WS_EX_CLIENTEDGE;
*p++ = LOWORD(lStyle);
*p++ = HIWORD(lStyle);
*p++ = LOWORD(lExtStyle); *p++ = HIWORD(lExtStyle);
*p++ = nCtrl;
*p++ = pD->x; *p++ = pD->y; *p++ = pD->cx; *p++ = pD->y;
*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:
//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 ...
static DLG_INDIRECT *
pDlg = new DLG_INDIRECT(hwnd);
pDlg -> set_menu(menu_struct);
if(!pDlg) error ...
↑
Ressourcen von dll's
Load the .EXE file that contains the dialog box you want to copy.
//NICHT LAUFFÄHIG ...
char buf[MAX_PATH], *pB = buf, *pF = __FILE__;
memset(buf,0,MAX_PATH); err_if(!pF,"__FILE__");
while(pF && *pF &&(*pF != '.')
&& ((pB-buf) < MAX_PATH) ) *pB++ = *pF++;
*pB++='.';*pB++='e';*pB++='x';*pB++='e'; *pB++='\0';
pB = buf;
HMODULE
hExe = LoadLibrary("notepad.exe");
err_if(!hExe,"LoadLibrary");
// Locate the dialog box resource in the .EXE file.
HRSRC //RT_ACCELERATOR,RT_BITMAP,RT_DIALOG,RT_MENU,RT_STRING
hRes = FindResource(hExe, "#14", RT_DIALOG);
err_if(!hRes,"FindResource");
HRSRC // Load the dialog box into global memory
hResLoad = (HRSRC)LoadResource(hExe, hRes);
err_if(!hResLoad, "LoadResource");
LPVOID // Lock the dialog box into global memory.
lpResLock = LockResource(hResLoad);
err_if(!lpResLock, "LockResource");
// Open the file to which
// you want to add the dialog box resource.
HANDLE //buf = "ziel.exe"
hUpdateRes = BeginUpdateResource(buf, FALSE);
err_if(!hUpdateRes, "BeginUpdateResource");
BOOL // Add the dialog box resource to the update list.
ok = UpdateResource(hUpdateRes, // update resource handle
RT_DIALOG,
// change dialog box resource
"#14",
// dialog box name
MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),// neutral language
lpResLock,
// ptr to resource info
SizeofResource(hExe, hRes));// size of resource info.
err_if(!ok, "UpdateResource");
// Write changes to FOOT.EXE and then close it.
ok = EndUpdateResource(hUpdateRes, FALSE);
err_if(!ok, "EndUpdateResource");
ok = FreeLibrary(hExe);
err_if(!ok, "FreeLibrary");
return ;
}
| Dialoge | Eingebaute klassen zur Ereignisbehandlung | Modale Dialoge | MessageBox() | Beispiele: MessageBox || ./img/messagebox0.gif || ./img/messagebox1.gif || ./img/messagebox4.gif ||
./img/messagebox3.gif || ./img/messagebox2.gif || ./img/messagebox5.gif | DialogBox() | Beispiel: DialogBox als Hauptprogramm | About-Dialog | *.RC-File-Ausschnitt | Aufruf des AboutDialogs: | Modless Dialoge | für Modeless: Haupnachrichten-Schleife | für Modeless: in der CALLBACK | für Modeless: Aufruf | für Modeless: im Fenster hinterlegen | CreateDialog() - Aufruf
| für Modeless: | *.RC enthält | *.CPP enthält | Interne Dialog - CALLBACK - Funktion | Standard - Dialoge | Controls | Static Text Control | Button Control | Edit Control | Beispiel zu Edit |
List Box Control | Combo Box Control | Beispiel: Stringtable | Scroll Bar Control | Arrow - Keys und Notification Nachrichten || ./img/scroll.gif | Keyboard - Interface für Scroll - Bars | Custom
Controls | Hex-Rechner1 mit *.rc || ./img/rechner.gif | Hex-Rechner1 ohne *.rc | hex_rechner2 | Eingebaute Klassen (Methode 1) | Eingebaute Klassen (Methode 2) | Sub-Classing | DialogErzeugung | Hauptnachrichten-Schleife für Modeless | Textausgabe in Control | Taschenrechner mit Texteingabe
↑
↑
Dialoge
Eingebaute klassen zur Ereignisbehandlung
Der Entwickler kann eigene Klassen anlegen (RegisterClass) und dort eine CALLBACK-Funktion für die Ereignissteuerung hinterlegen. Es existieren auch
bereits verfügbare Windows-Klassen, die der Ereignissteuerung dienen und die bereits eine CALLBACK-Funktion enthalten. Die ersten WindowsVersionen 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"
Wie können Informationen über existierende Klassen (hier z.B. Dialog Box Klasse #32770) beschafft werden?
WNDCLASSEX tem = {0}; tem.cbSize = sizeof(WNDCLASSEX);
BOOL ok = GetClassInfoEx(GetModuleHandle(0),TEXT("#32770"), &tem);
Die WNDCLASSEX-Struktur enthält:
// #ifndef UNICODE :
typedef struct tagWNDCLASSEXA {
UINT
cbSize;
/* Win 3.x */
UINT
style;
WNDPROC
lpfnWndProc;
int
cbClsExtra;
int
cbWndExtra;
HINSTANCE
hInstance;
HICON
hIcon;
HCURSOR
hCursor;
HBRUSH
hbrBackground;
LPCSTR
lpszMenuName;
LPCSTR
lpszClassName;
/* Win 4.0 */
HICON
hIconSm;
} WNDCLASSEXA;
// #ifdef UNICODE :
typedef struct tagWNDCLASSEXW {
UINT
cbSize;
/* Win 3.x */
UINT
style;
WNDPROC
lpfnWndProc;
int
cbClsExtra;
int
cbWndExtra;
HINSTANCE
hInstance;
HICON
hIcon;
HCURSOR
hCursor;
HBRUSH
hbrBackground;
LPCWSTR
lpszMenuName;
LPCWSTR
lpszClassName;
/* Win 4.0 */
HICON
hIconSm;
} WNDCLASSEXW;
Wie lautet der Klassen-Name?
void VerboseClassName(TCHAR ach[])
{
if
(lstrcmpi(ach,_T("#32770"))
else if(lstrcmpi(ach,_T("#32768"))
else if(lstrcmpi(ach,_T("#32769"))
else if(lstrcmpi(ach,_T("#32771"))
else if(lstrcmpi(ach,_T("#32772"))
}
==
==
==
==
==
0)
0)
0)
0)
0)
Gehört hwnd zur Dialog Box Klasse #32770?
BOOL is_dlg_class(HWND hwnd) {
TCHAR buf [256];
int anz = GetClassName(hwnd, buf, 256);
lstrcat(ach,_T("Dialog")
);
lstrcat(ach,_T("Menu")
);
lstrcat(ach,_T("Desktop window")
);
lstrcat(ach,_T("Task-switch window"));
lstrcat(ach,_T("Icon title")
);
int diff = CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH,
buf, -1, TEXT("#32770"), -1 );
return ( diff == CSTR_EQUAL ) ;
}
Wie kann auf einzelne Elemente der Klasse zugegriffen werden? Beispiele:
int cbClsExtra = (int) GetClassLong(hwnd, GCL_CBCLSEXTRA);
int cbWndExtra = (int) GetClassLong(hwnd, GCL_CBWNDEXTRA);
Beim Anlegen der Klasse #32770 verwendet das System WNDCLASSEX.cbWndExtra = 30, d.h.
int cbWndExtra = (int) GetClassLong(hwnd, GCL_CBWNDEXTRA); gibt 30 zurück, d.h. bei Dialogen ist cbWndExtra = 30. In den Windows-Fenster
können Daten hinterlegt und geholt werden.
SetWindowLong(hwnd, GWL_USERDATA, val);
GetWindowLong(hwnd, GWL_USERDATA)
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
Check box ("BUTTON")
Client object (text, graphics)
Combo box ("COMBOBOX")
Pop-up menu ("#32768")
Progress bar control
(PROGRESS_CLASS, "msctls_progress" in
Commctrl.h)
Push button ("BUTTON")
Radio button ("BUTTON")
Scroll bar ("SCROLLBAR")
Size grip (special mouse pointer)
Cursor
Slider control
IDC_ARROW "Normal",
IDC_IBEAM "Edit",
IDC_WAIT "Wait",
IDC_CROSS "Graphic",
IDC_UPARROW "Up",
IDC_SIZENWSE "NWSE size",
IDC_SIZENESW "NESW size",
IDC_SIZEWE "Horizontal size",
IDC_SIZENS "Vertical size", IDC_SIZEALL "Move", IDC_NO "Forbidden",
IDC_APPSTARTING "App start",IDC_HELP "Help",
Custom cursor "Unknown"
(TRACKBAR_CLASS, "msctls_trackbar" in
Commctrl.h)
Static text ("STATIC")
Status bar control
Dialog box ("#32770")
(STATUSCLASSNAME, "msctls_statusbar32" in
Commctrl.h)
Switch window ("#32771")
Tab control
Edit control "EDIT", "RichEdit", "RichEdit20A"
Header 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
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
Desktop window ("#32769")
(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
CreateDialogIndirect
DefDlgProc
DialogBoxIndirectParam
EndDialog
GetDlgItem
GetNextDlgGroupItem
CreateDialogIndirectParam
DialogBox
DialogBoxParam
GetDialogBaseUnits
GetDlgItemInt
GetNextDlgTabItem
IsDialogMessage
MessageBoxEx
SetDlgItemText
↑
MapDialogRect
SendDlgItemMessage
MessageBoxIndirect
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 Push-Buttons.
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
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 DialogCALLBACK-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 User-Daten. Dies kann Zugeordnet erfolgen, indem durch SetWindowLong( hDlg, GWL_USERDATA, value ) ein 4
Byte-Wert value hinterlegt wird. SetWindowLong() gibt den alten gespeicherten Wert zurück und hinterlegt den neuen value.
↑
für Modeless: im Fenster hinterlegen
LONG old_value = SetWindowLong( hDlg, DWL_USER,(LONG)value );
}
↑
CreateDialog() - Aufruf
↑
für Modeless:
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
switch ( iMsg ) {
...
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_MENUITEM_MODELESS: //Aufruf der About - Box
Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) ;
break ;
}
}
...
return DefWindowProc( hWnd, iMsg, wParam, lParam ) ;
}
Die Funktion Create_Dialog( hWnd, IDD_DIALOG_MODELESS, dlgModelessProc ) benötigt die Resource IDD_DIALOG_MODELESS und die
CALLBACK - Funktion dlgModelessProc().
↑
*.RC enthält
IDD_DIALOG_MODELESS DIALOG DISCARDABLE 0, 0, 186, 129
STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Modeless"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT
"IDC_EDIT0",IDC_STATIC,6,6,38,8
EDITTEXT
IDC_EDIT0,5,17,115,14,ES_AUTOHSCROLL
PUSHBUTTON
"showEB 0",IDC_BUTTON0,129,18,50,14
DEFPUSHBUTTON
"OK",IDOK,130,108,50,14, WS_TABSTOP
END
↑
*.CPP enthält
BOOL CALLBACK dlgModelessProc( HWND hWnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
static CHAR * pEdit;
switch ( iMsg ) {
int len, idx; HWND hCtl0;
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 ;
}
↑
●
Ein Dialog enthält untergeordnete Fenster ( Controls ).
●
Zu einem Control gehört i.a. eine eingebauten Klasse.
Controls
●
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
↑
Beispiel zu Edit
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,
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)
fEnable)
fAddEOL)
line, lpch, cchMax)
lprc)
lpch, cchMax)
cchMax)
ich)
line)
line)
lpszReplace)
dv, dh)
h)
fModified)
ch)
lprc)
lprc)
ichStart, ichEnd)
cTabs, lpTabs)
lpsz)
lpfnWordBreak)
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
ComboBox_SelectItemData
ComboBox_SetCurSel
ComboBox_SelectString
ComboBox_SetExtendedUI
ComboBox_SetEditSel
ComboBox_SetItemHeight
ComboBox_SetItemData
ComboBox_SetText
ComboBox_ShowDropdown
↑
(hCtl)
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
(hCtl,
indexStart, data)
index)
indexStart, lpszSelect)
flags)Win32
ichStart, ichEnd)
cyItem)Win32
index, data)
lpsz)
fShow)
Beispiel: Stringtable
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;
}
↑
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.
Hex-Rechner1 mit *.rc
Als Beispiel soll ein Hex-Rechner betrachtet werden. Die Buttons, Combo-Control, Edit-Control werden in einem *.rc-File abgelegt. Die Konstanten
(IDC_BUTTON0, IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4, IDC_BUTTON5, IDC_COMBO1, IDC_EDIT1 und
IDD_DIALOG_HEXCALC) entsprechen WORD-Zahlen ( z.B. ab 5000), die im *.rc-File und im *.CPP-Filt gebraucht werden. Diese Konstanten werden
meistens im *.h-File definiert (z.B. #define IDC_BUTTON0 5000 ).
IDD_DIALOG_HEXCALC DIALOG DISCARDABLE 5, 10, 188, 135
STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_THICKFRAME
CAPTION "Hex - Calc"
FONT 8, "MS Sans Serif"
BEGIN
COMBOBOX
IDC_COMBO0, 5,5,115,125,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON
"0",48,6,117,14,14,NOT WS_TABSTOP
PUSHBUTTON
"1",49,6,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"2",50,24,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"3",51,42,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"4",52,6,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"5",53,24,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"6",54,42,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"7",55,6,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"8",56,24,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"9",57,42,64,14,14,NOT WS_TABSTOP
PUSHBUTTON
"A",65,42,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"B",66,24,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"C",67,6,47,14,14,NOT WS_TABSTOP
PUSHBUTTON
"D",68,42,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"E",69,24,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"F",70,6,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"+",43,64,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"-",45,64,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"*",42,82,81,14,14,NOT WS_TABSTOP
PUSHBUTTON
"/",47,82,99,14,14,NOT WS_TABSTOP
PUSHBUTTON
"%",37,64,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
"=",61,24,117,31,14,NOT WS_TABSTOP
PUSHBUTTON
"&&",38,82,63,14,14,NOT WS_TABSTOP
PUSHBUTTON
"|",124,64,63,14,14,NOT WS_TABSTOP
PUSHBUTTON
"^",94,64,46,14,14,NOT WS_TABSTOP
PUSHBUTTON
"<",60,82,30,14,14,NOT WS_TABSTOP
PUSHBUTTON
">",62,82,46,14,14,NOT WS_TABSTOP
PUSHBUTTON
"M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOP
PUSHBUTTON
"M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOP
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
PUSHBUTTON
DEFPUSHBUTTON
CONTROL
CONTROL
"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>
#define err_if(e,str) \
if(e)MessageBox(0,(str),0,MB_OK|MB_ICONSTOP);
/////////////////////////////////////////////////
// globales
/////////////////////////////////////////////////
const
const
const
const
const
UINT
UINT
UINT
UINT
UINT
MAX_EDIT_CHAR
MAX_COMBO_CHAR
USE_CE = 1; //
USE_CL = 2; //
USE_EM = 4; //
=2048;//für Edit_LimitText()
=
8;//ComboBox_LimitText()
Ziel Combo-Edit
Ziel Combo-Liste
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
/////////////////////////////////////////////////
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;
}
/////////////////////////////////////////////////
// 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;
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);
}
/////////////////////////////////////////////////
//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;
}
↑
hex_rechner2
Zu den Dialogen gehört die Dialog-Klasse "#32770", die bereit vom System mit RegisterClassEx() angelegt wurde. Die Dialog-Klasse "#32770" enthält die
"eingebaute" CALLBACK-Funktion. Diese setzt z.B. mit der Tab-Taste den Focus für Tasteneingaben auf das nächste Control, falls bei diesem Control im
Window-Style das WS_TABSTOP-Bit gesetzt ist.
↑
Eingebaute Klassen (Methode 1)
Es gibt Eingebaute Klassen (incl. CALLBACK-Funktion). Wie kann diese Klasse erhalten werden? Mit
WNDCLASSEX wc = { 0 }; //Dialog-Klasse "#32770"
GetClassInfoEx(hInst,"#32770",&wc);
wird wc "gefüllt" und der Funktionszeiger wc.lpfnWndProc kann erhalten werden. Nun können in wc die zu ändernden Komponenten wc.xxx neu gesetzt
werden (z.B. wc.lpszClassName = "my_dlg_class";). Mit
RegisterClassEx(&wc);
wird eine modifizierte "my_dlg_class" mit eigener CALLBACK-Funktionen angelegt werden.
OldWndProc = wc.lpfnWndProc; //aufheben
NewWndProc = my_new_callback_fkt;
Innerhalb jeder NewWndProc-CALLBACK-Funktionen kann dann am Ende anstelle von
return FALSE; nun
return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
aufgerufen werden. Dadurch werden die unbearbeiteten Nachrichten an die OldWndProc-Funktion weiter gereicht.
↑
Eingebaute Klassen (Methode 2)
Existiert bereits ein Fenster (oder ein Modeless-Dialog), so ist das hwnd bekannt und die alte CALLBACK-Funktion kann beim Eintragen der neuen
CALLBACK-Funktion erhalten werden:
OldWndProc=(WNDPROC)
SetWindowLong(hwnd,GWL_WNDPROC,(LONG)NewWndProc);
Innerhalb jeder NewWndProc-CALLBACK-Funktionen kann dann am Ende anstelle von
return FALSE; nun
return CallWindowProc(OldWndProc,hwnd,uMsg,wParam,lParam);
aufgerufen werden. Dadurch werden die unbearbeiteten Nachrichten an die OldWndProc-Funktion weiter gereicht.
↑
Sub-Classing
Öfters ist es erforderlich, an die eingebaute CALLBACK-Funktion "heran zu kommen" und deren Nachrichten vorher durch eine vorgeschaltete eigene
CALLBACK-Funktion zu schicken. Die eigene CALLBACK-Funktion kann dann Änderungen und Ergänzungen vor der eingebauten CALLBACKFunktion vornehmen. Ist das Handle eines Controls hCtrl bekannt, Die folgende Funktion wird einmal externen Aufruf (ausserhalb der CALLBACK)
aufgerufen, richtet dabei ein sub-Classing ein, hinterlegt sich als Zeiger selbst in den Window-daten (d.h. hinterlegt sich selbst als CALLBACK-Funktion)
und ist bei jedem folgenden AUfruf selbst die gewünschte CALLBACK-Funktion, die die Nachrichten bearbeitet. Am Ende wird die alte CALLBACKFunktion aufgerufen.
/////////////////////////////////////////////////
// initialisierender Sub-Class-Aufruf gemäss:
// dlg_proc_bekommt_alle_keys_von(hwnd_combo_hex,0,0,0);
// Dann schickt
// if(uMsg==WM_GETDLGCODE){return DLGC_WANTALLKEYS;}
// alle Tasten an die Parent-CALLBACK-Funktion
// und dort wird bei DM_GETDEFID der (hier ENTER key)
// abgefangen.
//
// Achtung! Hinweis:
// Das folgende Sub-Classing-Muster ist zwar
// "Kompliziert" aber in sich "geschlossen".
// WNDPROC entspricht den "alten" LONG FAR PASCAL
// WNDPROC führt (leider) bei Win98/NT zu
// "schweren Laufzeitabstürzen".
// Deshalb wurde LONG FAR PASCAL und
// if (cb<4)SetClassLong(hCtrl,GCL_CBWNDEXTRA,4);
// verwendet.
/////////////////////////////////////////////////
LONG FAR PASCAL dlg_proc_bekommt_alle_keys_von
(HWND hCtrl,UINT uMsg,WPARAM wParam,LONG lParam)
{
err_if(!IsWindow(hCtrl),"!IsWindow(hCtrl)");
FARPROC oldCtrlProc=(FARPROC)GetWindowLong(hCtrl,GWL_USERDATA);
if(!oldCtrlProc) { //nur einmal hinterlegen
int cb = GetClassLong(hCtrl,GCL_CBWNDEXTRA);
if (cb<4)SetClassLong(hCtrl,GCL_CBWNDEXTRA,4);
oldCtrlProc =(FARPROC)
SetWindowLong(hCtrl,GWL_WNDPROC,
(DWORD)dlg_proc_bekommt_alle_keys_von);
err_if(!oldCtrlProc,"!oldCtrlProc");
SetWindowLong(hCtrl,GWL_USERDATA,(LONG)(WNDPROC)oldCtrlProc);
}
if(uMsg==WM_GETDLGCODE){return DLGC_WANTALLKEYS;}
err_if(!oldCtrlProc,"!oldCtrlProc");
return CallWindowProc((WNDPROC)oldCtrlProc,hCtrl,uMsg,wParam,lParam);
}
Beispiele für eingebaute Klassen sind:
0x0080 "Button", 0x0081 "Edit",
0x0082 "Static",
0x0083 "ListBox", 0x0084 "ScrollBar", 0x0085 "ComboBox"
Die folgende Funktion setzt eine neuen CALLBACK-Funktion als Zeiger (4 Byte) in den Window-Daten (Subclassing). Achtung! Bei der Dialogklasse ruft
die eingebaute #32770-CALLBACK-Funktion die User-Dialog-CALLBACK-Funktion auf. Würde die #32770-CALLBACK-Funktion in den WindowDaten einfach ersetzt, wie dies durch "grün" angedeutet ist, so entstehen Rekursionen.
WNDPROC set_wndproc(HWND hwnd, WNDPROC m_wnd_proc)
{
if(!m_wnd_proc) return NULL;
// GRÜN GIBT FEHELER! WARUM WOHL ...
//
TCHAR buf [256];
//
int anz = GetClassName(hwnd, buf, 256);
//
int diff = CompareString( LOCALE_USER_DEFAULT,
//
NORM_IGNORECASE|NORM_IGNOREKANATYPE
//
|NORM_IGNOREWIDTH,buf,-1,TEXT("#32770"),-1);
WNDPROC old_proc = NULL;
// if(diff == CSTR_EQUAL) // hinterlege bei Dialog-Klasse:
// {
//
old_proc = (WNDPROC)
//
SetWindowLong(hwnd,DWL_DLGPROC,(LONG)(WNDPROC)m_wnd_proc);
// } else { // sonst
old_proc = (WNDPROC)
SetWindowLong(hwnd,GWL_WNDPROC,(LONG)(WNDPROC)m_wnd_proc);
// }
return old_proc;
}
↑
Dialog-Erzeugung
Modeles-Dialoge werden mit CreateDialog...() erzeugt. Hierzu wird die Dialog-CALLBACK-Funktion myDlgProc gebraucht, die bei jedem Ereignis
aufgerufen wird.
a) Wenn das Dialog-Temlate IDD_... im *.rc existiert:
hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_...),
hParent, (DLGPROC)myDlgProc );
b) Wenn
hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_...),
hParent,(DLGPROC)dlgProc,(LPARAM)p);
p erscheint einmalig unter
WM_INITDIALOG in der CALLBACK-Funktion
c) Wenn das Dialog-Temlate im RAM (hier buf) existiert:
hDlg = CreateDialogIndirect(hInst, (LPDLGTEMPLATE)buf,
hParent,(DLGPROC)dlgProc);
Create... deutet darauf hin, dass die Speicherfreigabe mit DestroyWindow(hDlg) durch den User erfolgen soll.
↑
Hauptnachrichten-Schleife für Modeless
Für Modeless-Dialoge wird die Hauptnachrichten-Schleife ergänzt. Existiert ein globaler Array für Modeles-Handles HWND ghwnd[10], so kann
ghwnd[0] für die "Umschaltung" auf das jeweils aktuellen (Eingabe-) Dialog verwendet werden, indem JEDE CALLBACK-Funktion bei
WM_ACTIVATE das aktuelle handle ghwnd[0] setzt.
case WM_ACTIVATE:
if ( WA_INACTIVE == LOWORD(wParam) ) {
ghwnd[0] = NULL; //becoming inactive
} else {ghwnd[0] = hwnd;}//becoming active
break;
case WM_DESTROY:{ PostQuitMessage(0); break;}
Bei einem Ereignis ruft in der Hauptnachrichten-Schleife die Funktion IsDialogMessage(ghwnd[0],&msg)) die zu dem Modeless-Dialog gehörende
CALLBACK-Funktion auf.
int APIENTRY WinMain //Hauptprogramm
(HINSTANCE hInst,HINSTANCE hiPr,PSTR pCmd,int iShow)
{
ghwnd[1] = Create....(...);
BOOL bRet; MSG msg;
while (bRet=GetMessage(&msg, NULL,0,0)){
err_if(-1==bRet,"GetMessage()");
if (!IsWindow(ghwnd[0])
|| !IsDialogMessage(ghwnd[0],&msg)){
TranslateMessage(&msg);
DispatchMessage (&msg);
}
} return 0;
}
↑
Textausgabe in Control
Mit SetWindowText kann in das hDst-Fenster Text geschrieben werden. Soll Formatierter text ausgegeben werden, so ist eine printf-ähnliche Funktion
brauchbar.
//////////////////////////////////////////////
// print_to() 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, aber
// print_to(hEdit, 0, "schreibt von vorn");
//
// Anstelle der Aufruffolge:
//
print_to(hEdit,hEdit, "\r\n");
//
print_to(hEdit,hEdit, "%u ", u1);
//
print_to(hEdit,hEdit, "%u ", u2);
//
// ist günstiger:
//
print_to(hEdit,hEdit,"\r\n%u %u ",u1,u2);
//////////////////////////////////////////////
int CDECL print_to(HWND hDst,HWND hSrc,LPTSTR pFormat,...)
{ static TCHAR Buf[2048];
err_if(!hDst,"print_to(): 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);
}
//isalpha(c):if ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))return TRUE;
↑
Taschenrechner mit Texteingabe
#include <windows.h>
#include <windowsx.h> //für ComboBox_InsertString()
#include <limits.h>
//für UINT_MAX
//#include <stdio.h>
//////////////////////////////////////////////
// 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
#define err_if(e,errStr) if(e) MessageBox(0,(errStr),0,\
MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
#pragma warning( disable: 4311 )
#pragma warning( disable: 4312 )
#pragma warning( disable: 4244 )
//////////////////////////////////////////////
// Hex-Rechner: globales
//////////////////////////////////////////////
// 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
// UINT (M)em(SUM)men-Speicher MSUM
// MSUM hält den Summenwert ('M+','M-')
//'MR' für Anzeige, 'MC' setzt MSUM=0
UINT MSUM;
//////////////////////////////////////////////
// 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-&gt;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;//|WS_EX_CONTROLPARENT;
*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;
}
/////////////////////////////////////////////////
// Beispiel: UINT erg = berechne(6,'+',4);
/////////////////////////////////////////////////
UINT berechne(UINT uNum1, char Op, UINT uNum2 )
{ UINT erg;
switch ( Op ) {
default : erg = 0; return erg;
case '=' : erg
case '+' : erg
case '-' : erg
case '*' : erg
case '&' : erg
case '|' : erg
case '^' : erg
case '<' : erg
case '>' : erg
case '/' : erg
break;
case '%' : erg
break;
}
return erg;
=
=
=
=
=
=
=
=
=
=
uNum2 ; return erg;
uNum1 + uNum2 ; break;
uNum1 - uNum2 ; break;
uNum1 * uNum2 ; break;
uNum1 & uNum2 ; break;
uNum1 | uNum2 ; break;
uNum1 ^ uNum2 ; break;
uNum1 << uNum2 ; break;
uNum1 >> uNum2 ; break;
uNum2?uNum1/uNum2:UINT_MAX ;
= uNum2?uNum1%uNum2:UINT_MAX ;
}
/////////////////////////////////////////////////
// CALLBACK
/////////////////////////////////////////////////
BOOL CALLBACK HexCalcProc
(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
static BOOL isNew = TRUE ; static char Op = ' ' ;
static UINT uNum1, uNum2, erg ; //1.2.-Zahl
static WORD LW; char buf[1024], *p;
switch ( iMsg ) {
case WM_INITDIALOG: { break; }
case WM_COMMAND : {
if(HIWORD(wParam))return FALSE;
switch ( LOWORD(wParam) ) {
default:{
LW = LOWORD(wParam);
if ( isxdigit(LW) ) {
// hex digit
if(isNew) print_to(hCombo,0,"");
print_to(hCombo,hCombo,"%c",(char)LW);
isNew = FALSE ;
} else {
// operation
if(iscntrl(LW))return FALSE;
if( LW != '=' ){
print_to(hCombo,hCombo,"%c",(char)LW);
return FALSE;
}
//jetzt: '=' veranlasst Berechnung:
memset(buf,0,sizeof(buf)); p=buf;
GetWindowText(hCombo,buf,sizeof(buf));
while(*p && isspace(*p))p++;
uNum1 = strtol(&buf[p-buf], &p, 16 );
while(*p && isspace(*p))p++;
Op = *p++;
while(*p && isspace(*p))p++;
uNum2 = strtol(&buf[p-buf], &p, 16 );
erg = berechne(uNum1, Op, uNum2) ;
memset(buf,0,sizeof(buf));
wsprintf(buf,"%x %c %x = %x",uNum1,Op,uNum2,erg);
print_to(hCombo,0,buf);
print_to(hEdit,hEdit,
"(0x%x %c 0x%x )= 0x%x\r\n",uNum1,Op,uNum2,erg);
//Max 30 Einträge in Combo-Liste:
if ( ComboBox_GetCount(hCombo) >= 30)
{
ComboBox_DeleteString(hCombo, 30);
} ComboBox_InsertString(hCombo,0,buf);
isNew = TRUE ;
}
return FALSE;}// Ende von default
case IDHELP: //=0x9
MessageBox(hwnd,
"Quelltext-Beschreibung ist im Skript"
"\r\nim Kapitel über Dialoge ...",
"Hilfetext",MB_OK);
break ;
case IDCLOSE: //=0x8,Achtung: IDOK gibt Ärger ...
SendMessage(hwnd,WM_CLOSE,0,0);return TRUE;
break;
case 1000://"BS";
err_if(1, "nicht eingebaut");
case 1001:
//"M+";
memset(buf,0,sizeof(buf));
GetWindowText(hCombo,buf,sizeof(buf));
uNum = strtol(buf, &p, 16 );
MSUM = berechne(MSUM,'+',uNum);
isNew = TRUE ;
break;
case 1002:
//"M-";
memset(buf,0,sizeof(buf));
GetWindowText(hCombo,buf,sizeof(buf));
uNum = strtol(buf, &p, 16 );
MSUM = berechne(MSUM,'-',uNum);
isNew = TRUE ;
break;
case 1003:
//zeige MSUM an: "MR"
print_to(hCombo,0,
"%X",MSUM);
print_to(hEdit,hEdit,"MR=0x%X\r\n",MSUM);
break;
case 1004: MSUM = 0;//Clear MSUM: "MC"
print_to(hEdit,hEdit,"MR=0x%X\r\n",MSUM);
break;
case 1005:
// Clear Combo: "AC"
print_to(hCombo,0,"0");
isNew = TRUE ;
break;
case 1006:
// Clear Edit:
"EC"
print_to(hEdit,0," ");
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
case DM_GETDEFID:{ // ENTER key abfangen
if (hwnd!=GetForegroundWindow())return FALSE;
if(0x8000 & GetKeyState(VK_RETURN)){
SendMessage(hwnd,WM_COMMAND,'=',0);
PostMessage(hwnd,WM_CHAR,0x0A,0);
}
return TRUE; }
}
return FALSE;
}
/////////////////////////////////////////////////
LONG FAR PASCAL dlg_proc_bekommt_alle_keys_von
(HWND hCtrl,UINT uMsg,WPARAM wParam,LONG lParam)
{
err_if(!IsWindow(hCtrl),"!IsWindow(hCtrl)");
FARPROC oldCtrlProc=(FARPROC)GetWindowLong(hCtrl,GWL_USERDATA);
if(!oldCtrlProc) { //nur einmal hinterlegen
int cb = GetClassLong(hCtrl,GCL_CBWNDEXTRA);
if (cb<4)SetClassLong(hCtrl,GCL_CBWNDEXTRA,4);
oldCtrlProc =(FARPROC)
SetWindowLong(hCtrl,GWL_WNDPROC,
(DWORD)dlg_proc_bekommt_alle_keys_von);
err_if(!oldCtrlProc,"!oldCtrlProc");
SetWindowLong(hCtrl,GWL_USERDATA,(LONG)(WNDPROC)oldCtrlProc);
}
if(uMsg==WM_GETDLGCODE){return DLGC_WANTALLKEYS;}
err_if(!oldCtrlProc,"!oldCtrlProc");
return CallWindowProc((WNDPROC)oldCtrlProc,hCtrl,uMsg,wParam,lParam);
}
/////////////////////////////////////////////////
HWND hex_rechner_indirect(HWND ghwnd) {
// 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;
/////////////////
// Controls in ds zusammenbauen:
x=x0; y=y0;
dlg_init (&ds,X,Y,DX,DY, "HEX_RECHNER");
WORD IDC_COMBO = 1000;
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;
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;
WORD IDC_EDIT = 2000;
dlg_editM(&ds,x0,y+4,95,70,
"",
IDC_EDIT);
//IDOK beendet allzuleicht!!!, besser ist IDCLOSE
dlg_button(&ds, x0,DY-27,43,dy," Beenden ",IDCLOSE);
dlg_button(&ds,DX/2,DY-27,43,dy,"Quelltext",IDHELP);
/////////////////////////////////////////////////
// jetzt komm der spannende Create-Moment ...
// DialogBoxIndirect(GetModuleHandle(0),
// (LPDLGTEMPLATE)ds.buf,ghwnd,(DLGPROC)ds.dlgProc);
ghwnd = CreateDialogIndirect(GetModuleHandle(0),
(LPDLGTEMPLATE)ds.buf,ghwnd,(DLGPROC)ds.dlgProc);
hEdit = GetDlgItem(ghwnd,IDC_EDIT);
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,2048);
Edit_SetText(hEdit, pInfoText );
hCombo = GetDlgItem(ghwnd, IDC_COMBO);
err_if(!hCombo,"hCombo");
dlg_proc_bekommt_alle_keys_von(hCombo,0,0,0);
ComboBox_LimitText(hCombo,128);
ComboBox_SetText (hCombo, "0");
return ghwnd;
}
/////////////////////////////////////////////////
//Hauptprogramm
int APIENTRY WinMain
(HINSTANCE hInst,HINSTANCE hiPr,PSTR pCmd,int iShow)
{
ghwnd[0] =
ghwnd[1] = hex_rechner_indirect(ghwnd[1]);
BOOL bRet; MSG msg;
while (bRet=GetMessage(&msg, NULL,0,0)){
err_if(-1==bRet,"GetMessage()");
if (!IsWindow(ghwnd[0])
|| !IsDialogMessage(ghwnd[0],&msg)){
TranslateMessage(&msg);
DispatchMessage (&msg);
}
} return 0;
}
| DLLs | Lebensdauer von Objekten | Static-Linking | Dynamic-Linking | Unterschiede zwischen Static-Dynamic-Linking | shared data segment | Verwenden einer Funktion
aus einer DLL
↑
DLLs
Ein typisches Windows-Programm ( *.exe ) erzeugt Fenster, deren CALLBACK-Funktion die Nachrichten aus dem Applikations-Buffer
geschickt werden. Eine Laufzeibibliothek ist eine Zusammenfassung von Code, Daten, und Ressourcen in einem Modul, der Funktionalität
zur Verfügung stellen kann (Export) und von anderen DLLs beziehen (Import) kann. DLLs ( dynamic link libraries, Laufzeibibliotheken,
*.dll ) sind i.a. nicht direkt ausführbar, bekommen i.a. keine direkten Nachrichten und enthalten die API-System-Funktionen, die von
Programmen oder anderen DLLs genutzt werden können ( Export-Table ). Eine DLL braucht ( benutzt ) i.a. Funktionen von anderen
DLLs ( Import-Table ). DLLs ( dynamic link libraries ) können wie eine Sammlung von Funktionen in Maschinen-Code betrachtet
werden. DLLs können auch Ressourcen enthalten.
1. Eine Laufzeitbibliothek hat nur eine Instanz
2. Eine Laufzeitbibliothek bleibt im Speicher, solange die DLL von einer Anwendung benötigt wird
3. Eine Laufzeitbibliothek ist keine eigenständige Task, sondern läuft unter einem anderen Prozess
4. Eine Laufzeitbibliothek hat keinen Stack, d.h läuft unter einem anderen Prozess und nutzt den Stack des
DLL-benutzenden Prozesses. Lokale Variablen, Funktionsparameter und Rücksprungadressen werden auf
dem Stack der Anwendung gelegt.
5. Eine Laufzeitbibliothek bleibt im solange im Arbeits-Speicher bis kein Prozess (Anwendung) mehr die DLL
benötig. Dann wird die DLL automatisch aus dem Speicher entfernt (z.B. bei Speichermangel)
6. Eine Laufzeitbibliothek kann ein eigenes Datensegment haben
Wie kann die Funktionsadresse von myDllFunc aus der DLL erhalren werden?
typedef void (FAR PASCAL *MYPROC)(LPSTR);
MYPROC hProc;
if( NULL == (hProc = (MYPROC)GetProcAddress32W(ghLib, "myDllFunc" )))
{
MessageBox( hWnd, "keine Adr!", "App16?", MB_OK );
...
}
↑
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 )
Programm, Block
(System bei stock)
Programm
(System bei stock)
ca. 32 Byte
GDI Objekte
USER-Funktionen
( Linker mit *.lib, Lader )
System
( Programm )
Programm, Block
bis zur Freigabe
( System bei stock )
ca. 30-50 Byte
User Objekte
↑
Linker
Programm, Block
Programm, Block
bis zur Freigabe
ca. 30-50 Byte
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. Beim statischem Linken ( static linking ) werden Bibliotek-Object-Files ( Maschinen-Code, .obj ) in den
ausführbaren File aufgenommen, d.h. der Maschinencode der Biblioteken wird zu einem festen Bestandteil des *.exe-Files verbunden (
Linker, permanenten Linken ).
Zu .exe und .dll gehören Instanzen. Wie kann HINSTANCE ermittelr werden? Es kann den Fall geben, daß z.B. in einer statischen Lib die
HINSTANCE des Moduls benötigt wird. Nun kann man vorher nicht wissen, ob diese Lib nun in eine Dll oder die Exe gelinkt wird. In
einer Dll funktionert der Aufruf von GetModuleHandle() mit NULL für den Modulenamen nicht, dann wird das Handle der Exe geliefert.
Auch ist der Name der Dll innerhalb der Lib nicht bekannt. Als Abhilfe kann diese Funktion dienen:
#include <windows.h>
HINSTANCE get_hinstance(VOID)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery((PVOID)get_hinstance, &mbi, sizeof(mbi));
return ((HINSTANCE) mbi.AllocationBase);
}
↑
Dynamic-Linking
Dynamisches Linken ( dynamic linking ) verknüpft die Bibliotheken zur Laufzeit. DLLs werden nicht in die Applikation kopiert, sondern
haben einen eigenen Adressraum und können von mehreren Anwendungen genutzt werden. Wenn eine DLL genutzt werden soll, so läd das
Operating-System die DLL ( aufgrund des File-Namens ) in en Speicher. Wird eine DLL von keiner Alpplikation benötigt, so wird die DLL
vom Operating-System ( unload ) aus dem Speicher entfernt. Der Lade/Entlade-Mechanismus kann explizit durch die Applikation oder
implizit Operating-System ausgelöst werden.
↑ Unterschiede zwischen Static-Dynamic-Linking
WDifferences Between Static-Link Libraries and Windows DLLs Windows DLLs differ considerably from static-link libraries. Basic
differences between the two are as follows:
●
Statische Bibliotheken sind in *.LIB-Files ( object files ) enthalten
●
Jede Applikation hat eine Kopie der statischen Bibliothek.
●
Die statische Bibliotek nutzt den Adressraum der Applikation.
●
Dynamische Bibliotheken sind in ladbaren, auführbaren Files ( *.exe explizit ladbar mit LoadLibrary, *.dll
implizit ladbar ) untergebracht.
●
Dynamische Bibliotheken können Maschinen-Code, Daten, Ressourcen ( z.B. Bitmaps, Icons, Cursors, usw.
) enthalten.
●
Beispiele für DLLs 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 DLLs 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.
↑
shared data segment
What makes a data segment shared?
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);
}
↑
Verwenden einer Funktion aus einer DLL
Normalerweise bindet der Linker mit Hilfe von .lib-Files das laden der DLL und den Funktionsaufruf ein (implizite Funktionsausführung).
Ist aber z.B. kein .lib-File verfügbar, so kann ein Funktionszeiger explizit geholt (GetProcAddress) und die Funktion ausgeführt werden.
Als Beispiel wird durch die Funktion my_msg_box() die MessageBoxA-Funktion aus USER32.DLL geholt und durch
my_msg_box("my_msg_box", "geholgt aus USER32.DLL");
ausgeführt:
typedef int (CALLBACK * MSGBOX)(HWND,LPCSTR,LPCSTR,UINT);
void my_msg_box(LPCSTR titel, LPCSTR inhalt)
{
// Lade USER32.DLL...:
HMODULE hDLL = LoadLibraryA("USER32.DLL");
err_if(!hDLL,"!hDLL");
// hole Adresse der ANSI-Version von "MessageBoxA":
MSGBOX MsgBox = (MSGBOX) GetProcAddress(hDLL,"MessageBoxA");
err_if(!pMsgBox,"!pMsgBox");
////////////////////////////////////////////////////////////
// Achtung! Windows.h hat typedef int (CALLBACK* FARPROC)();
// FARPROC liefert error C2197:
// 'int (__stdcall *)(void )' : too many actual parameters
////////////////////////////////////////////////////////////
MsgBox(NULL,inhalt,titel,MB_OK);// MessageBox() aufrufen
FreeLibrary(hDLL); // USER32.DLL freigeben
}
| MFC | Grober Zusammenhang mit ATL | Entwicklungskriterien | MFC und Nachrichten | MFC-Klassen-Typen | MFC-Schreibweise | Hinweise zur Programmierung | Beispiel für CWND_Member-Funktion
| CArray-Beispiel | Handles und MFC | MFC-Klassenhirachie (CE) || ./img/mfc_hierachy_categories.gif || ./img/mfc_1.gif || ./img/mfc_2.gif | MFC-Klassenhirachie | Hinweise zum Übersezungsvorgang
↑
MFC
Software-Syteme entwickeln sich und damit können sich Änderungen des Programmiermodell, der Entwicklungsumgebung, der Klassen-Bibliotheken, der APIFunktionssammlung ergeben. 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 ).
Es gibt Versionsfortschreibungen, wie z.B.:
MFC
Visual C++
MFC, Version 1.0
Microsoft C/C++, Version 7.0
MFC, Version 2.0
Visual C++, Version 1.0
MFC, Version 2.5
Visual C++, Version 1.5
MFC, Version 3.0
Visual C++, Version 2.0
MFC, Version 3.1
Visual C++, Version 2.1
MFC, Version 3.2
Visual C++, Version 2.2
MFC, Version 4.0
Visual C++, Version 4.0
MFC, Version 4.1
Visual C++, Version 4.1
MFC, Version 4.2
Visual C++, Version 4.2
MFC, Version 4.21 (noch mit mfc42.dll)Visual C++, Version 5.0
MFC, Version 6.0 (noch mit mfc42.dll) Visual C++, Version 6.0
MFC, Version 7.0 (mfc70.dll)
Visual C++ .NET 2002
MFC, Version 7.1 (mfc71.dll)
Visual C++ .NET 2003
Literaturhinweise
Visual C++ .NET, How to program,
Pearson Education (Prentice Hall) 2004
D. J. Kruglinski:
Inside Visual C++, Version 6.0, MS Press
Jeff Prosise:
Windows Programmierung mit MFC, MS Press
Jeffrey Richter:
Microsoft Windows, Programmierung für Experten, MS Press
Jeffrey Richter:
Microsoft .NET Framework Programmierung, MS Press
J. Templeman/ A. Olsen: Visual C++ .NET, Schritt für Schritt, MS Press
I. Griffiths et al.:
Mastering Visual Studio .NET, O'Reilly
Microsoft:
Online-Dokumentation zu Visual C++ .NET
H. M. Deitel et al.:
Versionsfortschreibung: Mit der Verwendung von Visual Studio .NET müssen vorher erstellte DLL- oder LIB-Dateien neu erstellt werden. MFC-Dialoganwendungen
entsprechen bei .NET Windows-Forms-Anwendungen. Bis ATL 3.0 (Visual C++ 6.0) wurden Zeichenfolgenkonvertierungen immer mittels der Makros (atlconv.h,
ANSI-Codeseite des Systems, CP_ACP) durchgeführt. Ab ATL 7.0 (Visual C++ .NET) werden Zeichenfolgenkonvertierungen (ohne
_CONVERSION_DONT_USE_THREAD_LOCALE) mit der standardmäßigen ANSI-Codeseite des aktuellen Threads durchgeführt.
// Versionsprüfung:
void versionstest(void)
{
DWORD dwVersion = GetVersion();
DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
err_if(dwWindowsMajorVersion<5,"leider zu alte Windows-Version ...");
DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
DWORD dwBuild = 0;
if (dwVersion < 0x80000000)
// Windows NT
dwBuild = (DWORD)(HIWORD(dwVersion));
else if (dwWindowsMajorVersion < 4)
// Win32s
dwBuild = (DWORD)(HIWORD(dwVersion) & ~0x8000);
else dwBuild = 0;
// Windows Me/98/95
}
////////////////////////////////////////////////
// DllVersionsprüfung:
if(GetDllVersion(TEXT("comctl32.dll")) >= PACKVERSION(4,71)) {
//Proceed.
} else { // Use an alternate approach for older DLL versions.
}
#define PACKVERSION(major,minor) MAKELONG(minor,major)
DWORD GetDllVersion(LPCTSTR lpszDllName)
{
HINSTANCE hinstDll;
DWORD dwVersion = 0;
hinstDll = LoadLibrary(lpszDllName);
if(hinstDll) {
DLLGETVERSIONPROC pDllGetVersion;
pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll,"DllGetVersion");
if(pDllGetVersion) { DLLVERSIONINFO dvi; ZeroMemory(&dvi,sizeof(dvi));
dvi.cbSize = sizeof(dvi);
HRESULT hr = (*pDllGetVersion)(&dvi);
if(SUCCEEDED(hr)) {
dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
}
} FreeLibrary(hinstDll);
} return dwVersion;
}
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. Die MFC-Verwendung bietet Portabilität zwischen unterschiedlichen Betriebssystemen und zwischen verschiedenen Prozessoren. Die MFC ist
zwar in C++ geschrieben, geht aber über den hinaus (DLL's, CALLBACK-Funktionen, sprachspezifische STRINGTABLE-Ressourcen, usw.) und ist deshalb nicht mit
dem C++-ANSI-Standard kompatibel.
↑
Grober Zusammenhang mit ATL
MFC
"Microsoft Foundation Class" oder "MFC-Quelltext-Bibliothek"; Framework-Klassen von Windows-API-Funktionen zur Erstellung von Anwendungen;
MFC Classes, Hierarchy Chart, Class Library Overview, MFC Macros and Globals, MFC Technical Notes, usw.
ATL
"Active Template Library"; C++-Klassen, die die Programmierung von COM-Objekten vereinfachen (ATL 3.0 ab Visual C++ 6.0).
ATL Server C++-Klassen, zum Erstellen von Webanwendungen, XML-Webdienste und andere Serveranwendungen
Unterstüzung Beispielcodes, Microsoft Macro Assembler (MASM), Plattform SDK-Tools wie z.B.:
Debugger-Tools (DBMon=Debug Monitor, MapSym=MAPSYM, NTSD=Symbolic Debuggers, WinDbg=WinDbg Debugger),
Spy-Tools,
File-Mangement-Tools (Where, WinDiff),
Performance-Tools ( Bind = Minimizes application load time, ExCtrLst = Extensible counter list utility, PerfMtr = Performance meter, Performance =
Monitor Performance monitor, PStat = Performance statistics, VADUMP = Virtual address dump),
Testing-Tools (PfMon = Monitors process faults, SC = Tests a service program) ,
Cryptography-Tools (Cert2SPC = Creates a test software publisher certificate, CertMgr = Manages certificates, certificate trust lists, and certificate
revocation lists. MakeCat = Creates a catalog file, MakeCert = Creates an X.509 certificate, MakeCTL = Creates a certificate trust list, SetReg = Sets
registry values to control the certificate verification process, SignTool = Digitally signs a file, verifies signatures in files, or time stamps files),
Rebase, usw.
↑
Entwicklungskriterien
Die MFC-Klassen-Bibliothek wurde unter den folgenden Kriterien und Richtlinien entwickelt:
●
Ausführungsgeschwindigkeit höchstens 5% geringer als bei C-Language Win-API
●
Vereinfachung der Windows-Programmierung, geringe Einarbeitungszeit gegenüber der API-Programmierung
●
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_CREATE() // kein ; ON_WM_SIZE() // kein ; ON_WM_SETFOCUS() // kein ;
//}}AFX_MSG_MAP
↑
MFC und Nachrichten
Menü- und Button-Ereignisse ergeben WM_COMMAND-Nachrichten. Die MFC versteckt diese "case WM_COMMAND: switch(LOWORD(wParam))..."Konstruktioen in einer MESSAGE_MAP-Tabelle. 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. Die Macroaufrufe einer messageMap-Tabelle sehen etwa wie folgt aus:
// Beispiel:
BEGIN_MESSAGE_MAP(CMdiApp, CWinApp)// kein ;
//{{AFX_MSG_MAP(CMdiApp)
ON_WM_CREATE()
// kein ;
ON_WM_SIZE()
// kein ;
ON_WM_SETFOCUS() // kein ;
ON_COMMAND(IDM_ABOUT, OnAbout) // kein ;
ON_COMMAND_EX_RANGE(IDM_1, IDM_16, On...) // kein ;
//}}AFX_MSG_MAP
END_MESSAGE_MAP()// kein ;
Das BEGIN_MESSAGE_MAP-Macro erstellt eine Funktion GetMessageMap(), die die Adresse dieser Tabelle zurückgibt, bevor eine messageMap aus afxwin.h
definiert wird. Die BEGIN_MESSAGE_MAP und END_MESSAGE_MAP Macros haben etwa den folgenden Aufbau:
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_COMDAT const AFX_MSGMAP theClass::messageMap = \
{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{ \
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
// Grobstrktur:
#ifndef AFX_MSG_CALL
#define AFX_MSG_CALL
#endif
struct AFX_MSGMAP_ENTRY //Tabellenstruktur
{ 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)
};
enum AfxSig { // Typenbeschreibung (signature type action)
AfxSig_end = 0, // [marks end of message map]
AfxSig_bb,
// BOOL (BOOL)
...
AfxSig_is,
// int (LPTSTR)
...
AfxSig_vv,
// void (void)
...};
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
#define
CN_COMMAND 0 // void ()
#define ON_COMMAND(id, memberFxn) \
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv,(AFX_PMSG)&memberFxn
},
// ON_COMMAND
(
id, OnFoo) is the same as
// ON_CONTROL
(0, id, OnFoo) or
// ON_BN_CLICKED(0, id, OnFoo)
#define ON_WM_CREATE() \
{ WM_CREATE, 0, 0, 0, AfxSig_is, \
(AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL
CWnd::*)(LPCREATESTRUCT))&OnCreate },
Der afxmsg_.h-File beschreibt 9 Format-Möglichkeiten, wie diese Tabelleneinträge gestaltet werden können:
// Entries in a message map (a 'AFX_MSGMAP_ENTRY') table can be of 9 formats
//
// 1) control notification message (i.e. in response to WM_COMMAND)
//
WM_COMMAND, nNotifyCode, nControlID, nControlID, signature type,
parameterless member function
//
(eg: WM_COMMAND, LBN_SELCHANGE, IDC_LISTBOX, AfxSig_vv, ... )
// 2) control notification message range (i.e. in response to WM_COMMAND)
//
WM_COMMAND, nNotifyCode, nControlIDFirst, nControlIDLast, signature type,
parameterless member function
//
(eg: WM_COMMAND, LBN_SELCHANGE, IDC_LISTBOX1, IDC_LISTBOX5, AfxSig_vw, ... )
// 3) WM_NOTIFY notification
//
WM_NOTIFY, nNotifyCode, nControlID, nControlID, signature type, ...)
// 3) Update Command UI
//
-1, 0, nControlID, 0, signature Unknown, parameterless member function
// 4) Update Command UI Range
//
-1, 0, nControlIDFirst, nControlIDLast, signature Unknown, parameterless
member function
// 5) menu/accelerator notification message (i.e. special case of first format)
//
WM_COMMAND, 0, nID, 0, signature type, parameterless member function
//
(eg: WM_COMMAND, 0, IDM_FILESAVE, 0, AfxSig_vv, ... )
// 6) menu/accelerator notification message range
//
WM_COMMAND, 0, nIDFirst, nIDLast, signature type, parameterless member
function
//
(eg: WM_COMMAND, 0, IDM_FILE_MRU1, IDM_FILE_MRU4, AfxSig_vw, ... )
// 7) constant windows message
//
nMessage, 0, 0, 0, signature type, member function
//
(eg: WM_PAINT, 0, ...)
// 8) variable windows message (using RegisterWindowMessage)
//
0xC000, 0, 0, 0, &nMessage, special member function
//
// The end of the message map is marked with a special value
//
0, 0, AfxSig_end, 0
Weil zum Verteilen der Nachrichten die Klasse CWnd verwendet wird ist bei der MFC ist eine CALLBACK-Funktion meist nicht selbst zu schreiben. Die Funktion
nWndMsg() ruft z.B. bei WM_COMMAND die Funktion 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;
}
↑
MFC-Klassen-Typen
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.
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. )
MFC hat wenige abstrakte Basis-Klassen ( CObject, CCmdTarget ). MFC benutzt 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
HDC hDC;
HGDIOBJ hGdiObj;
HPEN hPen;
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;
SIZE size;
CSize
size;
RECT rect;
CRect
rect;
HRGN hRgn;
HSZ hszStr;
POINT pt;
↑
MFC-Klassenhirachie (CE)
MFC-Library für Windows CE in tabellarischer Darstellung:
NICHT von der Klasse
CObject abgeleitet (CE):
Von der Klasse CObject
(root class) abgeleitet (CE):
Application Architecture Classes
Internet Services Classes
ActiveX Type Wrappers
Support Classes
Array Classes
List Classes
Automation Types
Synchronization Support
Control Bar Classes
Map Classes
Run-Time Object Model Support
Typed Template Collections
Control Classes
Menu Classes
Simple Value Types
Windows CE Database Classes
Control Support Classes
Property Sheets
Structures
Dialog Box Classes
Synchronization Classes
Exception Classes
View Classes
(allg.)
Internet Server API
Run-Time Object Model Support
File Service Classes
Window Class Categories
Structures
Simple Value Types
Frame Windows and Splitter Windows
Windows CE Database Classes
Support Classes
Typed Template Collections
Graphical Drawing Classes
Windows Sockets Classes
OLE Type Wrappers
OLE Automation Types
Graphical Drawing Object Classes
↑
MFC-Klassenhirachie
Grobe MFC-Hierachy-Categories von CObject:
MFC-Grafische Darstellung der Objekt-Hierachie:
Synchronization
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;
class CWnd;
class CDialog;
// a target for user commands
// 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;
class CDataExchange;
class CCommandLineInfo;
class CDocManager;
//
//
//
//
Menu/button enabling
Data exchange and validation context
CommandLine parsing helper
CDocTemplate manager object
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, "nafxcwd.lib")
#else
#pragma comment(lib, "nafxcw.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "uafxcwd.lib")
#else
#pragma comment(lib, "uafxcw.lib")
#endif
#endif
| C Sharp (Einführung) | Was ist .NET? | C#-Entwickler-Tools | C#-keywords | C#-keywords | Typen in C# | Boxing and Unboxing | dll-Funktionen in C# | C#-Console-Applikation | Beispiel für cs-Console-Applikation
↑
↑
C Sharp (Einführung)
Was ist .NET?
.NET enthält einen Satz von Software-Technologien (.NET Framework, Umgebung für Entwicklung, Einsatz und Ausführung von Windows-Anwendungen und Services) und kann gemeinsame Objekte (geräteübergreifend,
integrale Windows-Komponenten, Software-Integration) erstellen und verwenden. XML Web Services werden unterstützt.
↑
Was ist C Sharp?
C# (C Sharp) ist eine einfache, objekt-orientierte, typ-sichere Programmiersprache. C# hat Ähnlichkeiten zu C/C++/Java und ist für C-/C++/Java-Programmierer leicht zu lernen. C# ist ein Teil der .NET Framework Initiative und
wurde von Anders Hejlsberg, Scott Wiltamuth und Peter Golde entwickelt. Die internationale Normung der C# Language Specification (Standard ECMA-334, 2nd edition, Dez. 2002) basiert auf der Zusammenarbeit von HewlettPackard, Intel, Microsoft. In ECMA-334 steht: The name C# is pronounced "C Sharp".
CLI : Common Language Infrastructure, ECMA-335, 2nd Edition, December 2002
CLS : Common Language Specification
BCL : Base Class Library
(simple file access, custom attributes, security attributes,
string manipulation, formatting, streams, and collections)
IEC : the International Electrotechnical Commission
IEEE: the Institute of Electrical and Electronics Engineers
ISO : the International Organization for Standardization
Extended Array Library (ISO/IEC 23271: 2002)
Das .NET Framework SDK enthält zahlreiche Tools, die der Software-Erstellung dienen. Hier einige:
Assembly Binding Log Viewer (Fuslogvw.exe) ist ein Windows-based Tool zum Untersuchen des Assembly und der Resourcen-Bindungen.
Assembly Linker (Al.exe) ist für das Erstellen des assembly manifests, satellite assemblies, und dem Arbeiten mit dem Global Assembly Cache (GAC).
Der MSIL Disassembler (Ildasm.exe) ist ein Windows-basiertes Tool zum Untersuchen der manifest-Einträge (containing metadata) und des MSIL-Codes im Assemblies.
Der Resource Editor (RESEDITOR) ist ein Windows-based Editor der .resx und .resources-Files erzeugt.
Der Resource File Generator (Resgen.exe) ist eine Consolen-Applikation die Text-Files und .resx-Files in binäre .resourcen-Files wandelt. Der ResX Generator (RESXGEN) ist eine Console-Applikation, die Bilder in XMLumformattieren und .resx-Files umformatieren kann.
Der Windows Forms Resource Editor (Winres.exe) ist eine Windows-basierte Applikation, für Anpassungen an unterschiedliche Weltsprachen.
Die Common Language Runtime (CLR) basiert auf einer abstrakten Stack-Maschine, die ausschließlich Anweisungen des Zwischencodes MSIL (Microsoft Intermediate Language) verarbeitet. Programm Executable (PE)
verwendet zur Ausführung das Virtual Execution System, das aus dem Class Loader (Verifier und JIT) besteht, der den Managed Code erzeugt.
Programm Executable (PE)
Compiler:
Virtual Execution System
besteht aus:
Managed Code
besteht aus:
Verifier
Gabage
Collector
JIT
Security
Thread
Support
Ein Assembly enthält den ausführbaren Code (falls erforderlich in mehreren Modulen mit den bereitgestellten Typen). Jedes Assembly enthält außerdem eine Manifest-Anteil mit detaillierten Informationen.
...
Manifest
Name, Version, Shared Name, Hash, Custom Attributes
Files, Referenced Assemblies, Types, Security, Product Information
Attribute
Ein Assembly kann durch die folgenden
Attribute modifiziert werden:
using System.Reflection;
using System.Runtime.CompilerServices;
Assembly
besteht
aus:
Metadata (Module 1)
Type 1 (IL-Code)
Type 2 (IL-Code), ...
Resources
...
↑
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
[assembly:
AssemblyTitle("")]
AssemblyDescription("")]
AssemblyConfiguration("")]
AssemblyCompany("")]
AssemblyProduct("")]
AssemblyCopyright("")]
AssemblyTrademark("")]
AssemblyCulture("")]
AssemblyVersion("1.0.*")]
AssemblyDelaySign(false)]
AssemblyKeyFile("")]
AssemblyKeyName("")]
...
C#-Entwickler-Tools
C# - Konfigurations- und Weitergabetools
Ermöglicht einem Administrator bzw. einem Installationsprogramm, die Skriptzuordnungen für eine ASP.NET-Anwendung so zu aktualisieren, dass sie auf die mit dem Tool
ASP.NET IIS-Registrierungstool
verknüpfte ASP.NET ISAPI-Version zeigen. Sie können mit dem Tool auch andere ASP.NET-Konfigurationsvorgänge ausführen. Hinweis: Aspnet_regiis.exe befindet sich in
(Aspnet_regiis.exe)
%windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Ermöglicht das Anzeigen und Ändern der Inhalte des globalen Assemblycache mit Windows Explorer. Hinweis: Shfusion.dll befindet sich in
Assembly Cache Viewer (Shfusion.dll)
%windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Generiert eine Datei mit einem Assemblymanifest aus einer oder mehreren Ressourcendateien bzw. aus Microsoft Intermediate Language-Dateien (MSIL). Hinweis: Al.exe befindet
Assembly-Linker (Al.exe)
sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Liest die Metadaten in einer Assembly und fügt die erforderlichen Einträge zur Registrierung hinzu, damit COM-Clients die .NET Framework-Klassen transparent erstellen können.
Assemblyregistrierungstool (Regasm.exe)
Hinweis: Regasm.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Assemblybindungs-Protokollanzeige
Zeigt die Details für fehlgeschlagene Assemblybindungen an. Mit diesen Informationen können Sie festzustellen, weshalb .NET Framework eine Assembly zur Laufzeit nicht finden
(Fuslogvw.exe)
kann.
Globales Assemblycache-Tool
Ermöglicht das Anzeigen und Ändern des Inhalts im globalen Assemblycache und Downloadcache. "Shfusion.dll" stellt ähnliche Funktionen bereit. Sie können "Gacutil.exe" in
(Gacutil.exe)
Buildskripts, Makefile-Dateien und Batchdateien verwenden.
Ermöglicht das Installieren und Deinstallieren von Serverressourcen durch Ausführen der Installerkomponenten einer angegebenen Assembly. Hinweis: Installutil.exe befindet sich in
Installer-Tool (Installutil.exe)
%windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Tool für den isolierten Speicher
Entfernt oder listet den gesamten Speicher für den angemeldeten Benutzer auf.
(Storeadm.exe)
Tool zum Generieren von systemeigenen Erstellt ein systemeigenes Abbild von einer verwalteten Assembly und installiert es im systemeigenen Abbildcache auf dem lokalen Computer. Hinweis: Ngen.exe befindet sich in
Abbildern (Ngen.exe)
%windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Stellt eine grafische Oberfläche zum Verwalten der .NET Framework-Sicherheitsrichtlinie und der Anwendungen bereit, die Remotedienste verwenden. Dieses Tool ermöglicht
.NET Framework-Konfigurationstool
daneben das Verwalten und Konfigurieren von Assemblys im globalen Assemblycache. Hinweis: Mscorcfg.msc befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx,
(Mscorcfg.msc)
wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Installationstool für die .NET-Dienste
(Regsvcs.exe)
Soapsuds-Tool (Soapsuds.exe)
Typbibliothek-Exportierprogramm
(Tlbexp.exe)
Typbibliothek-Importierprogramm
(Tlbimp.exe)
WSDL-Tool (Web Services Description
Language) (Wsdl.exe)
Webdienste-Suchtool (Disco.exe)
Tool für die XML-Schemadefinition
(Xsd.exe)
Microsoft CLR Debugger (DbgCLR.exe)
Laufzeit-Debugger (Cordbg.exe)
Tool für die Zertifikatserstellung
(Makecert.exe)
Tool für die Zertifikatsverwaltung
(Certmgr.exe)
Zertifikatsüberprüfungstool
(Chktrust.exe)
Sicherheitsrichtlinientool für den
Codezugriff (Caspol.exe)
Tool für die Dateisignierung
(Signcode.exe)
Tool zum Anzeigen von Berechtigungen
(Permview.exe)
PEVerify-Tool (PEverify.exe)
Secutil-Tool (Secutil.exe)
Registrierungstool (Setreg.exe)
SPC-Testtool (Cert2spc.exe)
Strong Name-Tool (Sn.exe)
Common Language RuntimeMinidumptool (Mscordmp.exe)
Lizenzencompiler (Lc.exe)
Management Strongly Typed Class
Generator (Mgmtclassgen.exe)
Fügt durch Laden und Registrieren der Assembly und durch Erzeugen, Registrieren und Installieren der Typbibliothek in einer vorhandenen COM+ 1.0-Anwendung verwaltete
Klassen zu den Windows 2000-Komponentendiensten hinzu. Hinweis: Regsvcs.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer
des verwendeten .NET Frameworks ist.
Unterstützt Sie bei der Kompilierung von Clientanwendungen, die über die sog. Remoting-Technik mit XML-Webdiensten kommunizieren.
Generiert eine Typbibliothek aus einer CLR-Assembly (Common Language Runtime).
Konvertiert die Typendefinitionen in einer COM-Typbibliothek in äquivalente Definitionen im verwalteten Metadatenformat.
Generiert Code für XML-Webdienste und XML-Webdienstclients aus WSDL-Dateien (Web Services Description Language), XSD-Dateien (XML Schema Definition) und .discomapDiscoverydokumenten.
Sucht die URLs von auf einem Webserver befindlichen XML-Webdiensten und speichert die mit den einzelnen XML-Webdiensten zusammenhängenden Dokumente auf einem
lokalen Datenträger.
Generiert XML-Schemas, die der XML-Schema Definition (XSD) des World Wide Web Consortiums (W3C) entsprechen. Das Tool generiert Common Language Runtime- und
DataSet-Klassen aus einer XSD-Schemadatei.
Debugtools
Stellt Debugdienste mit einer grafischen Oberfläche bereit, damit Entwickler Laufzeitprobleme in Programmen finden und beheben können. Weitere Informationen finden Sie unter
Der CLR Debugger in der .NET Framework SDK-Dokumentation. Hinweis: Der Microsoft CLR Debugger (DbgCLR.exe) befindet sich in dem Ordner
Microsoft.NET\SDK\v1.1\GuiDebug.
Stellt mit der Common Language Runtime Debug-API Befehlszeilen-Debugdienste bereit. Verwenden Sie dieses Tool, um Probleme in Programmen zu finden und zu beheben, die
mit der Laufzeit in Verbindung stehen.
Sicherheitstools
Generiert X.509-Zertifikate, die nur zu Testzwecken dienen.
Verwaltet Zertifikate, Zertifikatsvertrauenslisten und Zertifikatssperrlisten (CRLs).
Überprüft die Gültigkeit einer Datei, die mit einem X.509-Zertifikat signiert wurde.
Ermöglicht das Überprüfen und Ändern von Sicherheitsrichtlinien für den Codezugriff von Computern, Benutzern sowie auf Unternehmensebene. Hinweis: Caspol.exe befindet sich
in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.
Signiert eine PE-Datei (Portable Executable) mit einer digitalen Authenticode-Signatur.
Zeigt die minimalen, optionalen und verweigerten Berechtigungen an, die von einer Assembly angefordert werden. Sie können mit diesem Tool auch die von einer Assembly
verwendete deklarative Sicherheit anzeigen.
Überprüft die MSIL-Typensicherheit und die Gültigkeit der Metadaten für eine angegebene Assembly.
Extrahiert öffentliche Schlüsselinformationen für starke Namen oder Authenticode-Publisherzertifikate aus einer Assembly in einem Format, das in Code eingebunden werden kann.
Ermöglicht das Ändern der Registrierungseinstellungen für die Schlüssel Software Publishing State, die das Verhalten der Zertifikatsüberprüfung steuern.
Erstellt ausschließlich zu Testzwecken ein SPC (Software Publisher's Certificate), das aus mindestens einem X.509-Zertifikat besteht.
Hilft beim Erstellen von Assemblys mit starken Namen. Sn.exe bietet Optionen für die Schlüsselverwaltung, die Signaturgenerierung und die Signaturüberprüfung.
Allgemeine Tools
Erstellt eine Datei, die Informationen zum Analysieren von Systemproblemen zur Laufzeit enthält. Das Tool Microsoft Dr. Watson (Drwatson.exe) startet dieses Programm
automatisch.
Liest Textdateien, die Lizenzinformationen enthalten, und erstellt eine .licenses-Datei, die in einer ausführbaren Common Language Runtime-Datei eingebettet werden kann.
Ermöglicht das schnelle Generieren einer früh gebundenen Klasse in C#, Visual Basic oder JScript für eine angegebene WMI-Klasse (Windows Management Instrumentation).
MSIL-Assembler (Ilasm.exe)
MSIL-Disassembler (Ildasm.exe)
Generierungstool für Ressourcendateien
(Resgen.exe)
Visual J#-Binärkonvertierungstool
(JbImp.exe)
Generiert eine PE-Datei aus MSIL (Microsoft Intermediate Language). Sie können diese Datei ausführen, die den MSIL-Code und die erforderlichen Metadaten enthält, um zu
überprüfen, ob der MSIL-Code ordnungsgemäß ausgeführt wird. Hinweis: Ilasm.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer
des verwendeten .NET Frameworks ist.
Erstellt aus einer PE-Datei, die MSIL-Code enthält, eine Textdatei, die als Eingabe für den MSIL-Assembler (Ilasm.exe) verwendet werden kann.
Konvertiert Textdateien und .resx-Dateien (XML-basiertes Ressourcenformat) in .resources-Dateien der .NET Common Language Runtime, die in einer ausführbaren LaufzeitBinärdatei eingebettet oder in Satellitenassemblys kompiliert werden können.
Dieses Tool konvertiert bestimmte Bytecodedateien in der Programmiersprache Java (.class-Dateien) zu MSIL (Microsoft® Intermediate Language). Mit diesem Tool können
Entwickler die meisten Bibliotheken und Anwendungen der JDK 1.1.4–Ebene, die nur als Bytecodedateien verfügbar sind, in MSIL-Assemblys umwandeln und sie mit dem Visual J#
Redistributable Package auf .NET Framework ausführen. Verwenden Sie dieses Tool nur, wenn die Java-Quellen für die Anwendungen bzw. Bibliotheken nicht verfügbar sind. Wenn
die Java-Quellen verfügbar sind, sollten Sie stattdessen den Visual J#-Compiler (vjc.exe) verwenden. Hinweis: Zur Verwendung dieses Tools muss das Visual J# .NET Redistributable
Package, Version 1.1, installiert sein. Visual J# Redistributable Package wird installiert.
Importierprogramm für Windows Forms
Konvertiert Typendefinitionen in einer COM-Typbibliothek für ein ActiveX-Steuerelement in einem Windows Forms-Steuerelement.
ActiveX-Steuerelemente (Aximp.exe)
Windows Forms-Klassenanzeige
Sucht verwaltete Klassen, die mit den angegebenen Suchkriterien übereinstimmen, und zeigt mit der Reflektions-API Informationen über die Klassen an.
(Wincv.exe)
Ressourcen-Editor für Windows Forms
Ermöglicht das einfache und schnelle Lokalisieren von Windows Forms-Formularen.
(Winres.exe)
↑
C#-keywords
In C# gibt es die folgenden "Schlüsselworte":
abstract as
base
bool
break
byte
class
const
continue decimal
event
explicit extern
if
new
case
catch
char
checked
default
delegate do
double
else
enum
false
finally
fixed
for
foreach
goto
implicit in
int
interface internal is
lock
long
namespace
null
object
operator out
override params private
readonly ref
return
sbyte
sealed
short
sizeof
stackalloc static
string
struct
switch
this
throw
true
try
typeof
uint
unchecked
unsafe
ushort
using
virtual
void
volatile
while
float
protected public
ulong
Ein Vergleich mit den Schlüsselwörtern des CPP-Betriessystem-Compilers zeigt Unterschiede auf. Neuerungen (z.B. Einführung von DLL's) ändern auch die Unterstützung durch "Standard-CPP-Compiler". CPP-Schlüsselwörter
(hier MS-Keywords) sind reservierte, vordefinierte Identifizierer, die eine besondere Bedeutung haben und deshalb im eigenen C++-Quelltext nicht frei verwende werden können. Identifizierer mit führenden Underscores ("__...")
sind MS-Erweiterungen.
Schlüsselwörter des CPP-Betriessystem-Compilers
__abstract
__alignof
__asm
__assume
__based
__box
__cdecl
__declspec
__delegate
__event
__except
__fastcall
__finally
__forceinline
__gc
__hook
__identifier
__if_exists
__if_not_exists __inline
__int64
__interface
__leave
__noop
__pin
__try_cast
__try/__except,
__try/__finally
__int8
__int16
__int32
__m128
__m128d
__m128i
__multiple_inheritance __nogc
__property
__raise
__sealed
__single_inheritance __stdcall
__unhook
__uuidof
__value
__virtual_inheritance __w64
__super
↑
bool
break
case
catch
continue
default
delete
dynamic_cast else
friend
goto
long
novtable
char
class
const
const_cast
deprecated dllexport
dllimport
do
double
enum
explicit
extern
false
float
for
if
inline
int
mutable
naked
namespace new
noinline
noreturn
nothrow
operator
private
property
protected
public
register
reinterpret_cast
return
selectany
short
signed
sizeof
static
static_cast
struct
switch
template
this
thread
throw
true
try
typedef
typeid
typename
union
unsigned
using declaration, uuid
using directive
virtual
void
volatile
wchar_t,__wchar_t while
Typen in C#
c# hat class-Modifizierer: new, public, protected, internal, private, abstract, sealed Das Common Type System (CTS) umfasst einen reichhaltigen Satz von Datentypen, die sich grob in "Value Types" und "Reference Types"
klassifizieren lassen.
Value Types
System Value Types Enumerations
User Value Types
Referenz Types
Pointers
Self-describng types
Interface
a) Classes: Delegates,User-Defined,Boxed Values)
b) Arrays
Reference (class)
"wie eine Adresse"
Value (struct)
"wie ein Stück Speicher"
Variable holds
Reference
Eine Refrenztyp-Variable zeigt auf
die Heap-Instanz des Objektes.
A a = new A("Fred"); A b = a; b.Name = "xxx";//mutator
Es gibt immutable class
Actual value
int i = 123; int j = i;
i = 55; hat keinen Einfluß auf j
Value lives
On the heap
Inline (on the stack, or inline with an object)
Default Value
Null
Zeroed
= means
Copy reference
Copy value
↑
Boxing and Unboxing
int value = 123;
object o = value;
// box int into an object box
int value2 = (int) o;
// unbox into value2
Das Folgende zeigt lediglich das "Carsting"-Prinzip (alles ist ein Objekt, Boxing and Unboxing), wie es etwa in C (auf der unteren Ebene) implementiert ist.
tagVARIANT ist in
oaidl.h definiert
struct tagVARIANT {
union {
struct __tagVARIANT {
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union {
LONGLONG llVal;
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;SCODE scode;
_VARIANT_BOOL bool; CY cyVal;
DATE date;
BSTR bstrVal;
IUnknown *punkVal;
BYTE *pbVal;
IDispatch *pdispVal; SHORT *piVal;
SAFEARRAY *parray;
LONG *plVal;
LONGLONG *pllVal;
FLOAT *pfltVal;
DOUBLE *pdblVal;
SCODE *pscode;
VARIANT_BOOL *pboolVal;
_VARIANT_BOOL *pbool;CY *pcyVal;
BSTR *pbstrVal;
DATE *pdate;
IUnknown **ppunkVal;
IDispatch **ppdispVal;
SAFEARRAY **pparray; CHAR cVal;
VARIANT *pvarVal;
PVOID byref;
USHORT uiVal;
ULONG ulVal;
ULONGLONG ullVal;
INT intVal;
UINT uintVal;
DECIMAL *pdecVal;
CHAR *pcVal;
USHORT *puiVal;
ULONG *pulVal;
ULONGLONG *pullVal;
INT *pintVal;
UINT *puintVal;
struct __tagBRECORD {
PVOID pvRecord; IRecordInfo *pRecInfo;
} __VARIANT_NAME_4;
} __VARIANT_NAME_3;
} __VARIANT_NAME_2;
DECIMAL decVal;
} __VARIANT_NAME_1;
} ;
Wie funktioniert (intern) Boxing and Unboxing?
BasicType ist in
VARENUM ist in
cvconst.h definiert
wtypes.h definiert
enum VARENUM {
enum BasicType {
VT_EMPTY = 0, VT_NULL
btNoType = 0,
VT_I2
= 2, VT_I4
VT_R4
= 4, VT_R8
btVoid
= 1,
VT_CY
= 6, VT_DATE
btChar
= 2,
VT_BSTR
= 8, VT_DISPATCH
VT_ERROR = 10, VT_BOOL
btWChar
= 3,
VT_VARIANT= 12, VT_UNKNOWN
btInt
= 6,
VT_DECIMAL= 14, VT_I1
btUInt
= 7,
VT_UI1
= 17, VT_UI2
VT_UI4
= 19, VT_I8
btFloat
= 8,
VT_UI8
= 21, VT_INT
btBCD
= 9,
VT_UINT
= 23, VT_VOID
VT_HRESULT
= 25,
btBool
= 10,
VT_PTR
= 26,
btLong
= 13,
VT_SAFEARRAY
= 27,
VT_CARRAY
= 28,
btULong
= 14,
VT_USERDEFINED
= 29,
btCurrency= 25,
VT_LPSTR
= 30,
btDate
= 26,
VT_LPWSTR
= 31,
VT_RECORD
= 36,
btVariant = 27,
VT_INT_PTR
= 37,
btComplex = 28,
VT_UINT_PTR
= 38,
VT_FILETIME
= 64,
btBit
= 29,
VT_BLOB
= 65,
btBSTR
= 30,
VT_STREAM
= 66,
VT_STORAGE
= 67,
btHresult = 31
VT_STREAMED_OBJECT = 68,
};
VT_STORED_OBJECT
= 69,
printVariant()-Beispiel
=
=
=
=
=
=
=
=
=
=
=
=
1,
3,
5,
7,
9,
11,
13,
16,
18,
20,
22,
24,
void printVariant( VARIANT& v )
{
switch( v.vt )
{
case VT_I8://* LONGLONG VT_I8
printf( "%ld", v.llVal );break;
case VT_I4: //* LONG VT_I4
printf( "%d", v.lVal ); break;
case VT_UI1://* BYTE VT_UI1
printf( "%d", v.bVal);
break;
case VT_I2: //* SHORT VT_I2
printf( "%d", v.iVal);
break;
case VT_I1: //* CHAR VT_I1
printf( "%d", v.cVal);
break;
case VT_UI2: //* USHORT VT_UI2
printf( "%d", v.uiVal); break;
case VT_UI4://* ULONG VT_UI4
printf( "%d", v.ulVal); break;
case VT_UI8: //* ULONGLONG VT_UI8
printf( "%ld", v.ullVal);
break;
case VT_INT: //* INT VT_INT
printf( "%d", v.intVal); break;
case VT_UINT://*
UINT VT_UINT
printf( "%d", v.uintVal);break;
default:
printf( "<Not implemented>" );
break;
}
VT_BLOB_OBJECT
= 70,
VT_CF
= 71,
VT_CLSID
= 72,
VT_VERSIONED_STREAM = 73,
VT_BSTR_BLOB
= 0xfff,
VT_VECTOR
= 0x1000,
VT_ARRAY
= 0x2000,
VT_BYREF
= 0x4000,
VT_RESERVED
= 0x8000,
VT_ILLEGAL
= 0xffff,
VT_ILLEGALMASKED= 0xfff,
VT_TYPEMASK = 0xfff
} ;
}
↑
dll-Funktionen in C#
Bei mehr als 1000 DLL'S (ca. 40 000 API-Funktionen) gibt es viele Nativ-Funktionen, die exportiert werden. Wie können diese DLL-Funktionen, die sich in DLL's befinden, in C# genutzt werden?
Wie werden in C# Funktionen aus den dll's genutzt?
Als Beispiel soll die Funktion bool Beep(int frequency, int duration); benutzt werden, die von "kernel32.dll" exportiert wird. Durch Für einen akustischen Hinweis ist meist die C++-Funktion BOOL MessageBeep(UINT
[DllImport("kernel32.dll")] oder
soundtype) günstiger, die in C# als bool MessageBeep(BeepType beepType); benutzt
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] wird eine Import-Einbindung in unsere Klasse veranlaßt. Nach [DllImport("...dll")] werden kann. Im C++-Header File winuser.h sind Konstanten definiert, wie z.B.
folgt der Prototyp public static extern bool Beep(int frequency, int duration);, der dem C#-Compiler bei der "Typsicherheit hilft".
"MB_ICONHAND", die nach C# gewandelt werden können, etwa:
using System;
using System.Runtime.InteropServices;
class myClass_nutzt_dll_funktion
{
[DllImport("kernel32.dll")]
public static extern
bool Beep(int frequency, int duration);
static void Main(string[] args) {
Random random = new Random();
for (int i = 0; i < 100; i++) {
Beep(random.Next(10000),100);
}
}
}
using System;
class IndexerClass {
private int [] myArray = new int[100];
public int this [int index] {//Indexer declaration
get {
if (index < 0 || index >= 100) return 0; else
return myArray[index];
}
set {
if (!(index < 0 || index >= 100))
myArray[index] = value;
}
}
}
public class MainClass {
public static void Main() {
IndexerClass b = new IndexerClass();
b[2] = 1024; b[3] = 256;
for (int i=0; i < 5; i++) {
Console.WriteLine("Element #{0} = {1}",
i,
b[i]);
}
}
}
Ausgabe:
Element #0 = 0
Element #1 = 0
Element #2 = 1024
public enum BeepType {
SimpleBeep
= -1,
IconAsterisk
= 0x00000040,
IconExclamation = 0x00000030,
IconHand
= 0x00000010,
IconQuestion
= 0x00000020,
Ok
= 0x00000000,
}
benutze:
[DllImport("user32.dll")]
public static extern
bool MessageBeep(BeepType beepType);
C# Aufruf:
MessageBeep(BeepType.IconQuestion);
Element #3 = 256
Element #4 = 0
↑
C#-Console-Applikation
Eine C#-Console-Applikation wird mit csc.exe /t:exe übersetzt. Als Beispiel wird hier auch der Aufruf einer statischen Methode bei einem "nested namespace" angegeben.
#define P01
#if P01
class HalloWelt {
static void Main()
{
System.Console.WriteLine
("Hallo Welt! Ohne using System;");
}
}
#endif
//- - - - - oder - - - - #if P02
using System;
class HalloWelt {
static void Main() {
Console.WriteLine
("Hallo Welt! Mit \nusing System;");
}
}
#endif
↑
Beispiel für cs-Console-Applikation
#undef
#undef
#undef
#undef
#undef
#define
P01
P02
P03
P04
P05
P01
#if P01
/////////////////////////////////////////////////
// ohne using System;
/////////////////////////////////////////////////
class HalloWelt {
static void Main() {
System.Console.WriteLine(
"\n*** Hallo Welt!"
+"\n*** Ohne Verwendung von"
+"\n*** using System;");
#if P03
using System;
namespace SomeNameSpace {
public class MyClass {
[STAThread]
public static void Main()
{
Nested.NestedNameSpaceClass.SayHello();
}
}
namespace Nested { // a nested namespace
public class NestedNameSpaceClass {
public static void SayHello()
{
Console.WriteLine("Hello");
}
}
}
}
#endif
}
}
#endif
#if P02
/////////////////////////////////////////////////
// mit using System;
/////////////////////////////////////////////////
using System;
class HalloWelt {
static void Main() {
Console.WriteLine(
"\n*** Hallo Welt!"
+"\n*** Mit Verwendung von"
+"\n*** using System;");
}
}
#endif
#if P03
/////////////////////////////////////////////////
// Starte das übersetzte Programm myproc.exe mit
// Kommandozeilen-Argumenten, wie z.B.:
// myproc.exe A B C D
// und xml-Extraktion
/////////////////////////////////////////////////
using System;
public class HalloWelt03 {
public static void Main(string[] args) {
Console.WriteLine("Hallo! Mit Main(string[] args)");
Console.WriteLine("Anzahl = {0}", args.Length );
for (int i=0; i < args.Length; i++)
{
Console.WriteLine("args[{0}] = {1}",i,args[i]);
}
}
}
#endif
#if P04
namespace P04 {
/////////////////////////////////////////////////
// mehrer Kommandozeilen eingeben
/////////////////////////////////////////////////
using System;
/// <summary>
/// Zusammenfassung für P04
/// </summary>
class HalloWelt04 {
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung
/// ist Main(string[] args)
/// </summary>
[STAThread]
static void Main(string[] args) {
Console.WriteLine("\n*** quit beendet");
string currentLine = Console.In.ReadLine();
while(currentLine != null) {
if(currentLine =="quit" )break;
Console.Out.WriteLine(currentLine);
currentLine = Console.In.ReadLine();
}
}
}
}
#endif

Documentos relacionados