我們將做更多的實踐去了解有關文本的諸多屬性如字體和顏色等。
理論:
Windows 的顏色系統是用RGB值來表示的,R 代表紅色,G 代表綠色,B 代表蘭色。如果您想指定一種顏色就必須給該顏色賦相關的 RGB 值,RGB 的取值范圍都是從 0 到 255,譬如您想要得到純紅色,就必須對RGB賦值(255,0,0),純白色是 (255,255,255)。從我們下面的例子中您可以看出來要想運用好這套基於數字的顏色系統並不容易,這要求您必須對混色和顏色匹配有良好的感覺。
您可以用函數 SetTextColor 和 SetBkColor 來“繪制”背景色和字符顏色,但是必須傳遞一個“設備環境”的句柄和 RGB 值作為參數。RGB 的結構體的定義如下:
RGB_value struct
unused db 0
blue db ?
green db ?
red db ?
RGB_value ends
其中第一字節為 0 而且始終為 0,其它三個字節分別表示蘭色、綠色和紅色,剛好和 RGB 的次序相反。這個結構體用起來挺別扭,所以我們重新定義一個宏用它來代替。該宏接收紅綠藍三個參數,並在 eax 寄存器中返回 32 位的 RGB 值,宏的定義如下:
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
您可以把該宏放到頭文件中以方便使用。
您可以調用 CreateFont 和 CreateFontIndirect 來創建自己的字體,這兩個函數的差別是前者要求 您傳遞一系列的參數,而後著只要傳遞一個指向 LOGFONT 結構的指針。這樣就使得後者使用起來更方便,尤其當您需要頻繁創建字體時。在我們的例子中由於只要創建一種字體,故用 CreateFont 就足夠了。在調用該函數後會返回所創建的字體的句柄,然後把該句柄選進“設備環境”使其成為當前字體,隨後所有的“繪制”文本串的函數在被調用時都要把該句柄作為一個參數傳遞
例子:
.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 assembly is great and easy!",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
分析:
CreateFont 函數產生一種邏輯字體,它盡可能地接近參數中指定的各相關值。這個函數大概是所有 Windows API函數中所帶參數最多的一個。它返回一個指向邏輯字體的句柄供調用 SelectObject 函數使用。下面我們詳細講解該函數的參數:
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: 希望使用的字體的高度,0為缺省。
nWidth: 希望使用的字體的寬度,一般情況下最好用0, 這樣 Windows 將會自動為您選擇一個和高度匹配的值。因為在我們的例子中那樣做的話會使得字符因太小而無法顯示,所以 我 們設定它為16。
nEscapement: 每一個字符相對前一個字符的旋轉角度,一般設成0。900代表轉90度,1800轉190度,2700轉270度。
nOrientation: 字體的方向。
nWeight: 字體筆畫的粗細。
Windows 為我們預定義了如下值:
FW_DONTCARE 等於 0
FW_THIN 等於 100
FW_EXTRALIGHT 等於 200
FW_ULTRALIGHT 等於 200
FW_LIGHT 等於 300
FW_NORMAL 等於 400
FW_REGULAR 等於 400
FW_MEDIUM 等於 500
FW_SEMIBOLD 等於 600
FW_DEMIBOLD 等於 600
FW_BOLD 等於 700
FW_EXTRABOLD 等於 800
FW_ULTRABOLD 等於 800
FW_HEAVY 等於 900
FW_BLACK 等於 900
cItalic: 0為正常,其它值為斜體。
cUnderline: 0為正常,其它值為有下劃線。
cStrikeOut: 0為正常,其它值為刪除線。
cCharSet: 字體的字符集。一般選擇OEM_CHARSET,它使得 Windows 會選用和操作系統相關的字符集。
cOutputPrecision: 指定我們選擇的字體接近真實字體的精度。 一般選用OUT_DEFAULT_PRECIS,它決定了缺省的映射方式。
cClipPrecision: 指定我們選擇的字體在超出裁剪區域時的裁剪精度。 一般選用CLIP_DEFAULT_PRECIS,它決定了裁剪精度。
cQuality: 指定輸出字體的質量。它指出GDI應如何盡可能的接近真實 字體,一共有三種方式:DEFAULT_QUALITY, PROOF_QUALITY 和DRAFT_QUALITY。
cPitchAndFamily:字型和字體家族。
lpFacename: 指定字體的名稱。
上面的描述不一定好理解,您如果要的到更多的信息,應參考 WIN32 API 指南。
invoke SelectObject, hdc, eax
mov hfont,eax
在我們得到了指向邏輯字體的句柄後必須調用 SelectObject 函數把它選擇進“設備環境”,我們還可以調用該函數把諸如此類的像顏色、筆、畫刷 等GDI對象選進“設備環境”。該函數會返回一個舊的“設備環境”的句柄。您必須保存該句柄,以便在完成“繪制”工作後再把它選回。在調用 SelectObject 函數後一切的繪制函數都是針對該“設備環境”的。
RGB 200,200,50
invoke SetTextColor,hdc,eax
RGB 0,0,255
invoke SetBkColor,hdc,eax
我們用宏 RGB 產生顏色,然後分別調用 SetTextColor 和 SetBkColor。
invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
我們調用 TextOut 在客戶區用我們前面選定的字體和顏色“繪制”文本串。
invoke SelectObject,hdc, hfont
在我們“繪制”完成後,必須恢復“設備環境”。我們必須每一次都這麼做。