516
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 | Software- Interrupt | 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 | RTL- Typen | 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 | WNDCLASSEX- Struktur | 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()

Systemprogrammierung II (SP II,Script 2005)

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Systemprogrammierung II (SP II,Script 2005)

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 | Software-Interrupt | 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 | RTL-Typen | 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 | WNDCLASSEX-Struktur | 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()

Page 2: Systemprogrammierung II (SP II,Script 2005)

↑ 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 | Hex-

Rechner1 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

Page 3: Systemprogrammierung II (SP II,Script 2005)

↑ 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 | CS-

keywords | Typen in C# | Boxing and Unboxing | dll-Funktionen in C# | CS-Console-Applikation | Beispiel für cs-Console-Applikation

Page 4: Systemprogrammierung II (SP II,Script 2005)

SP2-Praktikum-Gruppeneinteilung

Mi 1. 8.00- 9.30 C405: Gruppe A1, .. Mi 2. 9.50-11.20 C405: Gruppe B1, B2Mi 3. 11.30-13.00 C405: Gruppe C1, ..--------------------------------------------Do 4. 14.00-15.30Do 5. 15.45-17.15 F305: VorlesungDo 6. 17.30-19.00 C405: Gruppe D1

Wie wird das SP2-Praktikum durchgeführt?

1. Aufgaben per Internet 2. Bearbeitungszeit 1 Woche 3. Punktbewertung + Kontrollfragen 4. keine Überschreitung der Bearbeitungszeit

Page 5: Systemprogrammierung II (SP II,Script 2005)

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;

Page 6: Systemprogrammierung II (SP II,Script 2005)

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 | Hardware-

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

Page 7: Systemprogrammierung II (SP II,Script 2005)

.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) =%d\n", sizeof(PSZ)); }

↑Tests zu Macros,Datentypen, Zeigern

Mit dieser Console-Applikation sollen Macros für die Ausgabe-Umleitung erstellt und getestet werden. Hier einige Macro-

Beispiele:

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

Page 8: Systemprogrammierung II (SP II,Script 2005)

FALSE hat den Wert ...TRUE hat den Wert ...( a < *p ) hat den Wert ... ( (BYTE) a < (BYTE) *p ) hat den Wert ...*(p+3) hat den Wert ...

Welche Änderungen ergeben sich, wenn 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 ; }

Page 9: Systemprogrammierung II (SP II,Script 2005)

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?

Page 10: Systemprogrammierung II (SP II,Script 2005)

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]] = ....

Page 11: Systemprogrammierung II (SP II,Script 2005)

| 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 | UNIX-

Standardisierungen | 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()

↑ BetriebssystemAchtung! 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:

Page 12: Systemprogrammierung II (SP II,Script 2005)

Moderne Prozessoren können verschiedene Speicher-Adressiersarten haben ( Memory-Management: Segnmentierung, Paging ):

Page 13: Systemprogrammierung II (SP II,Script 2005)

Moderne Prozessoren können Descriptoren haben: ( Zugriffstypen, Zugriffrechte, Privilege Level, Call Gates, Interrupt and Exception-Handling, usw. )

Page 14: Systemprogrammierung II (SP II,Script 2005)

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

Page 15: Systemprogrammierung II (SP II,Script 2005)

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

Page 16: Systemprogrammierung II (SP II,Script 2005)

*.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:

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

Beispiel für AUTOEXEC.BAT:

@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

Speicher-Bild: +-----------------------------------+ | | ↑ ↓

Tabellen- |----|----|----| ... |----|----|----| ... |----|-- ... ------------- Index 0. 1. 2. 33. 34. 35. 255. Zielstelle

Wesentliche Teile des MS-Dos-Betriebssystem werden über eine Interrupt-Adress-Tabelle abgewickelt. Dadurch ergeben sich die folgenden Vorteile: Wird das

Betriebssystem verbessert oder erweitert, so wird der Maschinencode an der Zielstelle geändert. Die Folge der Adressen an den Zielstellen verschieben sich. Wenn

Page 17: Systemprogrammierung II (SP II,Script 2005)

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

Page 18: Systemprogrammierung II (SP II,Script 2005)

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 )

↑ WindowsWindows ist überwiegend in ANSI - C geschrieben. Einige wenige zeitkritische Teile des Betriebssystem - Kerns für die Hardware Abstraktions Layer ( HAL ) sind in

Assembler - Code geschrieben. Das Betriebssystem ist modular. Bei Bedarf werden die benötigten Teile ( DLL's ) geladen/entfernt.

Es gibt verschiedene Windows-Betriebssysteme:

1985 MS präsentiert Windows 1.01; 1987 Windows 2; 1987 OS/2 von IBM / MS, zeichenorientiert 1988 OS/2 von IBM/MS mit grafischer Oberfläche 1990 Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet die Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste kommerzielle Internet-Provider den Dienst auf.

Page 19: Systemprogrammierung II (SP II,Script 2005)

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 UNIX1995 Windows 95, ( unterstützt 32-Bit-Anwendungen und die so genannte Plug-and-Play-Technologie, mitgeliefert wurde der Internet-Browser Internet Explorer, für Heimmarkt = Small Office/Home Office; 1998 Windows 98 ( Update für Windows 95, Active Desktop bindet den Webbrowser Internet Explorer, unterstützt werden: FAT32, DVD- und MMX-Technologie, AGP (siehe Graphikkarte) USB-Anschlüsse ( Universal Serial Bus ), AGP ( Accelerated Graphics Port, 1997 Intel, direkte Verbindung von der Grafikkarte zum Prozessor sowie zum Arbeitsspeicher, Taktfrequenz 66 MHz, AGP 1X = 266 MByte/s, AGP 2X = 533 MByte/s, AGP 4X = 1066 MByte/s, Pipelining, 8 zusätzliche Leitungen, DIME-Auslagerungsmodus für Texturen ); 2000 Windows 2000 wird in 4 Zusammenstellungen ausgeliefert: Windows 2000 Professional ( für PC und Notebook ), Windows 2000 Server ( einfache Netzanwendungen ), Windows 2000 Advanced Server ( Unternehmenskritische und komplexe Netzanwendungen ) Windows 2000 Datacenter Server ( für Rechenzentren, Lagerverwaltungssysteme und Finanzsysteme ); 2001 Windows ME; 2002 Windows XP

NT-Design Ziele NT-Server

Page 20: Systemprogrammierung II (SP II,Script 2005)

● Kompatibilität: Durch seine Submodule ist Windows

NT in der Lage, Applikationen für die Betriebssyteme

Windows 3.x, Windows 95, MS-DOS, OS/2 und

POSIX zu betreiben.

● Portierbarkeit: Windows NT ist fast vollständig in C

geschrieben. Für eine neue Hardware Architektur muß

deswegen lediglich eine neue HAL (Hardware

Abstraction Layer) geschrieben werden und ein NT-

komformer Compiler verfügbar sein.

● Skalierbarkeit: Windows NT unterstützt das

symmetrische Multiprocessing.

● Sicherheit: Windows NT beinhaltet ein

durchgängiges Sicherheitskonzept, das darauf

ausgelegt ist, die Sicherheitsanforderungen des

Amerikanischen Verteidungsministeriums zu erfüllen

(C2).

● Verteilte Systeme: Windows NT hat schon im

Betriebssystemkern weitreichende Funktionalität, um

Prozesse auf anderen Rechnern ablaufen zu lassen.

● Zuverlässigkeit und Stabilität: Durch sein Konzept

unterscheidet 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.

● Die Server - Version unterstützt beliebig viele

gleichzeitige Datei- und Druckerverbindungen,

Datei- und Druckerserver auch für Macintosh,

● Die Benutzerinformationen stehen allen Servern zur

Verfügung (Domänen Konzept),

● NT-Server ermöglicht eine zentrale

Benutzeradministration, Verzeichnis-Replikation,

● TCP/IP Unterstützung ( DHCP, WINS, DNS, etc.),

● NetWare Unterstützung ( GSNW, Migration Tool,

FPNW kompatibel ),

● fehlertolerante Plattenkonzepte werden unterstützt (

Parity, RAID 5 ),

● Multiuser Remote Access Service

Page 21: Systemprogrammierung II (SP II,Script 2005)

● 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

Page 22: Systemprogrammierung II (SP II,Script 2005)

NT-Subsysteme

Page 23: Systemprogrammierung II (SP II,Script 2005)

Darüber hinaus stellt Windows NT eine Reihe geschlossener Subsysteme zur Ausführung von Applikationen zur Verfügung. Sie alle kommunizieren mit dem darunterliegenden Betriebssystem und regeln ihre Bildschirmausgaben über die Windows32-Graphikschnittstelle.

● Win32: Ausführung von 32-Bit Windows-Programmen, beinhaltet das WOW-Modul (Windows-on-Windows) zur Ausführung von 16-Bit-

Programmen.

● OS/2: OS/2 2.x Subsystem.

● POSIX: Zeichenorientiertes POSIX-Subsystem.

● Sicherheit: Subsystem zur Überwachung der Sicherheit der anderen Subsysteme

NT-Objekte NT-Objekte NT-Objekte

Resourcen als Objekte:

● Dateien

● Gemeinsam

benutzter Speicher

● Physikalische

Geräte jeder Art

● Prozesse/Threads

Ein NT-Thread:

● teilt sich das Code-

und Daten-

Segment eines

Prozesses mit

anderen Threads,

● hat seine eigenen

CPU-Register,

Stack-Raum und

einen eigenen

Instruktions -

Zähler,

● erhält vom System

eine gewisse CPU -

Zeit, so daß alle

Threads des

Unterschiedliche Objekte sind:

● Executive Objects

● hat bereits Windows NT 3.5 mit

Service Pack 3 die C2-

Zertifizierung für NT-Rechner

ohne Netzwerkanbindung

erhalten.

● NT ist für B1-Security ausgelegt.

● Für jedes Objekt gibt es ein

Zugriffstoken

Page 24: Systemprogrammierung II (SP II,Script 2005)

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 HardwaresichtAlle 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

Page 25: Systemprogrammierung II (SP II,Script 2005)

Zahlen in wissenschaftlicher Notation bestehen aus Vorzeichen ( Sign Bit ) , Mantisse ( Significant ) und Exponent ( Biased Exponent ). Wir müssen daher bei en sehr

genau zwischen der Von der Größe einer Gleitpunktzahl ( Wert des Exponenten ) ist die Darstellungsgenauigkeit ( Anzahl der gespeicherten Ziffern ) zu unterscheiden.

Das Format von Gleitpunktzahlen ist in IEEE 754 ( Floating Point Standard ) festgelegt.

Es gibt die Daten-Formate:

● Word Integer ( Zweierkomplement, Bereich 104, Genauigkeit 16 Bit ),

● Short Integer ( Zweierkomplement, Bereich 109, Genauigkeit 32 Bit ),

● Long Integer ( Zweierkomplement, Bereich 1018, Genauigkeit 64 Bit ),

● Packed BCD ( Bereich 1018, Genauigkeit 18 Digits ),

● Single Precision ( 8 Bit für Exponenten, Bereich 10+38; 24 Bits für Mantisse, Genauigkeit 24 Bit ),

● Double Precision ( 11 Bit für Exponenten, Bereich 10+308; 53 Bits für Mantisse, Genauigkeit 53 Bit ),

● Extended Precision ( 16 Bit für Exponenten, Bereich 10+-4932; 64 Bits für Mantisse, Genauigkeit 64 Bit ).

Gleitpunktzahlen werden vielfältig benötigt ( naturwissenschaftlichen, technischen Anwendungen, Grafik, numerische Mathematik, usw. ). Wegen des Zeitbedarfes

werden Fließkommaoperationen von Gleitpunktzahlen (engl. Floating Point Numbers ) in digitalen Einheiten ( Coprozessor ) ausgeführt.

Bitweise Darstellung einer double-Zahl

63 .. 56 55 .. 48 47 .. 40 39 .. 32 31 .. 24 23 .. 16 15 .. 8 7 .. 0

3 2 1 0 9 8 7 6 5 4 3 2 1 0 0 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0

s -

Wert = (-1)s * 2e-e0 * ( normalisierte Mantisse ) mit

e = Exponent ( -1022 ...1023 ),

e0 := 1023 und

1 <= normalisierte Mantisse < 2

Beispiel:

Page 26: Systemprogrammierung II (SP II,Script 2005)

dez 25678.34 = = dez 2.567834*104 =

= bin 0110 0100 0100 1110.0101 0111 =

= bin 0110 0100 0100 1110. 0101 0111 =

( . um 14 Positionen verschieben, begrenzen der Mantisse auf 3 Byte: )

= bin 1.1001 0001 0011 1001 0101 11oo * 2dez 14

( e0+14 = dez 1023 + 14 = dez 1037 = bin 100 0000 1101 )

0 1 0 0 0 0 0 0 1 1 0 1 1 0 0 1 0 0 0 1 0 0 1 1 1 0 0 1 0 1 0 1 1 1 0 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4 6 C 8 9 C A E 0 0 0 0 0 0 0 0

↑ Beispiel: Unicode

Eine lesbare Schrift besteht aus Schriftzeichen. Eine Repräsentation von Bildern als Zeichen wird Font genannt. Outline-Typeface ist eine Konturschrift ( Vektoren,

Zeichen nur aus Umrisslinien ). TrueType-Fonts wurden von Apple und Microsoft entwickelt ( Zeichen werden 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.

Page 27: Systemprogrammierung II (SP II,Script 2005)

● 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

Page 28: Systemprogrammierung II (SP II,Script 2005)

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-textdata type name

SBCS (_UNICODE, _MBCS not defined) _MBCS defined _UNICODE defined

_TCHAR char char wchar_t

_TINT int int wint_t

_TSCHAR signed char signed char wchar_t

_TUCHAR unsigned char unsigned char wchar_t

_TXCHAR char unsigned char wchar_t

Page 29: Systemprogrammierung II (SP II,Script 2005)

_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

_tprintf() kann generische _TCHAR verwenden 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

Page 30: Systemprogrammierung II (SP II,Script 2005)

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 __super

__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, using directive

uuid 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

Page 31: Systemprogrammierung II (SP II,Script 2005)

↑ C++Grundtypen

C++ kennt main() für Program Startup and Termination und die Standard-Streams: cin ( for standard input ), cout ( for standard output ), cerr ( for unbuffered standard

error output ), clog ( for buffered standard error output ).

C++ kennt die Header-Files ( bzw. subset ) : algorithm, bitset, cassert, cctype, cerrno, cfloat, ciso646, climits, clocale, cmath, complex, csetjmp, csignal, cstdarg, cstddef,

cstdio, cstdlib, cstring, ctime, cwchar, cwctype, deque, exception, fstream, functional, iomanip, ios, iosfwd, iostream, istream, iterator, limits, list, locale, map, memory,

numeric, ostream, queue, set, sstream, stack, stdexcept, streambuf, string, strstream, utility, valarray, vector

Unterschiedliche Maschinen haben unterschiedlich geeignete Darstellungen ( Speicherbedarf, Geschwindigkeit, Vorzeichen, Big/Little Endian, usw. ).

C++ garantiert die folgenden Relationen:1 == sizeof(char) <= sizeof(short) <= sizeof(int)

<= sizeof(long) <= sizeof(float) <= sizeof(double) Typ Beispiel

Typen für Integer char entspricht bei vielen Maschinen einem 8-Bit-signed-Wert;

char t = '\t'; /* 0x09 */char c0 = ( char ) 0x61;/* 'a' */char *p = & c0; /* pStr -> c0 */char c[5] = {'A', 'B', 'C'}; // 0x41 0x42 0x43 0x00 0x00 char *ptrs[5] = {"abc","ABC"}; // ptrs[0] -> 0x61 0x62 0x63 0x00 0x00 // ptrs[1] -> 0x41 0x42 0x43 0x00 0x00 // ptrs[2] == NULL// ptrs[3] == NULL// ptrs[4] == NULLchar *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

Page 32: Systemprogrammierung II (SP II,Script 2005)

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 bitset.h for defining a template class that administers sets of bits

cassert.h for enforcing assertions when functions execute cctype.h for classifying characters

cerrno.h for testing error codes reported by library functions cfloat.h for testing floating-point type properties

ciso646.h for programming in ISO 646 variant character sets climits.h for testing integer type properties

clocale.h for adapting to different cultural conventions cmath.h for computing common mathematical functions

complex.h for defining a template class that supports complex arithmetic csetjmp.h for executing nonlocal goto statements

csignal.h for controlling various exceptional conditions cstdarg.h for accessing a varying number of arguments

cstddef.h for defining several useful types and macros cstdio.h for performing input and output

cstdlib.h for performing a variety of operations cstring.h for manipulating several kinds of strings

ctime.h for converting between various time and date formats cwchar.h for manipulating wide streams and several kinds of strings

cwctype.h for classifying wide characters deque.h for defining a template class that implements a deque container

exception.h for defining several functions that control exception handling fstream.h for defining several iostreams template classes that manipulateexternal files

Page 33: Systemprogrammierung II (SP II,Script 2005)

functional.h for defining several templates that help construct predicatesfor the templates defined in algorithm.h and numeric.h

iomanip.h for declaring several iostreams manipulators that take an argument

ios.h for defining the template class that serves as the base for manyiostreams classes

iosfwd.h for declaring several iostreams template classes before they arenecessarily defined

iostream.h for declaring the iostreams objects that manipulate the standard streams iso646.h.h for programming in ISO 646 variant character sets

istream.h for defining the template class that performs extractions iterator.h for defining several templates that help define and manipulate iterators

limits.h for testing numeric type properties list.h for defining a template class that implements a list container

locale.h for defining several classes and templates that control locale-specificbehavior, as in the iostreams classes

map.h for defining template classes that implement associative containers

memory.h for defining several templates that allocate and free storage forvarious container classes

new.h for declaring several functions that allocate and free storage

numeric.h for defining several templates that implement useful numeric functions ostream.h for defining the template class that performs insertions

queue.h for defining a template class that implements a queue container set.h for defining template classes that implement associative containerswith unique elements

sstream.h for defining several iostreams template classes that manipulatestring containers

stack.h for defining a template class that implements a stack container

stdexcept.h for defining several classes useful for reporting exceptions streambuf.h for defining template classes that buffer iostreams operations

string.h for defining a template class that implements a string container strstream.h for defining several iostreams classes that manipulate in-memorycharacter sequences

typeinfo.h for defining class type_info, the result of the typeid operator utility.h for defining several templates of general utility

valarray.h for defining several classes and template classesthat support value-oriented arrays

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 TypesEs gibt Zahlreiche Betriebssystemstrukturen (Interface-Funktionen, Parameterart und -folge auf Stack, Nachrichtenspezifikationen, Systemparamter, Alignment, Hardware-

und 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.

Page 34: Systemprogrammierung II (SP II,Script 2005)

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

Page 35: Systemprogrammierung II (SP II,Script 2005)

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

Page 36: Systemprogrammierung II (SP II,Script 2005)

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 8-bit 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 16-bit Unicode characters.

LPDWORD Windef.h: typedef DWORD *LPDWORD; Pointer to a DWORD.

Page 37: Systemprogrammierung II (SP II,Script 2005)

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 8-bit Windows (ANSI) characters.

PCTSTR Winnt.h: #ifdef UNICODE typedef LPCWSTR PCTSTR; #else typedef LPCSTR PCTSTR;

A PCWSTR if is defined, a PCSTR otherwise.

PCWSTR Winnt.h: typedef CONST WCHAR *PCWSTR; Pointer to a constant null-terminated string of 16-bit 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.

Page 38: Systemprogrammierung II (SP II,Script 2005)

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 64-bit 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 sign-extended 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 PTSTR;

A PWSTR if is defined, a PSTR otherwise.

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.

Page 39: Systemprogrammierung II (SP II,Script 2005)

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_HANDLE

Winsvc.h: typedef HANDLE SERVICE_STATUS_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.

Page 40: Systemprogrammierung II (SP II,Script 2005)

ULONGLONG Winnt.h: #if !defined(_M_IX86) typedef unsigned __int64 ULONGLONG; #else typedef double ULONGLONG

64-bit unsigned integer.

ULONG_PTR Basetsd.h: #if defined(_WIN64) typedef unsigned __int64 ULONG_PTR; #else typedef unsigned long ULONG_PTR;

Unsigned LONG_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.

↑ RTL-TypenWindows-Standard Typen der RTL ( Run-Time Library )

Typ Beschreibung deklariert in

clock_t structure Stores time values; used by clock. TIME.H

_complex structure Stores real and imaginary parts of complex numbers; used by _cabs. MATH.H

_dev_t short or unsigned integer Represents device handles. SYS\TYPES.H

div_t, ldiv_t structures Store values returned by div and ldiv, respectively. STDLIB.H

_exception structure Stores error information for _matherr. MATH.H

FILE structure Stores information about current state of stream; used in all stream I/O operations. STDIO.H

_finddata_t,_wfinddata_t

_wfinddatai64_tstructures

_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 user-defined trap handler by _fpieee_flt.

FPIEEE.H

Page 41: Systemprogrammierung II (SP II,Script 2005)

fpos_t (long integer, __int64,or structure, dependingon 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

_off_t long integer Represents file-offset value. SYS\TYPES.H

_onexit_t pointer Returned by _onexit. STDLIB.H

_PNH pointer to function Type of argument to _set_new_handler. NEW.H

ptrdiff_t integer Result of subtraction of two pointers. STDDEF.H

sig_atomic_t integer Type of object that can be modified as atomic entity, even in presence of asynchronous interrupts; used with signal.

SIGNAL.H

size_t unsigned integer Result of sizeof operator. STDDEF.H and other include files

_stat structure Contains file-status information returned by _stat and _fstat. SYS\STAT.H

time_tlong integer Represents time values in mktime and time. TIME.H

_timeb structure Used by _ftime to store current system time. SYS\TIMEB.H

tm structure Used by asctime, gmtime, localtime, mktime, and strftime to store and retrieve time information.

TIME.H

_utimbuf structure Stores file access and modification times used by _utime to change file-modification dates.

SYS\UTIME.H

va_list structure 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

wchar_t internaltype of a wide character

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

wint_t integer Type of data object that can hold any wide character or wide end-of-file value. WCHAR.H

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

Page 42: Systemprogrammierung II (SP II,Script 2005)

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, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data);

| Prefix Naming Conventions

↑ Prefix Naming ConventionsPrefix 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

Page 43: Systemprogrammierung II (SP II,Script 2005)

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

a Array

b BOOL (int)

c Char

cb Count of bytes

cr Color reference value

cx Count of x (short)

dwDWORD (unsigned long)

fFlags (usually multiple bit values)

fn Function

g_ Global

h Handle

i Integer

l Long

Prefix Description

lp Long pointer

m_Data member of a class

n Short int

p Pointer

s String

sz Zero terminated String

tm Text metric

u Unsigned int

ulUnsigned long (ULONG)

wWORD (unsigned short)

x,yx, y coordinates (short)

Prefix Combination Description

pszMyString A pointer to a string.

m_pszMyStringA pointer to a string that is a data member of a class.

Convention Description

CMyClass Prefix 'C' for C++ class names.

COMyObjectClassPrefix 'CO' for COM object class names.

CFMyClassFactoryPrefix 'CF' for COM class factory names.

IMyInterfacePrefix 'I' for COM interface class names.

CImpIMyInterfacePrefix 'CImpI' for COM interface implementation classes.

↑ Windows-Header-Files

Page 44: Systemprogrammierung II (SP II,Script 2005)

Das Betriessystem wurde überwiegend mit C/C++ entwickelt. Die System-Funktionen sind als Maschinencode in DLL's enthalten. Für die Entwicklung der System-

Funktionen wurden Header-Quelltext-Files benutzt. Diese Header-Files werden auch für die Programm-Entwicklungen verwendet. Es gibt zahlreiche Windows-Header-

Files:

_dbdao.h _entryid.h a.txt accctrl.h aclapi.h aclcls.h aclsid.h acsmgtc.h acssvcc.h activecf.h activeds.h activex.mak activex.rcv activex.ver activscp.h activscp.idl addrlkup.h admex.h adminext.h adoid.h adoint.h adomd.h adomd.idl adptif.h ads.odl adsdb.h adserr.h adshlp.h adsiid.h adsnms.h adssts.h advpub.h agtctl.h agtctl_i.c agterr.h agtsvr.h agtsvr_i.c algorithm alphaops.h amaudio.h amrtpdmx.h amrtpnet.h amrtpss.h amrtpuid.h amstream.h amstream.idl amvideo.h amvpe.idl ansiapi.h appavcap.h appc_c.h appccfg.h appfftp.h asptlb.h assert.h atalkwsh.h attrname.h austream.h austream.idl avifmt.h aviriff.h axcore.idl axextend.idl basemake.inc basetsd.h basetyps.h bdnapi.h bh.h bh.mak bhcommon.ver bherr.h bherr.inc bhfilter.h bhsupp.h bhtypes.h bhver.h bitset bkoffice.mak blberr.h bpcpri.h bpcreg.h bpcsusp.h bradm.idl brerror.h bridge.h brprop.h brtest.h bttncur.h buffer.h callconv.inc cassert cctype cderr.h cdialog.h cerrno certadm.h certcli.h certenc.h certexit.h certext.h certif.h certpol.h certsrv certsrv.h cfloat cguid.h chanmgr.h chanmgr.idl channelt.h chanstr.h chprop.h cierror.h ciso646 climits clocale cluadmex.h cluadmex.idl clusapi.h clusmsg.h cmath cmc.h cmdproc.h codecs.h color.dlg colordlg.h comcat.h comcat.idl comdef.h comip.h comlite.h commctrl.h commctrl.rh commdlg.h common.ver complex compobj.h computer.odl comutil.h conio.h control.h control.odl convclss.h convcwrp.h convdll.h convdllc.h convdlle.h convengn.h convincl.h convreg.h convregh.h convstrc.h copyfile.mak core.odl cpl.h cplext.h crtdbg.h csetjmp csignal cstdarg cstddef cstdio cstdlib cstring ctime ctl3d.h ctype.h custcntl.h customaw.h cutlist.h cwchar cwctype cwindow.h cxq_cust.h d3d.h d3dcaps.h d3drm.h d3drmdef.h d3drmobj.h d3drmwin.h d3dtypes.h d3dvec.inl danim.h daogetrw.h dapi.h dapimsg.h data.h datapath.h dbcsstr.h dbdao.h dbdaoerr.h dbdaoid.h dbdaoint.h dbsets.h dbt.h dde.h dde.rh ddeml.h ddkernel.h ddraw.h ddrawex.h ddstream.h ddstream.idl delayhlp.cpp delayimp.h deque devenum.idl devguid.h devtype.h digitalv.h dinput.h direct.h dispatch.h dispdib.h dispex.h dispex.idl dlcapi.h dlgs.h docobj.h docobj.idl domain.odl dos.h dplay.h dplobby.h dprintf.h drivinit.h dsetup.h dskquota.h dsnamesp.odl dsound.h dssclien.h dssenum.h dtchelp.h dv.h dvdevcod.h dvdif.idl dvdmedia.h dvobj.h dvp.h dxmrtp.h edbback.h edbbcli.h edbmsg.h edevdefs.h edk.h edkafx.h edkcfg.h edkcode.h edkdebug.h edkevent.h edkguid.h edkmapi.h edkmdb.h edkmsg.h edksetup.h edktrack.h edkutcpp.h edkutils.h effect.h eh.h emsabtag.h epgdisp.h epgdspid.h epgldrx.h episodet.h epprop.h errcpp.h errcppd.h errno.h error.h errors.h evcode.h eventcpts.h eventcpts_i.c exadmin.h exception exchcli.h exchext.h exchform.h exchinst.h excpt.h exdisp.h exdisp.idl exdisp.odl exdispid.h fastfile.h fcntl.h fileopen.dlg filter.h filterr.h findtext.dlg float.h fmi.h font.dlg fpieee.h frame.h fserv.odl fshare.odl fstream fstream.h ftsiface.h functional g711uids.h genre.h gizmobar.h gl globlmak.mak group.odl gwmain.h gwreport.h header.h hlguids.h hliface.h hliface.idl hlink.h hlink.idl htmlguid.h httpext.h httpfilt.h iaccess.h iaccess.idl iadmw.h iads.h iamovie.idl icm.h icmui.dlg icrsint.h idf.h idispids.h ih26xcd.h iiis.h iimgctx.h iiscnfg.h il21dec.h ilogobj.hxx ils.idl ilsguid.h imagehlp.h ime.h imessage.h imm.h imsconf2.idl inetreg.h inetsdk.h inetsdk.idl inetsdk.mak inilib.h initguid.h initoid.h intshcut.h io.h iomanip iomanip.h ios ios.h iosfwd iostream iostream.h ipifcons.h ipinfoid.h ipmcdefs.h ipmconv.h iprtrmib.h ipxconst.h ipxrip.h ipxrtdef.h ipxsap.h ipxtfflt.h irtprph.h irtpsph.h isguids.h iso646.h issper16.h issperr.h istream istream.h iterator itvx.h javaattr.h javadbg.h javaexec.h jdbgguid.h kerbcon.h kerberos.h ks.h ksuuids.h largeint.h limits limits.h list list.h listing.inc lm.h lmaccess.h lmalert.h lmapibuf.h lmat.h lmaudit.h lmbrowsr.h lmchdev.h lmconfig.h lmcons.h lmdfs.h lmerr.h lmerrlog.h lmmsg.h lmremutl.h lmrepl.h lmserver.h lmshare.h lmsname.h lmstats.h lmsvc.h lmuse.h lmuseflg.h lmwksta.h loadperf.h locale locale.h locality.odl lsapi.h lua_c.h lzexpand.h make.inc malloc.h map mapi.h mapicode.h mapidbg.h mapidefs.h mapiform.h mapiguid.h mapihook.h mapinls.h mapioid.h mapispi.h mapitags.h mapiutil.h mapival.h mapivb.bas mapiwin.h mapiwz.h mapix.h math.h mbctype.h mblogon.h mbstring.h mbxdata.h mciavi.h mcx.h mdcommsg.h mddefw.h mdmsg.h mdsi.h mdsimsgs.h memory memory.h mgmtapi.h midles.h mimeinfo.h mimeinfo.idl minmax.h mlang.h mlang.idl mmc.h mmc.idl mmreg.h mmstream.h mmstream.idl mmsystem.h moniker.h monitor.h monshare.h mpconfig.h mpegtype.h mprapi.h mprerror.h mprui.h mq.h mqoai.h msacm.h msacmdlg.dlg msacmdlg.h msado15.idl msclus.h msclus.idl msclus.tlb msconf.h mscpydis.h msdadc.h msdaguid.h msdaora.h msdaosp.h msdasc.h msdasql.h msdatsrc.h msdetect.h msfs.h msgemit.h msgfiltr.h mshtmcid.h mshtmdid.h mshtmhst.h mshtmhst.idl mshtml.h mshtml.idl msi.h msiquery.h msitool.mak mspab.h mspst.h msregdb.h msshared.h mssip.h msstkppg.h mstask.h mstask.idl msterr.h mstv.h mswsock.h msxml.h msxml.idl msxmldid.h mtsevents.h mtsevents_i.c mtsgrp.h mtsgrp_i.c mtx.h mtxadmin.h mtxadmin_i.c mtxattr.h mtxdm.h mtxdm_i.c mtxspm.h multimon.h multinfo.h nal.h naltypes.h namesps.odl nativcom.h native.h nb30.h nddeapi.h nddesec.h neterr.h network.h new new.h newpst.h nspapi.h ntlmsp.h ntmsapi.h ntmsmli.h ntquery.h ntsdexts.h ntsecapi.h ntverp.h ntwin32.mak numeric oaidl.h oaidl.idl objbase.h objectty.h objerror.h objidl.h objidl.idl objmodel objsafe.h objsafe.idl ocidl.h ocidl.idl ocmm.idl odbcinst.h odbcss.h odbcver.h oemnsvbh.inf oid.h oldplib.h ole.h ole2.h ole2ver.h oleacc.h oleauto.h olectl.h olectlid.h oledb.h oledb11spec.hh oledberr.h oledberr.mc oledbjvs.inc oledbvbs.inc oledlg.dlg oledlg.h oleidl.h oleidl.idl olenls.h olesampl.mak olescrpt.h olestd.h oletx2xa.h ostream ostream.h packet.h parser.h pbt.h pcrt32.h pdh.h pdhmsg.h penwin.h perf.h perf.inc perfsym.h perhist.h perhist.idl plan32.h playlist.h poppack.h postmake.inc printer.odl printjob.odl prnsetup.dlg process.h propbag2.h propbag2.idl proptag.h protocol.h proxygen.h proxyinf.h prsht.h pshpack1.h pshpack2.h pshpack4.h pshpack8.h qnetwork.h qos.h qosname.h qrycodes.h queue queue.h ras.h rasauth.h rasdlg.h raseapif.h raserror.h rassapi.h rasshost.h rating.h ratings.h ratingsy.h rclsid.h recguids.h reconcil.h regstr.h rend.h resapi.h resource.odl retcode.h richedit.h richole.h rmfacade.h rnderr.h rndnot.h routprot.h rpc.h rpcasync.h rpcbak.h rpcdce.h rpcdcep.h rpcndr.h rpcnsi.h rpcnsip.h rpcnterr.h rpcpri.h rpcproxy.h rpcpub.h rtflib.h rtinfo.h rtm.h rtp.h rtutils.h rulecls.h sadapi.h scarddat.h scarddat.idl scarddat_i.c scarderr.h scardmgr.h scardmgr.idl scardmgr_i.c scardsrv.h scardsrv.idl scardsrv_i.c schema.odl schnlsp.h scode.h scrnsave.h scrptids.h sdkbld.mak sdkpropbld.mak sdpblb.h sdperr.h search.h secext.h seclink.h secpkg.h security.h sehmap.h semfperf.h serv.odl servprov.h servprov.idl session.h session.odl set setjmp.h setjmpex.h setupapi.h setupdd.h sgwdata.h share.h shellapi.h shlguid.h shlobj.h shlwapi.h signal.h simpdata.h simpdata.idl sipbase.h smbdata.h smpab.h smpms.h smpxp.h smsapi.h smsinfo.h sna_cnst.h sna_dlc.h snados.h snanls.h snapmon.h snmp.h sporder.h sql.h sqldb.h sqlext.h sqlfront.h sqlole.h sqloleid.h sqltypes.h sqlucode.h srv.h srvapi.h srvconst.h srvdbtyp.h srvmisc.h srvstruc.h srvtok.h srvtypes.h sspguid.h sspi.h sspserr.h sspsidl.h sspsidl.idl sspsidl_i.c sstream stablize.h stack station.h stats.h stattype.h stdarg.h stddef.h stdexcept stdexcpt.h stdio.h stdiostr.h stdlib.h stm.h storage.h streamb.h streambuf streamty.h string string.h strmhelp.h strmif.h strmif.idl strstrea.h strstream subgenre.h subsmgr.h subsmgr.idl svcguid.h svrapi.h syncdtct.h sys tagnames.h tapi.h tapi3.h tchar.h theme.h time.h timeslot.h tlhelp32.h tnef.h tpstart.h trace.h transact.h trkcom.h trkcom.idl trnsdt.h tspi.h tss.h tssadmin.odl tssqsec.h tssutil.h tvdisp.h tvdisp.odl tvdispid.h txcoord.h txctx.h txdtc.h typeinfo typeinfo.h uastrfnc.h unknwn.h

Page 45: Systemprogrammierung II (SP II,Script 2005)

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

↑ EntwicklungsumgebungUm 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

Page 46: Systemprogrammierung II (SP II,Script 2005)

● Editor ( einfache bzw. auswendige Textbearbeitung

und -gestaltung ),

● Quelltext-Generierung ( Assistenten ),

● Assembler ( übersetzt von Assembler nach

Maschinencode ),

● Compiler ( übersetzt in Assembler bzw.

Maschinencode ),

● Linker ( fügt compilierte Files zusammen ),

● Projektverwaltung ( überwacht den Build-Prozess ),

● Resourcen - Tools ( erstellt, übersetzt Properties ),

● Debugger ( schrittweiser Programmablauf ) ,

● Nachrichten - Verfolgung ( Spy - Tools ),

● On-Line-Hilfe ( Dokumentation )

● *.asm für Assembler - Quelltexte, *.c für C-Quell-

Texte, *.cpp für C++-Quell-Texte,

● *.obj für binärer OpCode nach dem Compilieren,

● *.lib für Bibliotheks-Routinen und Dll-Zuordnungen,

● *.rc für Resourcen - Quelltexte,

● *.res für binärere Resourcen - Files,

● *.map für die DLL - Adressen,

● *.exe für den executierbarer File,

● *.rtf für ASCII-Rich-Text-File incl. Formatierung,

● *.hlp für binärer HeLP-Files

Moderne Werkzeuge bestehen aus Software - Komponenten zur Programmentwicklung. 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

Page 47: Systemprogrammierung II (SP II,Script 2005)

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

Page 48: Systemprogrammierung II (SP II,Script 2005)

kann, sind außerdem z.B. die folgenden Bibliotheken

● kernel32.lib

● user32.lib

● gdi32.lib

● coredll.lib

● msvcrt.lib

in das Projekt aufzunehmen. Soll zusätzlich die "messaging functionality" in das eigene Programm aufgenommen werden, so ist #include Msgstore.h erforderlich. Soll

zusätzlich die "e-mail functionality" in das eigene Programm aufgenommen werden, so ist #include Addrstor.h erforderlich. Natürlich sind auch die zugehörigen *.lib -

Files in die Entwicklungs - Umgebung aufzunehmen. Oft werden die folgenden ( voreingstellten ) *.lib - Files verwerdet:

kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

↑ Linker - Fehler

Von den Entwicklungs - Werkzeugen mußte der Linker immer mehr Aufgaben übernehmen. Die Linker - Zeiten übersteigen vielfach die Compiler - Zeiten. Eine Teilung

der Linker - Aufgaben in traditionelles Linken und der Resourcen - Erstellung ist angezeigt.

Der Linker fügt Binärcode aneinander und verbindet die wechselseitigen Zuordnungen ( Adressen ). Bei einem Linker - Fehler ist der Zusammenhang mit dem lesbaren

ASCII - Quelltext verloren. Der Linker gibt im Fehlerfall die Namen der nicht gefundenen bzw. doppelt vorhanden Symbole aus. Weil bei C und C++ - Code gemäß

#ifdef __cplusplus extern "C" { #endif ... ... #ifdef __cplusplus }

Page 49: Systemprogrammierung II (SP II,Script 2005)

#endif

gemischt werden können, ist zur Fehlererkennung vielfach auf die Schreibweise der ausgegebenen Namen zu beachten.

Linker-Fehler-Anzeige

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:

Page 50: Systemprogrammierung II (SP II,Script 2005)

Um einen ausführbaren, binär - File ( *.EXE ) zu erzeugen, müssen ASCII - Files in Maschinen-Code übersetzt werden:

*.C, *.CPP ===> Compiler ===> *.OBJ *.H, *.RC ===> Resourcen-Compiler ===> *.RES *.OBJ, *.DEF ===> Linker ===> (*.EXE) (*.EXE), *.RES ===> Resourcen-Compiler ===> *.EXE

Die 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-KernAm 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,

Page 51: Systemprogrammierung II (SP II,Script 2005)

● 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 -

Page 52: Systemprogrammierung II (SP II,Script 2005)

Index - Zuordnungen sind in LIB - Dateien ( Libary ) enthalten. Beim Erstellen eines Programmes werden diese Indizes der DLL - Funktions - Adress - Tabelle in den

Maschinencode eingefügt. Der Linker trägt den Index in das Maschinenprogramm ein. Der DLL - Name wird nur einmal in das Applikationsprogramm eingetragen.

↑ KRNL386.EXE

Die Dateien KRNL386.EXE ist eine DLL ( Dynamic Link Libarys ). KRNL386.EXE

● kontrolliert und verwaltet den Speicher,

● lädt Applikationen,

● verteilt die Resourcen an Programme und Tasks.

In KRNL386.EXE sind binäre Funktionen enthalten. Die wesentlichen Funktionen sind in der folgende Tabelle zusammengefaßt.

Object Creator function Destroyer function Object Creator function Destroyer function

Changenotification

Communications FindFirstChangeNotification FindCloseChangeNotification device GetStdHandle CloseHandle

Event CreateEvent,OpenEvent

CloseHandle Event log OpenEventLog,RegisterEventSource,OpenBackupEventLog

CloseEventLog

File CreateFile CloseHandle,DeleteFile

File mapping CreateFileMapping,OpenFileMapping

CloseHandle

Find file FindFirstFile FindClose Heap HeapCreate HeapDestroy

Mailslot CreateMailslot CloseHandle Module LoadLibrary,GetModuleHandle

FreeLibrary

Mutex CreateMutex,OpenMutex

CloseHandle Pipe CreateNamedPipe,CreatePipe

CloseHandle,DisconnectNamedPipe

Process CreateProcess,OpenProcess,GetCurrentProcess

CloseHandle,TerminateProcess

Semaphore CreateSemaphore,OpenSemaphore

CloseHandle

Page 53: Systemprogrammierung II (SP II,Script 2005)

Thread CreateThread,CreateRemoteThread,GetCurrentThread

CloseHandle,TerminateThread

Timer CreateWaitableTimer,OpenWaitableTimer

CloseHandle

Update resource BeginUpdateResource EndUpdateResource

↑ USER.EXE

Der File USER.EXE ist eine DLL, die die auf dem Bildschirm die Fenster erzeugt und manipuliert ( create, move, size, remove), die Icons und andere Komponenten des

Benutzer-Interface behandelt, die Eingaben ( dispatch ) von Keyboard, Mause und anderen Eingabe-Geräten an die zugehörige Applikation verteilt. Mit den Funktionen

von USER.EXE können interaktive Fenster ( desktop - shell ) erstellt werden. Die User Interface Services

● erzeugen und manipulieren Bildschirm - Fenster ( Screen Windows ),

● behandeln Icons und andere Komponenten des Benutzerinterfaces,

● verteilen die Eingabe von Keyboard, Maus und anderen Geräten an die zugehörigen Applikationen

USER.EXE enthält

Funktionen für die Dialogelemente ( Controls ):

lesbare Daten ( Resources ) sind:

Programmierschnittstelle ( Shell and Common Controls

):

Benutzer-Eingaben( User Input )

Fensternhirachie ( Windowing )

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

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 (

Page 54: Systemprogrammierung II (SP II,Script 2005)

Multiple Document Interface )

Die folgenden Funktionen werden zum Erzeugen und Manipulieren von Fenstern benutzt.

AdjustWindowRect AdjustWindowRectEx AnimateWindow ArrangeIconicWindows BeginDeferWindowPos BringWindowToTop CascadeWindows ChildWindowFromPoint ChildWindowFromPointEx CloseWindow CreateWindow CreateWindowEx DeferWindowPos DestroyWindow EnableWindow EndDeferWindowPos EnumChildProc EnumChildWindows EnumThreadWindows EnumThreadWndProc EnumWindows EnumWindowsProc FindWindow FindWindowEx GetClientRect GetDesktopWindow GetForegroundWindow GetLastActivePopup GetNextWindow GetParent GetTopWindow GetWindow GetWindowPlacement GetWindowRect GetWindowText GetWindowTextLength GetWindowThreadProcessId IsChild IsIconic IsWindow IsWindowUnicode IsWindowVisible IsZoomed MoveWindow OpenIcon SetForegroundWindow SetParent SetWindowLong SetWindowPlacement SetWindowPos SetWindowText ShowOwnedPopups ShowWindow ShowWindowAsync TileWindows WindowFromPoint WinMain

↑ GDI.EXE

GDI ist eine Abkürzung für (G)raphic (D)evice (I)nterface. Der File GDI.EXE ist eine DLL, die das Graphics Device Interface ( GDI ) mit den Funktionen zur Bild -

Erzeugung und Bild - Anzeige ( nicht nur Screen ) enthält. Hierher gehören z.B. auch Fonts und Device - Kontext.

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

● Fonts

● Device - Kontext

Den Device Kontext benutzen die folgenden Funktionen.

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

Mit Fonts und Texten werden die folgenden Funktionen benutzt:

Page 55: Systemprogrammierung II (SP II,Script 2005)

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

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

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

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

↑ Beispiel: GetDeviceCaps()

Als ein Beispiel für den Umfang einer Funktion soll hier GetDeviceCaps() angegeben werden. GetDeviceCaps() gibt Informationen zum Device Kontext zurück.

int GetDeviceCaps( HDC hDC, // device-context handle int nIndex // index of capability to query );

Für den Parameter nIndex kann eine der folgenden Zahlen gewählt werden. Die eingerückten Konstanten kennzeichnen die zugehörigen Rückgabewerte.

Page 56: Systemprogrammierung II (SP II,Script 2005)

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 fileHORZSIZE 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

Page 57: Systemprogrammierung II (SP II,Script 2005)

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>

Page 58: Systemprogrammierung II (SP II,Script 2005)

//#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) ;

Page 59: Systemprogrammierung II (SP II,Script 2005)

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);

Page 60: Systemprogrammierung II (SP II,Script 2005)

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

Page 61: Systemprogrammierung II (SP II,Script 2005)

● der Funktion int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hiPrev, PSTR pCmdMain, int iShowMain ) { ... }

WinMain entspricht der main() - Funktion in C. Der (W)indow -(S)tyle WS_OVERLAPPEDWINDOW entspricht

#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) #define WS_POPUPWINDOW (WS_POPUP|WS_BORDER|WS_SYSMENU)

↑ WinMain()

Die Start - Adresse einer Window - Applikation ist die WinMain() - Funktion( APIENTRY ). WinMain ist der Haupt - Eintritts - Punkt für eine Windows - Anwendung.

Diese Funktion entspricht der Funktion main() bei einem C-Programm. Der WinMain - Startup - Code ruft die WinMain-Funktion durch den Namen auf. Windows

verwendet diese Funktion als "initial entry point" APIENTRY). Beim Start wird der Startup-Code ausgeführt, der u.a. die Windows-Funktionen

● InitTask ( KRNL386 ),

● InitApp ( USER ) und

● WaitEvent( KERNEL)

aufruft. Danach ruft der Startup - Code unsere WinMain - Funktion auf. Diese Schritte bei Start eines Win - Programmes können grob skizziert werden:

↑ WinMain() initialisiert Register

InitTask füllt bei Win16 die folgenden Register mit Werten, die beim Laden der Applikation auf den Stack gelegt werden:

BX = Stack-Grösse, CX = Heap-Grösse, DI = Instanz-Handle, SI = vorherige Instanz, ES = PSP-Adresse

↑ WinMain() initialisiert den Stack

Außerdem initialisiert InitTask pStackTop, pStackMin, pStackBottom im Task - Header der aufrufenden Tastk. DLL´s sind keine Task´s, rufen aber in ihrem Startup-Code

auch InitTask auf.

Page 62: Systemprogrammierung II (SP II,Script 2005)

↑ 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,

Page 63: Systemprogrammierung II (SP II,Script 2005)

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.

Page 64: Systemprogrammierung II (SP II,Script 2005)

● Das System kennt bereits die Klassen BUTTON, COMBOBOX, EDIT, LISTBOX, MDICLIENT, SCROLLBAR, STATIC.

↑ CreateWindowEx()

Bis auf dwExStyle ist CreateWindowEx() identisch mit CreateWindow(). CreateWindowEx() kann ein Overlapped -, Pop - Up -, oder Child - Window erstellen.

● CreateWindowEx() sendet die WM_NCCREATE-, WM_NCCALCSIZE-, WM_CREATE-Nachrichten zu dem angelegten Fenster. Der

Rückgabewert ist das Handle des neuen Fensters.

Dabei ist das Fenster noch nicht sichtbar, obwohl das Handle != NULL den allokierten Speicher referenziert und Fenster-Daten eingetragen wurden.

HWND CreateWindowEx( DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data );

dwExStyle spezifiziert erweiterte Styles: WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_CLIENTEDGE, WS_EX_CONTEXTHELP, WS_EX_CONTEXTHELP, WS_EX_CONTROLPARENT, WS_EX_DLGMODALFRAME(double border), WS_CAPTION, WS_EX_LEFT, WS_EX_LEFTSCROLLBAR, WS_EX_LTRREADING, WS_EX_MDICHILD, WS_EX_NOPARENTNOTIFY,WS_EX_OVERLAPPEDWINDOW, WS_EX_PALETTEWINDOW, WS_EX_RIGHT, WS_EX_RIGHTSCROLLBAR,WS_EX_RTLREADING, WS_EX_STATICEDGE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_EX_WINDOWEDGE

lpClassName zeigt auf einen "null-terminated string" der den Window - Class - Namen spezifiziert oder ist ein integer atom ( GlobalAddAtom ). lpClassName zeigt auf

Page 65: Systemprogrammierung II (SP II,Script 2005)

einen "null-terminated string" der den Window - Namen spezifiziert ( Titelzeile, Text eines Controls ). dwStyle spezifiziert den Style des Fensters und Funktionalität:

WS_BORDER, WS_CAPTION, WS_CHILD, WS_CHILDWINDOW, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_DISABLED, WS_DLGFRAME, WS_GROUP, WS_HSCROLL, WS_ICONIC, WS_MAXIMIZE, WS_MAXIMIZEBOX, WS_MINIMIZE, WS_MINIMIZEBOX,WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_POPUPWINDOW, WS_SIZEBOX, WS_SYSMENU, WS_TABSTOP, WS_THICKFRAME, WS_TILED, WS_TILEDWINDOW, WS_VISIBLE, WS_VSCROLL

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

CALLBACK - Funktion weitergereicht werden.

In CreateWindowEx() können für die horizontale/vertikale Fenster - Position anstelle von festen int x-, y-, nWidth-, nHeight- Werten auch Bildschirm - bezogene Werte (

z.B. GetSystemMetrics(SM_CXSCREEN)*1/8, GetSystemMetrics(SM_CYSCREEN)*1/5, GetSystemMetrics(SM_CXSCREEN)*6/8,

GetSystemMetrics(SM_CYSCREEN)*6/5 ) verwendet werden.

↑ 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.

Page 66: Systemprogrammierung II (SP II,Script 2005)

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

Wenn mit PostThreadMessage() per Programm eine Nachricht versendet wird, so ist hWnd == NULL, sonst identifiziert hWnd das Fenster. wMsgFilterMin,

wMsgFilterMax werden zum Eingrenzen der Nachrichten verwendet ( z.B. WM_KEYFIRST, WM_KEYLAST, WM_MOUSEFIRST, WM_MOUSELAST ).

↑ TranslateMessage()

Die Funktion BOOL TranslateMessage( CONST MSG *lpMsg ) wandelt eine Virtual-Key-Nachricht in eine Zeichen-Nachricht um ( WM_KEYDOWN, WM_KEYUP,

WM_SYSKEYDOWN, WM_SYSKEYUP ). WM_KEYDOWN und WM_KEYUP Kombinationen ergeben WM_CHAR oder WM_DEADCHAR - Nachrichten.

WM_SYSKEYDOWN und WM_SYSKEYUP Kombinationen ergeben WM_SYSCHAR oder WM_SYSDEADCHAR - Nachrichten. Die Zeichen - Nachricht wird in die

Applikations - Nachrichten - Buffer gestellt. Mit GetMessage() oder PeekMessage() wird diese Nachricht geholt.

Page 67: Systemprogrammierung II (SP II,Script 2005)

↑ 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

Page 68: Systemprogrammierung II (SP II,Script 2005)

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,

Page 69: Systemprogrammierung II (SP II,Script 2005)

↑ 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.

Page 70: Systemprogrammierung II (SP II,Script 2005)

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

Page 71: Systemprogrammierung II (SP II,Script 2005)

);

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 |

Page 72: Systemprogrammierung II (SP II,Script 2005)

MB_YESNO) == IDYES ) { DestroyWindow( hWnd ); //sendet WM_DESTROY } return 0; case WM_DESTROY: // Hauptfenster schliessen, zerstoert automatisch die Child-Windows. PostQuitMessage( 0 ); return 0;

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

Nachricht gesendet, d.h. die

● LRESULT CALLBACK WndProc( HWND hWnd , UINT 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_NCHITTEST, WM_NCPAINT, WM_NCACTIVATE, WM_CANCELMODE, WM_SETTEXT, WM_GETTEXT, WM_GETTEXTLENGTH, WM_PAINT, WM_PAINTICON, WM_ERASEBKGND,WM_ICONERASEBKGND, WM_SYNCPAINT, WM_SYSCOMMAND, WM_ACTIVATE, WM_SETREDRAW, WM_WINDOWPOSCHANGING,WM_WINDOWPOSCHANGED,WM_CTLCOLOR, WM_SETCURSOR, WM_MOUSEACTIVATE, WM_SHOWWINDOW, WM_NCLBUTTONDOWN,WM_NCLBUTTONUP, WM_NCLBUTTONDBLCLK, WM_NCMOUSEMOVE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP,WM_SYSKEYUP, WM_SYSCHAR, WM_CLOSE, WM_QUERYOPEN, WM_QUERYENDSESSION, WM_ISACTIVEICON,WM_CHARTOITEM, WM_VKEYTOITEM, WM_DRAWITEM, WM_GETHOTKEY, WM_SETHOTKEY, WM_QUERYDRAGICON,WM_QUERYDROPOBJECT, WM_DROPOBJECT,

Page 73: Systemprogrammierung II (SP II,Script 2005)

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 Teil-

Aufgabe 1, 2, 3, ..., usw. bearbeitet werden. Zur Reduzierung der Tipp-Tätigkeit darf von dem angegebenen cpp-Rahmen-

Programm ausgegangen werden. Das cpp-Rahmen-Programm wird erweitern.

Zum besseren Verstehen des Nachrichten-Konzeptes sind einige Tests durchzuführen. Es ist z.B. aktuelle Maus-

Position 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 ( Maus-

Nachrichten, 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 .cpp-

Rahmen-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 Tasten-

Ereignis 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 ein-

geschalteter 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 Font-

Benutzung zu erweitern. Für Source-Hinweis siehe gdi-class-Quelltext

Page 74: Systemprogrammierung II (SP II,Script 2005)

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 WM_LBUTTONUP: break; case WM_RBUTTONUP: break; case WM_MBUTTONUP: break; case WM_LBUTTONDOWN: break; case WM_RBUTTONDOWN: break; case WM_MBUTTONDOWN: break; case WM_LBUTTONDBLCLK: break; case WM_MBUTTONDBLCLK: break; case WM_RBUTTONDBLCLK: break; case WM_MOUSEMOVE: break;

char MouseMsgStrings[][20] = { " ", "WM_LBUTTONUP ", "WM_RBUTTONUP ", "WM_MBUTTONUP ", "WM_LBUTTONDOWN ", "WM_RBUTTONDOWN ", "WM_MBUTTONDOWN ", "WM_LBUTTONDBLCLK ", "WM_MBUTTONDBLCLK ", "WM_RBUTTONDBLCLK ", };

In lParam ist die Maus-Position enthalten. Hinweis:

Page 75: Systemprogrammierung II (SP II,Script 2005)

↑ 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_ABORTRETRYIGNOREMB_OKCANCEL MB_RETRYCANCELMB_YESNO MB_YESNOCANCELMB_DEFBUTTON2 MB_DEFBUTTON3MB_ICONHAND MB_ICONSTOP MB_ICONERROR MB_ICONQUESTION MB_ICONASTERISK MB_ICONEXCLAMATION MB_ICONWARNING 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_ICONSTOP MB_ICONERROR MB_ICONQUESTION MB_ICONASTERISK MB_ICONEXCLAMATION MB_ICONWARNING 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

Page 76: Systemprogrammierung II (SP II,Script 2005)

case '\b': break; //Rücktaste case '\t': break; //Tabulatortaste case '\n': break; //LF-Taste default : break; //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: { break; } case VK_NUMPAD5:{ break; } } // ende switch break; } // ende WM_KEYDOWN

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 Windows-

CALLBACK-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

Page 77: Systemprogrammierung II (SP II,Script 2005)

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 ?

Page 78: Systemprogrammierung II (SP II,Script 2005)

cpp-Rahmen für Window-ApplikationEin 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; }

Page 79: Systemprogrammierung II (SP II,Script 2005)

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);

Page 80: Systemprogrammierung II (SP II,Script 2005)

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.hInstance = hInstance; wndClass.lpszClassName = TEXT("my_class"); wndClass.lpfnWndProc = WndProc;

wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.lpszMenuName = NULL; wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);

