九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
【原創(chuàng)】Nasm
標(biāo) 題: 【原創(chuàng)】Nasm-Win32匯編學(xué)習(xí)4-繪制文本
作 者: littlefire
時 間: 2009-11-11,20:35:59
鏈 接: http://bbs.pediy.com/showthread.php?t=101077


繪制文本

    今天我們將學(xué)習(xí)如何在窗口的客戶區(qū)“繪制”字符串。我們還將學(xué)習(xí)關(guān)于“設(shè)備環(huán)境”的概念。

    Windows中的文本是一個GUI(圖形用戶界面)對象。每一個字符實際上是由許多的像素點組成,這些點在有筆畫的地方顯示出來,這樣就會出現(xiàn)字符。這也是為什么我說“繪制”字符,而不是寫字符。通常你都是在你應(yīng)用程序的客戶區(qū)“繪制”字符串(盡管你也可以在客戶區(qū)外“繪制”)。Windows下的“繪制”字符串方法和Dos下的截然不同,在Dos下你可以把屏幕想象成85x25的一個平面,而Windows下由于屏幕上同時有幾個應(yīng)用程序的畫面,所以你必須嚴(yán)格遵從規(guī)范。Windows通過把每一個應(yīng)用程序限制在他的客戶區(qū)來做到這一點。當(dāng)然客戶區(qū)的大小是可變的,你隨時可以調(diào)整。
    提示:客戶區(qū)是指我們窗體與用戶交互的部分。打個比方,比如我們Windows的notepad記事本程序的客戶區(qū)就是它的編輯框,非客戶區(qū)則是指它的標(biāo)題欄和菜單欄及滾動條。
    在你在客戶區(qū)“繪制”字符串前,你必須從Windows那里得到你客戶區(qū)的大小,確實你無法像在Dos下那樣隨心所欲地在屏幕上任何地方“繪制”,繪制前你必須得到Windows的允許,然后Windows會告訴你客戶區(qū)的大小,字體,顏色和其它GUI對象的屬性。你可以用這些來在客戶區(qū)“繪制”。

    什么是“設(shè)備環(huán)境”(DC)呢?它其實是由Windows內(nèi)部維護(hù)的一個數(shù)據(jù)結(jié)構(gòu)。一個“設(shè)備環(huán)境”和一個特定的設(shè)備相連。像打印機(jī)和顯示器。對于顯示器來說,“設(shè)備環(huán)境”和一個個特定的窗口相連。
    “設(shè)備環(huán)境”中的有些屬性和繪圖有關(guān),像:顏色,字體等。你可以隨時改動那些缺省值,之所以保存缺省值是為了方便。你可以把“設(shè)備環(huán)境”想象成是Windows為你準(zhǔn)備的一個繪圖環(huán)境,而你可以隨時根據(jù)需要改變某些缺省屬性。

    當(dāng)應(yīng)用程序需要繪制時,你必須得到一個“設(shè)備環(huán)境”的句柄。通常有幾種方法:

    在WM_PAINT消息中使用call BeginPaint。
    在其他消息中使用call GetDC。
    call CreateDC建立自己的DC。

    你必須牢記的是,在處理單個消息后你必須釋放“設(shè)備環(huán)境”句柄。不要在一個消息處理中獲得“設(shè)備環(huán)境”句柄,而在另一個消息處理中再釋放它。
    我們在Windows發(fā)送WM_PAINT消息時處理繪制客戶區(qū),Windows不會保存客戶區(qū)的內(nèi)容,它用的方法是“重繪”機(jī)制(譬如當(dāng)客戶區(qū)剛被另一個應(yīng)用程序的客戶區(qū)覆蓋),Windows會把WM_PAINT消息放入該應(yīng)用程序的消息隊列。重繪窗口的客戶區(qū)是各個窗口自己的責(zé)任,你要做的是在窗口過程處理WM_PAINT的部分知道繪制什么和如何繪制。

    你必須了解的另一個概念是“無效區(qū)域”。Windows把一個最小的需要重繪的正方形區(qū)域叫做“無效區(qū)域”。當(dāng)Windows發(fā)現(xiàn)了一個“無效區(qū)域”后,它就會向該應(yīng)用程序發(fā)送一個WM_PAINT消息,在WM_PAINT的處理過程中,窗口首先得到一個有關(guān)繪圖的結(jié)構(gòu)體,里面包括無效區(qū)的坐標(biāo)位置等。你可以通過調(diào)用BeginPaint讓“無效區(qū)”有效,如果你不處理WM_PAINT消息,至少要調(diào)用缺省的窗口處理函數(shù)DefWindowProc,或者調(diào)用ValidateRect讓“無效區(qū)”有效。否則你的應(yīng)用程序?qū)盏綗o窮無盡的WM_PAINT消息。

    下面是響應(yīng)該消息的步驟:
   
    1、取得“設(shè)備環(huán)境”句柄
    2、繪制客戶區(qū)
  3、釋放“設(shè)備環(huán)境”句柄

    假如,我們程序的客戶區(qū)假設(shè)被另一個應(yīng)用程序的客戶區(qū)所覆蓋,那些此刻另一個應(yīng)用程序退出,相應(yīng)我們程序被覆蓋客戶區(qū)需要發(fā)生重繪,而被覆蓋的這部分叫做“無效區(qū)域”,這時候Windows就會檢測到我們需要發(fā)生重繪的無效區(qū)域,然后發(fā)送給我們程序的消息隊列中一個WM_PAINT消息。此刻我們就需要在我們的窗口過程中處理WM_PAINT消息,即使不處理也要調(diào)用缺省的DefWindowProc函數(shù)。BeginPaint函數(shù)默認(rèn)使無效區(qū)有效。那么BeginPaint返回了一個設(shè)備環(huán)境的句柄。因為我們Windows下的硬件設(shè)備都是以相關(guān)的驅(qū)動形式來和Windows通信的,那么我們的設(shè)備環(huán)境也就關(guān)聯(lián)了相應(yīng)的設(shè)備。例如我們的窗體對象關(guān)聯(lián)了相應(yīng)的顯示器設(shè)備,那么此時我們要想在窗體上顯示文本,我們必須通過設(shè)備驅(qū)動,因為Windows提供給了我們相應(yīng)的函數(shù)以及相應(yīng)的數(shù)據(jù)類型,我們只需要取得設(shè)備環(huán)境的句柄,然后通過相應(yīng)的函數(shù)來調(diào)用,此時我們不需要知道它是如何實現(xiàn)的,我們只需要遵守Windows的規(guī)則就可以了。下面我們通過一段代碼來深入分析一下。

