Tutorial 5: Mehr über Text
Wir werden noch mehr mit Textattributen herum experimentieren, z.B. Schriftarten und Farben.
Laden Sie hier das Beispiel herunter.
Theorie:
Windows Farbensystem basiert auf den RGB-Werten, R=Rot, G=Grün, B=Blau. Wenn Sie in Windows eine Farbe definieren wollen, müssen Sie die gewünschte Farbe anhand dieser drei Grundfarben zusammensetzen. Jede Farbe hat einen Wert zwischen 0 und 255 (ein Byte Wert). Wenn Sie zum Beispiel pures Rot haben wollen, müssen Sie 255,0,0 benutzen. Oder wenn Sie pures Weiss haben wollen, müssen Sie 255,255,255 benutzen. Wie Sie anhand der Beispiele sehen können, ist es sehr schwierig, die gewünschte Farbe zu bekommen, die Sie benötigen, da Sie ein gutes Verständnis fürs mischen der passenden Farben haben müssen.
Für Textfarbe und Hintergrund können Sie SetTextColor und SetBkColor benutzen. Beide benötigen ein Handle des Device Context und einen 32-bit RGB Wert. Die Struktur der 32-bit RGB Werte ist wie folgt definiert:
RGB_value struct
unbenutzt db 0
blau db ?
grün db ?
rot db ?
RGB_value ends
Beachten Sie, dass das erste Byte nicht benutzt wird und gleich Null sein sollte. Die Reihenfolge der übrigen drei Bytes ist umgekehrt, Blau, Grün, Rot. Wie dem auch sei, wir werden diese Struktur nicht benutzen, da sie lästig zu initialisieren und zu benutzen ist. Statt dessen werden wir eine Makro erstellen. Dem Makro werden folgende drei Parameter übergeben: Rot-, Grün- und Blauwerte. Es wird den gewünschten 32-bit RGB Wert erzeugen und in EAX speichern. Das Makro sieht wie folgt aus:
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
Sie können das Makro in die Include-Datei einfügen, für späteren Gebrauch.
Sie können einen Font (Schriftart) "kreieren" indem Sie CreateFont oder CreateFontIndirect aufrufen. Der Unterschied zwischen den beiden Funktionen ist, dass CreateFontIndirect nur ein Parameter übergeben wird: einen Zeiger auf eine logische Font Struktur, LOGFONT. CreateFontIndirect ist der flexiblere Weg der beiden, insbesondere, wenn ihr Programm den Font öfters ändern muss.
Wie dem auch sei werden wir in unserem Beispiel nur ein Font zur Demonstration "kreieren", so dass wir mit CreateFont auskommen. Nach dem Aufruf von CreateFont, wird ein Handle auf den Font welchen Sie im Device Context auswählen müssen. Danach wird jede Text-API-Funktion den im Device Context ausgewählten Font benutzen.
Inhalt:
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
TestString db "Win32 Assembler ist grossartig und einfach!",0
FontName db "script",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
LOCAL hfont:HFONT
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
ADDR FontName
invoke SelectObject, hdc, eax
mov hfont,eax
RGB 200,200,50
invoke SetTextColor,hdc,eax
RGB 0,0,255
invoke SetBkColor,hdc,eax
invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
invoke SelectObject,hdc, hfont
invoke EndPaint,hWnd, ADDR ps
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
Analyse:
invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
ADDR FontName
CreateFont erzeugt einen logischen Font, der den angegebenen Parametern am nächsten kommt und auch verfügbar ist. Diese Funktion hat mehr Parameter als jede andere Funktion in Windows. Sie gibt einen Handle auf den logischen Font zurück, welcher von der SelectObject Funktion gebraucht wird. Wir werden uns die Parameter im Detail anschauen.
CreateFont proto nHeight:DWORD,\
nWidth:DWORD,\
nEscapement:DWORD,\
nOrientation:DWORD,\
nWeight:DWORD,\
cItalic:DWORD,\
cUnderline:DWORD,\
cStrikeOut:DWORD,\
cCharSet:DWORD,\
cOutputPrecision:DWORD,\
cClipPrecision:DWORD,\
cQuality:DWORD,\
cPitchAndFamily:DWORD,\
lpFacename:DWORD
nHeight Die gewünschte Höhe der Buchstaben. 0 bedeutet Standardgröße.
nWidth Die gewünschte Breite der Buchstaben. Normalerweise sollte dieser Wert 0 sein, was Windows erlaubt, die Breite an die Höhe anzupassen. Wie dem auch sei, in unserem Beispiel ist die Standardbreite der Buchstaben schwer zu lesen, weshalb ich die Breite 16 statt dessen benutze.
nEscapement Spezifiziert die Ausrichtung des nächsten Buchstabens relativ zum vorherigen, in Zehntel Grad. Normalerweise auf 0 gesetzt. Geben Sie 900 an, um alle Buchstaben vom ersten an nach oben auszugeben, 1800 um rückwärts zu schreiben oder 2700 um jeden Buchstaben von oben nach oben auszugeben.
nOrientation Spezifiziert um wieviel der Buchstabe rotiert werden soll, wenn die Ausgabe in Zehntel Grad statt findet. Geben Sie 900 an, um alle Buchstaben auf dem Kopf auszugeben, 1800 für eine Auf- und Ab-Ausgabe, etc.
nWeight Setzt die Dicke der Buchstaben fest. Windows definiert folgende Größe:
FW_DONTCARE equ 0
FW_THIN equ 100
FW_EXTRALIGHT equ 200
FW_ULTRALIGHT equ 200
FW_LIGHT equ 300
FW_NORMAL equ 400
FW_REGULAR equ 400
FW_MEDIUM equ 500
FW_SEMIBOLD equ 600
FW_DEMIBOLD equ 600
FW_BOLD equ 700
FW_EXTRABOLD equ 800
FW_ULTRABOLD equ 800
FW_HEAVY equ 900
FW_BLACK equ 900
cItalic 0 für normal, jeden anderen Wert für kursive Buchstaben.
cUnderline 0 für normal, jeden anderen Wert für unterstrichene Buchstaben.
cStrikeOut 0 für normal, jeden anderen Wert für durchgestrichene Buchstaben.
cCharSet Der Buchstabensatz des Fonts. Normalerweise OEM_CHARSET, was Windows erlaubt einen Betriebssystem abhängigen Font zu wählen.
cOutputPrecision Spezifiziert wie dicht der ausgewählte Font an den Vorgaben sein muss, die wir wollen. Sollte normalerweise OUT_DEFAULT_PRECIS sein, was das Standard-Font-Auswahl-Verhalten definiert.
cClipPrecision Spezifiziert die 'Abschneide'-Genauigkeit. Die 'Abschneide'-Genauigkeit definiert wie ein Buchstabe abgeschnitten wird, wenn er teilweise außerhalb der 'Abschneide'-Region liegt. Sie sollten mit CLIP_DEFAULT_PRECIS auskommen, was das Standard-'Abschneide'-Verhalten definiert.
cQuality Spezifiziert die Ausgabequalität. Die Ausgabequalität definiert wie genau das GDI versucht, den Attributen des logischen Font, denen des aktuellen physischen Font nahe zu kommen. Es gibt drei zur Auswahl: DEFAULT_QUALITY, PROOF_QUALITY und DRAFT_QUALITY.
cPitchAndFamily Spezifiziert Neigung und Familie des Fonts. Sie müssen beides mit dem 'oder'-Operator verbinden.
lpFacename Ein Zeiger auf einen Nullterminierten String, der die Schriftart des Fonts spezifiziert.
Die obige Beschreibung ist mehr als kurz. Sie sollten ihre Win32 API-Referenz für mehr Details zu Rate ziehen.
invoke SelectObject, hdc, eax
mov hfont,eax
Nachdem wir das Handle auf den logischen Font erhalten haben, müssen wir es benutzen, um den Font in dem Device Context auszuwählen, indem wir SelectObject aufrufen. SelectObject fügt die neuen GDI Objekte wie Pens, Brushs und Fonts in den Device Context ein, die von GDI-Funktionen benutzt werden. Sie liefert ein Handle des ersetzten Objekts zurück, welches wir für weitere SelectObjekt Aufrufe sichern sollten. Nach dem SelectObject-Aufruf wird jede Textausgabe-Funktion den Font benutzen, den wir für den Device Context ausgewählt haben.
RGB 200,200,50
invoke SetTextColor,hdc,eax
RGB 0,0,255
invoke SetBkColor,hdc,eax
Benutzen Sie das RGB Makro um einen 32-bit RGB Wert zu erzeugen, der von SetColorText und SetBkColor benutzt wird.
invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
Rufen Sie die TextOut Funktion auf, um den Text in der Client Area auszugeben. Der Text wird in der Font-Art und Farbe erscheinen, die Sie vorher ausgewählt haben.
invoke SelectObject,hdc, hfont
Wenn wir mit dem Font fertig sind, sollten wir den alten Font im Device Context wiederherstellen. Sie sollten immer das Objekt wiederherstellen, dass Sie im Device Context ersetzt haben.
Deutsche Übersetzung: Joachim Rohde
Die original Win32Asm-Tutorials stammen von Iczelion's Win32 Assembly HomePage