Page 81: Systemprogrammierung II (SP II,Script 2005)

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

Page 82: Systemprogrammierung II (SP II,Script 2005)

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}, // 0x0000 {TEXT("WM_CREATE"), WM_CREATE}, // 0x0001 {TEXT("WM_DESTROY"), WM_DESTROY}, // 0x0002 {TEXT("WM_MOVE"), WM_MOVE}, // 0x0003 {TEXT("WM_SIZE"), WM_SIZE}, // 0x0005 {TEXT("WM_ACTIVATE"), WM_ACTIVATE}, // 0x0006 {TEXT("WM_SETFOCUS"), WM_SETFOCUS}, // 0x0007 {TEXT("WM_KILLFOCUS"), WM_KILLFOCUS}, // 0x0008 {TEXT("WM_ENABLE"), WM_ENABLE}, // 0x000A {TEXT("WM_SETREDRAW"), WM_SETREDRAW}, // 0x000B {TEXT("WM_SETTEXT"), WM_SETTEXT}, // 0x000C {TEXT("WM_GETTEXT"), WM_GETTEXT}, // 0x000D {TEXT("WM_GETTEXTLENGTH"), WM_GETTEXTLENGTH}, // 0x000E

Page 83: Systemprogrammierung II (SP II,Script 2005)

{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

Page 84: Systemprogrammierung II (SP II,Script 2005)

{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

Page 85: Systemprogrammierung II (SP II,Script 2005)

{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

Page 86: Systemprogrammierung II (SP II,Script 2005)

{TEXT("LB_SETITEMHEIGHT"), LB_SETITEMHEIGHT}, // 0x01A0 {TEXT("LB_GETITEMHEIGHT"), LB_GETITEMHEIGHT}, // 0x01A1 {TEXT("LB_FINDSTRINGEXACT"), LB_FINDSTRINGEXACT}, // 0x01A2 {TEXT("LB_SETLOCALE"), LB_SETLOCALE}, // 0x01A5 {TEXT("LB_GETLOCALE"), LB_GETLOCALE}, // 0x01A6 {TEXT("LB_SETCOUNT"), LB_SETCOUNT}, // 0x01A7 {TEXT("WM_MOUSEMOVE"), WM_MOUSEMOVE}, // 0x0200 {TEXT("WM_LBUTTONDOWN"), WM_LBUTTONDOWN}, // 0x0201 {TEXT("WM_LBUTTONUP"), WM_LBUTTONUP}, // 0x0202 {TEXT("WM_LBUTTONDBLCLK"), WM_LBUTTONDBLCLK}, // 0x0203 {TEXT("WM_RBUTTONDOWN"), WM_RBUTTONDOWN}, // 0x0204 {TEXT("WM_RBUTTONUP"), WM_RBUTTONUP}, // 0x0205 {TEXT("WM_RBUTTONDBLCLK"), WM_RBUTTONDBLCLK}, // 0x0206 {TEXT("WM_MBUTTONDOWN"), WM_MBUTTONDOWN}, // 0x0207 {TEXT("WM_MBUTTONUP"), WM_MBUTTONUP}, // 0x0208 {TEXT("WM_MBUTTONDBLCLK"), WM_MBUTTONDBLCLK}, // 0x0209 {TEXT("WM_PARENTNOTIFY"), WM_PARENTNOTIFY}, // 0x0210 {TEXT("WM_ENTERMENULOOP"), WM_ENTERMENULOOP}, // 0x0211 {TEXT("WM_EXITMENULOOP"), WM_EXITMENULOOP}, // 0x0212 {TEXT("WM_MDICREATE"), WM_MDICREATE}, // 0x0220 {TEXT("WM_MDIDESTROY"), WM_MDIDESTROY}, // 0x0221 {TEXT("WM_MDIACTIVATE"), WM_MDIACTIVATE}, // 0x0222 {TEXT("WM_MDIRESTORE"), WM_MDIRESTORE}, // 0x0223 {TEXT("WM_MDINEXT"), WM_MDINEXT}, // 0x0224 {TEXT("WM_MDIMAXIMIZE"), WM_MDIMAXIMIZE}, // 0x0225 {TEXT("WM_MDITILE"), WM_MDITILE}, // 0x0226 {TEXT("WM_MDICASCADE"), WM_MDICASCADE}, // 0x0227 {TEXT("WM_MDIICONARRANGE"), WM_MDIICONARRANGE}, // 0x0228 {TEXT("WM_MDIGETACTIVE"), WM_MDIGETACTIVE}, // 0x0229 {TEXT("WM_MDISETMENU"), WM_MDISETMENU}, // 0x0230 {TEXT("WM_ENTERSIZEMOVE"), WM_ENTERSIZEMOVE}, // 0x0231 {TEXT("WM_EXITSIZEMOVE"), WM_EXITSIZEMOVE}, // 0x0232 {TEXT("WM_DROPFILES"), WM_DROPFILES}, // 0x0233 {TEXT("WM_MDIREFRESHMENU"), WM_MDIREFRESHMENU}, // 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 } } }

Page 87: Systemprogrammierung II (SP II,Script 2005)

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 m_hwnd; // Fenster-Daten-"Pointer" HDC m_hdc; // DeviceContext PAINTSTRUCT m_ps; // für BeginPaint() COLORREF m_crColor; // Farbe UINT m_PenWidth;// Zeichenstift HPEN m_hPen, m_hPenOld; RECT 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() 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;

Translation mat_transl(dx, dy)

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 }

Skalierung mat_scale(sx,sy)

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

Rotation mat_rotat(w)

Der Winkel w wird in Grad angegeben

Page 88: Systemprogrammierung II (SP II,Script 2005)

Grösse der 2D-Weltmat_ortho(xMin,xMax,yMin,yMax)

mat_ortho() berechnet und setzt die Abbildungsfaktoren, _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.00.0 <= double g <= 1.00.0 <= double b <= 1.0auf 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_gdiclass GDI {

HWND m_hwnd; // Fenster-Daten-"Pointer" HDC m_hdc; // DeviceContext PAINTSTRUCT m_ps; // für BeginPaint() COLORREF m_crColor; // Farbe UINT m_PenWidth;// Zeichenstift HPEN m_hPen, m_hPenOld; RECT 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

Page 89: Systemprogrammierung II (SP II,Script 2005)

}

#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 sx, double sy) { double m[6]; m[0]= sx; m[1]=0.0; m[2]=0.0; m[3]=0.0; m[4]= sy; m[5]=0.0; mat_mult(m); // _M := _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; }

Page 90: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 91: Systemprogrammierung II (SP II,Script 2005)

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)

Page 92: Systemprogrammierung II (SP II,Script 2005)

{#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,

Page 93: Systemprogrammierung II (SP II,Script 2005)

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);

Page 94: Systemprogrammierung II (SP II,Script 2005)

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

Page 95: Systemprogrammierung II (SP II,Script 2005)

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

Page 96: Systemprogrammierung II (SP II,Script 2005)

| 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)

