Netwide Assembler (NASM) >> Assembly (x86) >> Win32 API >> Single Document Interface (SDI)

Create Window


參考資訊:
1. nasm
2. masm32

Windows的視窗可以分成:Dialog、Single Document Interface(SDI)、Multiple Document Interface(MDI)三種類別,相對於SDI、MDI,Dialog類別是比較容易上手學習的一個類別,相當適合初次學習Windows視窗設計的使用者,而Windows視窗程式設計的核心就是圍繞着事件處理(處理Message),任何的視窗設定或者溝通都是以事件導向為原則,因此,寫出一個簡單的視窗框架,將有助於了解Windows視窗程式的運作

main.asm

    [bits 32]
    global _start

    extern _sprintf
    extern _LineTo@12
    extern _Ellipse@20
    extern _MoveToEx@16
    extern _FillRect@12
    extern _SetPixel@16
    extern _EndPaint@8
    extern _SetTimer@16
    extern _Rectangle@20
    extern _CreatePen@12
    extern _KillTimer@8
    extern _BeginPaint@8
    extern _ExitProcess@4
    extern _GetMessageA@16
    extern _MessageBoxA@16
    extern _DeleteObject@4
    extern _SelectObject@8
    extern _SetScrollPos@16
    extern _DestroyWindow@4
    extern _RegisterClassA@4
    extern _DefWindowProcA@16
    extern _SetScrollRange@20
    extern _SetWindowTextA@8
    extern _SetWindowLongA@12
    extern _CallWindowProcA@20
    extern _GetCommandLineA@0
    extern _CreateWindowExA@48
    extern _PostQuitMessage@4
    extern _CreateSolidBrush@4
    extern _GetModuleHandleA@4
    extern _DispatchMessageA@4

    %define ARG1             8h
    %define ARG2             0ch
    %define ARG3             10h
    %define ARG4             14h
    %define sprintf          _sprintf
    %define LineTo           _LineTo@12
    %define Ellipse          _Ellipse@20
    %define MoveToEx         _MoveToEx@16
    %define FillRect         _FillRect@12
    %define SetPixel         _SetPixel@16
    %define EndPaint         _EndPaint@8
    %define SetTimer         _SetTimer@16
    %define Rectangle        _Rectangle@20
    %define KillTimer        _KillTimer@8
    %define CreatePen        _CreatePen@12
    %define BeginPaint       _BeginPaint@8
    %define GetMessage       _GetMessageA@16
    %define MessageBox       _MessageBoxA@16
    %define ExitProcess      _ExitProcess@4
    %define DeleteObject     _DeleteObject@4
    %define SelectObject     _SelectObject@8
    %define SetScrollPos     _SetScrollPos@16
    %define DestroyWindow    _DestroyWindow@4
    %define RegisterClass    _RegisterClassA@4
    %define DefWindowProc    _DefWindowProcA@16
    %define SetScrollRange   _SetScrollRange@20
    %define SetWindowText    _SetWindowTextA@8
    %define SetWindowLong    _SetWindowLongA@12
    %define CallWindowProc   _CallWindowProcA@20
    %define GetCommandLine   _GetCommandLineA@0
    %define CreateWindowEx   _CreateWindowExA@48
    %define PostQuitMessage  _PostQuitMessage@4
    %define CreateSolidBrush _CreateSolidBrush@4
    %define GetModuleHandle  _GetModuleHandleA@4
    %define DispatchMessage  _DispatchMessageA@4
   
    %macro CreateMyPen 2
        push %2
        push %1
        push PS_SOLID
        call CreatePen
    %endmacro
   
    %macro DrawMyLine 6
        push %2
        push %1
        call SelectObject
        
        push 0
        push %4
        push %3
        push %1
        call MoveToEx
        
        push %6
        push %5
        push %1
        call LineTo
    %endmacro
   
    struc RECT
        .left:   resd 1
        .top:    resd 1
        .right:  resd 1
        .bottom: resd 1
        .SIZE:
    endstruc
       
    struc PAINTSTRUCT
        .hdc:         resd 1
        .fErase:      resd 1
        .rcPaint:     resb RECT.SIZE
        .fRestore:    resd 1
        .fIncUpdate:  resd 1
        .rgbReserved: resb 32
        .SIZE:
    endstruc
       
    struc POINT
        .x: resd 1
        .y: resd 1
        .SIZE:
    endstruc
             
    struc MSG
        .hwnd:    resd 1
        .message: resd 1
        .wParam:  resd 1
        .lParam:  resd 1
        .time:    resd 1
        .pt:      resb POINT.SIZE
        .SIZE:
    endstruc

    struc WNDCLASS
        .style:         resd 1
        .lpfnWndProc:   resd 1
        .cbClsExtra:    resd 1
        .cbWndExtra:    resd 1
        .hInstance:     resd 1
        .hIcon:         resd 1
        .hCursor:       resd 1
        .hbrBackground: resd 1
        .lpszMenuName:  resd 1
        .lpszClassName: resd 1
        .SIZE:
    endstruc
    
    PS_SOLID            equ 0
    GWL_WNDPROC         equ -4
    SB_LINEUP           equ 0
    SB_LINELEFT         equ 0
    SB_LINEDOWN         equ 1
    SB_LINERIGHT        equ 1
    SB_PAGEUP           equ 2
    SB_PAGELEFT         equ 2
    SB_PAGEDOWN         equ 3
    SB_PAGERIGHT        equ 3
    SB_VERT             equ 1
    SW_SHOWNORMAL       equ 1h
    WC_DIALOG           equ 8002h
    WM_PAINT            equ 0fh
    WM_VSCROLL          equ 115h
    WM_TIMER            equ 113h
    WM_MOUSEMOVE        equ 200h
    WM_SYSKEYDOWN       equ 104h
    WM_KEYDOWN          equ 100h
    WM_DESTROY          equ 2h
    WM_CLOSE            equ 10h
    WS_VSCROLL          equ 200000h
    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_VISIBLE          equ 10000000h
    WS_EX_LEFT          equ 00000000h
    WS_OVERLAPPEDWINDOW equ WS_OVERLAPPED | \
                            WS_CAPTION | \
                            WS_SYSMENU | \
                            WS_THICKFRAME | \
                            WS_MINIMIZEBOX | \
                            WS_MAXIMIZEBOX
             
    section .drectve info
