Fasm---Win32彙編學習7

         Fasm---Win32彙編學習7

學習更多關於“繪製”文本串的知識

 

我們將做更多的實踐去了解有關文本的諸多屬性如字體和顏色等。

理論:

Windows 的顏色系統是用RGB值來表示的,R 代表紅色,G 代表綠色,B 代表蘭色。如果您想指定一種顏色就必須給該顏色賦相關的 RGB 值,RGB 的取值範圍都是從 0 到 255,譬如您想要得到純紅色,就必須對RGB賦值(255,0,0),純白色是 (255,255,255)。從我們下面的例子中您可以看出來要想運用好這套基於數字的顏色系統並不容易,這要求您必須對混色和顏色匹配有良好的感覺。

您可以用函數 SetTextColor 和 SetBkColor 來“繪製”背景色和字符顏色,但是必須傳遞一個“設備環境”的句柄和 RGB 值作爲參數。RGB 的結構體的定義如下:

struct RGB_value
    unused db 0
    blue db ?
    green db ?
    red db ?
ends

    其中第一字節爲 0 而且始終爲 0,其它三個字節分別表示蘭色、綠色和紅色,剛好和 RGB 的次序相反。這個結構體用起來挺彆扭,所以我們重新定義一個宏用它來代替。該宏接收紅綠藍三個參數,並在 eax 寄存器中返回 32 位的 RGB 值,宏的定義如下:

macro RGB red, green, blue
{
    xor eax,eax
    mov ah, blue
    shl eax, 8
    mov ah, green
    mov al, red
}

 


您可以把該宏放到頭文件中以方便使用。

    您可以調用 CreateFont 和 CreateFontIndirect 來創建自己的字體,這兩個函數的差別是前者要求 您傳遞一系列的參數,而後着只要傳遞一個指向 LOGFONT 結構的指針。這樣就使得後者使用起來更方便,尤其當您需要頻繁創建字體時。在我們的例子中由於只要創建一種字體,故用 CreateFont 就足夠了。在調用該函數後會返回所創建的字體的句柄,然後把該句柄選進“設備環境”使其成爲當前字體,隨後所有的“繪製”文本串的函數在被調用時都要把該句柄作爲一個參數傳遞 。

 



例子:

format PE GUI 4.0
include 'win32ax.inc'


macro RGB red, green, blue
{
    xor eax,eax
    mov ah, blue
    shl eax, 8
    mov ah, green
    mov al, red
}

macro memmov [dst, src]
{
common
push [src]
pop [dst]
}

ID_TIMER1 equ 100
;************************數據********************************
szClassName db 'first Windows',0
szWndName db '我的第一個程序',0
szFontName db 'mefont',0
szCommand dd ?
hIcon rd 1
hInstanse rd 1
hCursor rd 1
hWnd rd 1
systime SYSTEMTIME

entry $
invoke GetModuleHandle,NULL
mov [hInstanse], eax
invoke GetCommandLine,NULL
mov [szCommand], eax
stdcall _WinMain,hInstanse, NULL, [szCommand], SW_SHOWDEFAULT
invoke ExitProcess,NULL

proc _WinMain hInstance:DWORD, hPrevInstance:DWORD, lpCmdLine:DWORD, nCmdShow:DWORD
local @wc : WNDCLASSEX
local @msg : MSG


invoke RtlZeroMemory,addr @wc,sizeof.WNDCLASSEX
invoke LoadIcon,NULL, IDI_WINLOGO
mov [hIcon], eax
invoke LoadCursor,NULL, IDC_ARROW
mov [hCursor], eax
mov [@wc.cbSize], sizeof.WNDCLASSEX
mov [@wc.style], CS_HREDRAW or CS_VREDRAW
mov [@wc.lpfnWndProc], _WndProc
mov [@wc.cbClsExtra], NULL
mov [@wc.cbWndExtra], NULL
memmov @wc.hInstance, hInstance
memmov @wc.hIcon, hIcon
memmov @wc.hCursor, hCursor
mov [@wc.hbrBackground], COLOR_WINDOW
mov [@wc.lpszMenuName], NULL
mov [@wc.lpszClassName], szClassName
;註冊窗口類
invoke RegisterClassEx,addr @wc
;建立窗口

invoke CreateWindowEx, NULL, szClassName, szWndName,/
WS_OVERLAPPEDWINDOW,/
100, 100, 600, 400,/
NULL, NULL, [hInstanse], NULL
mov [hWnd], eax
invoke ShowWindow,[hWnd],SW_SHOWNORMAL
invoke UpdateWindow,[hWnd]