Page 97: Systemprogrammierung II (SP II,Script 2005)

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 CANCEL-

Button (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

Page 98: Systemprogrammierung II (SP II,Script 2005)

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 =

Page 99: Systemprogrammierung II (SP II,Script 2005)

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?

Page 100: Systemprogrammierung II (SP II,Script 2005)

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

Page 101: Systemprogrammierung II (SP II,Script 2005)

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

Page 102: Systemprogrammierung II (SP II,Script 2005)

HACCEL m_hAccel; // aktuelle Accel-Tabelle HICON m_hIcon; // 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

Page 103: Systemprogrammierung II (SP II,Script 2005)

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;

Page 104: Systemprogrammierung II (SP II,Script 2005)

} // ende WinMain

Page 105: Systemprogrammierung II (SP II,Script 2005)

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

Page 106: Systemprogrammierung II (SP II,Script 2005)

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"); }

Page 107: Systemprogrammierung II (SP II,Script 2005)

~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-DatenHICON 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-DatenMENU_STRUCT * set_menu_tab(HWND hwnd, MENU_STRUCT pms[]){

Page 108: Systemprogrammierung II (SP II,Script 2005)

if(!pms) return NULL; MENU_STRUCT *pOld = (MENU_STRUCT*) SetWindowLong(hwnd,GWL_USERDATA,(LONG)pms); return pOld;}

// hole Zeiger pms aus den Window-DatenMENU_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: SubclassingWNDPROC 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)//////////////////////////////////////////////////////

Page 109: Systemprogrammierung II (SP II,Script 2005)

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

Page 110: Systemprogrammierung II (SP II,Script 2005)

} //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;

Page 111: Systemprogrammierung II (SP II,Script 2005)

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; }// 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);}

Page 112: Systemprogrammierung II (SP II,Script 2005)

// get_hwnd_index() gibt den Index des aktuellen Fensters zurückint 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 gesetztBOOL 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");

Page 113: Systemprogrammierung II (SP II,Script 2005)

// 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); }

Page 114: Systemprogrammierung II (SP II,Script 2005)

} 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 verwendetHWND 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;

Page 115: Systemprogrammierung II (SP II,Script 2005)

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))

Page 116: Systemprogrammierung II (SP II,Script 2005)

{ 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 );

Page 117: Systemprogrammierung II (SP II,Script 2005)

};

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

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

Page 118: Systemprogrammierung II (SP II,Script 2005)

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));

Page 119: Systemprogrammierung II (SP II,Script 2005)

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){

Page 120: Systemprogrammierung II (SP II,Script 2005)

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; }

Page 121: Systemprogrammierung II (SP II,Script 2005)

default: return DefWindowProc(hwnd,uMsg,wParam,lParam);

} return 0;}

// _tWinMain braucht TCHAR.HINT 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);

Page 122: Systemprogrammierung II (SP II,Script 2005)

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

Page 123: Systemprogrammierung II (SP II,Script 2005)

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 while-Schleife 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.

Page 124: Systemprogrammierung II (SP II,Script 2005)

//Hauptprogrammint 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 : {

Page 125: Systemprogrammierung II (SP II,Script 2005)

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 Resourcen-

Workshop kann unmittelbar das Menu einfügen. Alternativ kann z.B. das Menu IDM_MENU ( zur Laufzeit ) unter case WM_INITDIALOG mit SetMenu()

geladen und angezeigt werden.

SetMenu(hwnd, LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDM_MENU)));

Page 126: Systemprogrammierung II (SP II,Script 2005)

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

Page 127: Systemprogrammierung II (SP II,Script 2005)

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 ).

Page 128: Systemprogrammierung II (SP II,Script 2005)

BEGIN //RESOURCECOMBOBOX IDC_COMBO1,5,5,115,125,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOPPUSHBUTTON "0",48, 6,117,14,14,NOT WS_TABSTOPPUSHBUTTON "1",49, 6, 99,14,14,NOT WS_TABSTOPPUSHBUTTON "2",50,24, 99,14,14,NOT WS_TABSTOPPUSHBUTTON "3",51,42, 99,14,14,NOT WS_TABSTOPPUSHBUTTON "4",52, 6, 81,14,14,NOT WS_TABSTOPPUSHBUTTON "5",53,24, 81,14,14,NOT WS_TABSTOPPUSHBUTTON "6",54,42, 81,14,14,NOT WS_TABSTOPPUSHBUTTON "7",55, 6, 64,14,14,NOT WS_TABSTOPPUSHBUTTON "8",56,24, 64,14,14,NOT WS_TABSTOPPUSHBUTTON "9",57,42, 64,14,14,NOT WS_TABSTOPPUSHBUTTON "A",65,42, 47,14,14,NOT WS_TABSTOPPUSHBUTTON "B",66,24, 47,14,14,NOT WS_TABSTOPPUSHBUTTON "C",67, 6, 47,14,14,NOT WS_TABSTOPPUSHBUTTON "D",68,42, 30,14,14,NOT WS_TABSTOPPUSHBUTTON "E",69,24, 30,14,14,NOT WS_TABSTOPPUSHBUTTON "F",70, 6, 30,14,14,NOT WS_TABSTOPPUSHBUTTON "+",43,64, 81,14,14,NOT WS_TABSTOPPUSHBUTTON "-",45,64, 99,14,14,NOT WS_TABSTOPPUSHBUTTON "*",42,82, 81,14,14,NOT WS_TABSTOPPUSHBUTTON "/",47,82, 99,14,14,NOT WS_TABSTOPPUSHBUTTON "%",37,64, 30,14,14,NOT WS_TABSTOPPUSHBUTTON "=",61,24,117,31,14,NOT WS_TABSTOPPUSHBUTTON "&&",38,82, 63,14,14,NOT WS_TABSTOPPUSHBUTTON "|",124,64, 63,14,14,NOT WS_TABSTOPPUSHBUTTON "^",94,64, 46,14,14,NOT WS_TABSTOPPUSHBUTTON "<",60,82, 30,14,14,NOT WS_TABSTOPPUSHBUTTON ">",62,82, 46,14,14,NOT WS_TABSTOPPUSHBUTTON "M+",IDC_BUTTON0,105,30,17,14,NOT WS_TABSTOPPUSHBUTTON "M-",IDC_BUTTON1,105,46,17,14,NOT WS_TABSTOPPUSHBUTTON "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOPPUSHBUTTON "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOPPUSHBUTTON "BS",8,64,117,31,14,NOT WS_TABSTOPPUSHBUTTON "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP

Achtung! Es ist sinnvoll, die folgenden Konstanten- Bezeichner zu verwenden: IDC_COMBO1 IDC_EDIT1 IDC_BUTTON0 IDC_BUTTON1 IDC_BUTTON2 IDC_BUTTON3 IDC_BUTTON4 IDC_BUTTON5 Windows kenn bereits:

Page 129: Systemprogrammierung II (SP II,Script 2005)

CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,98,30,6,101CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,5,21,116,6CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,58,29,6,101CONTROL "",IDC_STATIC,"Static",SS_BLACKRECT,7,132,116,6EDITTEXT IDC_EDIT1,7,141,113,45,ES_MULTILINE |WS_TABSTOP|ES_WANTRETURN|WS_VSCROLL|WS_HSCROLLDEFPUSHBUTTON "Schliessen",IDOK,37,193,50,14,NOT WS_TABSTOPEND

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 ;

Page 130: Systemprogrammierung II (SP II,Script 2005)

case '<' : return iFirstNum << iNum ; case '>' : return iFirstNum >> iNum ; case '/' : return iNum ? iFirstNum / iNum : UINT_MAX ; case '%' : return iNum ? iFirstNum % iNum : UINT_MAX ; }}

BOOL CALLBACK dlgHexCalcProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { static BOOL bNewNumber = TRUE ; static INT iOperation = '=' ; static UINT iAsc,iNumber, iFirstNum ; static CHAR * pCombo1; static HWND hCombo1;

switch ( iMsg ) { case WM_INITDIALOG: if ( pCombo1 != NULL ) { free( pCombo1 ); pCombo1 = NULL; } pCombo1 = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); strcpy( pCombo1, "0" ); hCombo1 = GetDlgItem( hwnd, IDC_COMBO1 ) ; ComboBox_SetText ( hCombo1, pCombo1 ); break; case WM_COMMAND : if(HIWORD(wParam)) break; //Notifications switch ( LOWORD( wParam ) ) { case IDOK: SendMessage( hwnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; case IDC_BUTTON0://M+ case IDC_BUTTON1://M- case IDC_BUTTON2://MR case IDC_BUTTON3://MC case IDC_BUTTON4://AC case IDC_BUTTON5://BS break ;

default: iAsc = LOWORD( wParam );

Page 131: Systemprogrammierung II (SP II,Script 2005)

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

Page 132: Systemprogrammierung II (SP II,Script 2005)

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?

Page 133: Systemprogrammierung II (SP II,Script 2005)

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 Notify-

Nachrichten von Controls. Wie würden Sie (unmittelbat nach WM_COMMAND) die Notify-Nachrichten "abblocken"?

Lösung durch:

case WM_COMMAND: if(HIWORD(wParam)) ....;

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

Page 134: Systemprogrammierung II (SP II,Script 2005)

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 ADer 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 functionalityBOOL my_open_file_dialog(HWND hwnd, TCHAR buf[], DWORD nChar) { TCHAR * pTitle = "mein file open"; TCHAR * pFilt =

Page 135: Systemprogrammierung II (SP II,Script 2005)

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

Page 136: Systemprogrammierung II (SP II,Script 2005)

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");

Page 137: Systemprogrammierung II (SP II,Script 2005)

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);

Page 138: Systemprogrammierung II (SP II,Script 2005)

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;

Page 139: Systemprogrammierung II (SP II,Script 2005)

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),

Page 140: Systemprogrammierung II (SP II,Script 2005)

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) {

Page 141: Systemprogrammierung II (SP II,Script 2005)

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);}

Page 142: Systemprogrammierung II (SP II,Script 2005)

↑ 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); } } }}

Page 143: Systemprogrammierung II (SP II,Script 2005)

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));

Page 144: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 145: Systemprogrammierung II (SP II,Script 2005)

↑ 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 Abbrechen! (Dialog, aktuellen Task)

Return-Taste Ausführen! (aktive Menu-Option oder Button-Schaltfläche)

Tab Shift+Tab

Vorwärts/Rückwärts durch die Optionen bewegen

Strg+Tab Strg+Shift+Tab

Vorwärts/Rückwärts durch Contol-Folge oder Registerkarten bewegen

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)

Page 146: Systemprogrammierung II (SP II,Script 2005)

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 CALLBACK-

Funktion, 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 gibt Pushbutton-Identifizierer psh1,psh2,...,pshHelp=psh15,psh16.Es gibt Edit-Control-Identifizierer edt1,edt2,...,edt16Es gibt ComboBox-Identifizierer cmb1,cmb2, ...,cmb16Es gibt 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.

Page 147: Systemprogrammierung II (SP II,Script 2005)

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);

Page 148: Systemprogrammierung II (SP II,Script 2005)

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?

Page 149: Systemprogrammierung II (SP II,Script 2005)

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

Page 150: Systemprogrammierung II (SP II,Script 2005)

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

Page 151: Systemprogrammierung II (SP II,Script 2005)

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);

Page 152: Systemprogrammierung II (SP II,Script 2005)

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 text 0")); ListBox_AddString(hList1, TEXT("links text 1")); ListBox_AddString(hList1, TEXT("links text 2")); ListBox_AddString(hList1, TEXT("links text 3")); ListBox_AddString(hList1, TEXT("links text 4"));

ListBox_AddString(hList2, TEXT("rechts text 0")); ListBox_AddString(hList2, TEXT("rechts text 1")); ListBox_AddString(hList2, TEXT("rechts text 2")); ListBox_AddString(hList2, TEXT("rechts text 3")); ListBox_AddString(hList2, TEXT("rechts text 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 ;

Page 153: Systemprogrammierung II (SP II,Script 2005)

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;

Page 154: Systemprogrammierung II (SP II,Script 2005)

}

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)");

Page 155: Systemprogrammierung II (SP II,Script 2005)

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:

Page 156: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 157: Systemprogrammierung II (SP II,Script 2005)

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

Page 158: Systemprogrammierung II (SP II,Script 2005)

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

Page 159: Systemprogrammierung II (SP II,Script 2005)

}

// 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 6 herunter bis 7 von den ny=10-Teilen // 0,1,2 bedeutet von links 0 nach rechts bis 1 von den 2-horizontalen Teilen g.dlg_static(5,6,ny, 0,1,2, TEXT("0,1,2 static-Text:"));//static-Text in Dialog // 1,2,2 bedeutet von links 1 nach rechts bis 2 von den 2-horizontalen Teilen

Page 160: Systemprogrammierung II (SP II,Script 2005)

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));

Page 161: Systemprogrammierung II (SP II,Script 2005)

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.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);

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.

Page 162: Systemprogrammierung II (SP II,Script 2005)

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;

Page 163: Systemprogrammierung II (SP II,Script 2005)

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

--------|-----------------|--------------------------

Page 164: Systemprogrammierung II (SP II,Script 2005)

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?

Page 165: Systemprogrammierung II (SP II,Script 2005)

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);

}

Page 166: Systemprogrammierung II (SP II,Script 2005)

#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)

Page 167: Systemprogrammierung II (SP II,Script 2005)

{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

Page 168: Systemprogrammierung II (SP II,Script 2005)

{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

Page 169: Systemprogrammierung II (SP II,Script 2005)

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-DatenMENU_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;}

Page 170: Systemprogrammierung II (SP II,Script 2005)

public:

// hole Zeiger pms aus den Window-DatenMENU_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-DatenHICON 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) {

Page 171: Systemprogrammierung II (SP II,Script 2005)

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;

Page 172: Systemprogrammierung II (SP II,Script 2005)

// DWORD time; POINT pt;// } MSGMSG 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ückint 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++) {

Page 173: Systemprogrammierung II (SP II,Script 2005)

if(hwnd == hwa[i]) return i; } return 0; }

// get_hwnd_next() gibt den Index des nächsten// Fenster-Handle im Array hwa[i] zurückint 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:

Page 174: Systemprogrammierung II (SP II,Script 2005)

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);

Page 175: Systemprogrammierung II (SP II,Script 2005)

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; }

Page 176: Systemprogrammierung II (SP II,Script 2005)

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 gesetztBOOL 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);

Page 177: Systemprogrammierung II (SP II,Script 2005)

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

Page 178: Systemprogrammierung II (SP II,Script 2005)

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)

Page 179: Systemprogrammierung II (SP II,Script 2005)

|| !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 {

Page 180: Systemprogrammierung II (SP II,Script 2005)

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);

Page 181: Systemprogrammierung II (SP II,Script 2005)

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");}

Page 182: Systemprogrammierung II (SP II,Script 2005)

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)

Page 183: Systemprogrammierung II (SP II,Script 2005)

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

Page 184: Systemprogrammierung II (SP II,Script 2005)

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 RechteckPWORD 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;

Page 185: Systemprogrammierung II (SP II,Script 2005)

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"));

Page 186: Systemprogrammierung II (SP II,Script 2005)

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");

Page 187: Systemprogrammierung II (SP II,Script 2005)

}

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

Page 188: Systemprogrammierung II (SP II,Script 2005)

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,

Page 189: Systemprogrammierung II (SP II,Script 2005)

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:

Page 190: Systemprogrammierung II (SP II,Script 2005)

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

Page 191: Systemprogrammierung II (SP II,Script 2005)

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.

Page 192: Systemprogrammierung II (SP II,Script 2005)

Eine MDI-Apllikation besteht aus einem Haupt-Fensters (Rahmen-Fenster bildet die Client Area), einem unsichtbaren Client Fenster (Klassen-Name "MDICLIENT") MDI-Cild-

Fenstern, die sich auf der Client Area befinden und durch die "MDICLIENT"-Klasse mit eingebauter CALLBACK-Funktion, kontrolliert werden. Typisches Aussehen:

MENU-Identifizierer: winuser.h-MDI-Nachrichten Aussehen etwa:

#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 ...

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

|

| | | | |

Page 193: Systemprogrammierung II (SP II,Script 2005)

MDI Child 1

WS_CHILDWS_VISIBLE

WS_CLIPCHILDREN

MDI Child 2

WS_CHILDWS_VISIBLE

WS_CLIPCHILDREN

MDI Child 3

WS_CHILDWS_VISIBLE

WS_CLIPCHILDREN

MDI Child 4

WS_CHILDWS_VISIBLE

WS_CLIPCHILDREN

MDI Child n

WS_CHILDWS_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);

// 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_HORIZONTALIDM_WINDOW_ARRANGE IDM_WINDOW_SHOWMINIMIZEIDM_WINDOW_SHOWDEFAULT IDM_WINDOW_SHOWMAXIMIZEIDM_WINDOW_CLOSEALL IDM_ENUM_WINDOW_DATEN

Page 194: Systemprogrammierung II (SP II,Script 2005)

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", IDM_WINDOW_CASCADE "&Vertikal", IDM_WINDOW_TILE_VERTIKAL "&Horizontal", IDM_WINDOW_TILE_HORIZONTAL "&Minimieren", IDM_WINDOW_SHOWMINIMIZE "&Nomale Größe", IDM_WINDOW_SHOWDEFAULT "Ma&ximieren", IDM_WINDOW_SHOWMAXIMIZE "&Symbole Anordnen", IDM_WINDOW_ARRANGE "&Alle Fenster schließen", 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 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")

Page 195: Systemprogrammierung II (SP II,Script 2005)

//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-FrameHMENU m_hMenu[MAX_ANZ_HWND]; // [] für menu'sHACCEL m_hAccel; // aktuelle Accel-TabelleHWND m_hClient; // mdi-Client-fensterHWND m_hDlg; // aktueller DialogMSG 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;

Page 196: Systemprogrammierung II (SP II,Script 2005)

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

Page 197: Systemprogrammierung II (SP II,Script 2005)

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

Page 198: Systemprogrammierung II (SP II,Script 2005)

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, WPARAM wParam, LPARAM lParam){ switch(uMsg)

Page 199: Systemprogrammierung II (SP II,Script 2005)

{ 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; }

Page 200: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 201: Systemprogrammierung II (SP II,Script 2005)

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äß:

Page 202: Systemprogrammierung II (SP II,Script 2005)

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 Comiler-

fehlern kann unwichtiges zunächst auskommentiert werden:

LRESULT CALLBACK mdi_default_child_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 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;}

Page 203: Systemprogrammierung II (SP II,Script 2005)

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);

Page 204: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 205: Systemprogrammierung II (SP II,Script 2005)

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=====|==========|=========="));

Page 206: Systemprogrammierung II (SP II,Script 2005)

}

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

Page 207: Systemprogrammierung II (SP II,Script 2005)

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

Page 208: Systemprogrammierung II (SP II,Script 2005)

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; }

Page 209: Systemprogrammierung II (SP II,Script 2005)

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 anschauen):#define IDM_FILE_OPEN 4001#define IDM_FILE_SAVE 4002#define IDM_FILE_SAVE_AS 4003#define IDM_APP_EXIT 4004#define IDM_EDIT_NEW_TEXT 4005#define IDM_EDIT_CLOSE_TEXT 4006#define IDM_WINDOW_CASCADE 4007#define IDM_WINDOW_TILE_VERTIKAL 4008#define IDM_WINDOW_TILE_HORIZONTAL 4009 #define IDM_WINDOW_ARRANGE 4010#define IDM_WINDOW_SHOWMINIMIZE 4011#define IDM_WINDOW_SHOWDEFAULT 4012#define IDM_WINDOW_SHOWMAXIMIZE 4013#define IDM_WINDOW_CLOSEALL 4014#define IDM_ENUM_CHILD_WINDOW_DATEN 4015

Page 210: Systemprogrammierung II (SP II,Script 2005)

#define IDM_ENUM_ALL_WINDOW_DATEN 4016#define IDM_EDIT_UNDO 4017#define IDM_EDIT_CUT 4018#define IDM_EDIT_COPY 4019#define IDM_EDIT_PASTE 4020#define IDM_EDIT_CLEAR 4021#define IDM_EDIT_SELECT_ALL 4022#define IDM_FIND_MARKIERTEN_TEXT 4024#define IDM_ERSETZE_PRAE_POST 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();

Page 211: Systemprogrammierung II (SP II,Script 2005)

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);

Page 212: Systemprogrammierung II (SP II,Script 2005)

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

Page 213: Systemprogrammierung II (SP II,Script 2005)

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

Page 214: Systemprogrammierung II (SP II,Script 2005)

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

Page 215: Systemprogrammierung II (SP II,Script 2005)

(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 Edit-Window 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

Page 216: Systemprogrammierung II (SP II,Script 2005)

..", 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;

Page 217: Systemprogrammierung II (SP II,Script 2005)

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; }

Page 218: Systemprogrammierung II (SP II,Script 2005)

// 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;}

-->

Page 219: Systemprogrammierung II (SP II,Script 2005)

Hier einige "Brocken" zur Aufgabe 6

ACHTUNG!return FALSE meint break;return TRUE meint return 0;

//globale Konstanten:#define FIRST_CHILD_IDX 50000

#define MAX_ANZ_HWND ((int)30) 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-TabelleHWND m_hClient; // mdi-Client-fensterHWND m_hDlg; // aktueller DialogMSG m_msg; // aktuelle Nachricht HINSTANCE m_hInst; // = GetModuleHandle(0);

#define MAX_BUF 1024CHAR 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

Page 220: Systemprogrammierung II (SP II,Script 2005)

| 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")\

Page 221: Systemprogrammierung II (SP II,Script 2005)

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-DialogBOOL IDM_FILE_OPEN(void) { HWND hwnd = get_aktiv_edit(); TCHAR szFileName[_MAX_PATH]; szFileName[0] = '\0';

Page 222: Systemprogrammierung II (SP II,Script 2005)

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);

Page 223: Systemprogrammierung II (SP II,Script 2005)

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

Page 224: Systemprogrammierung II (SP II,Script 2005)

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);

Page 225: Systemprogrammierung II (SP II,Script 2005)

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;

Page 226: Systemprogrammierung II (SP II,Script 2005)

}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;

Page 227: Systemprogrammierung II (SP II,Script 2005)

}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://////////////////////////////////////////////////

Page 228: Systemprogrammierung II (SP II,Script 2005)

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;

Page 229: Systemprogrammierung II (SP II,Script 2005)

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

Page 230: Systemprogrammierung II (SP II,Script 2005)

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 ?");

Page 231: Systemprogrammierung II (SP II,Script 2005)

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

Page 232: Systemprogrammierung II (SP II,Script 2005)

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);

Page 233: Systemprogrammierung II (SP II,Script 2005)

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

Page 234: Systemprogrammierung II (SP II,Script 2005)

"\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;

Page 235: Systemprogrammierung II (SP II,Script 2005)

}

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;

Page 236: Systemprogrammierung II (SP II,Script 2005)

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"));

Page 237: Systemprogrammierung II (SP II,Script 2005)

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

Page 238: Systemprogrammierung II (SP II,Script 2005)

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)));

Page 239: Systemprogrammierung II (SP II,Script 2005)

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");

Page 240: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 241: Systemprogrammierung II (SP II,Script 2005)

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

Page 242: Systemprogrammierung II (SP II,Script 2005)

// 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 __declspec( dllexport )#else #define DLL_API __declspec( dllimport )#endif

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

#define _DLLBUILD_#include "sp2_dll.h"

///////////////////////////////////// einige DLL-Test-Beispiele /////////////////////////////////// DLL_API HINSTANCE hInst = 0; DLL_API HINSTANCE GetDllInstance() { return hInst; }

DLL_API void func(); DLL_API int i = 10; DLL_API int j; DLL_API int n;

///////////////////////////////////// Konstruktor der Klasse/////////////////////////////////// sp2_dllClass::sp2_dllClass() { return; }

///////////////////////////////////// SHARED-Variablen in der DLL///////////////////////////////////#pragma data_seg("SHARED")

Page 243: Systemprogrammierung II (SP II,Script 2005)

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

Projektes 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")

Page 244: Systemprogrammierung II (SP II,Script 2005)

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 = ???

}

ErweiterungenDie 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; }

Page 245: Systemprogrammierung II (SP II,Script 2005)

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

Page 246: Systemprogrammierung II (SP II,Script 2005)

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

Page 247: Systemprogrammierung II (SP II,Script 2005)

#ifndef sp2_dll_H#define sp2_dll_H///////////////////#include <windows.h>

#ifdef _DLLBUILD_ #define DLL_API __declspec( dllexport )#else #define DLL_API __declspec( dllimport )#endif

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

#define _DLLBUILD_#include "sp2_dll.h"

///////////////////////////////////// einige DLL-Test-Beispiele /////////////////////////////////// DLL_API HINSTANCE hInst = 0; DLL_API HINSTANCE GetDllInstance() { return hInst; }

DLL_API void func(); DLL_API int i = 10; DLL_API int j; DLL_API 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:

Page 248: Systemprogrammierung II (SP II,Script 2005)

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 DLL-

Projektes 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 = ???

}

Page 249: Systemprogrammierung II (SP II,Script 2005)

SP2-EinleitungDiese Veranstaltung hat das Ziel, in die Programmierung mit dem aktuellen ( Windows-) Betriebssystem einzuführen.

Die unfangreiche Funktionalität eines Betriessystem ( als Virtuelle Maschine und Resourcen-Verwalter ) wird auf den

"unteren Ebenen" für die Programmierung genutzt. Wegen der Komplexität und des Umfanges wird diese Einführung

nicht vollständig sein. Das Skript kann der Vor- und Nachbereitung der Veranstaltung dienen.

Ziel der Veranstaltung

In der Veranstaltung werden grundlegende Begriffe erklärt, und in die Programmierung der Betriebssystem-

Funktionalität eingeführt. Der Schwerpunkt liegt auf praktischen Anwendungsaspekten. Wegen des Stoff-Umfanges

kann nur eine spezielle Auswahl behandelt werden.

Kognitive Ziele

Verstehen von Sachverhalten bedeutet, dass wir ( innerhalb eines stillschweigend vorausgesetzten Kontext ) in

Begriffen, Schlüssen, Urteilen denken und Erkenntnisse in Zusammenhänge einordnen können.

● Beschreibungen antworten auf Wie - Fragen,

● Erklärungen antworten auf Warum - Fragen.

Praktische Ziele

Im engeren Sinne wird als Grunglage ein aktuelles Betriebssystem ( Windows ) und aktuelle Programmierwerkzeuge

verwendet ( Entwicklungsumgebung, Debbuger, Ressourcen-Erstellung, Nachrichtenverfolgung, usw. ).

Danke

Ich möchte mich

● bei meiner Frau für das Verständnis,

● bei den Kollegen für interessante Diskussionen,

● bei meinen Diplomanden für die geleistete Arbeit,

● bei den Tutoren für den aufopfernden Einsatz und

● bei den Studenten für zahlreiche Fragen

bedanken.

Ron Kritzfeld:

Der Pragmatiker entscheidet Fälle

nicht nach Grundsätzen,

sondern fallweise.

In dem Wort "Systemprogrammierung" steckt "System" und "Programmierung". Diese Begriffe werden unten

Page 250: Systemprogrammierung II (SP II,Script 2005)

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

Page 251: Systemprogrammierung II (SP II,Script 2005)

soll auch für nicht technische Systeme brauchbar sein. Das folgende Modell kann komplexe Prozesse beschreiben und

ist einem Computer-System nachgebildet. Es besteht aus den Komponenten: Memory, Prozessor, Receptor, Effektor,

Enviroment.

Memory Prozessor Wandler Enviroment

enthält:

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 )

==>

Effektor(

Aktor )

Übertragungs-

medium:

Weiterleitung

von

Signalfolgen

Memory Prozessor Wandler Enviroment

Bei einem ( biologischen ) lernenden System ist die Trennung von Speichern und Ausführen oft schwierig.

Ein technischer Prozessor kann Daten im Speicher ablegen, finden, holen, ändern, überschreibend-speichern. Es gibt

● Daten, die der Prozessor als von aussen kommende Befehle ( OpCode ) erkennt und

interpretiert ( fester Befehlssatz ). Solche Befehle sind z.B.

--- ausführen von elementaren Operationen

--- internes ( zwischen- ) speichern von aktuellen Ausdrücken

