;--- a simple 16-bit Windows "hello world".
;--- assemble: JWasm Win16.asm
;--- link:     wlink format windows file Win16.obj library libw.lib
;---
;--- alternatively the MS OMF linker can be used as well:
;---           link16 /A:16 Win16.obj,,,libw.lib,Win16.def;
;---
;--- libw.lib is the name of the import library for Win16 API calls.
;--- if libw.lib isn't available, create one with Open Watcom WLIB:
;---   wlib -ino -p=16 libw.lib + krnl386.exe + user.exe + gdi.exe
;--- (files krnl386.exe, user.exe and gdi.exe can be found in the Windows
;--- system directory).

        .286
        .model small
        .386
        option casemap:none

WINAPI    equ <FAR PASCAL>

UINT      typedef WORD
HINSTANCE typedef WORD
HWND      typedef WORD
HMENU     typedef WORD
HDC       typedef WORD
WPARAM    typedef WORD
LPARAM    typedef DWORD
LPSTR     typedef FAR PTR BYTE

NULL            equ 0

WS_OVERLAPPED   equ 000000000h
WS_MAXIMIZEBOX  equ 000010000h
WS_MINIMIZEBOX  equ 000020000h
WS_THICKFRAME   equ 000040000h
WS_SYSMENU      equ 000080000h
WS_CAPTION      equ 000C00000h
WS_OVERLAPPEDWINDOW equ WS_OVERLAPPED + WS_CAPTION + WS_SYSMENU + WS_THICKFRAME + WS_MINIMIZEBOX + WS_MAXIMIZEBOX

CS_VREDRAW      equ 0001h
CS_HREDRAW      equ 0002h

WM_DESTROY      equ 0002h
WM_PAINT        equ 000Fh
WM_COMMAND      equ 0111h

CW_USEDEFAULT   equ 8000h
SW_SHOWNORMAL   equ 1
COLOR_WINDOW    equ 5
IDC_ARROW       equ 32512

dt_CENTER       EQU 01h
dt_VCENTER      EQU 04h
dt_SINGLELINE   EQU 20h

MSG       struct
hwnd      HWND ?
message   UINT ?
wParam    WPARAM ?
lParam    LPARAM ?
time      dd ?
pt        dd ?
MSG       ends

WNDCLASS struct
style        dw  ?
lpfnWndProc  dd  ?
cbClsExtra   dw  ?
cbWndExtra   dw  ?
hInstance    HINSTANCE ?
hIcon        dw  ?
hCursor      dw  ?
hbrBackground dw ?
lpszMenuName  LPSTR ?
lpszClassName LPSTR ?
WNDCLASS ends

RECT        struct
left        dw ?
top         dw ?
right       dw ?
bottom      dw ?
RECT        ends

PAINTSTRUCT struct
hdc         HDC ?
fErase      dw ?
rcPaint     RECT <>
fRestore    dw ?
fIncUpdate  dw ?
rgbReserved db 16 dup(?)
PAINTSTRUCT ends

BeginPaint        proto WINAPI :HWND, :far ptr PAINTSTRUCT
CreateWindow      proto WINAPI lpszClass:LPSTR, lpszName:LPSTR, style:DWORD,
                     x:WORD, y:WORD, cx_:WORD, cy:WORD,
                     parent:HWND, menu:HMENU, hInst:HINSTANCE, lParam:LPARAM
DefWindowProc     proto WINAPI :HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM
DispatchMessage   proto WINAPI :far ptr MSG
DrawText          proto WINAPI :HDC, :LPSTR, :WORD, :far ptr RECT, :WORD
EndPaint          proto WINAPI :HWND, :far ptr PAINTSTRUCT
GetClientRect     proto WINAPI :HWND, :far ptr RECT
GetMessage        proto WINAPI :far ptr MSG, hWnd:HWND, msgfrom:WORD, msgto:WORD
InitApp           proto WINAPI :HINSTANCE
InitTask          proto WINAPI
LoadCursor        proto WINAPI :HINSTANCE, :LPSTR
PostQuitMessage   proto WINAPI :WORD
RegisterClass     proto WINAPI :far ptr WNDCLASS
ShowWindow        proto WINAPI :HWND, :WORD
TranslateMessage  proto WINAPI :far ptr MSG
WaitEvent         proto WINAPI :WORD

        .data

        dw 0,0,5,0,0,0,0,0  ;DGROUP first 16 bytes used by Windows

        .const