GetMsg:
invoke GetMessage,addr @msg, NULL, 0, 0
or eax, eax
jz EndMsg
invoke TranslateMessage,addr @msg
invoke DispatchMessage,addr @msg
jmp GetMsg


EndMsg:
mov eax, [@msg.wParam]
ret
endp



proc _WndProc uses ebx esi edi,hWnd:DWORD, wMsg:DWORD, wParam:DWORD, lParam:DWORD
local @hdc:DWORD
local @ps : PAINTSTRUCT
local @rect: RECT
local @hfont:DWORD
cmp [wMsg], WM_DESTROY
jz Quit
cmp [wMsg], WM_PAINT
jz PAIT
invoke DefWindowProc,[hWnd],[wMsg],[wParam],[lParam]
ret



PAIT:
invoke BeginPaint,[hWnd], addr @ps
mov [@hdc], eax ;保存獲得顯示緩衝區的顯示描述表
invoke CreateFont,0,16,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,/
                        DEFAULT_QUALITY, DEFAULT_PITCH or FF_SCRIPT,/
                        szFontName
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,szWndName,15
invoke SelectObject,[@hdc], [@hfont]

invoke EndPaint,[hWnd], addr @ps
jmp endWnd

Quit:
invoke PostQuitMessage,NULL
jmp endWnd


endWnd:
xor eax,eax
ret
endp


;///////////////////////////輸入表////////////////////////////////////////////////


section '.import' data import readable writeable


library kernel32, 'kernel32.dll',/
user32, 'user32.dll',/
gdi32, 'gdi32.dll'
include 'api/kernel32.inc'
include 'api/user32.inc'
include 'api/gdi32.inc'

 

 

 

分析

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: 指定字體的名稱。

上面的描述不一定好理解,更詳細的內容請參看MSDN。

 

其實上面的代碼很多在上上節課我們已經講解了,只有很少的一部分不同。。。

我們來學習。

 

invoke BeginPaint,[hWnd], addr @ps
mov [@hdc], eax ;保存DC
invoke CreateFont,0,16,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,/
                        DEFAULT_QUALITY, DEFAULT_PITCH or FF_SCRIPT,/
                        szFontName
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,szWndName,15
invoke SelectObject,[@hdc], [@hfont]

invoke EndPaint,[hWnd], addr @ps

 

譯者注:

   首先這裏要再次講解下設備環境。設備環境也經常簡寫爲DC,它是用來管理訪問顯示和打印設備的工具。我們在windows中不是直接寫入屏幕,我們是通過獲得設備環境的句柄,使用該句柄來畫設備環境,然後windows會進行判斷並且從我們的設備環境中獲得相應的像素顯示到屏幕上。

    BeginPaint只能在WM_PAINT消息中使用,它將返回DC的句柄。。在WM_PAINT消息期間,應用程序經常在屏幕上執行繪圖操作。Windows將繪圖視爲低級的任務,這樣做是很恰當的,不然可能你只要顯示一個小變化windows就發送WM_PAINT消息,這會造成WM_PAINT消息氾濫。通過處理正在等待的消息允許應用程序完成它所有的掛起任務,這將是無效區域可以很高效的一次性畫出。

 

   當然有些時候畫圖程序也應該立即執行,例如當某個字符按下,我們必須馬上將它輸送到我們的屏幕上。要想在WM_PAINT消息進行繪圖,你必須調用GetDC。

   GetDc函數獲得窗口客戶區部分的DC的句柄。

那麼這裏我們首先調用BeginPaint來獲得我們的設備環境的句柄,並且將我們的無效區域設置爲有效。然後

mov [@hdc], eax 保存我們的設備環境句柄,以備後用。

然後調用CreateFont函數來創建字體,返回的是我們創建字體的句柄,這個時候我們通過SelectObject函數來將我們創建的字體句柄選入到我們的dc中,剛我已經說了windows是通過設備環境句柄來繪畫DC的。然後這個SelectObject返回的是先前選擇的對象,也就是之前的字體對象以便在完成“繪製”工作後再把它選回。

此時通過調用SetTextColor和SetBkColor函數來設置字體和背景色的顏色。最後通過TextOut函數輸出我們的字符串。因爲此時windows會檢測到當前我們的DC環境,然後按照DC環境的配置來輸出我們的字符串。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章