--- interne Ausführungsverzweigungen durchführen ( Sprung, "bedingter

Adressversatz" )

--- Speichern aller internen Prozessordaten und umschalten auf einen neuen Prozess

oder in einen neuen Ausführungsmodus

● Nutz-Daten, die der Prozessor

holt, ändert, geändert speichert

● Daten, die dem Prozessor

äussere Zustände signalisieren ( Steuerbus-Signale ) und sein

gesamtes Verhalten beeinflussen. Solche Hardware/Software-Steuerdaten können den

Prozessor in einen anderen Zustand ( z.B. wach, schlafend ) umschalten. Im

schlafenden Zustand können unbewusste Aufräumungsarbeiten durchgeführt werden.

Die Folge von Prozessor-Befehlen bilden ein Programm. Ein Programm braucht zur Ausführung eine interpretierende

Apparatur. Jeder interpretierende Apparatur kann nur die eigenen Befehle interpretieren ( braucht speziell auf die

Apparatur abgestimmte Programm-Sequenzen ). Der Prozessor arbeitet mit dem Effektor und dem Receptor

zusammen, die Signalumwandlungen durchführen. Kommunikation ist ein wechselseitiger Prozess von Sender und

Empfänger ( feed back, Rückkoppelung zwischen Empfänger und Sender ).

Was ist ein System?

Page 252: Systemprogrammierung II (SP II,Script 2005)

In der Philosophie ist ein System [ griechisch: "gegliedertes Ganzes"; von griechisch systema: das Zusammengesetzte

], eine Bezeichnung für das geordnete Zusammenstellen von grundlegenden Erkenntnissen zu einem Ganzen, d.h. zu

einer Lehre, einer Doktrin oder einem Lehrgebäude. In der Wissenschaftstheorie ist ein System die Gesamtheit der

Prinzipien, die einer Theorie zugrunde liegen. Nach Immanuel Kant ( Kritik der reinen Vernunft, 1781 ) ist das

System "die Einheit der mannigfaltigen Erkenntnisse unter eine Idee".

Beispiel: Fachwerksystem Ein Fachwerk besteht aus einem System von Stäben, die miteinander verbunden sind. Die

Stäbe erfüllen erst dann die Funktionen des Fachwerksystems, wenn die Stäbe zu einem "neuen Ganzen" montiert

sind. Das Fachwerksystem kann Lasten tragen und damit seine Aufgabe erfüllen, wenn die Lasten über Stäbe und

Stabverbindungen ( an die Erde ) abgeleitet werden. "Schnittstellen" sind gedachte Trennstellen, um rechnerisch die

innen wirkenden Schnittgrössen ( Kräfte, Momente ) zu ermitteln.

Zu einem konkreten Systemen gehören ( meist ) unterteilende Fachbegriffe, die die Vielfalt spezifizieren und das

wissenschaftlichen Modell beschreiben. Als strukturbildende Einteilung wird der System-Begriff in allen

Wissenschaften verwenden.

Hier einige Beispiele: In der Psychologie formulierte Gregory Bateson ( 9.5.1904-11.6.1980 ) die Double-Bind-

Theorie zur Rolle der Familie bei der Entstehung von Schizophrenie.

Die zunehmende Bevölkerung führte zu Umweltschutz, Grenzen des Wachstums, Populationen, Ökologie,

Biozönosen, Nahrungsbeziehungen zwischen den Arten, usw. Die Biologie und Evolutionstheorie führten zu

verwobenen ( grossen ) Systemen. Die Ökologie ( zu griechisch oikos: Haus und lógos: Lehre ) beschreibt Systeme

undderen Wechselbeziehungen zwischen den Organismen der unbelebten/belebten Umwelt und dem Stoff- und

Energiehaushalt Es wird zwischen der unbelebten Umwelt ( abiotische Faktoren wie Klima, Boden ) und der belebte

Umwelt ( biotische Faktoren ) unterschieden.

● Die Aut-Ökologie behandelt Beziehungen zwischen Individuum und Umwelt Die Dem-

Ökologie ( Populationsökologie ) behandelt Beziehungen zwischen

Wechselbeziehungen artgleicher Individuen

● Die Syn-Ökologie behandelt Wechselbeziehungen verschiedener Populationen

Biozönosen kennzeichnet die Gesamtheit aller Lebewesen eines bestimmten

Lebensraums.

● Die System-Ökologie behandelt Ökosysteme untereinander

● Die Human-Ökologie behandelt Wechselwirkungen zwischen dem Menschen und

seiner natürlichen und technischen Umwelt

Syllogistik [griechisch] die, Logik: von Aristoteles begründete Lehre vom Schluss als Kernstück der traditionellen

Logik. Aus der Verbindung von zwei Vordersätzen (Prämissen) geht dabei der Schlusssatz (Konklusion) als logische

Folgerung hervor. Die Syllogistik stellt in der modernen Logik einen Teil der prädikatenlogischen Schlüsse dar (

Prädikat lateinisch: auszeichnende Bewertung ).

In der Mathematik ist der von D.Hilbert begründete ( nur aus Axiomen gewonne ) Formalismus als mathematisch

erweisbare Widerspruchsfreiheit gescheitert ( Gegenposition zum Intuitionismus ). K.Gödel hat 1931 den

Unvollständigkeitssatz bewiesen:

Eine mathematische Theorie,

die die Arithmetik umfasst,

Page 253: Systemprogrammierung II (SP II,Script 2005)

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

Page 254: Systemprogrammierung II (SP II,Script 2005)

Eigenschaften bestehen. Ein System ist ein Gefüge von Objekten und Beziehungen mit bestimmten Eigenschaften.

Der System - Begriff wird in vielfältiger Weise verwendet. Z.B. sind Programmen, Verfahren, Daten und Methoden

zur Informationsverarbeitung in einem.

In der Informatik wird der System - Begriff in vielfältiger Weise benutzt.

● Ein Hardware-System besteht z.B. Mikroprozessoren, elektronischen Bausteinen,

elektronischen Geräten, weiteren Schaltungen, physikalischen Sensoren und Aktoren

● Ein Computer besteht aus System-Software, Betriebssystem, Firmware, Middleware,

Software-Komponenten, Anwendungssoftware, Hardware-System, Speicher-System,

Ein- und Ausgabegeräten, Peripherie, usw.

● Eingabegeräten ( Tastatur, Maus, Laufwerk ),

● Ausgabegeräten ( Bildschirm, Laufwerk ) und

● Peripheriegeräten ( Drucker, Modem )

● Datenbanksystem ( Anwendungsprogramm zum Erfassen, Suchen, Sortieren und

Verwalten größerer Datenmengen, Daten-, Adressen- und Artikelverwaltung,

Buchhaltungssysteme, Rechnungssystem, SQL-Abfragen, Recherchen, Suchmaschinen

)

● CIM ( englisch computer integrated manufacturing, rechnerintegrierte Fertigung )

enthält für die Konstruktion und Fertigung mit Hilfe eines Rechners CAD ( Computer-

Aided-Design ) und CAM ( Computer-Aided-Manufacturing )

Nach DIN 19226 gilt:

Ein System ist eine abgegrenzte Anordnung von aufeinander einwirkenden Gebilden.

Solche Gebilde können sowohl Gegenstände als auch Denkmethoden und deren

Ergebnisse ( z.B. Organisationsformen, mathematische Methoden,

Programmiersprachen) sein. Diese Anordnung wird durch eine Hüllfläche von ihrer

Umgebung abgegrenzt oder abgegrenzt gedacht. Durch die Hüllfläche werden

Verbindungen des Systems mit seiner Umgebung geschnitten. Die mit diesen

Verbindungen übertragenen Eigenschaften und Zustände sind die Größen, deren

Beziehungen untereinander das dem System eigentümliche Verhalten beschreibt.

Durch zweckmäßiges Zusammenfügen und Unterteilen von solchen Systemen

können größere und kleinere Systeme entstehen.

Objektbezogene Systembezeichnungen:

Systeme können nach Prinzipien eingeteilt und unterschieden werden:

abstrakt: lat. abstrahere

Page 255: Systemprogrammierung II (SP II,Script 2005)

formal äußere Form ( nicht Inhalt )

verbal mündlich

konkret: gegenständlich

konzipiert lat. concipere

real lat., zu res "Sache"

Etwas auführlicher:

abstrakt:

lat. abstrahere: wegziehen, wegschleppen, von den individuellen Merkmalen losgelöst, nicht konkret, sinnlich nicht wahrnehmbar, rein begrifflich, unanschaulich, von der Wirklichkeit abgetrennt; Gegensatz: konkret. Abstrakt wird auch als Bezeichnung für die Erfassung des Wesentlichen verwendet ( z.B. Person – Mensch – Säugetier – Lebewesen – Seiendes etc. ). Aristoteles nannte es aphairesis ( griechisch: Wegnahme ) das methodische Erfassen des Wesentlichen ( Abstraktionsmethode, induktiven Logik, Phänomenologie ).

formal Formal meint die äußere Form ( nicht den Inhalt ) und kann ohne Entsprechung in der

Wirklichkeit sein, der Form genügend, nur äußerlich, nicht in Wirklichkeit, Axiome werden in Zeichen des Operationssystems ausgedrückt

verbal mündlich, mit Worten, mit Hilfe der Sprache

konkret:

gegenständlich, dinglich, fassbar, wirklich, tatsächlich, anschaulich, sinnlich wahrnehmbar;Gegensatz: abstrakt.

konzipiert lat. concipere: zusammenfassen, begreifen, sich vorstellen; von einer bestimmten

Vorstellung, Idee ausgehend etwas planen, entwerfen, entwickeln; einen Plan oder ein schriftliches Konzept für etwas machen;

real lat., zu res "Sache", wirklich, tatsächlich, nicht nur in der Einbildung, in der Wirklichkeit vorhanden, der Realität entsprechend;Gegensatz: irreal.

künstlich:Wer sich künstlich aufregt, regt sich über etwas mehr als nötig auf

natürlich:Die lateinische Fügung ( in natura ) entspricht der Bedeutung "in Wirklichkeit; in seiner wirklichen, natürlichen Gestalt". Das Haus sieht in natura ganz anders aus als auf dem Foto.

Ein System S besteht aus einer Menge M von Komponenten und damit definierten Relation R, d.h. aus dem

Begriffspaar S = ( M, R ).

Wird

M = { i, s, o } : Eingabe-, System-, Ausgabe - Zustände R = { I, S, O } : Eingabe-, Übergangs-, Ausgabe - Funktionen

in

S = ( M, R ) : Menge von Komponenten, Relationen

Page 256: Systemprogrammierung II (SP II,Script 2005)

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

Page 257: Systemprogrammierung II (SP II,Script 2005)

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 319Bauelemente-Bauplan; Gesamtlänge/Spannweite/Höhe=33,84/34,10/11,76 m

Page 258: Systemprogrammierung II (SP II,Script 2005)

Was sind Schnittstellen?Ein Fachwerksystem besteht aus Stäben, die miteinander verbunden sind. Die "Schnittstellen" sind gedachte

Trennstellen, für die innen wirkenden Schnittgrössen ( Kräfte, Momente ).

Bei verteilten Aufgaben erfolgt der Informationsaustausch an Übergangspunkten ( Schnittstellen ). Die

Kommunikation findet über die Schnittstellen statt. Engpässe an diesen Informations-Schnittstellen ( Mitarbeiter-

Abteilungsleiter, Abteilungsleiter-Führungsebene, Schnittstellen zwischen Software-Modulen, Schnittstellen zwischen

Hardware-Modulen, Schnittstellen zwischen Software-Hardware, usw. ) können zu Frust führen.

Hardware-Schnittstellen haben i.a. eine physische Übertragungsstrecke ( Sender, Kanal, Empfänger ). Software-

Schnittstellen nutzen für die asynchrone Kommunikation i.a. adressierbare Speicher ( Buffer, LIFO, FIFO, usw. ).

Besonders leistungsfähige Computer ( hohe Taktraten, großes Speichervolumen ) können helfen, die Informationen

am rechten Ort, zur rechten Zeit, in der rechten Form bereit zu stellen. Software-Schnittstellen regeln semantisch die

Nachrichten-Verteilung ( z.B. auf Quelltext-Modul-Ebene, auf Maschinen-Ebene bei DLL's ).

Eine Schnittstelle (engl. Interface) ist eine Beschreibung von Attributen, Methoden und Ereignissen. Bei Software-

Schnittstellen 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

Page 259: Systemprogrammierung II (SP II,Script 2005)

Die Schnittstelle zwischen dem Menschen und dem Computer ( Mensch-Maschine-Schnittstelle, Man-Machine-

Interface MMI, auch Human-Machine-Interface HMI ) ist meistens eine Benutzer-Oberflächen ( Bedienung,

Schnittstellen, HMI, MMI ), die visuelle Bildschirm-Fenster-Techniken nutzt SAA ( Mitte der 80er Jahre von IBM

entwickelt ) ist eine Abkürzung für System Application Architecture, die einen vereinheitlichter Aufbau der Mensch-

Computer-Schnittstelle definiert. Art der Gestaltung von Software, die die Arbeit erleichtert und bereichert sowie den

Gesundheitsschutz angemessen berücksichtigt. Zur Software-Ergonomie gehören vor allem Benutzerfreundlichkeit

sowie Möglichkeiten der individuellen Einstellung und Anpassung, z.B.: Auswahl, Anordnung und Größe der

Bedienungselemente, Farbwahl, Zoomen der Darstellung, Vorgaben für Tastatur und Maus ( etwa Wiederhol- und

Klicktempo ), Lautstärke- und Klangregelungen.

Zur Software-Ergonomie zählen außerdem Arbeitserleichterungen, die die Bedienung vereinfachen und dem Benutzer

Routinetätigkeiten abnehmen, z.B.

● Grafische Benutzeroberflächen

● Vereinfachte Verfahren wie Drag and Drop

● Zusammenfassen von Befehls- und Aktionsfolgen in Makros

● Automatisierte Funktionen ( z.B. kontexsensible Hilfen, intelligente

Aktionsunterstützung, Rechtschreibprüfung, Korrektur von "Drehern", usw.)

Die Software soll der Aufgabe angemessen, fehlertolerant, lernfördernd sein, und echte Dialoge bieten. Software-

Ergonomie ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG von 1990 ( DIN

66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter Dialog zwischen Mensch und Computer

erfüllen soll. Arbeitgeber sollen benutzerfreundliche Software einsetzen, die der ausführenden Tätigkeit angepasst ist (

verständliche Format, angemessenes Bearbeitungtempo, Rückmeldungen über Ergebnisse der Abläufe ).

KybernetikDer 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.

Page 260: Systemprogrammierung II (SP II,Script 2005)

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örperIm 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,

Page 261: Systemprogrammierung II (SP II,Script 2005)

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

Page 262: Systemprogrammierung II (SP II,Script 2005)

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.

Page 263: Systemprogrammierung II (SP II,Script 2005)

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

Volumen 1 l = 103 m3Temperatur-differenz 1 °C = 1 K

Druck 1 bar = 105 Pa Winkel 1° = PI rad/180

Für die Einheit 1 rad = 1 m/m darf nach DIN 1301 bei Zahlenrechnungen auch 1 stehen. Nach DIN 1301 können

Vorsätze für dezimale Vielfache und Teile verwendet werden:

Abkürzung: E P T G M k h da

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

Anz.Adressen: 1 024 1 048 576 1 073 741 824 16 256 65 536 4 294 967 296

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 Normungsinstitutionen1917 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.

Page 264: Systemprogrammierung II (SP II,Script 2005)

Internationale Normungsinstitutionen1906 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.

Page 265: Systemprogrammierung II (SP II,Script 2005)

ISO-8859 Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990.

ISO 9241-10 Grundsätze der Dialoggestaltung

ISO/DIS 9241-11

Richtlinien zur Gebrauchstauglichkeit

ISO/DIS 9241-12

Informationsdarstellung

ISO/DIS 9241-13

Benutzerführung

ISO 9241-14 Dialogführung über Menüs

ISO/DIS 9241-15

Dialogführung über Kommandosprachen. (DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO).

ISO/DIS 9241-1+

Dialogführung über direkte Manipulation. (DIS = Abkürzung für Draft International Standard, finaler Entwurf der ISO).

ISO/DIS 9241-17

Dialogführung über Bildschirmformulare (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, Prentice-Hall, 1990.

Page 266: Systemprogrammierung II (SP II,Script 2005)

ECMA-158 December 1997, Standardizing Information and Communication Systems, Portable Common Tool Environment (PCTE) - C Programming Language Binding

DIN 1304 Formelzeichen

DIN 66234 ( Teil 8)EG ( 90/270/ )

Software-Ergonomie ist ein wesentlicher Bereich der Arbeitsgestaltung. Die EG-Richtlinie 90/270/ EWG von 1990 ( DIN 66234, Teil 8 ) legt die Anforderungen fest, die ein ergonomisch gestalteter Dialog zwischen Mensch und Computer erfüllen soll. Arbeitgeber sollen benutzerfreundliche Software einsetzen, die der ausführenden Tätigkeit angepasst ist ( verständliche Format, angemessenes Bearbeitungtempo, Rückmeldungen über Ergebnisse der Abläufe ).

... 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-13File 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-74Measurement of Airborne Noise Emitted by Information Technology and Telecommunications Equipment, 6th edition (December 1999)

ECMA-948-Bit Single-Byte Coded Graphic Character Sets - Latin Alphabets No. 1 to No. 4, 2nd edition (June 1986)

ECMA-99Data 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-100Data 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-106Private 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-108Measurement of High-Frequency Noise emitted by Information Technology and Telecommunications Equipment, 3rd edition (December 1996)

ECMA-109Declared Noise Emission Values of Information Technology and Telecommunications Equipment, 4th edition (December 1996)

ECMA-1138-Bit Single-Byte Coded Graphic Character Sets - Latin/Cyrillic Alphabet, 3rd edition (December 1999)

ECMA-1148-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-1218-Bit Single-Byte Coded Graphic Character Sets - Latin/Hebrew Alphabet, 2nd edition (December 2000)

Page 267: Systemprogrammierung II (SP II,Script 2005)

ECMA-125Data 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-1288-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-133Private Integrated Services Network (PISN) - Reference Configurations for PISN Exchanges (PINX), 2nd edition (December 1998)

ECMA-1393,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS Format (June 1990)

ECMA-142Private Integrated Services Network (PISN) - Circuit Mode 64kbit/s Bearer Services - Service Description, Functional Capabilities and Information Flows (BCSD), 2nd edition (June 1997)

ECMA-143Private 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-1458 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording (December 1990)

ECMA-1463,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DATA/DAT Format (December 1990)

ECMA-147Data 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-148Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Identification Supplementary Services (ISSD), 3rd edition (June 1997)

ECMA-149Portable Common Tool Environment (PCTE) - Abstract Specification, 4th edition (December 1997)

ECMA-1503,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-151Data Compression for Information Interchange - Adaptive Coding with Embedded Dictionary - DCLZ Algorithm (June 1991)

ECMA-152Data Interchange on 12,7 mm 18-Track Magnetic Tape Cartridges - Extended Format, 2nd edition (December 1993)

ECMA-153Information 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-154Data 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-156Private 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-157Private Telecommunication Networks (PTN) - Signalling Protocol at the S Reference Point - Identification Supplementary Services (SSIG-ID), 2nd edition (June 1993)

ECMA-158Portable Common Tool Environment (PCTE) - C Programming Language Binding, 4th edition (December 1997)

ECMA-159Data Compression for Information Interchange - Binary Arithmetic Coding Algorithm (December 1991)

ECMA-160Determination of Sound Power Levels of Computer and Business Equipment Using Sound Intensity Measurements; Scanning Method in Controlled Rooms, 2nd edition (December 1992)

ECMA-161Private 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)

Page 268: Systemprogrammierung II (SP II,Script 2005)

ECMA-162Portable Common Tool Environment (PCTE) - Ada Programming Language Binding, 4th edition (December 1997)

ECMA-163Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Name Identification Supplementary Services (NISD), 3rd edition (September 1997)

ECMA-164Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Name Identification Supplementary Services (QSIG-NA), 3rd edition (September 1997)

ECMA-165Private 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-167Volume and File Structure for Write-Once and Rewritable Media using Non-Sequential Recording for Information Interchange, 3rd edition(June 1997)

ECMA-168Volume and File Structure of Read-Only and Write-Once Compact Disk Media for Information Interchange, 2nd edition (December 1994)

ECMA-1698 mm Wide Magnetic Tape Cartridge Dual Azimuth Format for Information Interchange - Helical Scan Recording (June 1992)

ECMA-1703,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-1713,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-173Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Diversion Supplementary Services (CFSD), 2nd edition (June 1997)

ECMA-174Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Diversion Supplementary Services (QSIG-CF), 2nd edition (June 1997)

ECMA-175Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Path Replacement Additional Network Feature (ANF-PRSD), 3rd edition (December 1998)

ECMA-176Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Path Replacement Additional Network Feature (QSIG-PR), 3rd edition (December 1998)

ECMA-177Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Transfer Supplementary Service (CTSD), 2nd edition (September 1997)

ECMA-178Private 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-182Data Interchange on 12,7 mm 48-Track Magnetic Tape Cartridges - DLT1 Format (December 1992)

ECMA-183Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1 Gigabyte per Cartridge (December 1992)

ECMA-184Data Interchange on 130 mm Optical Disk Cartridges - Capacity: 1,3 Gigabytes per Cartridge (December 1992)

ECMA-185Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Completion Supplementary Services (CCSD), 2nd edition (June 1997)

ECMA-186Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Completion Supplementary Services (QSIG-CC), 3rd edition (February 2000)

ECMA-189Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) Type using the SSF Method (June 1993)

ECMA-190Information Interchange on 300 mm Optical Disk Cartridges of the Write Once, Read Multiple (WORM) Type using the CCS Method (June 1993)

Page 269: Systemprogrammierung II (SP II,Script 2005)

ECMA-191Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Offer Supplementary Service (COSD), 2nd edition (June 1997)

ECMA-192Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Offer Supplementary Service (QSIG-CO), 3rd edition (June 1997)

ECMA-193Private 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-194Private 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-195Data 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-197Data Interchange on 12,7 mm 112-Track Magnetic Tape Cartridges - DLT2 Format (December 1993)

ECMA-1983,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-201Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 230 Megabytes per Cartridge, 2nd edition (December 1994)

ECMA-202Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Intrusion Supplementary Service (CISD), 2nd edition (June 1997)

ECMA-203Private 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-207Data 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-209Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT3 Format (December 1994)

ECMA-21012,65 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DATA-D3-1 Format, 2nd edition (December 1995)

ECMA-211Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Advice of Charge Supplementary Services (AOCSD), 2nd edition (June 1997)

ECMA-212Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Advice of Charge Supplementary Services (QSIG-AOC), 2nd edition (June 1997)

ECMA-213Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Recall Supplementary Service (RESD), 2nd edition (June 1997)

ECMA-214Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Recall Supplementary Service (QSIG-RE), 2nd edition (June 1997)

ECMA-215Private 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-216Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Location Registration Supplementary Service (QSIG-CTLR), 2nd edition (September 1997)

ECMA-217Services for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994)

Page 270: Systemprogrammierung II (SP II,Script 2005)

ECMA-218Protocol for Computer Supported Telecommunications Applications (CSTA) Phase II (December 1994)

ECMA-219Authentication and Priviledge Attribute Security Application with Related Key Distribution Functions - Part 1, 2 and 3, 2nd edition (March 1996)

ECMA-220Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Interception Additional Network Feature (ANF-CINTSD), 2nd edition (June 1997)

ECMA-221Private 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-223Data Interchange on 90 mm Optical Disk Cartridges - Capacity: 385 Megabytes per Cartridge (June 1995)

ECMA-224Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Transit Counter Additional Network Feature (ANF-TCSD), 2nd edition (June 1997)

ECMA-225Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Transit Counter Additional Network Feature (QSIG-TC), 2nd edition (June 1997)

ECMA-226Private Integrated Services Network (PISN) - Mapping Functions for the Employment of Dedicated Circuit Mode Connections as Inter-PTNX Connections (MAPPING-CM-STATIC) (June 1995)

ECMA-230Portable Common Tool Environment (PCTE) - IDL Binding (Interface Definition Language), 2nd edition (December 1997)

ECMA-231Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridges - DLT 4 Format (December 1995)

ECMA-232Private Integrated Services Network (PISN) - Profile Standard for the Connection of Radio Paging Equipment (RPE) to a PISN (December 1995)

ECMA-233Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Outgoing Call Additional Network Feature (QSIG-CTMO), 2nd edition (September 1997)

ECMA-234 Application Programming Interface for Windows (APIW) (December 1995)

ECMA-235 The ECMA GSS-API Mechanism (March 1996)

ECMA-2363,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-3 Format using 125 m Length Tapes (June 1996)

ECMA-238Data 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-239Data Interchange on 90 mm Optical Disk Cartridges - HS-1 Format - Capacity: 650 Megabytes per Cartridge (June 1996)

ECMA-240Data Interchange on 120 mm Optical Disk Cartridges using Phase Change PD Format - Capacity: 650 Mbytes per Cartridge (June 1996)

ECMA-241Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Message Waiting Indication Supplementary Service (MWISD), 4th edition (February 2002)

ECMA-242Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Message Waiting Indication Supplementary Service (QSIG-MWI), 3rd edition (December 1998)

ECMA-243Private Integrated Services Network (PISN) - Cordless Terminal Mobility (CTM) - Inter-Exchange Signalling Protocol - Cordless Terminal Authentication Supplementary Services (QSIG-CTAU), 2nd edition (September 1997)

ECMA-244Private Integrated Services Network (PISN) - Mapping Functions for the Employment of a Circuit Mode Basic Service and the Supplementary Service User-to-User Signalling as a pair of On-demand Inter-PINX Connections (Mapping-UUS), 2nd edition (September 2000)

Page 271: Systemprogrammierung II (SP II,Script 2005)

ECMA-245Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - PINX Clock Synchronization (SYNC-SIG), 2nd edition (September 1997)

ECMA-2468 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-1 Format, 2nd edition(June 1998)

ECMA-2478 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - HH-1 Format, 2nd edition(June 1998)

ECMA-24812,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-1 Format, 2nd edition (June 1998)

ECMA-2498 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DA-2 Format, 2nd edition (June 1998)

ECMA-250Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Common Information Additional Network Feature (ANF-CMNSD), 2nd edition (December 1998)

ECMA-251Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Common Information Additional Network Feature (QSIG-CMN), 2nd edition (December 1998)

ECMA-252Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Transit Counter Additional Network Feature (B-QSIG-TC) (December 1996)

ECMA-253Private 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-254Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Generic Functional Protocol (B-QSIG-GF), 2nd edition (December 1999)

ECMA-258Data 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-260Data Interchange on 356 mm Optical Disk Cartridges - WORM, using Phase Change Technology Capacity: 14,8 and 25 Gbytes per Cartridge (June 1997)

ECMA-261Broadband 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-263Private 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-264Private 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-265Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Signalling ATM Adaptation Layer (B-QSIG-SAAL) (September 1997)

ECMA-266Broadband 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-269Services for Computer Supported Telecommunications Applications (CSTA) Phase III, 4th edition (June 2000)

ECMA-270Portable Common Tool Environment (PCTE) - Mapping from CASE Data Interchange Format (CDIF) to PCTE (December 1997)

ECMA-271Extended Commercially Oriented Functionality Class for Security Evaluation (E - COFC), 2nd edition (December 1999)

Page 272: Systemprogrammierung II (SP II,Script 2005)

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-274Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes, 2nd edition (June 1999)

ECMA-275Measurement of structure-borne vibration induced by small air moving devices (AMDs) (June 1998)

ECMA-276Private Integrated Services Network (PISN) - Reference Configuration for PINX Extension Lines (June 1998)

ECMA-277Private Integrated Services Network (PISN) - Circuit Emulation Specification - Emulation of Basic Access by ATM Networks (June 1998)

ECMA-278Data Interchange on 12,7 mm 128-Track Magnetic Tape Cartridge - Parallel Serpentine Format, 2nd edition (June 2000)

ECMA-27980 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) (December 1998)

ECMA-280Data 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-281Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Private User Mobility (PUM) - Registration Supplementary Service (PUMRSD), 2nd edition(June 2000)

ECMA-282Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility (PUM) - Registration Supplementary Service (QSIG-PUMR), 2nd edition (June 2000)

ECMA-283Private 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-284Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Private User Mobility (PUM) - Call Handling Additional Network Features (QSIG-PUMCH), 2nd edition (June 2000)

ECMA-285Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III, 2nd edition (June 2000)

ECMA-286Data 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-2883,81 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - DDS-4 Format (June 1999)

ECMA-289Private 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-2918 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-1 with MIC Format (December 1999)

ECMA-2928 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording AIT-2 with MIC Format (December 1999)

ECMA-2938 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - MammothTape-2 Format (December 1999)

ECMA-294B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer Control Environment - Part 1: Protocol Specification (December 1999)

Page 273: Systemprogrammierung II (SP II,Script 2005)

ECMA-295

B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Call Control in a Separated Call and Bearer Control Environment - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999)

ECMA-296B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 1: Protocol Specification (December 1999)

ECMA-297B-ISDN and B-PISN - Digital Subscriber Signalling System No. two (DSS2), Broadband Inter-Exchange Signalling (B-QSIG), and Signalling System No. 7 (SS7) - Prenegotiation - Part 2: Protocol Implementation Conformance Statement (PICS) Proforma Specification (December 1999)

ECMA-298Broadband Private Integrated Services Network (B-PISN) - Inter-Exchange Signalling Protocol - Separated Bearer Control (SBC) (B-QSIG-SBC) (December 1999)

ECMA-299Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Single Step Call Transfer Supplementary Service (SSCT-SD) (February 2000)

ECMA-300Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Single Step Call Transfer Supplementary Service (QSIG-SSCT) (February 2000)

ECMA-301Private 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-302Private 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-303Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Wireless Terminal Call Handling Additional Network Features (WTMCH-SD) (June 2000)

ECMA-304Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal Call Handling Additional Network Features (QSIG-WTMCH) (June 2000)

ECMA-305Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Wireless Terminal Authentication Supplementary Services (WTMAU-SD) (June 2000)

ECMA-306Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Wireless Terminal Authentication Supplementary Services (QSIG-WTMAU) (June 2000)

ECMA-307Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Generic Functional Protocol for the Support of Supplementary Services (June 2000)

ECMA-308Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Transfer Supplementary Services, 2nd edition (June 2001)

ECMA-309Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Diversion Supplementary Services, 2nd edition (June 2001)

ECMA-310Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Simple Dialog Supplementary Service (SDSD) (June 2000)

ECMA-311Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Simple Dialog Supplementary Service (QSIG-SD) (June 2000)

ECMA-312Private Integrated Services Network (PISN) - Profile Standard for the Use of PSS1 (QSIG) in Air Traffic Services Networks, 2nd edition (June 2001)

ECMA-313Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Call Identification and Call Linkage Additional Network Feature (CIDLSD) (September 2000)

ECMA-314Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Call Identification and Call Linkage Additional Network Feature (QSIG-CIDL) (September 2000)

ECMA-31512,65 mm Wide Magnetic Tape Cassette for Information Interchange - Helical Scan Recording - DTF-2 (December 2000)

Page 274: Systemprogrammierung II (SP II,Script 2005)

ECMA-3168 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - VXA-1 Format (December 2000)

ECMA-317Data 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-318Private Integrated Services Network (PISN) - Use of QSIG at the C Reference Point between a PINX and an Interconnecting Network (December 2000)

ECMA-319Data Interchange on 12,7 mm - 384- Track Magnetic Tape Cartridges - Ultrium-1 Format (June 2001)

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

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

ECMA-322Data Interchange on 130 mm Magneto-Optical Disk Cartridges - Capacity: 9,1 Gbytes per Cartridge (June 2001)

ECMA-323XML Protocol for Computer Supported Telecommunications Applications (CSTA) Phase III (June 2001)

ECMA-324Private Integrated Services Network (PISN) - Specification, Functional Model and Information Flows - Short Message Service (SMSSD) (June 2001)

ECMA-325Private Integrated Services Network (PISN) - Inter-Exchange Signalling Protocol - Short Message Service (QSIG-SMS) (June 2001)

ECMA-326Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Call Completion Supplementary Services (June 2001)

ECMA-327ECMAScript 3rd Edition Compact Profile (June 2001)

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

ECMA-3298 mm Wide Magnetic Tape Cartridge for Information Interchange - Helical Scan Recording - AIT-3 Format (December 2001)

ECMA-330120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) (December 2001)

ECMA-331Case for 120 mm and 80 mm DVD-RAM Disks (December 2001)

ECMA-332Corporate Telecommunication Networks - Signalling Interworking between QSIG and H.323 - Basic Services (December 2001)

ECMA-333Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through H.323 Networks (December 2001)

ECMA-334C# Language Specification (December 2001)

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

ECMA-336Private Integrated Services Network (PISN) - Mapping Functions for the Tunnelling of QSIG through IP Networks (Mapping/IP-QSIG) (June 2002)

Historischeseinige Jahreszahlen

Page 275: Systemprogrammierung II (SP II,Script 2005)

1941 Zuse Z3, ab etwa 1960 Einführung von Dialogbetrieb ( Stapelbetrieb mit Operator )

