;-----------------------------------------
;   Sysmets2.asm -- System Metrics Display
;   based on Charles Petzold's Sysmets2.C
;
;   Translated into assembly 17/4/99 by
;   Ron Thomas Ron_Thom@Compuserve.com	
;-----------------------------------------

.386				; 32 bit when .386 appears before .MODEL
.MODEL FLAT,STDCALL

include windows.inc

include user32.inc
include kernel32.inc
include gdi32.inc
;include math.inc

includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib

lstrlenA	PROTO	WINAPI	:LPCSTR		; Not included in latest l2inc output
lstrlen		textequ	<lstrlenA>		; but lib can't be missing as function works 

WinMain		PROTO :DWORD, :DWORD, :DWORD, :SDWORD

.DATA
;ALIGN 4	
include sysmets.inc	; Data for System metrics display structure (based on Sysmets.h)

ClassName db "SimpleWinClass",0
AppName   db "Get System Metrics",0

cxChar  	DWORD	?
cxCaps		DWORD	?
cyChar		DWORD	?
cyClient	DWORD	?
iVscrollPos	DWORD	?
y		DWORD	?
 	  	
cyChar_byi	DD	?	
cxChar_by40	DD	?
cxCaps_by22	DD	?
CapsandChars	DD	?

szBuffer  db 10 DUP (?),0 		; Storage buffer

Fmt	  db "%5d",0			; Format control for wsprintf 

.DATA?
hInstance HINSTANCE ?
CommandLine LPSTR ?

;------------------------MACRO's-----------------------

LOWORD	MACRO 	bigword	;; Retrieves the low word from double word argument

	mov	eax,bigword
	and	eax,0FFFFh	;; Set to low word 
	ENDM

HIWORD	MACRO   bigword	;; Retrieves the high word from double word argument

	mov	ebx,bigword
	shr	ebx,16		;; Shift 16 for high word to set to high word
				
	ENDM

MAX	MACRO   word1, word2	;; Return the maximum of 2 integers in eax

	mov	ecx,word2
	mov	eax,word1
	.IF	eax < ecx
	mov	eax,word2	;; Set eax as max
	.ENDIF

	ENDM

MIN	MACRO	word1, word2	;; Return the minimum of 2 integers in eax

	mov	ecx,word2
	mov	eax,word1
	.IF	eax > ecx
	mov	eax,word2	;; Set eax as min
	.ENDIF

	ENDM
;----------------------------------------------------------------------------
.code
start:
	invoke GetModuleHandle, NULL
	mov    hInstance,eax
	invoke GetCommandLine
        invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
	invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
	LOCAL wc:WNDCLASSEX
	LOCAL msg:MSG
        LOCAL hwnd:HWND
	mov   wc.cbSize,SIZEOF WNDCLASSEX
	mov   wc.style, CS_HREDRAW or CS_VREDRAW
	mov   wc.lpfnWndProc, OFFSET WndProc
	mov   wc.cbClsExtra,NULL
	mov   wc.cbWndExtra,NULL
        push  hInstance
        pop   wc.hInstance
	mov   wc.hbrBackground,COLOR_WINDOW+1
	mov   wc.lpszMenuName,NULL
	mov   wc.lpszClassName,OFFSET ClassName
        invoke LoadIcon,NULL,IDI_APPLICATION
	mov   wc.hIcon,eax
        mov   wc.hIconSm,0
        invoke LoadCursor,NULL,IDC_ARROW
	mov   wc.hCursor,eax 
        invoke RegisterClassEx, addr wc
        INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW or WS_VSCROLL,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
        mov   hwnd,eax
        INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
        INVOKE UpdateWindow, hwnd
        .WHILE TRUE
                INVOKE GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)			;Escape loop if eax not true
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
        .ENDW
        mov     eax,msg.wParam
        ret
WinMain endp