szClass db "WndClassName",0
szWnd   db "Windows 16-bit sample in ASM",0
szHello db "Hello, world",0

        .code

;*** WM_COMMAND handler

OnCommand proc stdcall hWnd:HWND,wParam:WPARAM,lParam:LPARAM

        xor ax, ax
        cwd
        ret
OnCommand endp

;*** window procedure - must be FAR PASCAL

WndProc proc WINAPI <LOADDS> hWnd:HWND,message:UINT,wParam:WPARAM,lParam:LPARAM

local   ps:PAINTSTRUCT

        mov ax,message
        .if (ax == WM_COMMAND)
            invoke OnCommand,hWnd,wParam,lParam
        .elseif (ax == WM_PAINT)
            invoke BeginPaint, hWnd, addr ps
            invoke GetClientRect, hWnd, addr ps.rcPaint
            invoke DrawText, ps.hdc, addr szHello, -1, addr ps.rcPaint, DT_CENTER or DT_VCENTER or DT_SINGLELINE
            invoke EndPaint, hWnd, addr ps
            xor ax, ax
            cwd
        .elseif (ax == WM_DESTROY)
            invoke PostQuitMessage, 0
            xor ax,ax
            cwd
        .else
            invoke DefWindowProc, hWnd,message,wParam,lParam
        .endif
        ret
WndProc endp

;*** InitApplication: register window class

InitApplication proc stdcall hInstance:HINSTANCE

local   wc:WNDCLASS

        mov wc.style, CS_HREDRAW or CS_VREDRAW

        mov word ptr wc.lpfnWndProc+0, offset WndProc
        mov word ptr wc.lpfnWndProc+2, cs

        xor ax,ax
        mov wc.cbClsExtra,ax
        mov wc.cbWndExtra,ax

        mov ax,hInstance
        mov wc.hInstance,ax

        mov wc.hIcon, NULL

        invoke LoadCursor, 0, IDC_ARROW
        mov wc.hCursor,ax

        mov ax,COLOR_WINDOW + 1
        mov wc.hbrBackground,ax

        xor eax,eax
        mov wc.lpszMenuName,eax

        mov word ptr wc.lpszClassName+0, offset szClass
        mov word ptr wc.lpszClassName+2, ds

        invoke RegisterClass, addr wc
exit:
        ret
InitApplication endp

;*** InitInstance: create application window and show it

InitInstance  proc stdcall hInstance:HINSTANCE

        invoke CreateWindow, addr szClass, addr szWnd,
            WS_OVERLAPPEDWINDOW, 
            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, 0
        .if (ax)
            push ax
            invoke ShowWindow, ax, SW_SHOWNORMAL
            pop ax
        .endif
        ret

InitInstance  endp

;--- WinMain: create application window, enter message loop

WinMain proc pascal hInstance:HINSTANCE,hPrevInstance:HINSTANCE,lpszCmdline:LPSTR,cmdshow:UINT

local   msg:MSG

        .if hPrevInstance == 0              ;1. Instance?
            invoke InitApplication, hInstance
            and  ax,ax
            jz   exit
        .endif

        invoke InitInstance, hInstance
        and  ax,ax
        jz   exit
        .while 1
            invoke GetMessage, addr msg, 0, 0, 0
            .break .if (ax == 0)
            invoke TranslateMessage, addr msg
            invoke DispatchMessage, addr msg
        .endw
exit:
        ret

WinMain endp

;--- program entry: SS=DS=DGROUP

start:
        invoke InitTask
        and ax,ax
        jz error
        push es          ;es:bx -> cmdline
        pusha
        invoke WaitEvent, 0
        invoke InitApp, di
        popa
        pop es
        invoke WinMain, di, si, es::bx, dx
        mov ah,4ch
        int 21h
error:
        mov ax,4c01h
        int 21h

        end start