1960 Ken Thompson, Dennis Ritchie (Bell Labs, AT&T) u. MIT-Forscher entwickelten MULTICS, ein Mehrbenutzer-Betriebssystem für General Electric ( Mainframe GE645 ) Trotz Nicht-Einsatzes von MULTICS ( techn. Mängel ) Weiter-Entwicklung durch Thompson ( "Space Travel", 2 Benutzer) Verballhornung durch Brian Kernighan "UNICS" 1969, Betriebssystem UNICS, ab 1970: Unix ( Assembler ). Gleichzeitig: Thompson u. Ritchie entwickeln Sprache A (BCPL-* basiert), verbesserte Version B, Weiterentw. zu C. 1973, Unix erstes BS größtenteils in einer Hochsprache ( kaum 1000 Zeilen Maschinencode, portierbar ), Keine Vermarktung von Unix wg. US-Kartell-Bestimmungen 1975, BSD-UNIX: Abkürzung für Berkeley Software Distribution-UNIX. Bezeichnung für eine UNIX-Variante ( entwickelt an der Berkeley-Universität in Kalifornien, Abgabe an Universitäten zum Selbstkostenpreis ) 1980, Xenix ( Microsoft, ab Mitte 80er: Santa Cruz Operation, etwa bis 1990 )

1981 IBM bringt den ersten PC ( mit MS-DOS ) heraus: 8088-CPU, 4.77 MHz, 64 KByte Speicher, 5.25"-Diskettenlaufwerk. Microsoft entwickelt dazu eine erste Version des Betriebssystems MS-DOS. Hayes bringt ein Modem mit 1200 Bit/s heraus. Herwig Feichtinger, heute bei Shamrock, gründet mit "mc" eine der ersten Computer-Zeitschriften. Novell stellt ein Netzwerk vor, mit dem mehrere Computer auf eine gemeinsame Festplatte zugreifen können. Hewlett-Packet konstruiert den ersten 32-Bit-Mikroprozessor.

1981 MS-DOS ( Microsoft-Disc Operating System, angelehtn an CP/M 80 für 160 KByte Disketten entwickelt, Version 1.25 ( ab 1982 ) benutzt zweiseitige Disketten ( 320 KByte Kapazität );ab 1983 MS-DOS 2.11 mit FAT-Festplatten und User-Hardware-Anpassungen durch Treiber ( in der CONFIG.SYS );ab 1984 MS-DOS 3.2 mit HD-Disketten ( 5.25 Zoll, 720 KByte) und die Einbindung in Netzwerke. ab 1984 MS-DOS 3.3 konnten Platten mit mehr als 32 MByte verwaltet werden;ab 1988 gab es das fehlerbehaftete MS-DOS 4.X mit DOS-Shell, Festplatten bis 2 GByte, EMS-Speicher nach dem LIM-Standard;ab 1991 erschien MS-DOS 5.0 mit HMA und UMA ab 1993 MS-DOS 6.X mit Zusatzprogrammen, wie Online-Komprimierer Doublespace, einem Virenschutz- und einem Backup-Programm, Memmaker-Speicher-Optimierer, ab 6.22 als Drivespace; )

1983 Apple bringt mit "Lisa" erstmals einen per Maus bedienbaren Computer mit grafischer Oberfläche heraus. Wegen des hohen Preises von rund 75.000 Dollar wird er ein Flop. Microsoft kündigt Windows 1.0 an, es wird erst 1985 verfügbar. Sony kündigt die 3,5"-Diskette an. IBM und Microsoft entwickeln zusammen das Betriebssystem OS/2. Novell bringt die Netware-Software heraus. Microcom erfindet ein fehlerkorrigierendes Modem-Protokoll (MNP).

1984 POSIX ( Portable Operating System Interface for UNIX ). Schnittstellen-Standard der IEEE, der von allen UNIX-Derivaten benutzt wird, dementsprechend auch von Programmen, die unter UNIX laufen beziehungsweise Übergänge zu UNIX-Rechnern herstellen.

1988 Normung zu ANSI-C ( Komitee X3J11 ).

1991 Linux 0.02 ( Linus Torvalds entwickelt einen Kern, FIN )

1985 1985, MS präsentiert Windows 1.01; 1987, Windows 2; 1987, OS/2 von IBM / MS, zeichenorientiert 1988, OS/2 von IBM/MS mit grafischer Oberfläche 1990, Windows 3.0 ( 16 Bit ) erscheint und wird ein großer Erfolg ( Trennung IBM – MS ). Im Oktober startet die Inmarsat-Organisation eigene Satelliten für die maritime Kommunikation. In den USA nimmt der erste kommerzielle Internet-Provider den Dienst auf. Unter Federführung der Bundespost entsteht der Treiber-Standard CAPI 1.1 für ISDN-Karten. James Gosling und Bill Joy beginnen mit der Entwicklung der Programmiersprache Java; 1992, Windows 3.1; 1993, Windows 3.11; 1993 Windows NT ( Windows New Technology, 32-Bit-Betriebssystem, für Workstations Windows NT 3.1, für Windows NT 3.1 Advanced Server und Netzwerke );

Page 276: Systemprogrammierung II (SP II,Script 2005)

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

Page 277: Systemprogrammierung II (SP II,Script 2005)
Page 278: Systemprogrammierung II (SP II,Script 2005)
Page 279: Systemprogrammierung II (SP II,Script 2005)

Help Potenzen von 2 Nat. Zahlen i (Schritt 1)

Nat. Zahlen i (Schritt 2)

Brüche (Schritt 0.1)

Nat. Zahlen i (Schritt 1/8)

Brüche 1/i (Schritt 1)

Fibonacci Lucas Nat.Zahlen i (Basis=phi)

Nat. Zahlen 1/i

(Basis=phi)

Darstellung von Zahlen in einer Basis b:

Start i:

End i: Schritt:

Basis b: nmax: nmin:

1 0 0 0 0 0 0 0 0 0 0 1 | 0 0 2 0 0 0 0 0 0 0 0 0 1 0 | 0 0 3 0 0 0 0 0 0 0 0 0 1 1 | 0 0 4 0 0 0 0 0 0 0 0 1 0 0 | 0 0 5 0 0 0 0 0 0 0 0 1 0 1 | 0 0 6 0 0 0 0 0 0 0 0 1 1 0 | 0 0 7 0 0 0 0 0 0 0 0 1 1 1 | 0 0 8 0 0 0 0 0 0 0 1 0 0 0 | 0 0 9 0 0 0 0 0 0 0 1 0 0 1 | 0 0 10 0 0 0 0 0 0 0 1 0 1 0 | 0 0 11 0 0 0 0 0 0 0 1 0 1 1 | 0 0 12 0 0 0 0 0 0 0 1 1 0 0 | 0 0 13 0 0 0 0 0 0 0 1 1 0 1 | 0 0 14 0 0 0 0 0 0 0 1 1 1 0 | 0 0 15 0 0 0 0 0 0 0 1 1 1 1 | 0 0 16 0 0 0 0 0 0 1 0 0 0 0 | 0 0 17 0 0 0 0 0 0 1 0 0 0 1 | 0 0 18 0 0 0 0 0 0 1 0 0 1 0 | 0 0 19 0 0 0 0 0 0 1 0 0 1 1 | 0 0 20 0 0 0 0 0 0 1 0 1 0 0 | 0 0

Page 280: Systemprogrammierung II (SP II,Script 2005)

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.

Page 281: Systemprogrammierung II (SP II,Script 2005)
Page 282: Systemprogrammierung II (SP II,Script 2005)

=====================Einige C-Header-Files=====================

math.h=====================abs Return absolute value of integer parameteracos Calculate arccosineasin Calculate arcsineatan Calculate arctangentatan2 Calculate arctangent, 2 parametersatof Convert string to doubleceil Return the smallest integer that is greater or equal to xcos Calculate cosinecosh Calculate hyperbolic cosineexp Calculate exponentialfabs Return absolute value of floating-pointfloor Round down valuefmod Return remainder of floating point divisionfrexp Get mantissa and exponent of floating-point valuelabs Return absolute value of long integer parameterldexp Get floating-point value from mantissa and exponentlog Calculate natural logarithmlog10 Calculate logarithm base 10modf Spli floating-point value into fractional and integer partspow Calculate numeric powersin Calculate sinesinh Calculate hyperbolic sinesqrt Calculate square roottan Calculate tangenttanh Calculate hyperbolic tangent

Page 283: Systemprogrammierung II (SP II,Script 2005)

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.

Page 284: Systemprogrammierung II (SP II,Script 2005)

remove Delete a file.rename Rename a file or directory.rewind Reposition file pointer to the beginning of a stream.scanf Read formatted data from stdin.setbuf Change stream buffering.setvbuf Change stream buffering.sprintf Format data to a string.sscanf Read formatted data from a string.tmpfile Open a temporary file.tmpnam Generate a unique temporary filename.ungetc Push a character back into stream.

Streams.Streams are an abstraction used in C and C++ for input and output operations through I/O devices based on characters, like files, keyboard, printer, screen and I/O ports.A stdio.h stream is represented by a pointer to a FILE structure that contains internal info about properties and indicators of a file. Normally data contained in these structures are not referred directly. When using stdio.h functions, pointer to FILE structures are only used to be passed as parameters to I/O functions.

Properties.A stream has some properties that defines which functions can be used with it or how the functions will treat the stream. Most of them are defined in the mode parameter when fopen function is called.

AccessSpecifies if the operations performed with the stream will have read and/or write access to the file.

Text / BinaryText files are those where lines are delimited by the special character

Page 285: Systemprogrammierung II (SP II,Script 2005)

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.

BufferA buffer is a block of memory where data is accumulated before being physically reador 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 IndicatorThis 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 byany repositioning functions (rewind, fseek and fsetpos).

End-Of-File IndicatorWhen 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

Page 286: Systemprogrammierung II (SP II,Script 2005)

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 StreamsWhen a program that includes stdio.h begin its execution, three predefined streams are opened:

stdinThis is the standard input stream. By default stdin corresponds to the keyboard, but this can be redirected by the operating system.

stdoutThis 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.

stderrThe standard error stream. This is an output stream specifically intendend to receive error messages. By default is directed to the standard output (like stdout), but it can be redirected to a log file or any other output device.

stdlib.h===============* = not ANSI-C, but supported by most compilers.

abort Abort current process returning error codeabs Return absolute value of integer parameteratexit Specifies a function to be executed at exitatof Convert string to doubleatoi Convert string to integeratol Convert string to longbsearch Binary search

Page 287: Systemprogrammierung II (SP II,Script 2005)

calloc Allocate array in memorydiv Divide two integer values* ecvt Convert floating point value to stringexit Terminate calling process* fcvt Convert floating point value to stringfree Deallocate dynamically allocated memory* gcvt Convert floating point value to stringgetenv Get string from environment* itoa Convert integer to stringlabs Return absolute calue of long integer parameterldiv Divide two long integer values* lfind Linear search* lsearch Linear search* ltoa Convert long integer value to stringmalloc Allocate memory block* max Return the greater of two parameters* min Return the smaller of two parameters* putenv Create or modify environment variableqsort Sort using quicksort algorithmrand Generate random numberrealloc Reallocate memory blocksrand Initialize random number generatorstrtod Convert string to double-precision floating-point valuestrtol Convert string to long integerstrtoul Convert string to unsigned long integer* swab Swap bytessystem 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:

Page 288: Systemprogrammierung II (SP II,Script 2005)

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 charactermemcmp Compare two buffersmemcpy Copy bytes to buffer from buffermemmove Copy bytes to buffer from buffermemset Fill buffer with specified characterstrcat Append stringstrchr Find character in stringstrcmp Compare two stringsstrcoll Compare two strings using locale settingsstrcpy Copy stringstrcspn Search string for occurrence of charcter setstrerror Get pointer to error message string

Page 289: Systemprogrammierung II (SP II,Script 2005)

strlen Return string lengthstrncat Append substring to stringstrncmp Compare some characters of two stringsstrncpy Copy characters from one string to anotherstrpbrk Scan string for specified charactersstrrchr Find last occurrence of character in stringstrspn Get length of substring composed of given charactersstrstr Find substringstrtok Sequentially truncate string if delimiter is foundstrxfrm Transform string using locale settings

time.h=====================asctime Convert tm structure to stringclock Return number of clock ticks since process startctime Convert time_t value to stringdifftime Return difference between two timesgmtime Convert time_t value to tm structure as UTC timelocaltime Convert time_t value to tm structure as local timemktime Convert tm structure to time_t valuetime Get current time

Types and constants:CLK_TCKConstant that defines the number of clock ticks per second. Used by clock function.

clock_t and time_tData types returned by clock and time functions respectivelly. They are generally defined as long int.

Page 290: Systemprogrammierung II (SP II,Script 2005)

tmStructure returned or used by asctime, gmtime, localtime and mktime.

Page 291: Systemprogrammierung II (SP II,Script 2005)

/*****************************************************************************\* ** 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 __cplusplusextern "C" { /* Assume C declarations for C++ */#endif /* __cplusplus */

/****** KERNEL Macro APIs ****************************************************/

#define GetInstanceModule(hInstance) (HMODULE)(hInstance)

#define GlobalPtrHandle(lp) \ ((HGLOBAL)GlobalHandle(lp))

#define GlobalLockPtr(lp) \ ((BOOL)GlobalLock(GlobalPtrHandle(lp)))#define GlobalUnlockPtr(lp) \ GlobalUnlock(GlobalPtrHandle(lp))

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

Page 292: Systemprogrammierung II (SP II,Script 2005)

(cbNew), (flags))))#define GlobalFreePtr(lp) \ (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))

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

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

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

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

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

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

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

Page 293: Systemprogrammierung II (SP II,Script 2005)

(HGDIOBJ)(HFONT)(hfont)))#define GetStockFont(i) ((HFONT)GetStockObject(i))

#define DeleteBitmap(hbm) DeleteObject((HGDIOBJ)(HBITMAP)(hbm))#define SelectBitmap(hdc, hbm) ((HBITMAP)SelectObject((hdc), (HGDIOBJ)(HBITMAP)(hbm)))

#define InsetRect(lprc, dx, dy) InflateRect((lprc), -(dx), -(dy))

/****** USER Macro APIs ******************************************************/

#define GetWindowInstance(hwnd) ((HMODULE)GetWindowLong(hwnd, GWL_HINSTANCE))

#define GetWindowStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_STYLE))#define GetWindowExStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_EXSTYLE))

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

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

#define GetWindowID(hwnd) GetDlgCtrlID(hwnd)

#define SetWindowRedraw(hwnd, fRedraw) \ ((void)SendMessage(hwnd, WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L))

#define SubclassWindow(hwnd, lpfn) \ ((WNDPROC)SetWindowLong((hwnd), GWL_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))

#define IsMinimized(hwnd) IsIconic(hwnd)

Page 294: Systemprogrammierung II (SP II,Script 2005)

#define IsMaximized(hwnd) IsZoomed(hwnd)#define IsRestored(hwnd) ((GetWindowStyle(hwnd) & (WS_MINIMIZE | WS_MAXIMIZE)) == 0L)

#define SetWindowFont(hwnd, hfont, fRedraw) FORWARD_WM_SETFONT((hwnd), (hfont), (fRedraw), SendMessage)

#define GetWindowFont(hwnd) FORWARD_WM_GETFONT((hwnd), SendMessage)#if (WINVER >= 0x030a)#define MapWindowRect(hwndFrom, hwndTo, lprc) \ MapWindowPoints((hwndFrom), (hwndTo), (POINT *)(lprc), 2)#endif#define IsLButtonDown() (GetKeyState(VK_LBUTTON) < 0)#define IsRButtonDown() (GetKeyState(VK_RBUTTON) < 0)#define IsMButtonDown() (GetKeyState(VK_MBUTTON) < 0)

#define SubclassDialog(hwndDlg, lpfn) \ ((DLGPROC)SetWindowLong(hwndDlg, DWL_DLGPROC, (LPARAM)(DLGPROC)(lpfn)))

#define SetDlgMsgResult(hwnd, msg, result) (( \ (msg) == WM_CTLCOLORMSGBOX || \ (msg) == WM_CTLCOLOREDIT || \ (msg) == WM_CTLCOLORLISTBOX || \ (msg) == WM_CTLCOLORBTN || \ (msg) == WM_CTLCOLORDLG || \ (msg) == WM_CTLCOLORSCROLLBAR || \ (msg) == WM_CTLCOLORSTATIC || \ (msg) == WM_COMPAREITEM || \ (msg) == WM_VKEYTOITEM || \ (msg) == WM_CHARTOITEM || \ (msg) == WM_QUERYDRAGICON || \ (msg) == WM_INITDIALOG \

Page 295: Systemprogrammierung II (SP II,Script 2005)

) ? (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) \

Page 296: Systemprogrammierung II (SP II,Script 2005)

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) \

Page 297: Systemprogrammierung II (SP II,Script 2005)

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

Page 298: Systemprogrammierung II (SP II,Script 2005)

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

Page 299: Systemprogrammierung II (SP II,Script 2005)

#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)

Page 300: Systemprogrammierung II (SP II,Script 2005)

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

Page 301: Systemprogrammierung II (SP II,Script 2005)

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

Page 302: Systemprogrammierung II (SP II,Script 2005)

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

Page 303: Systemprogrammierung II (SP II,Script 2005)

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

Page 304: Systemprogrammierung II (SP II,Script 2005)

#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)))

Page 305: Systemprogrammierung II (SP II,Script 2005)

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

Page 306: Systemprogrammierung II (SP II,Script 2005)

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

Page 307: Systemprogrammierung II (SP II,Script 2005)

#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) \

Page 308: Systemprogrammierung II (SP II,Script 2005)

(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,

Page 309: Systemprogrammierung II (SP II,Script 2005)

(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) \

Page 310: Systemprogrammierung II (SP II,Script 2005)

((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)

Page 311: Systemprogrammierung II (SP II,Script 2005)

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

Page 312: Systemprogrammierung II (SP II,Script 2005)

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

Page 313: Systemprogrammierung II (SP II,Script 2005)

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

Page 314: Systemprogrammierung II (SP II,Script 2005)

((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)

Page 315: Systemprogrammierung II (SP II,Script 2005)

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

Page 316: Systemprogrammierung II (SP II,Script 2005)

#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))

Page 317: Systemprogrammierung II (SP II,Script 2005)

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

Page 318: Systemprogrammierung II (SP II,Script 2005)

#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))

Page 319: Systemprogrammierung II (SP II,Script 2005)

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

Page 320: Systemprogrammierung II (SP II,Script 2005)

(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) \

Page 321: Systemprogrammierung II (SP II,Script 2005)

((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) \

Page 322: Systemprogrammierung II (SP II,Script 2005)

(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

Page 323: Systemprogrammierung II (SP II,Script 2005)

/* void Cls_OnDisplayChange(HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT cyScreen) */#define HANDLE_WM_DISPLAYCHANGE(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (UINT)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(wParam)), 0L)#define FORWARD_WM_DISPLAYCHANGE(hwnd, bitsPerPixel, cxScreen, cyScreen, fn) \ (void)(fn)((hwnd), WM_DISPLAYCHANGE, (WPARAM)(UINT)(bitsPerPixel), (LPARAM)MAKELPARAM((UINT)(cxScreen), (UINT)(cyScreen)))

/* BOOL Cls_OnDeviceChange(HWND hwnd, UINT uEvent, DWORD dwEventData) */#define HANDLE_WM_DEVICECHANGE(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (UINT)(wParam), (DWORD)(wParam))#define FORWARD_WM_DEVICECHANGE(hwnd, uEvent, dwEventData, fn) \ (BOOL)(DWORD)(fn)((hwnd), WM_DEVICECHANGE, (WPARAM)(UINT)(uEvent), (LPARAM)(DWORD)(dwEventData))

/* void Cls_OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos) */#define HANDLE_WM_CONTEXTMENU(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)#define FORWARD_WM_CONTEXTMENU(hwnd, hwndContext, xPos, yPos, fn) \ (void)(fn)((hwnd), WM_CONTEXTMENU, (WPARAM)(HWND)(hwndContext), MAKELPARAM((UINT)(xPos), (UINT)(yPos)))

/****** Static control message APIs ******************************************/

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

#define Static_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))#define Static_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)#define Static_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

#define Static_SetIcon(hwndCtl, hIcon)

Page 324: Systemprogrammierung II (SP II,Script 2005)

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

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

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

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

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

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

#define Button_SetStyle(hwndCtl, style, fRedraw) ((void)SendMessage((hwndCtl), BM_SETSTYLE, (WPARAM)LOWORD(style), MAKELPARAM(((fRedraw) ? TRUE : FALSE), 0)))

/****** Edit control message APIs ********************************************/

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

#define Edit_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))#define Edit_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)#define Edit_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

Page 325: Systemprogrammierung II (SP II,Script 2005)

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

#define Edit_GetLineCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINECOUNT, 0L, 0L))#define Edit_GetLine(hwndCtl, line, lpch, cchMax) ((*((int *)(lpch)) = (cchMax)), ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINE, (WPARAM)(int)(line), (LPARAM)(LPTSTR)(lpch))))

#define Edit_GetRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_GETRECT, 0L, (LPARAM)(RECT *)(lprc)))#define Edit_SetRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECT, 0L, (LPARAM)(const RECT *)(lprc)))#define Edit_SetRectNoPaint(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECTNP, 0L, (LPARAM)(const RECT *)(lprc)))

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

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

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

#define Edit_LineFromChar(hwndCtl, ich) ((int)(DWORD)SendMessage((hwndCtl),

Page 326: Systemprogrammierung II (SP II,Script 2005)

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

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

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

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

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

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

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

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

Page 327: Systemprogrammierung II (SP II,Script 2005)

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

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

#define Edit_SetWordBreakProc(hwndCtl, lpfnWordBreak) ((void)SendMessage((hwndCtl), EM_SETWORDBREAKPROC, 0L, (LPARAM)(EDITWORDBREAKPROC)(lpfnWordBreak)))#define Edit_GetWordBreakProc(hwndCtl) ((EDITWORDBREAKPROC)SendMessage((hwndCtl), EM_GETWORDBREAKPROC, 0L, 0L))#endif /* WINVER >= 0x030a */

/****** ScrollBar control message APIs ***************************************/

/* NOTE: flags parameter is a collection of ESB_* values, NOT a boolean! */#define ScrollBar_Enable(hwndCtl, flags) EnableScrollBar((hwndCtl), SB_CTL, (flags))

#define ScrollBar_Show(hwndCtl, fShow) ShowWindow((hwndCtl), (fShow) ? SW_SHOWNORMAL : SW_HIDE)

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

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

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

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

Page 328: Systemprogrammierung II (SP II,Script 2005)

(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)))

Page 329: Systemprogrammierung II (SP II,Script 2005)

#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)

Page 330: Systemprogrammierung II (SP II,Script 2005)

((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)

Page 331: Systemprogrammierung II (SP II,Script 2005)

((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMHEIGHT, (WPARAM)(int)(index), MAKELPARAM((cy), 0)))#define ListBox_GetItemHeight(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMHEIGHT, (WPARAM)(int)(index), 0L))#endif /* WINVER >= 0x030a */

#define ListBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), LB_DIR, (WPARAM)(UINT)(attrs), (LPARAM)(LPCTSTR)(lpszFileSpec)))

/****** ComboBox control message APIs ****************************************/

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

#define ComboBox_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))#define ComboBox_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)#define ComboBox_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))

#define ComboBox_LimitText(hwndCtl, cchLimit) ((int)(DWORD)SendMessage((hwndCtl), CB_LIMITTEXT, (WPARAM)(int)(cchLimit), 0L))

#define ComboBox_GetEditSel(hwndCtl) ((DWORD)SendMessage((hwndCtl), CB_GETEDITSEL, 0L, 0L))#define ComboBox_SetEditSel(hwndCtl, ichStart, ichEnd) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEDITSEL, 0L, MAKELPARAM((ichStart), (ichEnd))))

#define ComboBox_GetCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_GETCOUNT, 0L, 0L))#define ComboBox_ResetContent(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_RESETCONTENT, 0L, 0L))

#define ComboBox_AddString(hwndCtl, lpsz) ((int)(DWORD)SendMessage((hwndCtl),

Page 332: Systemprogrammierung II (SP II,Script 2005)

CB_ADDSTRING, 0L, (LPARAM)(LPCTSTR)(lpsz)))#define ComboBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpsz)))

#define ComboBox_AddItemData(hwndCtl, data) ((int)(DWORD)SendMessage((hwndCtl), CB_ADDSTRING, 0L, (LPARAM)(data)))#define ComboBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data)))

#define ComboBox_DeleteString(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_DELETESTRING, (WPARAM)(int)(index), 0L))

#define ComboBox_GetLBTextLen(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXTLEN, (WPARAM)(int)(index), 0L))#define ComboBox_GetLBText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer)))

#define ComboBox_GetItemData(hwndCtl, index) ((LRESULT)(DWORD)SendMessage((hwndCtl), CB_GETITEMDATA, (WPARAM)(int)(index), 0L))#define ComboBox_SetItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data)))

#define ComboBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCTSTR)(lpszFind)))#define ComboBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))

Page 333: Systemprogrammierung II (SP II,Script 2005)

#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),

Page 334: Systemprogrammierung II (SP II,Script 2005)

(LPARAM)(int)cyItem))

#define ComboBox_GetExtendedUI(hwndCtl) ((UINT)(DWORD)SendMessage((hwndCtl), CB_GETEXTENDEDUI, 0L, 0L))#define ComboBox_SetExtendedUI(hwndCtl, flags) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L))#endif /* WINVER >= 0x030a */

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

/* USER MESSAGES: */

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

#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))

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

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

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

Page 335: Systemprogrammierung II (SP II,Script 2005)

(WPARAM)MAKELONG(id, cmd), (LONG)(hwnd)

#define WM_CTLCOLOR 0x0019

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

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

/* Note: the following are for interpreting MDIclient to MDI child messages. */#define GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wp, lp) (lp == (LONG)hwnd)#define GET_WM_MDIACTIVATE_HWNDDEACT(wp, lp) (HWND)(wp)#define GET_WM_MDIACTIVATE_HWNDACTIVATE(wp, lp) (HWND)(lp)/* Note: the following is for sending to the MDI client window. */#define GET_WM_MDIACTIVATE_MPS(f, hwndD, hwndA)\ (WPARAM)(hwndA), 0

#define GET_WM_MDISETMENU_MPS(hmenuF, hmenuW) (WPARAM)hmenuF, (LONG)hmenuW

#define GET_WM_MENUCHAR_CHAR(wp, lp) (TCHAR)LOWORD(wp)#define GET_WM_MENUCHAR_HMENU(wp, lp) (HMENU)(lp)#define GET_WM_MENUCHAR_FMENU(wp, lp) (BOOL)HIWORD(wp)#define GET_WM_MENUCHAR_MPS(ch, hmenu, f) \ (WPARAM)MAKELONG(ch, f), (LONG)(hmenu)

Page 336: Systemprogrammierung II (SP II,Script 2005)

#define GET_WM_PARENTNOTIFY_MSG(wp, lp) LOWORD(wp)#define GET_WM_PARENTNOTIFY_ID(wp, lp) HIWORD(wp)#define GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp) (HWND)(lp)#define GET_WM_PARENTNOTIFY_X(wp, lp) (int)(short)LOWORD(lp)#define GET_WM_PARENTNOTIFY_Y(wp, lp) (int)(short)HIWORD(lp)#define GET_WM_PARENTNOTIFY_MPS(msg, id, hwnd) \ (WPARAM)MAKELONG(id, msg), (LONG)(hwnd)#define GET_WM_PARENTNOTIFY2_MPS(msg, x, y) \ (WPARAM)MAKELONG(0, msg), MAKELONG(x, y)

#define GET_WM_VKEYTOITEM_CODE(wp, lp) (int)(short)LOWORD(wp)#define GET_WM_VKEYTOITEM_ITEM(wp, lp) HIWORD(wp)#define GET_WM_VKEYTOITEM_HWND(wp, lp) (HWND)(lp)#define GET_WM_VKEYTOITEM_MPS(code, item, hwnd) \ (WPARAM)MAKELONG(item, code), (LONG)(hwnd)

#define GET_EM_SETSEL_START(wp, lp) (INT)(wp)#define GET_EM_SETSEL_END(wp, lp) (lp)#define GET_EM_SETSEL_MPS(iStart, iEnd) \ (WPARAM)(iStart), (LONG)(iEnd)

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

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

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

Page 337: Systemprogrammierung II (SP II,Script 2005)

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

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

#define _ncalloc calloc#define _nexpand _expand#define _ffree free#define _fmalloc malloc#define _fmemccpy _memccpy#define _fmemchr memchr#define _fmemcmp memcmp#define _fmemcpy memcpy#define _fmemicmp _memicmp#define _fmemmove memmove#define _fmemset memset#define _fmsize _msize#define _frealloc realloc#define _fstrcat strcat#define _fstrchr strchr#define _fstrcmp strcmp#define _fstrcpy strcpy#define _fstrcspn strcspn#define _fstrdup _strdup#define _fstricmp _stricmp#define _fstrlen strlen#define _fstrlwr _strlwr#define _fstrncat strncat#define _fstrncmp strncmp#define _fstrncpy strncpy

Page 338: Systemprogrammierung II (SP II,Script 2005)

#define _fstrnicmp _strnicmp#define _fstrnset _strnset#define _fstrpbrk strpbrk#define _fstrrchr strrchr#define _fstrrev _strrev#define _fstrset _strset#define _fstrspn strspn#define _fstrstr strstr#define _fstrtok strtok#define _fstrupr _strupr#define _nfree free#define _nmalloc malloc#define _nmsize _msize#define _nrealloc realloc#define _nstrdup _strdup#define hmemcpy MoveMemory

#define DECLARE_HANDLE32 DECLARE_HANDLE

#ifdef __cplusplus} /* End of extern "C" { */#endif /* __cplusplus */

#endif /* !_INC_WINDOWSX */

Page 339: Systemprogrammierung II (SP II,Script 2005)
Page 340: Systemprogrammierung II (SP II,Script 2005)

============================================= ACHTUNG! Nicht lauffähig! Nur Pseudo Code!=============================================

LRESULT API IDefWindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { int i; HBRUSH hbr; HWND hWndT;

switch ( iMsg ) { case WM_NCCREATE: // If WS_HSCROLL or WS_VSCROLL, initialize storage for scroll positions. // NOTE: Scroll bar storage and text storage will be freed automatically //by Windows during CreateWindow() if (TestWF(hWnd, (WFHSCROLL | WFVSCROLL))) { // Initialize extra storage for if (InitPwSB(hWnd) == NULL) return((LONG)FALSE); } // Store window text if present. return((LRESULT)(LONG)DefSetText(hWnd, ((LPCREATESTRUCT)lParam)->lpszName));

case WM_NCCALCSIZE: // wParam = fCalcValidRects // lParam = LPRECT rgrc[3]: // lprc[0] = rcWindowNew = New window rectangle // if fCalcValidRects: // lprc[1] = rcWindowOld = Old window rectangle // lprc[2] = rcClientOld = Old client rectangle // On return: // rgrc[0] = rcClientNew = New client rect // if fCalcValidRects: // rgrc[1] = rcValidDst = Destination valid rectangle // rgrc[2] = rcValidSrc = Source valid rectangle

Page 341: Systemprogrammierung II (SP II,Script 2005)

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.

Page 342: Systemprogrammierung II (SP II,Script 2005)

((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;

Page 343: Systemprogrammierung II (SP II,Script 2005)

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.

Page 344: Systemprogrammierung II (SP II,Script 2005)

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

Page 345: Systemprogrammierung II (SP II,Script 2005)

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

Page 346: Systemprogrammierung II (SP II,Script 2005)

// // Go ahead and hide or show this window, but only if: // // a) we need to be hidden, or // b) we need to be shown, and we were hidden by // an earlier WM_SHOWWINDOW message if ((!wParam && TestWF(hWnd, WFVISIBLE)) || (wParam && !TestWF(hWnd, WFVISIBLE) && TestWF(hWnd, WFHIDDENPOPUP))) { // Remember that we were hidden by WM_SHOWWINDOW processing ClrWF(hWnd, WFHIDDENPOPUP); if (!wParam) SetWF(hWnd, WFHIDDENPOPUP); ShowWindow(hWnd, (wParam ? SW_SHOWNOACTIVATE : SW_HIDE)); } } break;

case WM_NCLBUTTONDOWN: case WM_NCLBUTTONUP: case WM_NCLBUTTONDBLCLK: case WM_NCMOUSEMOVE: // Deal with mouse messages in the non-client area. DWP_NCMouse(hWnd, message, wParam, lParam); break;

case WM_KEYDOWN: // Windows 2.0 backward compatibility: // Alias F10 to the menu key // (only for apps that don't handle WM_KEY* messages themselves) if ((WORD)wParam == VK_F10) fF10Status = TRUE; break;

Page 347: Systemprogrammierung II (SP II,Script 2005)

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) ) {

Page 348: Systemprogrammierung II (SP II,Script 2005)

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;

Page 349: Systemprogrammierung II (SP II,Script 2005)

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));

Page 350: Systemprogrammierung II (SP II,Script 2005)

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);}

