
format PE64 GUI 6.0 at $10000 on "NUL"
stack 1000h,1000h
heap  1000h,1000h

entry start

include 'win64a.inc'

section '.text' code readable executable
; ============================================================================================

  start:

        enter   sizeof.MSG, 0
        mov     ebx, esp
        and     esp, -16       ; Make sure stack is QWORD aligned
        or      qword [rbx + MSG.wParam], -1

        call    CreateMainWnd
        jc      @F              ; Bail if main window wasn't created

        sub     esp, 32         ; Shadow spade for API's

  Pump: mov     ecx, ebx
        xor     edx, edx
        mov      r8, rdx
        mov      r9,  r8
        call    [GetMessage]
        cmp     eax, 1
        jb      @F
        jnz     Pump

        mov     ecx, ebx
        call    [TranslateMessage]
        mov     ecx, ebx
        call    [DispatchMessage]
        jmp     Pump

    @@: mov     ecx, dword [ebx + MSG.wParam]
        leave
        call    [ExitProcess]

; --------------------------------------------------------------------------------------------

CreateMainWnd:

        push    rbp
        mov     rbp, rsp
        xor     eax, eax

        push    rax             ; lpCreateParams
        push    rax             ; hInstance
        push    rax             ; hMenu
        push    rax             ; hwndParent
        sub     esp, 16         ; cy - cx - y - x
        mov     edi, esp

; Client windows size and position is going to be determined by desktop's metrics

        sub     esp, 32         ; Shadow space for API's
        call    [GetDesktopWindow]
        mov     ecx, eax
        mov     edx, edi
        call    [GetWindowRect]
        lea     esi, [edi+8]

    ; Now we are going to do calculations so the client window will be centered
    ; horizontally and with a small margin just off the bottom. Values here are going
    ; to assume a 2560 x 1080 desktop.

        lodsd                   ; EAX = 2560
        shr     eax, 1          ; EAX = 1280 -> Center position of frame
        mov     edx, eax
        shr     edx, 1          ; EDX = 640 -> Width of client window
        push    rdx
        shr     edx, 1
        sub     eax, edx        ; EAX = 960 -> X position of window
        stosd
        lodsd                   ; EAX = 1080
        shr     eax, 1          ; EAX = 540 -> Y position of window
        stosd
        mov     edx, eax
        shr     edx, 2          ; EDX = 1/4 of window height (135)
        sub     eax, edx        ; EAX = 405
        and     eax, -4         ; Round to an 4 byte boundary
        xchg    [rsp], rax      ; Need to save width first
        stosd
        pop     rax             ; RAX = 404 client height
        stosd

        xor     ecx, ecx
        call    [GetModuleHandle]
        mov     [rbp - 16], rax
        mov     [hInst], eax
        add     esp, 32         ; Kill shadow space

  STYLE  equ CS_VREDRAW or CS_HREDRAW or CS_OWNDC or CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW

; Build a WNDCLASSEX structure on stack.

        push    rcx                     ; <hIconSm>
        push    ClassName               ;  lpszClassName
        push    rcx                     ; <lpszMenuName>
        push    COLOR_BTNFACE-1         ;  hbrBackground
        push    rcx                     ; <hCursor>
        push    rcx                     ; <hIcon>
        mov     edi, esp
        push    rax                     ; hInstance
        push    rcx                     ; cbWndExtra & cbClsExtra
        push    MainWndProc
        mov     rax, STYLE * 0x100000000 + sizeof.WNDCLASSEX
        push    rax

    ; Now remaining values denoted by <...> can be retrieved and written to thier
    ; appropriate positions.

        sub     esp, 32                 ; Shadow space
        mov     edx, IDI_APPLICATION
        call    [LoadIcon]
        stosq                           ; Save @ hIcon
        mov     [edi+32], rax           ;        hIconSm
        xor     ecx, ecx
        mov     edx, IDC_ARROW
        call    [LoadCursor]
        stosq                           ; hCursor

        ; If required loading menu would go here but RDI would have to be bumped
        ; over hbrBackground

        mov     ecx, esp
        add     ecx, 32                 ; Points to base of WNDCLASSEX
        call    [RegisterClassEx]
        add     esp, 112                ; Kill shadow space and WNDCLASS structure
        test    ax, ax
        jnz     @F

        xor     ecx, ecx                ; Use desktop window
        mov     edx, ErrReg             ; Error text
        mov      r8, ApplName           ; Windows Caption text
        mov      r9, MB_ICONSTOP or MB_OK or MB_APPLMODAL
        call     [MessageBox]
        stc
        jmp     ErrEx

    @@: db      48      dup 90H

ErrEx:  stc
        leave
        ret

; --------------------------------------------------------------------------------------------

  MainWndProc:

        push    rbx
        push    rsi
        push    rdi

        enter   32, 0                 ; API's shadow space

        mov     edx, WM_DESTROY
        jnz     @F

        xor     ecx, ecx
        call    [PostQuitMessage]
        xor     eax, eax
        jmp     .exit

    @@: call    [DefWindowProc]

.exit:  leave                 ; Kill shadow space

        pop     rdi
        pop     rsi
        pop     rbx
        ret

section '.data' data readable writeable
; ============================================================================================

  ClassName     db      'PHRASEG', 0
   ApplName     db      'Phrase Guess', 0
     ErrReg     db      'Failed to register Main Window', 0

section '.bss' data readable writeable
; ============================================================================================

    MainWnd     dd      ?
    hInst       dd      ?

section '.idata' import data readable writeable
; ============================================================================================
  library kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
