Ch 01 Win64 標準視窗


視窗函式

在 Win64 系統中的基本觀念,與 Win32 系統中差不多,大部分的觀念都不太需要重新學習。畢竟如果做了大翻修,已熟悉 Windows 作業系統的人們必會群起抱怨,這絕不是微軟所樂見的。例如,訊息傳遞與設備內容 ( device context,縮寫為 DC ) 都相似,說到這兒,聰明的您當可知,小木偶又要省略了有關這部分的原理,您可以 Win32 組合語言的第二章,標準視窗,閱讀。這堙A小木偶想,只要把原始碼列出來,大致就完工了!

雖然如此,但是還是有一點必須注意。在 Win32 堙A系統呼叫視窗函式時,會把視窗函式所需的四個參數依次存到堆疊堙A亦即在進入視窗函式時,hWnd、uMsg、wParam、lParam 之值已在堆疊堣F;但是在 Win64 系統堙A系統會把視窗函式所需的四個參數依次存到 RCX、RDX、R8、R9 四個暫存器堙A而不是存入堆疊中,程式可視需要,自行決定是否要存入堆疊堙C


STDWND.ASM

這一章堙A小木偶會在 Win64 系統上顯示一個標準視窗,並在此視窗的工作區上顯示一個字串,如下圖:

標準視窗
其原始碼如下,把它存成 StdWnd.asm 後再組譯。

OPTION  CASEMAP:NONE

INCLUDELIB KERNEL32.LIB
INCLUDELIB USER32.LIb
INCLUDELIB GDI32.LIB

NULL            EQU     0

IDC_ARROW       EQU     32512
IDI_APPLICATION EQU     32512
CS_VREDRAW      EQU     1
CS_HREDRAW      EQU     2

COLOR_WINDOW    EQU     5
CW_USEDEFAULT   EQU     80000000H
WM_CREATE       EQU     1H
WM_DESTROY      EQU     2H
WM_PAINT        EQU     0fh

WS_OVERLAPPED   EQU     0H
WS_CAPTION      EQU     0C00000H
WS_SYSMENU      EQU     80000H
WS_THICKFRAME   EQU     40000H
WS_MINIMIZEBOX  EQU     20000H
WS_MAXIMIZEBOX  EQU     10000H
WS_OVERLAPPEDWINDOW     EQU     WS_OVERLAPPED OR WS_CAPTION OR WS_SYSMENU OR \
                                WS_THICKFRAME OR WS_MINIMIZEBOX OR WS_MAXIMIZEBOX
SW_SHOWNORMAL   EQU     1

DT_SINGLELINE   EQU     20h

POINT   STRUC
x       DWORD   ?
y       DWORD   ?
POINT   ENDS

RECT    STRUC
left    DWORD   ?
top     DWORD   ?
right   DWORD   ?
bottom  DWORD   ?
RECT    ENDS

MSG             STRUC
hwnd            QWORD   ?
message         DWORD   ?
padding1        DWORD   ?       ;padding1	
wParam          QWORD   ?
lParam          QWORD   ?
time            DWORD   ?
pt              POINT   <>
padding2        DWORD   ?       ;padding2
MSG             ENDS

WNDCLASSEX      STRUC
cbSize          DWORD   ?
style           DWORD   ?
lpfnWndProc     QWORD   ?
cbClsExtra      DWORD   ?
cbWndExtra      DWORD   ?
hInstance       QWORD   ?
hIcon           QWORD   ?
hCursor         QWORD   ?
hbrBackground   QWORD   ?
lpszMenuName    QWORD   ?
lpszClassName   QWORD   ?
hIconSm         QWORD   ?
WNDCLASSEX      ENDS

PAINTSTRUCT     STRUC
hDC             QWORD   ?
fErase          DWORD   ?
rcPaint         RECT    <>
fRestore        DWORD   ?
fIncUpdate      DWORD   ?
rgbReserved     BYTE    32 DUP (?)
padding         DWORD   ?
PAINTSTRUCT     ENDS

EXTRN GetModuleHandleA:PROC
EXTRN LoadIconA:PROC
EXTRN LoadCursorA:PROC
EXTRN RegisterClassExA:PROC
EXTRN ShowWindow:PROC
EXTRN UpdateWindow:PROC
EXTRN GetMessageA:PROC
EXTRN TranslateMessage:PROC
EXTRN DispatchMessageA:PROC
EXTRN DefWindowProcA:PROC
EXTRN CreateWindowExA:PROC
EXTRN PostQuitMessage:PROC
EXTRN BeginPaint:PROC
EXTRN EndPaint:PROC
EXTRN DrawTextA:PROC

;*******************************************************************************
.DATA	
hInstance       QWORD           ?
hWnd            QWORD           ?
hIcon           QWORD           ?
wcex            WNDCLASSEX      <>
msg             MSG             <>
szClassName     BYTE            "Win64Class",0
szWndTitleName  BYTE            "Win64 標準視窗",0
szHellowAsm     BYTE            "嗨!組合語言您好!",0
;*******************************************************************************
.CODE
;-------------------------------------------------------------------------------
;視窗函式
WndProc PROC    USES r15
        LOCAL   ps:PAINTSTRUCT,hDC:QWORD