WndProc proc uses ebx esi, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

	LOCAL hdc:HDC
	LOCAL ps:PAINTSTRUCT
	LOCAL tm:TEXTMETRIC
  
	mov   eax,uMsg

	.IF eax==WM_CREATE

	  invoke  GetDC, hWnd
	  mov	hdc,eax
	  
	  invoke  GetTextMetrics, hdc, ADDR tm		
	  
	  mov	ebx,tm.tmAveCharWidth		; Get average char width
	  mov	cxChar,ebx
	  mov	al,tm.tmPitchAndFamily		; Get info about pitch and family of font
 
	  .IF tm.tmPitchAndFamily & 1		; Test if variable width font
	      mov  eax,3			; use for var width 
	  .ELSE
	      mov  eax,2			; else for fixed pitch
	  .ENDIF

	  shr	ebx,1		; cxCaps/2	
	  mov	edx,0		; ??
	  mul	ebx		; (2 or 3)*cxCaps/2
	  mov	cxCaps,eax

	  mov	eax,tm.tmHeight			; Get height (ascent+decent) of chars
	  add	eax,tm.tmExternalLeading	; Get leading between rows
	  mov	cyChar,eax

	  invoke  ReleaseDC, hWnd, hdc

	  invoke  SetScrollRange, hWnd, SB_VERT, 0, NUMLINES-1, FALSE
	  invoke  SetScrollPos, hWnd, SB_VERT, iVscrollPos, TRUE

	.ELSEIF eax==WM_SIZE

	  HIWORD   lParam
	  mov  cyClient,ebx

	.ELSEIF eax==WM_VSCROLL

	    mov	   eax,cyClient
	    mov    edx,0
	    div    cyChar		
	    mov    ebx,eax		; Got # lines of displayable text within the client area

	    LOWORD   wParam		; Get mouse notification code (eax)

	    .IF     eax==SB_LINEUP	; Clicked top arrow of SB  

	        dec    iVscrollPos

	      .ELSEIF eax==SB_LINEDOWN	; Clicked bottom arrow of SB
   
	        inc  iVscrollPos

	      .ELSEIF eax==SB_PAGEUP	; Clicked area between top of SB and Thumb

	        sub  iVscrollPos,ebx	; Subtract # lines of displayable text

	      .ELSEIF eax==SB_PAGEDOWN	; Clicked area between Thumb and bottom of SB

	        add  iVscrollPos,ebx	; Add # lines of displayable text

	      .ELSEIF eax==SB_THUMBPOSITION

	        HIWORD  wParam		; Get current positiom of scroll bar (ebx)
	        mov  iVscrollPos,ebx	

	    .ENDIF

	  MIN   iVscrollPos, NUMLINES-1		; Make sure scroll position is between the  
	  MAX   0, eax				; min and max range values	

          invoke  GetScrollPos, hWnd, SB_VERT	; Get previous scroll position

	    .IF eax != iVscrollPos		; If scroll position has changed

		invoke  SetScrollPos, hWnd, SB_VERT, iVscrollPos, TRUE	; Update
		invoke  InvalidateRect, hWnd, NULL, TRUE		; and invalidate window

	    .ENDIF	  
 	      
        .ELSEIF eax==WM_PAINT

          invoke  BeginPaint,hWnd, ADDR ps
          mov     hdc,eax
	 
	  mov	  ebx,0			; offset index		  
	  mov	  esi,0			; use as line index
	   	
	  .WHILE	esi < NUMLINES	; Loop for all lines 

	    mov	  eax,esi		; Get index
 	    sub	  eax,iVscrollPos
	    mov	  edx,0
	    mul	  cyChar		; cyChar*(i - iVscrollPos) 
	    mov	  y,eax			; y = cyChar*(i - iVscrollPos) 
	  				
	    mov	  eax,cyChar
	    mov	  edx,0			; 
	    mul	  esi			; CyChar*i	
	    mov	  cyChar_byi, eax

	    invoke  lstrlen, ADDR sysmetrics.szLabel[ebx]	; get string length
	    invoke  TextOut, hdc, 0, y, ADDR sysmetrics.szLabel[ebx] ,eax 
;			          x  y             addr               length 
	    mov	  eax,cxCaps
	    mov	  ecx,22
	    mov	  edx,0			; 
	    mul	  ecx			; cxCaps*22
	    mov	  cxCaps_by22,eax

	    invoke  lstrlen, ADDR sysmetrics.szDesc[ebx]	
	    invoke  TextOut, hdc, cxCaps_by22, y, ADDR sysmetrics.szDesc[ebx], eax

	    invoke  SetTextAlign, hdc, (TA_RIGHT or TA_TOP)   ; Top right corner    

	    mov	  eax,cxChar
	    mov	  ecx,40
	    mov	  edx,0			; 	
	    mul	  ecx			; cxChar*40
	    add	  eax,cxCaps_by22	; cxCaps*22 + cxChar*40
	    mov	  CapsandChars,eax

	    invoke  GetSystemMetrics, sysmetrics.iIndex[ebx]  ; Return with System metric in eax
	    invoke  wsprintf, ADDR szBuffer, ADDR Fmt, eax    ; Return with # chars in eax 
	    invoke  TextOut, hdc, CapsandChars, y, ADDR szBuffer, eax ; Print the buffer

	    add	  ebx, SIZEOF items	; bump to next line of metrics
	    inc	  esi

	    invoke  SetTextAlign, hdc, (TA_LEFT or TA_TOP)    ; Top left corner  	 

	  .ENDW

           invoke EndPaint,hWnd, ADDR ps

        .ELSEIF eax==WM_DESTROY

	      invoke PostQuitMessage,NULL 
	.ELSE
              invoke DefWindowProc,hWnd,uMsg,wParam,lParam
              ret
	.ENDIF
        xor    eax,eax
	ret

WndProc endp

        end start