Page 351: Systemprogrammierung II (SP II,Script 2005)

| 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

↑ NachrichtenWindows 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 Applikation-

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

KEY-BOARD

(Ereignis)

Keyboard-Device-Driver

holt Scan-Codevom

Keyboard und stellt

diesen in

SYSTEM-MESSAGE-

QUEUE(geräte-

spezifisch)

Windows bringt

die geräte-spezifische

Nachricht aufstandardisierte

MSG-Form (WM_...),

stellt diese in

APPLICATION-MESSAGE-

QUEUE(Thread-

Message-Queue)(MSG: WM_...)

APPLICATION-NACHRICHTEN-

Schleife

DispatchMessage(&msg)

ruft die CALLBACK-Funktion auf,die zumsg.hWingehö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

Page 352: Systemprogrammierung II (SP II,Script 2005)

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:

Page 353: Systemprogrammierung II (SP II,Script 2005)

WM_KEYDOWN: lParam :

↑ Tabelle der Nachrichten-PrefixePrefix Message category

ABM Application desktop toolbar

BM Button control

CB Combo box control

CBEM Extended combo box control

CDM Common dialog box

DBT Device

DL Drag list box

DM Default push button control

DTM Date and time picker control

EM Edit control

Prefix Message category

HDM Header control

HKM Hot key control

IPM IP address control

LB List box control

LVM List view control

MCM Month calendar control

ABM Application desktop toolbar

PBM Progress bar

PGM Pager control

PSM Property sheet

RB Rebar control

Prefix Message category

SB Status bar window

ABM Application desktop toolbar

SBM Scroll bar control

STM Static control

TB Toolbar

TBM Trackbar

TCM Tab control

TTM Tooltip control

TVM Tree-view control

UDM Up-down 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.

Page 354: Systemprogrammierung II (SP II,Script 2005)

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

Page 355: Systemprogrammierung II (SP II,Script 2005)

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

Page 356: Systemprogrammierung II (SP II,Script 2005)

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

Page 357: Systemprogrammierung II (SP II,Script 2005)

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

Page 358: Systemprogrammierung II (SP II,Script 2005)

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 .codePUBLIC key_readkey_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 RETkey_read ENDP END

↑ Tasten - Scan - Code

Der folgende Tasten - Scan - Code ist festgelegt worden:

Page 359: Systemprogrammierung II (SP II,Script 2005)
Page 360: Systemprogrammierung II (SP II,Script 2005)
Page 361: Systemprogrammierung II (SP II,Script 2005)

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:

Page 362: Systemprogrammierung II (SP II,Script 2005)

Tasten-Nachricht

wParam, lParam enthalten ...

WM_ACTIVATE

fActive = LOWORD(wParam); // activation flagfMinimized = (BOOL) HIWORD(wParam); // minimized flaghwndPrevious = (HWND) lParam; // window handle

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

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

WM_KEYDOWNWM_KEYUP

nVirtKey = (int) wParam; // virtual-key codelKeyData = lParam; // key data

WM_CHARWM_SYSCHAR

chCharCode = (TCHAR) wParam; // character codelKeyData = lParam; // key data

WM_HOTKEY

idHotKey = (int) wParam; // identifier of hot keyfuModifiers = (UINT) LOWORD(lParam); // key-modifier flagsuVirtKey = (UINT) HIWORD(lParam); // virtual-key code

Tasten-Nachricht

wParam, lParam enthalten ...

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

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

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

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

WM_SYSKEYDOWNWM_SYSKEYUP

nVirtKey = (int) wParam; // virtual-key codelKeyData = 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 )

Page 363: Systemprogrammierung II (SP II,Script 2005)

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) ) {

Page 364: Systemprogrammierung II (SP II,Script 2005)

... case VK_RETURN: if ( lParam & 0x01000000L ) { // Enter-Taste ( numeric keypad ) } else { // Enter-Taste ( standard keypad ) } break ; } ... } ... } ... }

↑ Tabelle der Virtual - Tasten - Codes

Bei einer WM_KEYDOWN - Nachricht wird in LOWORD(wParam) der ( standardisierte ) Virtual - Key - Code übergeben. Die folgende Tabelle enthält die #define`s.

VK_LBUTTON = 0x01 VK_RBUTTON = 0x02 VK_CANCEL = 0x03 VK_MBUTTON = 0x04 VK_BACK = 0x08 VK_TAB = 0x09

VK_CLEAR = 0x0C VK_RETURN = 0x0D VK_SHIFT = 0x10 VK_CONTROL = 0x11 VK_MENU = 0x12 VK_PAUSE = 0x13

VK_CAPITAL = 0x14 VK_ESCAPE = 0x1B VK_SPACE = 0x20 VK_PRIOR = 0x21 VK_NEXT = 0x22 VK_END = 0x23

VK_HOME = 0x24 VK_LEFT = 0x25 VK_UP = 0x26 VK_RIGHT = 0x27 VK_DOWN = 0x28 VK_SELECT = 0x29

VK_PRINT = 0x2A VK_EXECUTE = 0x2B VK_SNAPSHOT = 0x2C VK_INSERT= 0x2D

VK_DELETE = 0x2E VK_HELP = 0x2F

VK_0..VK_9

= 0x30...0x39

VK_A..VK_Z

= 0x41..0x5A

VK_LWIN = 0x5B VK_RWIN = 0x5C VK_APPS = 0x5D VK_NUMPAD0 = 0x60

VK_NUMPAD1 = 0x61 VK_NUMPAD2 = 0x62 VK_NUMPAD3 = 0x63 VK_NUMPAD4 = 0x64 VK_NUMPAD5 = 0x65 VK_NUMPAD6 = 0x66

VK_NUMPAD7 = 0x67 VK_NUMPAD8 = 0x68 VK_NUMPAD9 = 0x69 VK_MULTIPLY= 0x6A

VK_ADD = 0x6B VK_SEPARATOR = 0x6C

VK_SUBTRACT = 0x6D VK_DECIMAL = 0x6E VK_DIVIDE = 0x6F VK_F1 = 0x70 VK_F2 = 0x71 VK_F3 = 0x72

VK_F4 = 0x73 VK_F5 = 0x74 VK_F6 = 0x75 VK_F7 = 0x76 VK_F8 = 0x77 VK_F9 = 0x78

VK_F10 = 0x79 VK_F11 = 0x7A VK_F12 = 0x7B VK_F13 = 0x7C VK_F14 = 0x7D VK_F15 = 0x7E

VK_F16 = 0x7F VK_F17 = 0x80 VK_F18 = 0x81 VK_F19 = 0x82 VK_F20 = 0x83 VK_F21 = 0x84

VK_F22 = 0x85 VK_F23 = 0x86 VK_F24 = 0x87 VK_NUMLOCK = 0x90 VK_SCROLL = 0x91 VK_LSHIFT= 0xA0

VK_RSHIFT = 0xA1 VK_LCONTROL = 0xA2 VK_RCONTROL= 0xA3

VK_LMENU= 0xA4

VK_RMENU = 0xA5VK_PROCESSKEYWINVER<=0x0400

= 0xE5

Page 365: Systemprogrammierung II (SP II,Script 2005)

VK_ATTN = 0xF6 VK_CRSEL = 0xF7 VK_EXSEL = 0xF8 VK_EREOF = 0xF9 VK_PLAY= 0xFA

VK_ZOOM= 0xFB

VK_NONAME = 0xFC VK_PA1 = 0xFD VK_OEM_CLEAR = 0xFE

Z.B. wird durch die Alt - Taste die wParam = VK_MENU - Nachricht generiert.

VK_L... bzw. VK_R... gehören zu der linken bzw. rechten Alt - , Ctrl - und Shift - Tasten und werden nur als Parameter bei den GetAsyncKeyState(), GetKeyState() -

Funktionen benutzt.

↑ Tasten - Zustand - Flags

Der aktuelle Zustand aller Tasten wird in einem Buffer protokolliert. Auch die Applikation kann diese Einträge lesen/schreiben, wobei zwischen synchron/asynchron

unterschieden wird. Wird eine neue Tasten - Nachricht in den Applikations - Nachrichten - Warteschlange ( Applikations - Buffer ) eingetragen, so ändert sich der

asynchron Keyboard - Zustand. Der synchron Keyboard - Zustand entspricht dem momentanen Zustand der Tastatur.

↑ Wie kann eine gedrücke SHIFT - Taste abgefragt werden?

if ( GetKeyState ( VK_SHIFT ) & 0x80000000L ) { // SHIFT - Taste gedrückt }

GetKeyState() ( imGegensatz zu GetAsyncKeyState ) liefert den Zustand ohne Verzögerung zurück. Durch GetKeyState ( VK_LBUTTON ) wird z.B. der aktuelle

Zustand der linken Maustaste abgefragt.

↑ Wie kann eine Berechnung abgebrochen werden?

Dauert z.B. eine Berechnung zu lange und soll diese Berechnung durch

● die Escape - Taste oder

● die linke Maus - Taste

abgebrochen werden, so kann dies mit der ( asynchronen ) GetAsyncKeyState() - Funktion

if ( ( GetAsyncKeyState ( VK_LBUTTON ) < 0 ) // linke Maus - Taste down || ( GetAsyncKeyState ( VK_ESCAPE ) < 0 ) // Escape Taste ) {

Page 366: Systemprogrammierung II (SP II,Script 2005)

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

Page 367: Systemprogrammierung II (SP II,Script 2005)

↑ Wie kann ein "floating-pop-up-menu"nach der Anzeige sichtbar bleiben?

case WM_RBUTTONDOWN: { BYTE buf[256]; GetKeyboardState( buf ); // hole VK_ - Keys buf[VK_RBUTTON] = 0x00; // setze "losgelassen" bei VK_RBUTTON - Maus - Taste SetKeyboardState( buf ); // schreibe VK_ - Keys zurück ... create - pop - up - Menu ... ... call TrackPopUp ... break; }

↑ lParam - Tastenflags

TranslateMessage() benutzt die Funktion ToAsciiEx() um den virtuellen Key - Code ( z.B. für die WM_KEYDOWN - Nachricht ) zu erzeugen. Eine Nachricht enthält

in LOWORD( lParam ) die Anzahl von automatischen Tasten - Wiederholungen. Durch diesen Anschlag - Wiederholungs - Zähler werden Überflutungen von

Nachrichten vermieden.

In HIWORD( lParam ) sind interessante Tasten - Flags, die im folgenden erklärt werden. Eine Nachricht enthält in HIWORD( lParam ) interessante Tasten - Flags, die

im folgenden erklärt werden.

Bit HIWORD( lParam ) - Bit Bit HIWORD( lParam ) - Bit Bit HIWORD( lParam ) - Bit Bit HIWORD( lParam ) - Bit

151 if the key is up;0 if the key is down.

141 if the key was previously up;0 if the key was previously down.

13 1 if the ALT key is down. 12 1 if Windows displays a menu.

Page 368: Systemprogrammierung II (SP II,Script 2005)

11 1 if Windows displays a dialog box. 10 Not used. 9 Not used. 81 if the key is extended;0 if it is not.

7 generally 0. 6..0hardware-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 ) ;

Page 369: Systemprogrammierung II (SP II,Script 2005)

}

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_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_RBUTTONDOWNWM_RBUTTONUPWM_MBUTTONDOWNWM_MBUTTONUPWM_LBUTTONDBLCLKWM_MBUTTONDBLCLKWM_RBUTTONDBLCLK

fwKeys = wParam; // key flagsxPos = LOWORD(lParam); // horizontal position of cursoryPos = 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 parentnHittest = (INT) LOWORD(lParam); // hit-test valueuMsg = (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

Page 370: Systemprogrammierung II (SP II,Script 2005)

WM_MOUSEWHEEL fwKeys = LOWORD(wParam); // key flagszDelta = (short) HIWORD(wParam); // wheel rotationxPos = (short) LOWORD(lParam); // horizontal position of pointeryPos = (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 cursoryPos = 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 borderHTBOTTOM In the lower horizontal border of a windowHTBOTTOMLEFT In the lower-left corner of a window borderHTBOTTOMRIGHT In the lower-right corner of a window borderHTCAPTION In a title barHTCLIENT In a client areaHTCLOSE 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 buttonHTHSCROLL In a horizontal scroll barHTLEFT In the left border of a windowHTMENU In a menuHTMAXBUTTON In Maximize buttonHTMINBUTTON In Minimize buttonHTNOWHERE On the screen background or on a dividing line between windowsHTREDUCE In a Minimize buttonHTRIGHT In the right border of a windowHTSIZE In a size box (same as HTGROWBOX)HTSYSMENU In a System menu or in a Close button in a child windowHTTOP In the upper horizontal border of a windowHTTOPLEFT In the upper-left corner of a window borderHTTOPRIGHT In the upper right corner of a window borderHTTRANSPARENT In a window currently covered by another windowHTVSCROLL In the vertical scroll bar

Page 371: Systemprogrammierung II (SP II,Script 2005)

HTZOOM In a Maximize button

WM_NCLBUTTONDBLCLKWM_NCLBUTTONDBLCLKWM_NCLBUTTONDOWNWM_NCLBUTTONUPWM_NCMBUTTONDBLCLKWM_NCMBUTTONDOWNWM_NCMBUTTONUPWM_NCMOUSEMOVEWM_NCRBUTTONDBLCLKWM_NCRBUTTONDOWNWM_NCRBUTTONUP

nHittest = (INT) wParam; // hit-test valuepts = MAKEPOINTS(lParam); // position of cursor nHittest see WM_NCHITTEST

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

Page 372: Systemprogrammierung II (SP II,Script 2005)

#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++).

Page 373: Systemprogrammierung II (SP II,Script 2005)

============================================= 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));

Page 374: Systemprogrammierung II (SP II,Script 2005)

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

Page 375: Systemprogrammierung II (SP II,Script 2005)

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

Page 376: Systemprogrammierung II (SP II,Script 2005)

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

Page 377: Systemprogrammierung II (SP II,Script 2005)

} } 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;

Page 378: Systemprogrammierung II (SP II,Script 2005)

// 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);}

Page 379: Systemprogrammierung II (SP II,Script 2005)

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);}

Page 380: Systemprogrammierung II (SP II,Script 2005)

| 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()

↑ ObjekteWindows-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 table

CreateAcceleratorTable DestroyAcceleratorTable Cursor CreateCursor

LoadCursor, GetCursor, SetCursor

DestroyCursor

DDE conver-sation

DdeConnect, DdeConnectList, DdeQueryNextServer, DdeReconnect

DdeDisconnect, DdeDisconnectList

Desktop GetThreadDesktop Applications cannot delete this object.

Page 381: Systemprogrammierung II (SP II,Script 2005)

Hook SetWindowsHook, SetWindowsHookEx

UnhookWindowsHook,UnhookWindowsHookEx

Menu CreateMenu, CreatePopupMenu, GetMenu, GetSubMenu, GetSystemMenu,LoadMenu, LoadMenuIndirect

DestroyMenu

Window CreateWindow, CreateWindowEx, CreateDialogParam, CreateDialogIndirectParam, CreateMDIWindow, FindWindow, GetWindow, GetClipboardOwner, GetDesktopWindow, GetDlgItem, GetForegroundWindow, GetLastActivePopup, GetOpenClipboardWindow, GetTopWindow, WindowFromDC, WindowFromPoint, and others

DestroyWindow Window position

BeginDeferWindowPos EndDeferWindowPos

Window station

GetProcessWindowStation Applications cannotdelete this object.

↑ Lebensdauer von Objekten

Applikationen können Objekte erzeugen und verwenden. Objekte entsprechen Instanzen ( Bitmuster im Speicher ). Ein Objekt kann auch von

mehreren Applikationen benutzt werden ( shared ). Das Betriessystem erzeugt und nutzt ( Stock - ) Objekte, die von Applikationen ( ohne

Freigabe ) genutzt werden können.

Typ Gebunden durch Sichtbarkeit Lebensdauer Overhead

Page 382: Systemprogrammierung II (SP II,Script 2005)

Automatic Compiler Funktion Funktion 0 (Stackwort)

Static Linker( Lader )

Programm, Block Programm 0 (Allignment)

Heap Systemallokiert

Programm, Block( System bei shared )

Programm, Blockbis 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, Blockbis zur Freigabe( System bei stock )

ca. 30-50 Byte

User Objekte Linker Programm, Block Programm, Blockbis 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 16-

bit C Run-time. Im folgenden werden statische C-run-time Funktionen und dynamischen Win32-Funktionen gegenüber gestellt.

String Manipulation C-Run-time Win32 C-Run-time Win32 C-Run-time Win32

strcat, wcscat lstrcat strchr, wcschr none strcmp, wcscmp lstrcmp

strcpy, wcscpy lstrcpy strcspn, wcscspn none _strdup, _wcsdup none

strerror FormatMessage _strerror FormatMessage _stricmp, _wcsicmp lstrcmpi

Page 383: Systemprogrammierung II (SP II,Script 2005)

strlen, wcslen lstrlen _strlwr, _wcslwrCharLower,CharLowerBuffer

strncat, wcsncat none

strncmp, wcsncmp none strncpy, wcsncpy none _strnicmp, _wcsnicmp none

_strnset, _wcsnsetFillMemory,ZeroMemory

strpbrk, wcspbrk none strrchr, wcsrchr none

_strrev, _wcsrev none _strset, _wcssetFillMemory,ZeroMemory

strspn, wcsspn none

strstr, wcsstr none strtok, wcstok none _strupr, _wcsuprCharUpper,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

_memicmp none memmove MoveMemory memsetFillMemory,ZeroMemory

_swab none

Character Classification C-Run-

timeWin32 C-Run-time Win32

C-Run-time

Win32C-Run-

timeWin32

isalnum IsCharAlphaNumeric isalphaIsCharAlpha,GetStringTypeW (Unicode)

__isascii none iscntrlnone,GetStringTypeW (Unicode)

__iscsym none __iscsymf none isdigitnone,GetStringTypeW (Unicode)

isgraph none

islowerIsCharLower,GetStringTypeW (Unicode)

isprint none ispunctnone,GetStringTypeW (Unicode)

isspacenone,GetStringTypeW (Unicode)

isupperIsCharUpper,GetStringTypeW (Unicode)

isxdigitnone,GetStringTypeW (Unicode)

__toascii none tolower CharLower

Page 384: Systemprogrammierung II (SP II,Script 2005)

_tolower none toupper CharUpper _toupper none

Directory Control C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32_chdir SetCurrentDirectory _chdrive SetCurrentDirectory _getcwd GetCurrentDirectory _getdrive GetCurrentDirectory

_mkdir CreateDirectory _rmdir RemoveDirectory _searchenv SearchPath

File Handling C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32_access none _chmod SetFileAttributes _chsize SetEndOfFile _filelength GetFileSize

_fstat See Note 5 _fullpath GetFullPathName _get_osfhandle none _isatty GetFileType

_locking LockFileEx _makepath none _mktemp GetTempFileName _open_osfhandle none

remove DeleteFile rename MoveFile _setmode none _splitpath none

_stat none _umask none _unlink DeleteFile

Creating Text Output Routines C-Run-time Win32 C-Run-time Win32

_displaycursor* SetConsoleCursorInfo _gettextcolor* GetConsoleScreenBufferInfo

_gettextcursor* GetConsoleCursorInfo _gettextposition* GetConsoleScreenBufferInfo

_gettextwindow* GetConsoleWindowInfo _outtext* WriteConsole

_scrolltextwindow* ScrollConsoleScreenBuffer _settextcolor* SetConsoleTextAttribute

_settextcursor* SetConsoleCursorInfo _settextposition* SetConsoleCursorPosition

_settextwindow* SetConsoleWindowInfo _wrapon* SetConsoleMode

Stream Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32clearerr none fclose CloseHandle _fcloseall none _fdopen none

feof none ferror none fflush FlushFileBuffers fgetc none

_fgetchar none fgetpos none fgets none _fileno none

Page 385: Systemprogrammierung II (SP II,Script 2005)

_flushall none fopen CreateFile fprintf none fputc none

_fputchar none fputs none fread ReadFilefreopen(std handles)

SetStdHandle

fscanf none fseek SetFilePointer fsetpos SetFilePointer _fsopen CreateFile

ftellSetFilePointer(check return value)

fwrite WriteFile getc none getchar none

gets none _getw none printf none putc none

putchar none puts none _putw none rewind SetFilePointer

_rmtmp none scanf none setbuf none setvbuf none

_snprintf none sprintf wsprintf sscanf none _tempnam GetTempFileName

tmpfile none tmpnam GetTempFileName ungetc none vfprintf none

vprintf none _vsnprintf none vsprintf wvsprintf

Low-Level I/O C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32_close _lclose, CloseHandle _commit FlushFileBuffers _creat _lcreat, CreateFile _dup DuplicateHandle

_dup2 none _eof none _lseek _llseek, SetFilePointer _open _lopen, CreateFile

_read _lread, ReadFile _sopen CreateFile _tellSetFilePointer(check return value)

_write _lread

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

Page 386: Systemprogrammierung II (SP II,Script 2005)

C-Run-time Win32 C-Run-time Win32C-Run-

timeWin32 C-Run-time Win32

_alloca none _bfreeseg* none _bheapseg* none calloc GlobalAlloc

_expand none free GlobalFree _freect* GlobalMemoryStatus _halloc* GlobalAlloc

_heapadd none _heapchk none _heapmin none _heapset none

_heapwalk none _hfree* GlobalFree malloc GlobalAlloc _memavl GlobalMemoryStatus

_memmax GlobalMemoryStatus _msize* GlobalSize realloc GlobalReAlloc _set_new_handler none

_set_hnew_handler* none _stackavail* none

Process and Environment Control Routines C-Run-time Win32 C-Run-time Win32 C-Run-time Win32 C-Run-time Win32abort none assert none atexit none _cexit none

_c_exit none _exec functions none exit ExitProcess _exit ExitProcess

Page 387: Systemprogrammierung II (SP II,Script 2005)

getenv GetEnvironmentVariable _getpid GetCurrentProcessId longjmp none _onexit none

perror FormatMessage _putenv SetEnvironmentVariable raise RaiseException setjmp none

signal(ctrl-c only)

SetConsoleCtrlHandler _spawn functions CreateProcess system CreateProcess

↑ Klassen - Objekte

↑ Fenster - Objekte

Alle existierenden Fenster-Objekte können in einer Schleife durchlaufen werden. Im folgenden Beispiel wird von einem existierenden hWnd-

Fenster gestartet und das erste Fensterhandle mit GetWindow( hWnd, GW_HWNDFIRST ) geholt. Die verkettete Liste endet mit hNext ==

NULL.

↑ Beispiel CreateWindow(), DestroyWindow()Eine Applikation führe z.B. CreateWindow() aus. CreateWindow() erzeugt im Speicher ein Window - Objekt und lieferte ein gültiges Handle.

Nach dem Create... kann das Objekt verwendet werden. Durch DestroyWindow() wird das Objekt vernichtet. Der reservierten Speicher wird frei

gegeben. Das Fenster - Handle wird ungültig und darf nicht mehr verwendet werden.

Page 388: Systemprogrammierung II (SP II,Script 2005)

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 }

Page 389: Systemprogrammierung II (SP II,Script 2005)

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, Win32!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ; EndPaint ( hWnd, & ps ) ; break ; //return 0;

benutzt. Die Aktualisierung findet im Client - Bereich statt. Durch GetWindowDC() oder GetDCEx() mit DCX_WINDOW kann der Device -

Kontext für das gesamte Fenster ( incl. not Client - Bereich mit (0,0) oben links, clipping region ) erhalten werden. Nach der Benutzung ist

dieser Device - Kontext durch ReleaseD() wieder frei zu geben.

Ist der Device - Kontext bekannt, so kann durch hWnd WindowFromDC( HDC hDC ); das Fenster - Handle ermittelt werden.

↑ Funktionen zum Zeichnen MoveToEx(), LineTo(), Polyline()

Unter WM_PAINT wird mit MoveToEx(), LineTo() eine x - Achse gezeichnet. Die y - Werte von POINT pt [NUM] - Array werden mit den sin()

- Werten gefüllt. Mit Polyline() wird die Folge von Punkten gezeichnet.

Page 390: Systemprogrammierung II (SP II,Script 2005)

#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 ) {

Page 391: Systemprogrammierung II (SP II,Script 2005)

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 012345678901234TextOut( 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 );

Page 392: Systemprogrammierung II (SP II,Script 2005)

TextOut( hDC, 50, 175, "4.Zeile", 7 );TextOut( hDC, 50, 200, "5.Zeile", 7 );TextOut( hDC, 50, 225, "6.Zeile", 7 );TextOut( hDC, 50, 250, "7.Zeile", 7 );TextOut( hDC, 50, 275, "8.Zeile", 7 );TextOut( hDC, 50, 300, "9.Zeile", 7 );EndPaint ( hWnd , & ps ) ; break;

↑ Beispiel: DrawText()

Die DrawText() - Funktion benutzt den Device Kontext hDC, der u.a. den ausgewählten Font, die Text - Farbe und die Text - Hintergrund -

Farbe enthält.

● Die DrawText() - Funktion schreibt einen String *lpString in ein umschließendes Rechteck *lpRect.

Falls die Anzahl der auszugebenden Zeichen nCount = -1 ist, so muß *lpRect ein 0 terminierter String sein. Der Text kann gemäß expandierender

Tabs, der Ausrichtung ( Linksbündig, Rechtsbündig, Zentriert ), der Umbrüche am Zeilenrand, usw. justiert werden. Diese Funktion verwendet

intern TextOut(). Die DrawText() gibt die Höhe des Textes zurück.

int DrawText( HDC hDC, // handle to device context LPCTSTR lpString, // pointer to string to draw int nCount, // string length, in characters LPRECT lpRect, // pointer to struct with formatting dimensions UINT uFormat // text-drawing flags );

Für uFormat können die Konstanten

DT_BOTTOM, DT_CALCRECT, DT_CENTER, DT_EDITCONTROL, DT_END_ELLIPSIS oder DT_PATH_ELLIPSIS, DT_EXPANDTABS, DT_EXTERNALLEADING,

Page 393: Systemprogrammierung II (SP II,Script 2005)

DT_INTERNAL, DT_LEFT, DT_MODIFYSTRING, DT_NOCLIP, DT_NOPREFIX, DT_RIGHT, DT_RTLREADING, DT_SINGLELINE, DT_TABSTOP, DT_TOP, DT_VCENTER, DT_WORDBREAK, DT_WORD_ELLIPSIS

benutzt werden. Für eine bequemere Benutzung können die benötigten uFormat - FLags unter einer Zahl < -1 angesprochen werden. Die folgende

Funktion int Draw_Text( ) setzt für uFormat = -1, bzw. 0 die gewünschten uFormat - FLags. Falls ( y1 >= y2 ) ist, so wird DrawText() benutzt,

um mit DT_CALCRECT die benötigte Rechteckgröße zu ermitteln.

int Draw_Text ( HDC hDC, //Handle für den Device Kontext LPCTSTR lpString , //auszugebender String int nCount , //falls nCount <= 0 ist, so muss ein \0-String vorliegen und //es wird dann automatisch strlen ( lpString ) benutzt LPRECT lpRect , //umschließendes Recheck int uFormat // Window DrawText-Format, wie z.B. // ( DT_CENTER / DT_LEFT / DT_RIGHT ) // ( DT_VCENTER / DT_TOP / DT_BOTTOM ) ) { RECT rcText; UINT Fmt ; int dx , dy ; if ( ( lpString == NULL ) || ( hDC == NULL ) ) return 0 ; if ( lpRect != NULL ) { rcText = * lpRect ; } else { HWND hWnd = WindowFromDC( hDC ); GetClientRect( hWnd , & rcText ); } if ( uFormat < 0 ) { // DEFAULT Fmt = DT_EXTERNALLEADING | DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_NOPREFIX | DT_WORDBREAK ; } else if ( uFormat == 0 ) { Fmt = DT_EXTERNALLEADING | DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ; } else { Fmt = uFormat ; }

Page 394: Systemprogrammierung II (SP II,Script 2005)

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 ) ;}

Page 395: Systemprogrammierung II (SP II,Script 2005)

| 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

↑ ResourcenUm einen ausführbaren, binär - File ( *.EXE ) zu erzeugen, müssen ASCII - Files in Maschinen-Code übersetzt werden:

*.C, *.CPP ===> Compiler ===> *.OBJ *.H, *.RC ===> Resourcen-Compiler ===> *.RES *.OBJ, *.DEF ===> Linker ===> (*.EXE) (*.EXE), *.RES ===> Resourcen-Compiler ===> *.EXE

Die *.RC - Resourcen - Files ( ASCII ) enthalten z.B.

● Filenamen für Bilder ( Mauszeiger, Rasterbilder, Icons ),

● Text - und Hotkey - Tabellen,

● Menu - und Dialog - Beschreibungen.

Die *.RC - Resourcen - Files ( ASCII ) können "von Hand" geschrieben werden, aber vielfach ist die "visuelle Erstellung" mit einem Tool ( Resourcen Workshop ) bequemer. Das Tool

benutzt einen binäre Hilfsfiles und generiert automatisch den *.RC - ASCII - File und den zugehörigen *.H-File für die Identifizierer. Die *.RC - Syntax wird bei der automatsichen

Generierung berücksichtigt und braucht nicht gelernt werden. Durch den Resourcen-Compiler wird der *.RC - File in einen binären *.RES - File übersetzt.

Eine "visuelle Erstellung" ändert, ergänzt und überschreibt den alten *.RC - ASCII - File automatisch. Eine *.RC - Erstellung sollte entweder "von Hand" oder durchgängig "visuelle" mit

einem Tool erstellt werden.

Weil im *.RC - File auch WS_ - , DS_ -, SS_ - Windows - Konstanten benutzt werden, so ist deren Bedeutung bei der Erzeugung von Dialog-Rssourcen ( trotz Automatik ) zu kennen.