;把參數存入堆疊
        mov     [rbp+10h],rcx   ;hWnd
        mov     [rbp+18h],rdx   ;uMsg
        mov     [rbp+20h],r8    ;wParam
        mov     [rbp+28h],r9    ;lParam

;設置堆疊框
        mov     r15,rsp
        sub     rsp,8*5
        and     rsp,0fffffffffffffff0h

;檢查訊息
        cmp     rdx,WM_PAINT
        je      WM_Paint

        cmp     rdx,WM_CREATE
        je      WM_Create

        cmp     rdx,WM_DESTROY
        je      WM_Destroy

;因為rcx、rdx、r8、r9並沒有改變,所以直接呼叫即可
        call    DefWindowProcA
        jmp     Exit1

;處理訊息
WM_Paint:
        lea     rdx,ps
        call    BeginPaint
        mov     hDC,rax
        mov     rcx,rax
        mov     rdx,OFFSET szHellowAsm
        mov     r8,-1
        lea     r9,ps.rcPaint
        mov     QWORD PTR [rsp+20h],DT_SINGLELINE
        call    DrawTextA
        mov     rcx,[rbp+10h]
        lea     rdx,ps
        call    EndPaint
        jmp     Exit1

WM_Destroy:
        xor     rcx,rcx
        call    PostQuitMessage
        jmp     Exit

WM_Create:
        jmp     Exit

Exit:   xor     rax,rax
Exit1:  mov     rsp,r15
        ret
WndProc ENDP
;-------------------------------------------------------------------------------
Start   PROC
        sub     rsp,68h

        xor     rcx,rcx
        call    GetModuleHandleA
        mov     hInstance,rax

;設定wcex結構,此結構是用來註冊視窗類別
        mov     rax,OFFSET WndProc
        mov     rcx,hInstance
        mov     wcex.cbSize,SIZEOF WNDCLASSEX
        mov     wcex.style,CS_HREDRAW or CS_VREDRAW
        mov     wcex.lpfnWndProc,rax
        mov     wcex.cbClsExtra,NULL
        mov     wcex.cbWndExtra,NULL
        mov     wcex.hInstance,rcx
        mov     wcex.hbrBackground,COLOR_WINDOW+1
        mov     wcex.lpszMenuName,NULL
        mov     rax,OFFSET szClassName
        mov     wcex.lpszClassName,rax

        mov     rdx,IDI_APPLICATION
        call    LoadIconA               ;取得系統圖示
        mov     wcex.hIcon,rax
        mov     wcex.hIconSm,rax
        mov     hIcon,rax

        mov     rcx,NULL
        mov     rdx,IDC_ARROW
        call    LoadCursorA             ;取得系統游標
        mov     wcex.hCursor,rax

        mov     rcx,OFFSET wcex
        call    RegisterClassExA        ;註冊視窗類別

;以註冊的視窗類別,建立視窗
        mov     rax,hInstance
        mov     QWORD PTR[rsp+58h],NULL         ;lpParam
        mov     [rsp+50h],rax                   ;hInstance
        mov     QWORD PTR[rsp+48h],NULL         ;hMenu
        mov     QWORD PTR[rsp+40h],NULL         ;hWndParent
        mov     QWORD PTR[rsp+38h],100          ;nHeight
        mov     QWORD PTR[rsp+30h],250          ;nWidth
        mov     QWORD PTR[rsp+28h],CW_USEDEFAULT;y
        mov     QWORD PTR[rsp+20h],CW_USEDEFAULT;x
        mov     r9,WS_OVERLAPPEDWINDOW
        lea     r8,szWndTitleName
        lea     rdx,szClassName
        xor     rcx,rcx
        call    CreateWindowExA
        mov     hWnd,rax

        mov     rcx,hWnd
        mov     rdx,SW_SHOWNORMAL
        call    ShowWindow      ;顯示視窗
        
        mov     rcx,hWnd
        call    UpdateWindow    ;更新視窗

;建立訊息迴圈
MsgLp:  xor     r9,r9
        xor     r8,r8
        xor     rdx,rdx
        mov     rcx,OFFSET msg
        call    GetMessageA     ;取得訊息
        or      rax,rax         ;終結訊息迴圈
        jz      Exit

        mov     rcx,OFFSET msg
        call    TranslateMessage

        mov     rcx,OFFSET msg
        call    DispatchMessageA
        jmp     MsgLp           ;跳到訊息迴圈起始位址

;結束程式,返回作業系統
Exit:   add     rsp,68h
        mov     rax,msg.wParam
        ret
Start   ENDP
;*******************************************************************************
END

組譯時,由『開始』→『附屬應用程式』→『命令提示字元』,執行 win64asm.bat ( 見組譯環境 ),後輸入下面指令加以組譯:

ml64 stdwnd.asm /link /entry:Start

即可得 StdWnd.exe。


回上一章回到首頁到下一章