%include '..\inc\nasmx.inc'
%include '..\inc\win32\windows.inc'
%include '..\inc\win32\kernel32.inc'
%include '..\inc\win32\user32.inc'

entry    start

[section .bss]
    hInstance:   resd 1
    hWnd:        resd 1
  lpCommandLine: resd 1

[section .data]
    szTitle:    db    "My First Window", 0x0
    szClass:    db    "FirstWindow", 0x0
  szText:    db    "My First Window Text", 0x0

    wc:
    istruc WNDCLASSEX                  ;聲明結(jié)構(gòu)體
        at WNDCLASSEX.cbSize,           dd    NULL
        at WNDCLASSEX.style,            dd    NULL
        at WNDCLASSEX.lpfnWndProc,      dd    NULL
        at WNDCLASSEX.cbClsExtra,       dd    NULL
        at WNDCLASSEX.cbWndExtra,       dd    NULL
        at WNDCLASSEX.hInstance,        dd    NULL
        at WNDCLASSEX.hIcon,            dd    NULL
        at WNDCLASSEX.hCursor,          dd    NULL
        at WNDCLASSEX.hbrBackground,    dd    NULL
        at WNDCLASSEX.lpszMenuName,     dd    NULL
        at WNDCLASSEX.lpszClassName,    dd    NULL
        at WNDCLASSEX.hIconSm,          dd    NULL
    iend

    message:
    istruc MSG
        at MSG.hwnd,                    dd    NULL
        at MSG.message,                 dd    NULL
        at MSG.wParam,                  dd    NULL
        at MSG.lParam,                  dd    NULL
        at MSG.time,                    dd    NULL
        at MSG.pt,                      dd    NULL
    iend

  ps:
  istruc PAINTSTRUCT    
  iend

    rect:
  istruc RECT
        at RECT.left,                  dd    NULL
        at RECT.top,                   dd    NULL
        at RECT.right,                 dd    NULL
        at RECT.bottom,                dd    NULL
    iend

[section .code]
proc    start

    invoke   GetModuleHandleA, dword NULL    
    mov      [hInstance], eax          
  
  invoke  GetCommandLineA            
  mov    [lpCommandLine], eax

    invoke   WinMain, dword [hInstance], dword NULL, dword lpCommandLine, dword SW_SHOWNORMAL    
    invoke   ExitProcess, dword NULL      
    ret

endproc