↑ *.RC-Syntax

Die *.RC - ASCII - Datei wird mit dem Resourcen-Compiler in eine *.RES - Binärdatei übersetzt. Der allgemeiner Aufbau einer *.RC Zeile ist:

ID - Identität RC-Typ Speicheroperationen Datenquelle auch BEGIN ... END

Die Speicher - Operationen PRELOAD ( nur Win16: mit *.exe geladen), LOADONCALL ( nur Win16: bei Ausführung geladen), FIXED ( nur Win16: Resource bleibt an fester Adresse ),

MOVEABLE ( nur Win16: Resource kann verschoben werden ), DISCARDABLE ( nur Win16: Resource kann entfernt werden ).

Page 396: Systemprogrammierung II (SP II,Script 2005)

Im C/C++ - Programm wird mit der ID - Identität ( identifizierende Zahl ) auf die Resource zugegriffen. Die Resourcen entsprechen einer Aufzählung von benötigten, lesbaren Daten.

Deshalb ist im *.RC-File die Reihenfolge der Resourcen nicht wesentlich.

Für Dialoge werden Control Parameter ( wie z.B. PUSHBUTTON or CHECKBOX ) verwendet. Die Breite cx wird in 1/4-character units angegeben. Die Höhe cy wird in 1/8-character

units angegeben. Controls ( innerhalb eines Rssourcen-Templates ) haben die Syntax:

Control-Typ [text,] id, x, y, cx, cy [, style [, extended-style]]

Diese CONTOLS gehören zu einer ( in Windows enthaltenen ) Klasse, wie z:b: "BUTTON", "EDIT", "LISTBOX", "SCROLLBAR", "COMBOBOX". Alternativ können Klassen ( mit

Prefix: 0xFFFF ) auch identifiziert werden. Zu jeder Klasse ist eine zugehörige CALLBACK-Funktion implizit verfügbar. Mit Hilfe von GetClassInfoEx() können die Daten in wcx

geschrieben werden. Die Dialog-Klasse MAKEINTRESOURCE(0x8002) z.B. durch GetClassInfoEx(GetModuleHandle(0),"#32770", &wcx). Beispiele:

#define BUTTON 0x80#define EDIT 0x81#define STATIC 0x82#define LISTBOX 0x83#define SCROLLBAR 0x84#define COMBOBOX 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 PUSHBUTTONtext, id, x, y, cx, cx, style

CONTROL text, id, "Button", BS_PUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy

#define DEFPUSHBUTTONtext, id, x, y, cx, cx, style

CONTROL text, id, "Button", BS_DEFPUSHBUTTON | WS_TABSTOP | style, x, y, cx, cy

#define RADIOBUTTONtext, 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

Page 397: Systemprogrammierung II (SP II,Script 2005)

↑ Vordefinierte Resourcen - Typen

Für die vordefinierte Resourcen - Typen gibt es die Konstanten:

#define RT_CURSOR MAKEINTRESOURCE(1) //für Mauszeiger #define RT_BITMAP MAKEINTRESOURCE(2) //für Rasterbilder #define RT_ICON MAKEINTRESOURCE(3) //Symbol - Rasterbilder #define RT_MENU MAKEINTRESOURCE(4) //für Menuleisten #define RT_DIALOG MAKEINTRESOURCE(5) //für Dialogfelder #define RT_STRING MAKEINTRESOURCE(6) //für Stringtabellen #define RT_FONTDIR MAKEINTRESOURCE(7) //Verzeichnisse der Schriftarten #define RT_FONT MAKEINTRESOURCE(8) //für Schriftarten #define RT_ACCELERATOR MAKEINTRESOURCE(9) //für Tastaturkürzel #define RT_RCDATA MAKEINTRESOURCE(10) //für Daten ohne feste Bindung #define RT_MESSAGETABLE MAKEINTRESOURCE(11) //für Nachrichten

↑ MAKEINTRESOURCE() - Macro

Der Kern des Betriebssystems vewaltet Atome. Einem String wird ein Hash - Code zugeordnet. Bei Resourcen werden i.a. WORD ID_ ... - Identifizierer verwendet. Benötigt eine

Windows - Funktion den zugeordneten String, so kann das MAKEINTRESOURCE() - Macro verwendet werden. Das MAKEINTRESOURCE() - Macro ist definiert durch

#define MAKEINTRESOURCE( idRes ) (LPSTR)((DWORD)((WORD)( idRes )))

↑ Resourcen - Itentifizierer

Ressourcen-Tools ( AppWizard zur Erzeugung der *.RC - Quelltexte ) benutzen i.a. typische Präfixe für die Identifizierer ( z.B. #define IDD_DIALOG1 1000: (I)(D)entifiziere-

einen_(D)ialog 1 ). Diese Identifizierer sind WORD - Zahlen und werden oft durch MAKEINTRESOURCE(IDD_DIALOG1) übergeben. In dem jeweiligen Kontext müssen die

Identifizierer so geählt werden, daß diese eindeutig sein. Die MFC - Konvention schlägt die folgenden Präfixe vor.

Prefix Type of Symbol Example Range

IDR_Identification shared by multipleresources 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_ String resource IDS_COPYRIGHT 1 to 0x7FFF

Page 398: Systemprogrammierung II (SP II,Script 2005)

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

Page 399: Systemprogrammierung II (SP II,Script 2005)

#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 XOR-

verknüpft. Der Hotspot gibt innerhalb der Maske die Pixel - Position an, welche z.B. die Spitze des Pfeils symbolisiert. Die Erstellung eines Maus - Cursor - Bitmap durch den Benutzer ist

nur dann erforderlich, wenn die verfügbaren Maus - Cursor - Bitmaps nicht ausreichen.

↑ Icon - Resource

Ist ein Icon in dem File "c:\\pfad\\...\\myName.ico" enthalten, so kann dieses Icon gemäß

IDI_MYICON ICON DISCARDABLE "c:\\pfad\\...\\myName.ico"

in den *.RC - ASCII - File aufgenommen werden. Im C/C++ - Programm wird dieses Icon z.B. durch

wndclass.hIcon = LoadIcon( GetModuleHandle(0), IDI_MYICON );

geladen.

↑ String - Table - Resource

Tabellen von Strings werden für Fehler - Meldungen, statische Anzeigetexte und Ausgaben benutzt. Das C/C++ - Programm läd bei Bedarf diese Strings. Wird eine Applikation in eine

andere Landes - Sprachen übersetzt, so muß nur die Stringtabellen auswechselt werden. Bei C/C++ wird ein String "..." automatisch mit einem zusätzlichem \0 - Zeichen abgeschlossen.

● Ein *.RC - String wird nicht automatisch mit einem \0 abgeschlossen.

● Sonderzeichen innerhalb eines *.RC - Strings müssen oktal eingegeben werden ( ein "für" wird zu "f\374r" ).

Page 400: Systemprogrammierung II (SP II,Script 2005)

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]; }

Page 401: Systemprogrammierung II (SP II,Script 2005)

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

Page 402: Systemprogrammierung II (SP II,Script 2005)

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 ) ) {

Page 403: Systemprogrammierung II (SP II,Script 2005)

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 ; }

Page 404: Systemprogrammierung II (SP II,Script 2005)

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 MenuMENUITEMTEMPLATEHEADER

Jedes Popup/ItemMENUITEMTEMPLATE

typedef struct { WORD versionNumber; // 0 WORD offset; // 0 } MENUITEMTEMPLATEHEADER;

typedef struct { WORD mtOption; // Item-Flag z.B. 0/MF_POPUP/MF_END WORD mtID; // ID, fehlt bei Popup-Eintrag WCHAR mtString[1]; // 00-beendeter Text } MENUITEMTEMPLATE;

Beispiel für den Menu-Ressourcen-Aufbau ( WORD-aligned )

Beispiel:

0 VersionNumber von MENUITEMTEMPLATEHEADER

0 Offset von MENUITEMTEMPLATEHEADER

MF_POPUP Kennzeichen für einen Pupup-Eintrag

'Pop1' als Pupup-Text Unicode-Word-Text mit 00-Ende

0 Kennzeichen für einen Item-Eintrag

IDM_100 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)

'Item 100' als Item-Text Unicode-Word-Text mit 00-Ende

0 Kennzeichen für einen Item-Eintrag

IDM_110 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)

'Item 110' als Item-Text Unicode-Word-Text mit 00-Ende

MF_END Kennzeichen für das letzte Item, das zu einem Popup gehören

IDM_120 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)

'Item 120' als Item-Text Unicode-Word-Text mit 00-Ende

MF_POPUP| MF_END Kennzeichen für den letzten Pupup-Eintrag

'Pop2' als Pupup-Text Unicode-Word-Text mit 00-Ende

Page 405: Systemprogrammierung II (SP II,Script 2005)

0 Kennzeichen für das letzte Item, das zu einem Popup gehören

IDM_200 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)

'Item 200' als Item-Text Unicode-Word-Text mit 00-Ende

MF_END Kennzeichen für das letzte Item, das zu einem Popup gehören

IDM_210 Identifizierer für das Menu; WM_COMMAND, LOWORD(wParam)

'Item 210' als Item-Text Unicode-Word-Text mit 00-Ende

verwendete User-Struktur Alternative mit LoadMenuIndirect()

typedef struct _MENU_STRUCT { 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

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; }

Alternative mit AppendMenu()

Page 406: Systemprogrammierung II (SP II,Script 2005)

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()

Page 407: Systemprogrammierung II (SP II,Script 2005)

[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-Grenzestruct 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//////////////////

Page 408: Systemprogrammierung II (SP II,Script 2005)

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

Page 409: Systemprogrammierung II (SP II,Script 2005)

} 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")){

Page 410: Systemprogrammierung II (SP II,Script 2005)

SendMessage(pD->hwnd,LB_ADDSTRING,0L,(LPARAM)pD->pText); } } }#undef es_ist};

user-typedef's

MENU_STRUCT DLG_STRUCT

WORD _id; // Menu-Id's,etwa ab 100 LPSTR _txt;// Menu-Item-Text MENUFUNC _fn; // auzurufende Funktion

mit typedef BOOL (* MENUFUNC)(HWND hwnd);kann WM_COMMAND-Aufruf 'automatisiert' werden

HWND hwnd; //des Ctrl's LPSTR pKlasse;//z.B."EDIT" LPSTR pText; //Initialisierung WORD x,y,cx,cy;//Ctrl-Position

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

Page 411: Systemprogrammierung II (SP II,Script 2005)

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_STRINGhRes = 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

Page 412: Systemprogrammierung II (SP II,Script 2005)

"#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 ;}

Page 413: Systemprogrammierung II (SP II,Script 2005)

| 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 | Hex-Rechner1 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

↑ Dialoge

↑ Eingebaute klassen zur Ereignisbehandlung

Der Entwickler kann eigene Klassen anlegen (RegisterClass) und dort eine CALLBACK-Funktion für die Ereignissteuerung hinterlegen. Es existieren auch

bereits verfügbare Windows-Klassen, die der Ereignissteuerung dienen und die bereits eine CALLBACK-Funktion enthalten. Die ersten Windows-

Versionen enthielten in User(32).dll und Comctl(32).dll die Klassen:

0x0080 "Button", 0x0081 "Edit", 0x0082 "Static", 0x0083 "ListBox", 0x0084 "ScrollBar", 0x0085 "ComboBox" und die Dialog Box Klasse "#32770".

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:

Page 414: Systemprogrammierung II (SP II,Script 2005)

// #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")) == 0) lstrcat(ach,_T("Dialog") ); else if(lstrcmpi(ach,_T("#32768")) == 0) lstrcat(ach,_T("Menu") ); else if(lstrcmpi(ach,_T("#32769")) == 0) lstrcat(ach,_T("Desktop window") ); else if(lstrcmpi(ach,_T("#32771")) == 0) lstrcat(ach,_T("Task-switch window")); else if(lstrcmpi(ach,_T("#32772")) == 0) lstrcat(ach,_T("Icon title") );}

Gehört hwnd zur Dialog Box Klasse #32770?

BOOL is_dlg_class(HWND hwnd) { TCHAR buf [256]; int anz = GetClassName(hwnd, buf, 256);

Page 415: Systemprogrammierung II (SP II,Script 2005)

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 (ANIMATE_CLASS, "SysAnimate32" in Commctrl.h)

Pop-up menu ("#32768")

Calendar control (MONTHCAL_CLASS, "SysMonthCal32" in Commctrl.h)

Progress bar control (PROGRESS_CLASS, "msctls_progress" in Commctrl.h)

Caret Push button ("BUTTON")

Check box ("BUTTON") Radio button ("BUTTON")

Client object (text, graphics) Scroll bar ("SCROLLBAR")

Combo box ("COMBOBOX") Size grip (special mouse pointer)

Page 416: Systemprogrammierung II (SP II,Script 2005)

Cursor IDC_ARROW "Normal", IDC_IBEAM "Edit", IDC_WAIT "Wait", IDC_CROSS "Graphic", IDC_UPARROW "Up", IDC_SIZENWSE "NWSE size", IDC_SIZENESW "NESW size", IDC_SIZEWE "Horizontal size", IDC_SIZENS "Vertical size", IDC_SIZEALL "Move", IDC_NO "Forbidden", IDC_APPSTARTING "App start",IDC_HELP "Help", Custom cursor "Unknown"

Slider control (TRACKBAR_CLASS, "msctls_trackbar" in Commctrl.h)

Desktop window ("#32769")

Static text ("STATIC") Dialog box ("#32770")

Status bar control (STATUSCLASSNAME, "msctls_statusbar32" in Commctrl.h)

Edit control "EDIT", "RichEdit", "RichEdit20A"

Switch window ("#32771") Header control (WC_HEADER, "SysHeader32" in Commctrl.h)

Tab control (WC_TABCONTROL, "SysTabControl" in Commctrl.h)

Hot key control (HOTKEY_CLASS, "msctls_hotkey32" in Commctrl.h)

Toolbar control (TOOLBARCLASSNAME, "ToolbarWindow32" in Commctrl.h)

List box ("LISTBOX")

ToolTip control (TOOLTIPS_CLASS, "tooltips_class" in Commctrl.h)

List view control (WC_LISTVIEW, "SysListView" in Commctrl.h)

Title bar MDI client window ("MDIClient")

Tree view control (WC_TREEVIEW, "SysTreeView" in Commctrl.h) Menu bar

Up-down control (UPDOWN_CLASS, "msctls_updown32" in Commctrl.h)

Menu item ( "#32768")

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

CreateDialog CreateDialogIndirect CreateDialogIndirectParamCreateDialogParam DefDlgProc DialogBox DialogBoxIndirect DialogBoxIndirectParam DialogBoxParam DialogProc EndDialog GetDialogBaseUnits GetDlgCtrlID GetDlgItem GetDlgItemInt GetDlgItemText GetNextDlgGroupItem GetNextDlgTabItem

Page 417: Systemprogrammierung II (SP II,Script 2005)

IsDialogMessage MapDialogRect MessageBox MessageBoxEx SendDlgItemMessage SetDlgItemInt SetDlgItemText MessageBoxIndirect

↑ Modale Dialoge

Ein modaler Dialog enthält eine eigene Nachrichten-Schleife. Erscheint ein ( Applikations-)modale Dialog - Box auf dem Bildschirm so wird in dieser

Nachrichten-Schleife "gewartet", bis der Benutzer reagieren und den Dialog beendet.

↑ MessageBox()

Eine MessageBox() entspricht einem modalen Dialog. Z.B. wird die Applikation blockiert, bis der Benutzer den "OK" - Button gedrückt hat. Eine

MessageBox() erzeugt die Anzeige - Box für Ausgabe-Text ohne externe Resourcen. Eine eingebaute ( intern verfügbare ) CALLBACK - Funktion

behandelt die Nachrichten. Es gibt eine Anzahl von verwendbaren Icons und Push-Buttons.

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

MessageBoxEx() hat gegenüber MessageBox() einen zusätlichen WORD wLanguageId - Parameter. Falls hWnd = NULL verwendet wird, so gehört die

Message - Box zu keinem speziellen Fenster. lpCaption zeigt auf den auszugebenden Text. Für lpszTitle = NULL ist, wird in der Titel - Zeile "Error"

angezeigt. Im Fehlerfall gibt die MessageBoxEx() den Wert 0 zurück. Im Erfolgsfall gibt die MessageBoxEx() eine positiven Wert zurück. Der Rückgabe -

Wert entspricht dem gedrückten Button.

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

Page 418: Systemprogrammierung II (SP II,Script 2005)

IDRETRY Retry button was selected. IDYES Yes button was selected.

Für uType kann verwendet werden:

MB_ABORTRETRYIGNORE three push buttons: Abort, Retry, and Ignore. MB_OK one push button: OK. This is the default. MB_OKCANCEL two push buttons: OK and Cancel. MB_RETRYCANCEL two push buttons: Retry and Cancel. MB_YESNO two push buttons: Yes and No. MB_YESNOCANCEL three push buttons: Yes, No, and Cancel. --------------------------------------------------------------MB_ICONEXCLAMATION, MB_ICONWARNING icon ( exclamation-point )MB_ICONINFORMATION, MB_ICONASTERISK icon ( i in a circle )MB_ICONQUESTION icon ( question-mark )MB_ICONSTOP, MB_ICONERROR, MB_ICONHAND icon ( stop -sign )--------------------------------------------------------------MB_DEFBUTTON1 The first button is the default button. MB_DEFBUTTON2 The second button is the default button. MB_DEFBUTTON3 The third button is the default button. MB_DEFBUTTON4 The fourth button is the default button. --------------------------------------------------------------more:MB_APPLMODAL, MB_SYSTEMMODAL, MB_TASKMODAL, MB_DEFAULT_DESKTOP_ONLY,MB_HELP, MB_RIGHT, MB_RTLREADING, MB_SETFOREGROUND, MB_TOPMOST,MB_SERVICE_NOTIFICATION, MB_SERVICE_NOTIFICATION_NT3X

↑ Beispiele: MessageBoxMessageBox() als einfacher ( Benachrichtigungs-) Dialog

Page 419: Systemprogrammierung II (SP II,Script 2005)

MessageBox( 0,"Client-Bereich",

0, MB_OK );

MessageBox( hwnd, "Client-Bereich",

"Titel", MB_OK );

MessageBox( hwnd,"MB_ICONSTOP",

"Titel",MB_OK|MB_ICONSTOP);

MessageBox(hwnd,"MB_ICONINFORMATION",

"Titel",MB_OK|MB_ICONINFORMATION);

MessageBox(hwnd,"MB_ICONQUESTION",

"Titel",MB_OK|MB_ICONQUESTION);

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

MB_OKCANCEL|MB_DEFBUTTON2);mb_val wirdt IDOK oder IDCANCEL

↑ DialogBox()

Der einfache Aufruf einer MessageBox()-Funktion begrenzt die optische Ausgestaltung, die Anzeigeposition und - Form, die enthaltenen Buttons (

Controls ), usw, auf das notwendigste. Eine erweiternde Gestaltung ist nicht möglich. Eine MessageBox() gehört zu den modalen Dialogen ( Benutzer muß

reagieren ). Eine ( allgemeine ) Dialog - Box kann mit der DialogBox()-Funktion aufgerufen werden. Die DialogBox()-Funktion braucht eine Dialog-

CALLBACK-Funktion und ein Ressourcen-Script ( flexible optische Gestaltung ). Die DialogBox() kann Controls enthalten, die Informationen angezeigen

und Benutzereingaben erlauben ( Texteingaben, Auswahlaktionen, usw. ). Diese Unter - Fenster ( Child - Windows == Controls ) einer DialogBox()

werden Controls genannt. Die "DialogBox() - Funktion" ist ein Macro, das gemäß

#define DialogBoxA( hInstance, lpTemplate, hWndParent, lpDialogFunc) \ DialogBoxParamA( hInstance, lpTemplate, hWndParent, lpDialogFunc, 0L)

Page 420: Systemprogrammierung II (SP II,Script 2005)

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.

Page 421: Systemprogrammierung II (SP II,Script 2005)

● Bevor die Dialog - Box sichtbar wird, sendet DialogBox() die WM_INITDIALOG - Nachricht an die lpDialogFunc -

Funktion. In der CALLBACK - Funktion wird WM_INITDIALOG im Normalfall mit return FALSE beendet.

● Falls die Dialog - Box den DS_SETFONT - Style hat, so wird die WM_SETFONT - Nachricht an die lpDialogFunc -

Funktion gesendet.

● Wenn der WS_VISIBLE - Style spezifiziert wurde, so erscheint die Dialog - Box.

● Durch EndDialog ( hWnd, wParam ) wird der Dialog beendet, der allokierte Speicher wird freigegeben. DialogBox() gibt

wParam zurück.

● Eine private Dialog - Klasse muß WNDCLASS - Struktur besetzten ( cbWndExtra = DLGWINDOWEXTRA ) und

RegisterClass() aufrufen. Das Dialog - Template muß dann das CLASS - Statement enthalten.

Gegenüber einer MessageBox() ist der Programmier - Aufwand bei Verwendung von DialogBox() größer.

int DialogBox( HINSTANCE hInstance, // handle to application instance LPCTSTR lpTemplate, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc // pointer to dialog box procedure);

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

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

Zur Behandlung der Ereignisse muß eine DIALOG - CALLBACK - Funktion geschrieben werden. Diese Funktion wird mit DLGPROC lpDialogFunc an

Page 422: Systemprogrammierung II (SP II,Script 2005)

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 :

Page 423: Systemprogrammierung II (SP II,Script 2005)

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, 141STYLE DS_SYSMODAL | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENUCAPTION "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

Page 424: Systemprogrammierung II (SP II,Script 2005)

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,14ENDIDR_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 ENDEND

↑ 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.

Page 425: Systemprogrammierung II (SP II,Script 2005)

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 ) ;}

Page 426: Systemprogrammierung II (SP II,Script 2005)

↑ 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 ) ;

Page 427: Systemprogrammierung II (SP II,Script 2005)

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) {

Page 428: Systemprogrammierung II (SP II,Script 2005)

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, 129STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAMECAPTION "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) {

Page 429: Systemprogrammierung II (SP II,Script 2005)

static CHAR * pEdit; int len, idx; HWND hCtl0; switch ( iMsg ) {

case WM_INITDIALOG: // idRes = lParam; if ( pEdit != NULL ) { DestroyWindow( hWnd ) ; //keine doppelten Dialoge } else { pEdit = ( CHAR * ) calloc( 256, sizeof( CHAR ) ); hCtl0 = GetDlgItem( hWnd, IDC_EDIT0 ) ; Edit_LimitText( hCtl0, 256 ); strcpy( pEdit, "...Text..." ); Edit_SetText ( hCtl0, pEdit ); } break;

case WM_ACTIVATE: if ( 0 == wParam ) hDlgModeless = NULL; // becoming inactive else hDlgModeless = hWnd; // becoming active return FALSE;

case WM_COMMAND:

switch ( LOWORD(wParam) ) { case IDC_BUTTON0: len = GetDlgItemText( hWnd, IDC_EDIT0, pEdit, 256 ); MessageBox( hWnd, pEdit, "Eingabe-Feld", MB_OK); break; case IDC_BUTTON1: len = GetDlgItemText( hWnd, IDC_COMBO1, p1, 256 ); MessageBox( hWnd, p1, "Kombinations-Feld", MB_OK); break; case IDOK: //fall case IDCANCEL: SendMessage( hWnd, WM_CLOSE, LOWORD(wParam), 0); return TRUE; } break;

case WM_CLOSE: free( pEdit ); pEdit = NULL;

Page 430: Systemprogrammierung II (SP II,Script 2005)

// EndDialog ( hWnd, wParam ); DestroyWindow( hWnd ) ; break; }

return FALSE;}

↑ Interne Dialog - CALLBACK - Funktion

Alle Dialog - Klassen sind Window - Klassen. Eine Dialog - Box ist ein Window zu einer vorhandenen Klasse. Es wird zusätzlicher Speicher

WNDCLASS cbWndExtra = DLGWINDOWEXTRA benötigt. Für einen DialogBox() - oder CreateDialog() - Aufruf wird i.a. keine eigene Klasse

registriert. Anstelle einer eigenen Klassen - CALLBACK - Funktion wird die eingebaute und bereits unter 0x8002 registrierte USER.EXE - interne

IDefDlgProc() - Funktion benutzt.

Durch DialogBox() werden die folgenden Nachrichten versendet.

DM_GETDEFID DM_REPOSITION DM_SETDEFID WM_CTLCOLORDLG WM_CTLCOLORMSGBOX WM_ENTERIDLE WM_GETDLGCODE WM_INITDIALOG WM_NEXTDLGCTL

In der internen IDefDlgProc() wird durch result = CallDlgProc( hWnd, iMsg, wParam, lParam)) die eingetragene Benutzer - CALLBACK - Funktion

aufgerufen. Der BOOL - Rückgabe - Wert entscheidet über die weitere Bearbeitung der Nachrichten. Die CALLBACK - Funktion

● BOOL myDlgProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )

des Benutzers sollte kann z.B. die Nachrichten WM_INITDIALOG, WM_CLOSE, WM_COMMAND ( mit IDOK und IDCANCEL ) bearbeiten. Der

BOOL - Rückgabe - Wert entscheidet über die weitere Bearbeitung der Nachrichten.

Falls in WM_INITDIALOG alles erledigt wurde, so wird der iMsg = WM_INITDIALOG - Case mit return TRUE, sonst return FALSE ( Normalfall )

beendet.

WM_CLOSE soll EndDialog ( hWnd, wParam ) aufrufen. WM_COMMAND mit IDOK und IDCANCEL kann z.B. die Nachricht ( hWnd,

Page 431: Systemprogrammierung II (SP II,Script 2005)

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) {

Page 432: Systemprogrammierung II (SP II,Script 2005)

return( (LRESULT)(DWORD) result ); } return( ( ( PDLG ) hWnd ) -> resultWP );}

↑ Standard - DialogeCHAR * get_Open_File_Name ( HWND hWnd, CHAR * pNamExt, CHAR * pTitle ){ OPENFILENAME ofn = { 0 } ; static char buf[MAX_PATH] ; buf[0] = '\0' ; if ( pNamExt == NULL ) pNamExt = "All Files\000*.*\000" ; ofn.lStructSize = sizeof( OPENFILENAME ); ofn.hwndOwner = hWnd ; ofn.hInstance = GetModuleHandle( NULL ); ofn.lpstrTitle = pTitle ; ofn.lpstrFile = buf ; ofn.nMaxFile = sizeof( buf ) ; ofn.lpstrFilter = pNamExt ; ofn.lpstrDefExt = "*" ; ofn.nFilterIndex = 1L ; if ( GetOpenFileName( & ofn ) ) return buf ; return NULL ;}

↑ Controls

● Ein Dialog enthält untergeordnete Fenster ( Controls ).

● Zu einem Control gehört i.a. eine eingebauten Klasse.

Page 433: Systemprogrammierung II (SP II,Script 2005)

● Die Klasse enthält eine eingebaute CALLBACK - Funktion, die die Ereignisse behandelt.

Zu einer ein/mehr - zeiligen Texteingabe gehört die Klasse "Edit". Zu einem Button gehört die Klasse "Button". Mit der Kenntnis dieser Control -

Ereignisse können die Controls genutzt werden.

Als Beispiel werden die Combo - Box - Ereignisse angefügt. Die Combo - Box ( Edit - Zeile mit List - Box ) kann die folgenden Nachrichten

senden/empfangen/behandeln:

Combo Box Messages

CB_ADDSTRING CB_DELETESTRING CB_DIRCB_FINDSTRING CB_FINDSTRINGEXACT CB_GETCOUNTCB_GETCURSEL CB_GETDROPPEDCONTROLRECT CB_GETDROPPEDSTATECB_GETDROPPEDWIDTH CB_GETEDITSEL CB_GETEXTENDEDUICB_GETHORIZONTALEXTENT CB_GETITEMDATA CB_GETITEMHEIGHTCB_GETLBTEXT CB_GETLBTEXTLEN CB_GETLOCALECB_GETTOPINDEX CB_INITSTORAGE CB_INSERTSTRINGCB_LIMITTEXT CB_RESETCONTENT CB_SELECTSTRINGCB_SETCURSEL CB_SETDROPPEDWIDTH CB_SETEDITSELCB_SETEXTENDEDUI CB_SETHORIZONTALEXTENT CB_SETITEMDATACB_SETITEMHEIGHT CB_SETLOCALE CB_SETTOPINDEXCB_SHOWDROPDOWN CBN_CLOSEUP CBN_DBLCLKCBN_DROPDOWN CBN_EDITCHANGE CBN_EDITUPDATECBN_ERRSPACE CBN_KILLFOCUS CBN_SELCHANGECBN_SELENDCANCEL CBN_SELENDOK CBN_SETFOCUSWM_COMPAREITEM WM_DRAWITEM WM_MEASUREITEM

Um einem Control eine Nachricht zu schicken wird anstelle von

HWND hCtl = GetDlgItem ( HWND hDlg, int idRes ); LONG SendMessage ( HWND hCtl, UINT iMsg, WPARAM wParam, LPARAM lParam);

oft

Page 434: Systemprogrammierung II (SP II,Script 2005)

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 ControlStatic Text Controls

StaticTextControls

Static_Enable (hCtl, fEnable) Static_GetIcon (hCtl, hIcon) Static_GetText (hCtl, lpch, cchMax) Static_GetTextLength(hCtl) Static_SetIcon (hCtl, hIcon) Static_SetText (hCtl, lpsz)

Page 435: Systemprogrammierung II (SP II,Script 2005)

↑ Button Control

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

Button Controls

ButtonControls

Button_Enable (hCtl, fEnable) Button_GetCheck (hCtl) Button_GetState (hCtl) Button_GetText (hCtl, lpch, cchMax) Button_GetTextLength(hCtl) Button_SetCheck (hCtl, check) Button_SetState (hCtl, state) Button_SetStyle (hCtl, style, fRedraw) Button_SetText (hCtl, lpsz)

Ein Button kann auf drei Arten selektiert werden:

● durch Klicken mit der Maus,

● durch Auswählen mit der Tab - Taste und dann die Enter - Taste drücken,

● durch Auswählen des Group - Rahmens mit der Tab - Taste ( falls der Button den WS_GROUP - Style hat ) und dann kann

innerhalb des Group - Rahmens mit den Pfeilchen - Tasten der Button selektiert weren.

Die Button - Auswahl bewirkt die folgenden Ereignisse:

● Button erhält den Keyboard - Focus ( WM_FOCUS ),

● Button sendet bei Selektion an das Parent - Window eine Benachrichtigung ( Notification Message ),

● das Parent - Window sendet an den Button eine Nachricht zur Zustands - Änderung,

Page 436: Systemprogrammierung II (SP II,Script 2005)

● 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 ) ; #elseint 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

Button-Notification-Messages

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

Page 437: Systemprogrammierung II (SP II,Script 2005)

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.

Page 438: Systemprogrammierung II (SP II,Script 2005)

↑ Edit ControlEdit Controls

EditControls

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

↑ Beispiel zu Edit

Page 439: Systemprogrammierung II (SP II,Script 2005)

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 ); }}

Page 440: Systemprogrammierung II (SP II,Script 2005)

↑ List Box Control List Box Controls

ListBoxControls

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)

Page 441: Systemprogrammierung II (SP II,Script 2005)

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