_entry    db "/entry:start "
_gdi32    db "/defaultlib:c:\\masm32\\lib\\gdi32.lib "
_user32   db "/defaultlib:c:\\masm32\\lib\\user32.lib "
_msvcrt   db "/defaultlib:c:\\masm32\\lib\\msvcrt.lib "
_kernel32 db "/defaultlib:c:\\masm32\\lib\\kernel32.lib "
              
    segment .data
hWin        dd 0
szName      db "main",0
hInstance   dd 0
CommandLine dd 0
     
msg istruc MSG
    at .hwnd,    dd 0
    at .message, dd 0
    at .wParam,  dd 0
    at .lParam,  dd 0
    at .time,    dd 0
    at .pt,      dd 0, 0
iend
             
ps istruc PAINTSTRUCT
    at .hdc,         dd 0
    at .fErase,      dd 0
    at .rcPaint,     dd 0, 0, 0, 0
    at .fRestore,    dd 0
    at .fIncUpdate,  dd 0
    at .rgbReserved, db 0
iend

wndClass istruc WNDCLASS
    at .style,         dd 0
    at .lpfnWndProc,   dd 0
    at .cbClsExtra,    dd 0
    at .cbWndExtra,    dd 0
    at .hInstance,     dd 0
    at .hIcon,         dd 0
    at .hCursor,       dd 0
    at .hbrBackground, dd 0
    at .lpszMenuName,  dd 0
    at .lpszClassName, dd 0
iend

    segment .text
WinMain:
    push ebp
    mov ebp, esp

    mov dword [wndClass + WNDCLASS.lpfnWndProc], DefWindowProc
    mov dword [wndClass + WNDCLASS.lpszClassName], szName
    push wndClass
    call RegisterClass
             
    push 0
    push 0
    push 0
    push 0
    push 300
    push 300
    push 0
    push 0
    push WS_OVERLAPPEDWINDOW | WS_VISIBLE
    push szName
    push szName
    push WS_EX_LEFT
    call CreateWindowEx
    mov [hWin], eax
            
.loop:
    push 0
    push 0
    push 0
    push msg
    call GetMessage
    cmp eax, 0
    je .exit
             
    push msg
    call DispatchMessage
    jmp .loop
             
.exit:
    mov eax, [msg + MSG.wParam]
    leave
    ret 16
             
_start:
    push 0
    call GetModuleHandle
    mov [hInstance], eax
             
    call GetCommandLine
    mov [CommandLine], eax
             
    push SW_SHOWNORMAL
    push dword [CommandLine]
    push 0
    push dword [hInstance]
    call WinMain
             
    push eax
    call ExitProcess

Line 130~142:struc用來定義Struct
Line 212~223:istruc則是宣告資料(Instance)的意思,at用來指定初始化的資料內容,如果沒有想要做資料初始化,可以省略at
Line 230~233:一般SDI視窗會註冊屬於自己的Class並且設定事件處理副程式,目前司徒著重在說明如何建立Windows視窗,因此,我們使用系統預設的事件處理副程式(DefWindowProc),視窗訊息統一交給系統幫忙處理,由於是自定義的Class,因此,需要幫這個Class設定一個名字,之後就可以用這個Class名字來建立Windows視窗
Line 235~248:使用剛剛註冊的Class來建立Windows視窗,WS_OVERLAPPEDWINDOW代表視窗有標題、最大化、最小化的按鈕,WS_VISIBLE是建立一個可視化的視窗
Line 251~255:從Queue提取Message(包含視窗、系統事件)
Line 259~260:分發Message到處理視窗事件的副程式,由於目前註冊的處理副程式是使用系統預設(DefWindowProc),因此,無法處理這個SDI視窗的Message,包含關閉視窗的Message,所以必須使用kill命令強制關閉該視窗
Line 269~274:一般習慣是在程式進入時,保存Instance、CommandLine的內容
Line 276~280:呼叫自定義的WinMain(),模擬C語言的WinMain(),當然也可以把內容都寫在start()裡面

Makefile

export WINEPREFIX=/home/user/.wine_amd64

TARGET=main
MYWINE=box86 wine
NASM32=/home/user/.wine_amd64/drive_c/nasm
MASM32=/home/user/.wine_amd64/drive_c/masm32

all:
	${MYWINE} ${NASM32}/bin/nasm.exe -fwin32 ${TARGET}.asm
	${MYWINE} ${MASM32}/bin/link.exe /SUBSYSTEM:WINDOWS /MERGE:.rdata=.text ${TARGET}.obj

run:
	${MYWINE} ${TARGET}.exe

clean:
	rm -rf ${TARGET}.exe ${TARGET}.obj

編譯、執行

$ make
$ make run


返回上一頁