proc    WinMain
hinst    argd        ; Current instance handle
hpinst   argd        ; Previous instance handle
cmdln    argd        ; Command line arguments
dwshow   argd        ; Display style

    mov     [wc + WNDCLASSEX.cbSize], dword WNDCLASSEX_size        
  mov    [wc + WNDCLASSEX.style], dword CS_HREDRAW | CS_VREDRAW    
  invoke  LoadIconA, dword NULL, dword IDI_APPLICATION
    mov     edx, eax
    mov     eax, dword argv(hinst)
    mov     ebx, dword szClass
    mov     ecx, dword WndProc
    mov     [wc + WNDCLASSEX.hInstance], eax
  mov    [wc + WNDCLASSEX.hbrBackground], dword COLOR_WINDOW + 1
    mov     [wc + WNDCLASSEX.lpszClassName], ebx
    mov     [wc + WNDCLASSEX.lpfnWndProc], ecx
    mov     [wc + WNDCLASSEX.hIcon], edx
    mov     [wc + WNDCLASSEX.hIconSm], edx

    invoke   RegisterClassExA, dword wc          

  
    invoke   CreateWindowExA, dword NULL, dword szClass, dword szTitle, dword WS_OVERLAPPEDWINDOW + WS_VISIBLE, dword CW_USEDEFAULT, dword CW_USEDEFAULT, dword CW_USEDEFAULT, dword CW_USEDEFAULT, dword NULL, dword NULL, dword [wc + WNDCLASSEX.hInstance], dword NULL
    mov      [hWnd], eax

    invoke   ShowWindow, dword hWnd, dword argv(dwshow)      
    invoke   UpdateWindow, dword hWnd              

    .WHILE:                            
        invoke   GetMessageA, dword message, dword NULL, dword NULL, dword NULL
        cmp      eax, dword 0
        je       .ENDW
        invoke   TranslateMessage, dword message
        invoke   DispatchMessageA, dword message
        jmp      .WHILE
    .ENDW:

    mov      eax, dword [message + MSG.wParam]
    ret

endproc

proc    WndProc
hwnd    argd        ; Window handle
umsg    argd        ; Window message
wparam  argd        ; wParam
lparam  argd        ; lParam

  locals                ;locals/local/endlocals,聲明局部變量,使用var()宏獲得變量地址
    local hdc, Dword          
  endlocals

  if argv(umsg), ==, dword WM_DESTROY                 
    invoke  PostQuitMessage, dword NULL

  elsif argv(umsg), ==, dword WM_PAINT
    invoke  BeginPaint, dword argv(hwnd), dword ps      ;重繪指定的窗口
    mov    dword var(hdc), eax
    invoke  GetClientRect, dword argv(hwnd), dword rect    ;獲取客戶區(qū)的坐標(biāo),放到RECT結(jié)構(gòu)體中
    invoke  DrawTextA, dword var(hdc), dword szText, dword -1, dword rect, dword DT_SINGLELINE | DT_CENTER | DT_VCENTER  ;在指定窗口寫入格式化文本。
    invoke  EndPaint, dword argv(hwnd), dword ps      ;指定窗口的繪制過程結(jié)束,這個函數(shù)在每次調(diào)用BeginPaint函數(shù)之后被請求。

  else 
    invoke  DefWindowProcA, dword argv(hwnd), dword argv(umsg), dword argv(wparam), dword argv(lparam)
    
  endif
  
  ret

endproc

    今天的代碼跟我們前面寫的窗口顯示代碼,只有幾點不同的地方。
    一、數(shù)據(jù)段中增加了兩個結(jié)構(gòu)體的聲明:PAINTSTRUCT和RECT
  ps:
  istruc PAINTSTRUCT    
  iend

    rect:
  istruc RECT
        at RECT.left,                  dd    NULL
        at RECT.top,                   dd    NULL
        at RECT.right,                 dd    NULL
        at RECT.bottom,                dd    NULL
    iend

  二、窗口過程中聲明了局部變量hdc:

  locals                ;locals/local/endlocals,聲明局部變量,使用var()宏獲得變量地址
    local hdc, Dword          
  endlocals
  
  上面這兩點中聲明的變量,都是由處理WM_PAINT消息的GDI函數(shù)調(diào)用。locals/local/endlocals是nasmx提供給我們在函數(shù)中聲明局部變量的宏,locals是局部變量區(qū)的開頭,endlocals是局部變量區(qū)的結(jié)尾,中間用local聲明,“l(fā)ocal parm, 數(shù)據(jù)類型(byte,word,dword等)”。使用var(parm)宏來調(diào)用。
  hdc用來存放調(diào)用BeginPaint返回的“設(shè)備環(huán)境”句柄。ps是一個PAINTSTRUCT數(shù)據(jù)類型的變量。它由Windows傳遞給BeginPaint,在結(jié)束繪制后再原封不動的傳遞給EndPaint。它的函數(shù)原型如下:

typedef struct tagPAINTSTRUCT { 
  HDC hdc; 
  BOOL fErase; 
  RECT rcPaint;
  BOOL fRestore;
  BOOL fIncUpdate;
  BYTE rgbReserved[32]; 
  } PAINTSTRUCT, *PPAINTSTRUCT; 
  PAINTSTRUCT 結(jié)構(gòu)體包含了用于繪制窗口客戶區(qū)的信息。
  hdc是用于繪制的句柄,fErase如果為非零值則擦除背景,否則不擦除背景,rcPaint 通過制定左上角和右下角的坐標(biāo)確定一個要繪制的矩形范圍,該矩形單位相對于客戶區(qū)左上角,后面三個參數(shù)都是系統(tǒng)預(yù)留的,編程一般用不到。
  
  rect是一個RECT結(jié)構(gòu)體類型的參數(shù),它的定義如下:
STRUC RECT
.left RESD 1
.top RESD 1
.right RESD 1
.bottom RESD 1
ENDSTRUC
  left和top是客戶區(qū)正方形左上角的坐標(biāo)。right和buttom是正方形右下角的坐標(biāo)。

  三、在窗口函數(shù)的消息判斷中增加了對WM_PAINT消息的處理

  elsif argv(umsg), ==, dword WM_PAINT
    invoke  BeginPaint, dword argv(hwnd), dword ps      ;重繪指定的窗口
    mov    dword var(hdc), eax
    invoke  GetClientRect, dword argv(hwnd), dword rect    ;獲取客戶區(qū)的坐標(biāo),放到RECT結(jié)構(gòu)體中
    invoke  DrawTextA, dword var(hdc), dword szText, dword -1, dword rect, dword DT_SINGLELINE | DT_CENTER | DT_VCENTER  ;在指定窗口寫入格式化文本。
    invoke  EndPaint, dword argv(hwnd), dword ps      ;指定窗口的繪制過程結(jié)束,這個函數(shù)在每次調(diào)用BeginPaint函數(shù)之后被請求。

  大家注意到了嗎?對hdc的引入是使用var(hdc)宏實現(xiàn)的。

  在上面已經(jīng)講過,Windows只要檢測到我們有需要重繪的無效區(qū)域,就會發(fā)送WM_PAINT消息,那么我們必須處理WM_PAINT或通過缺省的DefWindowProc函數(shù)來處理。因為BeginPaint函數(shù)接受一個窗口句柄和未初始化的PAINTSTRUCT型參數(shù)后,會自動的將我們的無效區(qū)域設(shè)置為有效,所以此時我們一般調(diào)用BeginPaint來設(shè)置我們的無效區(qū)域有效,而且BeginPaint函數(shù)返回我們相應(yīng)的窗體對象的設(shè)備環(huán)境的句柄,我們此時獲得相應(yīng)設(shè)備環(huán)境句柄后,再調(diào)用GetClientRect獲得我們應(yīng)用程序窗體客戶區(qū)的大小。大小放在rect結(jié)構(gòu)體中。然后把它傳給DrawTextA。DrawText的原型如下:

int DrawText(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);

  hdc:“設(shè)備環(huán)境”的句柄。
    lpString:要顯示的文本串,該文本串要么以NULL結(jié)尾,要么在nCount中指出它的長度。
  nCount:要輸出的文本的長度。若以NULL結(jié)尾,該參數(shù)必須是-1。
  lpRect:指向要輸出文本串的正方形區(qū)域的指針,該正方形必須是一個裁剪區(qū),也就是說超過該區(qū)域的字符將不能顯示。
  uFormat:指定如何顯示。我們可以用“|”把以下標(biāo)志“或”到一塊。
    DT_SINGLELINE:是否單行顯示。
    DT_CENTER:是否水平居中。
    DT_VCENTER:是否垂直劇中。

  四、在.data段中聲明了窗口顯示變量:

szText:    db    "My First Window Text", 0x0

  結(jié)束繪制后,必須調(diào)用EndPaint釋放“設(shè)備環(huán)境”的句柄。好了,現(xiàn)在我們把“繪制”文本串的要點總結(jié)如下:
  1、必須在開始和結(jié)束處分別調(diào)用BeginPaint和EndPaint;
  2、在BeginPaint和EndPaint之間調(diào)用所有的繪制函數(shù);
  3、如果在其它的消息處理中重新繪制客戶區(qū),你可以有兩種選擇;
    (1)用GetDC和ReleaseDC代替BeginPaint和EndPaint;
    (2)調(diào)用InvalidateRect或UpdateWindow讓客戶區(qū)無效,這將迫使Windows把WM_PAINT放入應(yīng)用程序消息隊列,從而使得客戶區(qū)重繪。                                 
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
見招拆招《Windows程序設(shè)計》(十二) 第二部分
PE文件格式--------------基本結(jié)構(gòu)信息
注冊機(jī)音樂
游戲引擎與游戲引擎開發(fā)入門
用Windows API實現(xiàn)一個簡單的文本輸入框
WIN32匯編: 27.工具提示控件
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服