ComboBoxControls

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)

Page 442: Systemprogrammierung II (SP II,Script 2005)

ComboBox_ResetContent (hCtl) ComboBox_SelectItemData (hCtl, indexStart, data) ComboBox_SetCurSel (hCtl, index) ComboBox_SelectString (hCtl, indexStart, lpszSelect) ComboBox_SetExtendedUI (hCtl, flags)Win32 ComboBox_SetEditSel (hCtl, ichStart, ichEnd) ComboBox_SetItemHeight (hCtl, cyItem)Win32 ComboBox_SetItemData (hCtl, index, data) ComboBox_SetText (hCtl, lpsz) ComboBox_ShowDropdown (hCtl, fShow)

↑ Beispiel: 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 BEGINIDS_STRING0 "(EB_ und 0.LB_Text0\000(1.LB_Text)\000(2.LB_Text)\000"ENDIDD_MYDIALOG DIALOG DISCARDABLE 0, 0, 186, 129STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAMECAPTION ...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_TABSTOPEND

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.

Page 443: Systemprogrammierung II (SP II,Script 2005)

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 ausComboBox_SetText( hCombo, buf ); //EB while ( idx < idxMax ) { //LBsComboBox_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;}

Page 444: Systemprogrammierung II (SP II,Script 2005)

↑ Scroll Bar Control Scroll Bar Controls

ScrollBarControls

ScrollBar_Enable (hCtl, flags) ScrollBar_GetPos (hCtl) ScrollBar_GetRange(hCtl, lpposMin, lpposMax) ScrollBar_SetPos (hCtl, pos, fRedraw) ScrollBar_SetRange(hCtl, posMin, posMax, fRedraw) ScrollBar_Show (hCtl, fShow)

↑ Arrow - Keys und Notification Nachrichten

Mit den Funktionen SetScrollInfo(), SetScrollPos(), SetScrollRange(), GetScrollInfo(), GetScrollPos() und GetScrollRange() können Scroll - Bars

eingerichtet werden. Scroll - Bars werden mit der Maus bedient. Das System unterstützt die Maus - Ereignisse. Wenn z.B. bei einer vertikalen Scroll Bar

ein Scroll - Ereignies eintritt, so wird die WM_VSCROLL - Nachricht an das Fenster gesendet. Die WM_VSCROLL - Nachricht enthält in wParam

und lParam die folgenden Anteile.

WM_VSCROLL - Nachricht

● nScrollCode = ( int ) LOWORD( wParam ); // scroll bar value

● nPos = ( short int ) HIWORD( wParam ); // scroll box position

● hwndScrollBar = ( HWND ) lParam; // handle of scroll bar

Der nScrollCode - Parameter kann die Werte

● SB_BOTTOM ( Scrolls to the lower right),

● SB_ENDSCROLL ( Ends scroll ),

Page 445: Systemprogrammierung II (SP II,Script 2005)

● 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.

Page 446: Systemprogrammierung II (SP II,Script 2005)

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 sendetvirtuellerKey-Code

und soll dieMaus-Notification-Nachrichtauslö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äß

Page 447: Systemprogrammierung II (SP II,Script 2005)

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,

Page 448: Systemprogrammierung II (SP II,Script 2005)

● Vollständige Neugestaltung, Registrierung einer eigenen Window - Klasse.

↑ Hex-Rechner1 mit *.rcAls 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 ).

Page 449: Systemprogrammierung II (SP II,Script 2005)

IDD_DIALOG_HEXCALC DIALOG DISCARDABLE 5, 10, 188, 135STYLE DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_THICKFRAMECAPTION "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

Page 450: Systemprogrammierung II (SP II,Script 2005)

PUSHBUTTON "MC",IDC_BUTTON2,105,81,17,14,NOT WS_TABSTOP PUSHBUTTON "MR",IDC_BUTTON3,105,63,17,14,NOT WS_TABSTOP PUSHBUTTON "BS",8,64,117,31,14,NOT WS_TABSTOP PUSHBUTTON "AC",IDC_BUTTON5,105,100,17,14,NOT WS_TABSTOP DEFPUSHBUTTON "Schliessen",IDOK,135,117,50,14,NOT WS_TABSTOP CONTROL "",IDC_STATIC,"Static", SS_BLACKRECT,126,5,6,125 CONTROL "",IDC_STATIC,"Static", SS_BLACKRECT,5,21,116,6END

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 ;

Page 451: Systemprogrammierung II (SP II,Script 2005)

}}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 ) ;

Page 452: Systemprogrammierung II (SP II,Script 2005)

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 *.rcMit Hilfe der CreateWindowEx()-Funktion und den Styles:

Button: WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOPComboBox: WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWNEdit: 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){

Page 453: Systemprogrammierung II (SP II,Script 2005)

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

Page 454: Systemprogrammierung II (SP II,Script 2005)

const UINT MAX_EDIT_CHAR =2048;//für Edit_LimitText()const UINT MAX_COMBO_CHAR = 8;//ComboBox_LimitText()const UINT USE_CE = 1; // Ziel Combo-Editconst UINT USE_CL = 2; // Ziel Combo-Listeconst UINT USE_EM = 4; // Ziel Edit-Multiline

// UINT (M)em(SUM)men-Speicher MSUM // MSUM hält den Summenwert ('M+','M-')//'MR' für Anzeige, 'MC' setzt MSUM=0 UINT MSUM;

// Verwendet werden hCombo, hEdit dadurch entfällt:// HWND hCombo = GetDlgItem(hwnd,IDC_COMBO);// HWND hEdit = GetDlgItem(hwnd,IDC_EDIT);HWND hCombo; //hCombo anstelle von IDC_COMBOHWND 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;}

Page 455: Systemprogrammierung II (SP II,Script 2005)

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

Page 456: Systemprogrammierung II (SP II,Script 2005)

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;

Page 457: Systemprogrammierung II (SP II,Script 2005)

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

Page 458: Systemprogrammierung II (SP II,Script 2005)

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);

Page 459: Systemprogrammierung II (SP II,Script 2005)

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; }

Page 460: Systemprogrammierung II (SP II,Script 2005)

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

Page 461: Systemprogrammierung II (SP II,Script 2005)

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;

Page 462: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 463: Systemprogrammierung II (SP II,Script 2005)

↑ hex_rechner2Zu 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:

Page 464: Systemprogrammierung II (SP II,Script 2005)

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 CALLBACK-

Funktion 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 CALLBACK-

Funktion 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".

Page 465: Systemprogrammierung II (SP II,Script 2005)

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

Daten einfach ersetzt, wie dies durch "grün" angedeutet ist, so entstehen Rekursionen.

WNDPROC set_wndproc(HWND hwnd, WNDPROC m_wnd_proc){

Page 466: Systemprogrammierung II (SP II,Script 2005)

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

Page 467: Systemprogrammierung II (SP II,Script 2005)

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;

Page 468: Systemprogrammierung II (SP II,Script 2005)

}

↑ 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

Page 469: Systemprogrammierung II (SP II,Script 2005)

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_COMBOHWND hEdit; //hEdit anstelle von IDC_EDIT// UINT (M)em(SUM)men-Speicher MSUM

Page 470: Systemprogrammierung II (SP II,Script 2005)

// 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");

Page 471: Systemprogrammierung II (SP II,Script 2005)

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)

Page 472: Systemprogrammierung II (SP II,Script 2005)

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

Page 473: Systemprogrammierung II (SP II,Script 2005)

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; } return erg;}/////////////////////////////////////////////////// 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,"");

Page 474: Systemprogrammierung II (SP II,Script 2005)

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

Page 475: Systemprogrammierung II (SP II,Script 2005)

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"

Page 476: Systemprogrammierung II (SP II,Script 2005)

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");

Page 477: Systemprogrammierung II (SP II,Script 2005)

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;

Page 478: Systemprogrammierung II (SP II,Script 2005)

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;

Page 479: Systemprogrammierung II (SP II,Script 2005)

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;}///////////////////////////////////////////////////Hauptprogrammint APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hiPr,PSTR pCmd,int iShow) { ghwnd[0] = ghwnd[1] = hex_rechner_indirect(ghwnd[1]); BOOL bRet; MSG msg;

Page 480: Systemprogrammierung II (SP II,Script 2005)

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;}

Page 481: Systemprogrammierung II (SP II,Script 2005)

| DLLs | Lebensdauer von Objekten | Static-Linking | Dynamic-Linking | Unterschiede zwischen Static-Dynamic-Linking | shared data segment | Verwenden einer Funktion

aus einer DLL

↑ DLLsEin 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 Systemallokiert

Programm, Block( System bei shared )

Programm, Blockbis 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, Blockbis zur Freigabe( System bei stock )

ca. 30-50 Byte

Page 482: Systemprogrammierung II (SP II,Script 2005)

User Objekte Linker Programm, Block Programm, Blockbis 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-LinkingWDifferences 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.

Page 483: Systemprogrammierung II (SP II,Script 2005)

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

Page 484: Systemprogrammierung II (SP II,Script 2005)

%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}

Page 485: Systemprogrammierung II (SP II,Script 2005)

| 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

↑ MFCSoftware-Syteme entwickeln sich und damit können sich Änderungen des Programmiermodell, der Entwicklungsumgebung, der Klassen-Bibliotheken, der API-

Funktionssammlung 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.0MFC, Version 2.0 Visual C++, Version 1.0MFC, Version 2.5 Visual C++, Version 1.5MFC, Version 3.0 Visual C++, Version 2.0MFC, Version 3.1 Visual C++, Version 2.1MFC, Version 3.2 Visual C++, Version 2.2MFC, Version 4.0 Visual C++, Version 4.0MFC, Version 4.1 Visual C++, Version 4.1MFC, Version 4.2 Visual C++, Version 4.2MFC, Version 4.21 (noch mit mfc42.dll) Visual C++, Version 5.0MFC, Version 6.0 (noch mit mfc42.dll) Visual C++, Version 6.0MFC, Version 7.0 (mfc70.dll) Visual C++ .NET 2002MFC, Version 7.1 (mfc71.dll) Visual C++ .NET 2003

Literaturhinweise H. M. Deitel et al.: 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

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) {

Page 486: Systemprogrammierung II (SP II,Script 2005)

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

Page 487: Systemprogrammierung II (SP II,Script 2005)

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 //{{...//}}

Page 488: Systemprogrammierung II (SP II,Script 2005)

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_MAPEND_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 } \ }; \

Page 489: Systemprogrammierung II (SP II,Script 2005)

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

Page 490: Systemprogrammierung II (SP II,Script 2005)

// 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){

Page 491: Systemprogrammierung II (SP II,Script 2005)

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;

Page 492: Systemprogrammierung II (SP II,Script 2005)

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.

Page 493: Systemprogrammierung II (SP II,Script 2005)

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 einevirtual Funktion?

Nein Ja

Ist eine Basis-Klasse? Nein CObject derived

Page 494: Systemprogrammierung II (SP II,Script 2005)

Kann direkt benutzt werden? Ja Maybe

Kann abgeleitet werden? Nein Ja

Hat einen "="-Operator? meist Nein

Hat einen Copy-Konstruktor? meist Nein

Wirkt wie ein eingebauter Type? meist Nein

Vergleich möglich? Usually Nein

Vergleichsreferenz möglich? Nein Ja (Addresse ist identisch)

↑ MFC-Schreibweise

MFC verwendet eine General Prefix Naming Conventions ( vereinfacht ungarische Notation ). Die Klassen enthalten als Member-Variable u.a. Daten vom Typ

HWND. CWnd::m_hWnd, and an accessor function, CWnd::GetSafeHwnd. Static member Variablen ( Klassen-Variablen ) haben einen "global class namespace" und

werden ohne Prefix verwendet.

Prefix

Prefix: C Type: Class or structure Example: CDocument, CPrintInfo

Prefix: m_ Type: Member variable Example: m_pDoc, m_nCustomers

Gegenüberstellung

Value-Objekte Framework-Objekte

Value-Übergabe( wenige Bytes )

void Do(CMyValue val); Referenz-Übergabe

( umfangreiche Size ) void Do( const CMyValue& val );

Value-Objekte benutzen

non-const Zeiger void GetSomething( CMyValue* pval );

Framework-Objektenbenutzen

const Zeiger-Übergabe void Do( const CMyView* pob );

return-Werte einesValue-Objektes

CMyValue GetCurrentValue(); return-Werte eines

Framework-Objektes CMyView* GetCurrentView();

↑ Hinweise zur Programmierung

Overloading-Operatoren und Copy-Konstructoren sollten vermieden werden ( insbesondere bei Framework-Klassen ). Falls dennoch erforderlich, so sollte der Copy-

Konstructor vom Argument "const classname&" sein.

Page 495: Systemprogrammierung II (SP II,Script 2005)

↑ 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,

Page 496: Systemprogrammierung II (SP II,Script 2005)

cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);#ifdef _DEBUGif (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:

Page 497: Systemprogrammierung II (SP II,Script 2005)

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

WindowsType

ExampleVariable

MFC Class ExampleObject

HWND hWnd; CWnd* pWnd;

HDLG hDlg; CDialog* pDlg;

HDC hDC; CDC* pDC;

HGDIOBJ hGdiObj; CGdiObject* pGdiObj;

HPEN hPen; CPen* pPen;1

HBRUSH hBrush; CBrush* pBrush;1

HFONT hFont; CFont* pFont;1

Page 498: Systemprogrammierung II (SP II,Script 2005)

HBITMAP hBitmap; CBitmap* pBitmap;1

HPALETTE hPalette; CPalette* pPalette;1

HRGN hRgn; CRgn* pRgn;1

HMENU hMenu; CMenu* pMenu;1

HWND hCtl; CStatic* pStatic;2

HWND hCtl; CButton* pBtn;2

HWND hCtl; CEdit* pEdit;2

HWND hCtl; CListBox* pListBox;2

HWND hCtl; CComboBox* pComboBox;2

HWND hCtl; CScrollBar* pScrollbar;2

HSZ hszStr; CString pStr;2

POINT pt; CPoint pt;

SIZE size; CSize size;

RECT rect; CRect rect;

↑ MFC-Klassenhirachie (CE)

MFC-Library für Windows CE in tabellarischer Darstellung:

Von der Klasse CObject(root class) abgeleitet (CE):

Application Architecture Classes Internet Services Classes

Array Classes List Classes

Control Bar Classes Map Classes

Control Classes Menu Classes

Control Support Classes Property Sheets

Dialog Box Classes Synchronization Classes

Exception Classes View Classes

NICHT von der KlasseCObject abgeleitet (CE):

ActiveX Type Wrappers Support Classes

Automation Types Synchronization Support

Run-Time Object Model Support Typed Template Collections

Simple Value Types Windows CE Database Classes

Structures

(allg.)

Internet Server API Run-Time Object Model Support

Page 499: Systemprogrammierung II (SP II,Script 2005)

File Service Classes Window Class Categories

Frame Windows and Splitter Windows Windows CE Database Classes

Graphical Drawing Classes Windows Sockets Classes

Graphical Drawing Object Classes

Structures Simple Value Types

Support Classes Typed Template Collections

OLE Type Wrappers OLE Automation Types

Synchronization

↑ MFC-Klassenhirachie

Grobe MFC-Hierachy-Categories von CObject:

MFC-Grafische Darstellung der Objekt-Hierachie:

Page 500: Systemprogrammierung II (SP II,Script 2005)
Page 501: Systemprogrammierung II (SP II,Script 2005)
Page 502: Systemprogrammierung II (SP II,Script 2005)
Page 503: Systemprogrammierung II (SP II,Script 2005)

Die MFC-Klassen-Deklarationen sind in stdafx.h enthalten. stdafx.h verwendet als MFC-Kern- und -Standardkomponenten afxwin.h. In afxwin.h sind die folgenden

Klassen deklariert:

class CSize; class CPoint; class CRect;

class CGdiObject; // CDC drawing tool class CPen; // a pen / HPEN wrapper class CBrush; // a brush / HBRUSH wrapper class CFont; // a font / HFONT wrapper class CBitmap; // a bitmap / HBITMAP wrapper class CPalette; // a palette / HPALLETE wrapper class CRgn; // a region / HRGN wrapper

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

class CMenu; // a menu / HMENU wrapper

class CCmdTarget; // a target for user commands class CWnd; // a window / HWND wrapper class CDialog; // a dialog

// standard windows controls class CStatic; // Static control class CButton; // Button control class CListBox; // ListBox control class CCheckListBox; // special listbox with checks class CComboBox; // ComboBox control class CEdit; // Edit control

Page 504: Systemprogrammierung II (SP II,Script 2005)

class CScrollBar; // ScrollBar control

// frame windows class CFrameWnd; // standard SDI frame class CMDIFrameWnd; // standard MDI frame class CMDIChildWnd; // standard MDI child class CMiniFrameWnd; // half-height caption frame wnd

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

class CWinThread; // thread base class class CWinApp; // application base class

class CDocTemplate; // template for document creation class CSingleDocTemplate;// SDI support class CMultiDocTemplate; // MDI support

class CDocument; // main document abstraction

//CObject//CException//CSimpleException class CResourceException;// Win resource failure exception class CUserException; // Message Box alert and stop operation

// Helper classes:class CCmdUI; // Menu/button enablingclass CDataExchange; // Data exchange and validation contextclass CCommandLineInfo; // CommandLine parsing helperclass CDocManager; // 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)

Page 505: Systemprogrammierung II (SP II,Script 2005)

return ::CallWindowProc(m_pfnSuper,m_hWnd,nMsg,wParam,lParam);

WNDPROC pfnWndProc; if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL) return ::DefWindowProc(m_hWnd,nMsg,wParam,lParam); else return ::CallWindowProc(pfnWndProc,m_hWnd,nMsg,wParam,lParam);}

↑ Hinweise zum Übersezungsvorgang

Die folgende Tabelle gibt Konfigurationsmakros ( Linker ) an:

Konfigurationsmakros ( Linker ) Macro-Name Macro-Typ

_AFXDLL Stand-alone dynamic-link library (DLL) version

_DEBUG Debug version including diagnostics

_MBCS Compilation for multi-byte character sets

_UNICODE Enables Unicode in an application

AFXAPI Function provided by MFC

WINAPI Function provided by Windows

CALLBACK Function called back via pointer

Der Linker kann unterschiedliche Bibliotheken ( z.B. Static- Library, Versionen ) binden.

NAFXCWD.LIB ist eine Debug version: MFC Static Link Library

UAFXCWD.LIB ist eine Debug version: MFC Static Link Library with Unicode support

NAFXCW.LIB ist eine Release version: MFC Static Link Library

UAFXCW.LIB ist eine Release version: MFC Static Link Library with Unicode support Mit der #pragma comment(lib, "...") -Präprozessor-Direktive kann der

Übersetzungsvorgang gesteuert werden:

#ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, "nafxcwd.lib") #else #pragma comment(lib, "nafxcw.lib") #endif #else

Page 506: Systemprogrammierung II (SP II,Script 2005)

#ifdef _DEBUG #pragma comment(lib, "uafxcwd.lib") #else #pragma comment(lib, "uafxcw.lib") #endif #endif

Page 507: Systemprogrammierung II (SP II,Script 2005)

| 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 Hewlett-

Packard, Intel, Microsoft. In ECMA-334 steht: The name C# is pronounced "C Sharp".

CLI : Common Language Infrastructure, ECMA-335, 2nd Edition, December 2002CLS : 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 XML-

umformattieren 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)

Virtual Execution System besteht aus:

Compiler:

Verifier JIT

Managed Code besteht aus:

GabageCollector

Security ThreadSupport

...

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.

Page 508: Systemprogrammierung II (SP II,Script 2005)

Assemblybesteht

aus:

Manifest Attribute

Name, Version, Shared Name, Hash, Custom Attributes Files, Referenced Assemblies, Types, Security, Product Information Ein Assembly kann durch die folgenden Attribute modifiziert werden:

using System.Reflection;using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("")][assembly: AssemblyDescription("")][assembly: AssemblyConfiguration("")][assembly: AssemblyCompany("")][assembly: AssemblyProduct("")][assembly: AssemblyCopyright("")][assembly: AssemblyTrademark("")][assembly: AssemblyCulture("")] [assembly: AssemblyVersion("1.0.*")][assembly: AssemblyDelaySign(false)][assembly: AssemblyKeyFile("")][assembly: AssemblyKeyName("")]

Metadata (Module 1)

Type 1 (IL-Code) Type 2 (IL-Code), ...

Resources

... ...

↑ C#-Entwickler-ToolsC# - Konfigurations- und Weitergabetools

ASP.NET IIS-Registrierungstool (Aspnet_regiis.exe)

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 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 %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Assembly Cache Viewer (Shfusion.dll) Ermöglicht das Anzeigen und Ändern der Inhalte des globalen Assemblycache mit Windows Explorer. Hinweis: Shfusion.dll befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Assembly-Linker (Al.exe) Generiert eine Datei mit einem Assemblymanifest aus einer oder mehreren Ressourcendateien bzw. aus Microsoft Intermediate Language-Dateien (MSIL). Hinweis: Al.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Assemblyregistrierungstool (Regasm.exe) 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. Hinweis: Regasm.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Assemblybindungs-Protokollanzeige (Fuslogvw.exe)

Zeigt die Details für fehlgeschlagene Assemblybindungen an. Mit diesen Informationen können Sie festzustellen, weshalb .NET Framework eine Assembly zur Laufzeit nicht finden kann.

Globales Assemblycache-Tool (Gacutil.exe)

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 Buildskripts, Makefile-Dateien und Batchdateien verwenden.

Installer-Tool (Installutil.exe) Ermöglicht das Installieren und Deinstallieren von Serverressourcen durch Ausführen der Installerkomponenten einer angegebenen Assembly. Hinweis: Installutil.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Tool für den isolierten Speicher (Storeadm.exe)

Entfernt oder listet den gesamten Speicher für den angemeldeten Benutzer auf.

Tool zum Generieren von systemeigenen Abbildern (Ngen.exe)

Erstellt ein systemeigenes Abbild von einer verwalteten Assembly und installiert es im systemeigenen Abbildcache auf dem lokalen Computer. Hinweis: Ngen.exe befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

.NET Framework-Konfigurationstool (Mscorcfg.msc)

Stellt eine grafische Oberfläche zum Verwalten der .NET Framework-Sicherheitsrichtlinie und der Anwendungen bereit, die Remotedienste verwenden. Dieses Tool ermöglicht daneben das Verwalten und Konfigurieren von Assemblys im globalen Assemblycache. Hinweis: Mscorcfg.msc befindet sich in %windir%\Microsoft.NET\Framework\v1.1.xxxx, wobei xxxx die Buildnummer des verwendeten .NET Frameworks ist.

Page 509: Systemprogrammierung II (SP II,Script 2005)

Installationstool für die .NET-Dienste (Regsvcs.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.

Soapsuds-Tool (Soapsuds.exe) Unterstützt Sie bei der Kompilierung von Clientanwendungen, die über die sog. Remoting-Technik mit XML-Webdiensten kommunizieren.

Typbibliothek-Exportierprogramm (Tlbexp.exe)

Generiert eine Typbibliothek aus einer CLR-Assembly (Common Language Runtime).

Typbibliothek-Importierprogramm (Tlbimp.exe)

Konvertiert die Typendefinitionen in einer COM-Typbibliothek in äquivalente Definitionen im verwalteten Metadatenformat.

WSDL-Tool (Web Services Description Language) (Wsdl.exe)

Generiert Code für XML-Webdienste und XML-Webdienstclients aus WSDL-Dateien (Web Services Description Language), XSD-Dateien (XML Schema Definition) und .discomap-Discoverydokumenten.

Webdienste-Suchtool (Disco.exe) 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.

Tool für die XML-Schemadefinition (Xsd.exe)

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

Microsoft CLR Debugger (DbgCLR.exe) 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.

Laufzeit-Debugger (Cordbg.exe) 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

Tool für die Zertifikatserstellung (Makecert.exe)

Generiert X.509-Zertifikate, die nur zu Testzwecken dienen.

Tool für die Zertifikatsverwaltung (Certmgr.exe)

Verwaltet Zertifikate, Zertifikatsvertrauenslisten und Zertifikatssperrlisten (CRLs).

Zertifikatsüberprüfungstool (Chktrust.exe)

Überprüft die Gültigkeit einer Datei, die mit einem X.509-Zertifikat signiert wurde.

Sicherheitsrichtlinientool für den Codezugriff (Caspol.exe)

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.

Tool für die Dateisignierung (Signcode.exe)

Signiert eine PE-Datei (Portable Executable) mit einer digitalen Authenticode-Signatur.

Tool zum Anzeigen von Berechtigungen (Permview.exe)

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.

PEVerify-Tool (PEverify.exe) Überprüft die MSIL-Typensicherheit und die Gültigkeit der Metadaten für eine angegebene Assembly.

Secutil-Tool (Secutil.exe) Extrahiert öffentliche Schlüsselinformationen für starke Namen oder Authenticode-Publisherzertifikate aus einer Assembly in einem Format, das in Code eingebunden werden kann.

Registrierungstool (Setreg.exe) Ermöglicht das Ändern der Registrierungseinstellungen für die Schlüssel Software Publishing State, die das Verhalten der Zertifikatsüberprüfung steuern.

SPC-Testtool (Cert2spc.exe) Erstellt ausschließlich zu Testzwecken ein SPC (Software Publisher's Certificate), das aus mindestens einem X.509-Zertifikat besteht.

Strong Name-Tool (Sn.exe) 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

Common Language Runtime-Minidumptool (Mscordmp.exe)

Erstellt eine Datei, die Informationen zum Analysieren von Systemproblemen zur Laufzeit enthält. Das Tool Microsoft Dr. Watson (Drwatson.exe) startet dieses Programm automatisch.

Lizenzencompiler (Lc.exe) Liest Textdateien, die Lizenzinformationen enthalten, und erstellt eine .licenses-Datei, die in einer ausführbaren Common Language Runtime-Datei eingebettet werden kann.

Management Strongly Typed Class Generator (Mgmtclassgen.exe)

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).

Page 510: Systemprogrammierung II (SP II,Script 2005)

MSIL-Assembler (Ilasm.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.

MSIL-Disassembler (Ildasm.exe) 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.

Generierungstool für Ressourcendateien (Resgen.exe)

Konvertiert Textdateien und .resx-Dateien (XML-basiertes Ressourcenformat) in .resources-Dateien der .NET Common Language Runtime, die in einer ausführbaren Laufzeit-Binärdatei eingebettet oder in Satellitenassemblys kompiliert werden können.

Visual J#-Binärkonvertierungstool (JbImp.exe)

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 ActiveX-Steuerelemente (Aximp.exe)

Konvertiert Typendefinitionen in einer COM-Typbibliothek für ein ActiveX-Steuerelement in einem Windows Forms-Steuerelement.

Windows Forms-Klassenanzeige (Wincv.exe)

Sucht verwaltete Klassen, die mit den angegebenen Suchkriterien übereinstimmen, und zeigt mit der Reflektions-API Informationen über die Klassen an.

Ressourcen-Editor für Windows Forms (Winres.exe)

Ermöglicht das einfache und schnelle Lokalisieren von Windows Forms-Formularen.

↑ C#-keywords

In C# gibt es die folgenden "Schlüsselworte":

abstract as base bool break byte case catch char checked

class const continue decimal default delegate do double else enum

event explicit extern false finally fixed float for foreach goto

if implicit in int interface internal is lock long namespace

new null object operator out override params private protected public

readonly ref return sbyte sealed short sizeof stackalloc static string

struct switch this throw true try typeof uint ulong unchecked

unsafe ushort using virtual void volatile while

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 __int8 __int16 __int32 __int64

__interface __leave __m128 __m128d __m128i __multiple_inheritance __nogc

__noop __pin __property __raise __sealed __single_inheritance __stdcall __super

__try_cast __try/__except,__try/__finally

__unhook __uuidof __value __virtual_inheritance __w64

Page 511: Systemprogrammierung II (SP II,Script 2005)

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, using directive

uuid 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 typesa) Classes: Delegates,User-Defined,Boxed Values) b) Arrays

Interface

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 boxint value2 = (int) o; // unbox into value2

Page 512: Systemprogrammierung II (SP II,Script 2005)

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.

Wie funktioniert (intern) Boxing and Unboxing?

tagVARIANT ist in oaidl.h definiert

BasicType ist in cvconst.h definiert

VARENUM ist in wtypes.h definiert

printVariant()-Beispiel

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;} ;

enum BasicType { btNoType = 0, btVoid = 1, btChar = 2, btWChar = 3, btInt = 6, btUInt = 7, btFloat = 8, btBCD = 9, btBool = 10, btLong = 13, btULong = 14, btCurrency= 25, btDate = 26, btVariant = 27, btComplex = 28, btBit = 29, btBSTR = 30, btHresult = 31};

enum VARENUM { VT_EMPTY = 0, VT_NULL = 1, VT_I2 = 2, VT_I4 = 3, VT_R4 = 4, VT_R8 = 5, VT_CY = 6, VT_DATE = 7, VT_BSTR = 8, VT_DISPATCH = 9, VT_ERROR = 10, VT_BOOL = 11, VT_VARIANT= 12, VT_UNKNOWN = 13, VT_DECIMAL= 14, VT_I1 = 16, VT_UI1 = 17, VT_UI2 = 18, VT_UI4 = 19, VT_I8 = 20, VT_UI8 = 21, VT_INT = 22, VT_UINT = 23, VT_VOID = 24, VT_HRESULT = 25, VT_PTR = 26, VT_SAFEARRAY = 27, VT_CARRAY = 28, VT_USERDEFINED = 29, VT_LPSTR = 30, VT_LPWSTR = 31, VT_RECORD = 36, VT_INT_PTR = 37, VT_UINT_PTR = 38, VT_FILETIME = 64, VT_BLOB = 65, VT_STREAM = 66, VT_STORAGE = 67, VT_STREAMED_OBJECT = 68, VT_STORED_OBJECT = 69, 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 } ;

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; }}

↑ 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 [DllImport("kernel32.dll")] oder [DllImport("kernel32.dll", CharSet = CharSet.Auto)] wird eine Import-Einbindung in unsere Klasse veranlaßt. Nach [DllImport("...dll")] folgt der Prototyp public static extern bool Beep(int frequency, int duration);, der dem C#-Compiler bei der "Typsicherheit hilft".

Für einen akustischen Hinweis ist meist die C++-Funktion BOOL MessageBeep(UINT soundtype) günstiger, die in C# als bool MessageBeep(BeepType beepType); benutzt werden kann. Im C++-Header File winuser.h sind Konstanten definiert, wie z.B. "MB_ICONHAND", die nach C# gewandelt werden können, etwa:

Page 513: Systemprogrammierung II (SP II,Script 2005)

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); } } }

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);

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

Page 514: Systemprogrammierung II (SP II,Script 2005)

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

#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

↑ Beispiel für cs-Console-Applikation

#undef P01#undef P02#undef P03#undef P04#undef P05#define P01

#if P01/////////////////////////////////////////////////// ohne using System; /////////////////////////////////////////////////class HalloWelt { static void Main() { System.Console.WriteLine( "\n*** Hallo Welt!" +"\n*** Ohne Verwendung von" +"\n*** using System;");

Page 515: Systemprogrammierung II (SP II,Script 2005)

} }#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 P04namespace 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)

Page 516: Systemprogrammierung II (SP II,Script 2005)

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