; ---------------------------------------------------------------------------
; FILE: BtnTest.Asm
; DATE: August 15, 2014
; ---------------------------------------------------------------------------

format  PE GUI 4.0
entry   start
stack   4000h, 4000h

    include 'Win32W.Inc'

; ---------------------------------------------------------------------------
section '.data' data readable writeable

    hMainWindow   dd 0
    hHandCursor   dd 0
    hAppBrush     dd 0
    pfnOldBtnProc dd 0
    ;
    ; UNICODE text
    ;
    wchMainClass  du 'CAppMainWnd',0
    wchBtnClass   du 'button',0
    wchBtnText    du 'High Five!',0
    wchMainText   du 'Button Has Hand Cursor',0

; ---------------------------------------------------------------------------
section '.code' code readable executable

; ---------------------------------------------------------------------------
; BUTTON WINDOW PROCEDURE
; ---------------------------------------------------------------------------
align 16
proc NewBtnProc uses ebx esi edi, hWnd, uiMsg, WParam, LParam
    ;
    ; If message is WM_SETCURSOR - set a hand cursor,
    ; otherwise - call old button procedure.
    ;
    cmp       [uiMsg], WM_SETCURSOR
    je        .set_hand

    invoke    CallWindowProcW, [pfnOldBtnProc], [hWnd], [uiMsg], [WParam], [LParam]

.exit:
    ret

.set_hand:
    invoke    SetCursor, [hHandCursor]
    ;
    ; Return TRUE
    ;
    push      1
    pop       eax
    jmp       .exit
endp

; ---------------------------------------------------------------------------
; MAIN WINDOW PROCEDURE
; ---------------------------------------------------------------------------
align 16
proc MainWindowProc uses ebx esi edi, hWnd, uiMsg, WParam, LParam
    ;
    ; Load message ID and branch to a proper handling code
    ;
    mov       eax, [uiMsg]
    mov       esi, [hWnd]

    cmp       eax, WM_CREATE
    je        .on_create

    cmp       eax, WM_DESTROY
    je        .on_destroy
    ;
    ; Let Windows handle the message
    ;
    invoke    DefWindowProcW, esi, eax, [WParam], [LParam]
    jmp       .exit

.on_create:
    mov       [hMainWindow], esi
    ;
    ; Create a standard button
    ;
    xor       ebx, ebx
    invoke    GetModuleHandleW, ebx

    invoke    CreateWindowExW, ebx,\
              wchBtnClass, wchBtnText, WS_CHILD or WS_VISIBLE,\
              32, 32, 100, 60, esi, 200h, eax, ebx
    ;
    ; Replace WNDPROC for the button with our own
    ;
    mov       esi, eax
    invoke    SetWindowLongW, esi, GWL_WNDPROC, NewBtnProc
    mov       [pfnOldBtnProc], eax
    ;
    ; Replace ugly font
    ;
    invoke    GetStockObject, DEFAULT_GUI_FONT
    invoke    SendMessageW, esi, WM_SETFONT, eax, 1
    jmp       .ret_zero

.on_destroy:
    invoke    PostQuitMessage, 0

.ret_zero:
    xor       eax, eax

.exit:
    ret       ; <-- this RET is hiding something!
endp

; ---------------------------------------------------------------------------
; PROGRAM ENTRY POINT
; ---------------------------------------------------------------------------
align 16
start:
    ;
    ; Allocate WNDCLASS structure on stack
    ;
    sub       esp, sizeof.WNDCLASS
    mov       edi, esp
    xor       ebx, ebx
    ;
    ; Load hand cursor
    ;
    invoke    LoadCursorW, ebx, IDC_HAND
    mov       [hHandCursor], eax
    ;
    ; Register main window class
    ;
    mov       [edi + WNDCLASS.cbClsExtra], ebx
    mov       [edi + WNDCLASS.cbWndExtra], ebx

    invoke    CreateSolidBrush, 0FAE6E6h   ; <-- web color: "Lavender"
    mov       [edi + WNDCLASS.hbrBackground], eax
    mov       [hAppBrush], eax

    invoke    LoadCursorW, ebx, IDC_ARROW
    mov       [edi + WNDCLASS.hCursor], eax

    invoke    LoadIconW, ebx, IDI_ASTERISK
    mov       [edi + WNDCLASS.hIcon], eax

    invoke    GetModuleHandleW, ebx
    mov       [edi + WNDCLASS.hInstance], eax

    mov       [edi + WNDCLASS.lpfnWndProc], MainWindowProc
    mov       [edi + WNDCLASS.lpszClassName], wchMainClass
    mov       [edi + WNDCLASS.lpszMenuName], ebx
    mov       [edi + WNDCLASS.style], CS_VREDRAW or CS_HREDRAW
    invoke    RegisterClassW, edi
    ;
    ; Create main window
    ;
    mov       ecx, CW_USEDEFAULT

    invoke    CreateWindowExW, WS_EX_APPWINDOW,\
              wchMainClass, wchMainText,\
              WS_OVERLAPPEDWINDOW, ecx, ecx, ecx, ecx,\
              ebx, ebx, [edi + WNDCLASS.hInstance], ebx

    mov       esi, eax
    invoke    ShowWindow, esi, SW_NORMAL
    invoke    UpdateWindow, esi
    ;
    ; Allocate MSG structure on stack
    ;
    sub       esp, sizeof.MSG
    mov       edi, esp
    ;
    ; Run the message loop
    ;
.next_msg:
    invoke    GetMessageW, edi, ebx, ebx, ebx
    test      eax, eax
    jz        .quit
    ;
    ; Proces the message and go for more...
    ;
    invoke    TranslateMessage, edi
    invoke    DispatchMessageW, edi
    jmp       .next_msg

.quit:
    invoke    ExitProcess, 0

; ---------------------------------------------------------------------------
section '.idata' import data readable writeable

    library kernel32,'KERNEL32.DLL',user32,'USER32.DLL',gdi32,'GDI32.DLL'

    include 'API\Kernel32.Inc'
    include 'API\User32.Inc'
    include 'API\Gdi32.Inc'



