            .586
            .model flat, stdcall
            option casemap:none   ; Case sensitive

            include    \AsmEditDir\include\windows.inc
            include    \HutchDir\include\user32.inc
            include    \HutchDir\include\GDI32.inc
            include    \HutchDir\include\kernel32.inc
            include    \HutchDir\include\comdlg32.inc
            include    \HutchDir\include\COMCTL32.inc

         include  \AsmEditDir\include\DSPMACRO.asm

            includelib \HutchDir\lib\user32.lib
            includelib \HutchDir\lib\GDI32.lib
            includelib \HutchDir\lib\kernel32.lib
            includelib \HutchDir\lib\comdlg32.lib
            includelib \HutchDir\lib\COMCTL32.lib

.const
IDM_SQR  equ 1
IDM_EXIT equ 2

EditID   equ 1

.data
ClassName   db  'Sqr Program',0
AppName     db  'Sqr Program',0
EditClass   db  'EDIT',0
MenuName    db  'SqrPgm',0
ErrorMsg    db  '** The output is out of range **            ',0
szOut       db  64 dup(0),0
szBuff      db  64 dup(0),0

PLBuff      db  25 dup(?),0
PRBuff      db  25 dup(?),0
ConvO       db  50 dup(?),0

hInst       dd  0
CommandLine dd  0
hWnd        dd  0 
hEdit       dd  0

RNum10  REAL10  ?
QWB         dq  0
QWO         dq  0
Base4       dd  0
w1          dd  0
BaseVal     dd  10   ; Base value = 2, 8, 10, or 16
Work        dd  0
CWNoRound WORD  0f7fh

WinMain         PROTO :DWORD,:DWORD,:DWORD,:DWORD
AsciiToBase     PROTO :DWORD, :DWORD, :DWORD
BaseToAscii     PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
AsciiToFloat    PROTO :DWORD

.code
start:
      INVOKE     GetModuleHandle, NULL
         mov     hInst, eax
      INVOKE     GetCommandLine
      INVOKE     WinMain, hInst ,NULL, CommandLine, SW_SHOWDEFAULT
      INVOKE     ExitProcess, eax

;--------------------------------------------------------------------------------
WinMain proc  hinst:DWORD, hPrevInst, CmdLine, CmdShow
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG

         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     hInst
         pop     wc.hInstance
         mov     wc.hbrBackground, COLOR_WINDOW+1
         mov     wc.lpszMenuName, OFFSET MenuName
         mov     wc.lpszClassName, OFFSET ClassName
      INVOKE     LoadIcon, NULL, IDI_APPLICATION
         mov     wc.hIcon, eax
         mov     wc.hIconSm, eax
      INVOKE     LoadCursor, NULL, IDC_ARROW
         mov     wc.hCursor, eax
      INVOKE     RegisterClassEx, addr wc
      INVOKE     CreateWindowEx, WS_EX_CLIENTEDGE, addr ClassName, addr AppName,\
                 WS_OVERLAPPEDWINDOW, 300,\
                 250, 300, 200, 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)
            INVOKE     TranslateMessage, addr msg
            INVOKE     DispatchMessage, addr msg
      .endw
         mov     eax, msg.wParam
      ret
WinMain endp

;-----------------------------------------------------------------------
WndProc proc  uses edx  hwnd:DWORD, wMsg, wParam, lParam
      .if wMsg == WM_CREATE
         INVOKE     CreateWindowEx, NULL, addr EditClass, NULL,\
                    WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or\
                    ES_AUTOHSCROLL or ES_AUTOVSCROLL,\
                    0, 0, 0, 0, hwnd, EditID, hInst, NULL
            mov     hEdit, eax
         INVOKE     SetFocus, hEdit

      .elseif wMsg == WM_SIZE
            mov     eax, lParam
            mov     edx, eax
            shr     edx, 16
            and     eax, 0ffffh
         INVOKE     MoveWindow, hEdit, 0, 0, eax, edx, TRUE

      .elseif wMsg == WM_DESTROY
        INVOKE     PostQuitMessage, NULL

      .elseif wMsg == WM_COMMAND
            cmp     lParam, 0
            jne     DefWin
            mov     eax, wParam

         .if ax == IDM_SQR
               mov     eax, offset SqRoot
            INVOKE     DialogBoxParam, hInst, 4000, hwnd, eax, 0

         .else
            INVOKE     DestroyWindow, hwnd
         .endif
      .else

DefWin:
         INVOKE     DefWindowProc, hwnd, wMsg, wParam, lParam
            ret
      .endif

         xor    eax,eax
         ret
WndProc endp

;=========================================================================
; Squar Root PROC
;=========================================================================
SqRoot PROC    hdlg:DWORD, wmsg, wparam, lparam

         cmp     wmsg, WM_INITDIALOG   ; If message is INITDIALOG then
         jne     ChkMsg                ; Check wmsg
      INVOKE     GetDlgItem, hdlg, 4001
        push     eax
      INVOKE     SetFocus, eax
         pop     eax
      INVOKE     SendMessage, eax, EM_SETLIMITTEXT, 19, 0  ; Max Num 4611686018427387904 4611686014132420609
      INVOKE     GetDlgItem, hdlg, 4010                             ; Get handle Base 10
      INVOKE     SendMessage, eax, BM_SETCHECK, BST_CHECKED, 0      ; Sets Base 10 to checked
         mov     BaseVal, 10
         jmp     DlgDone

ChkMsg:
         cmp     wmsg, WM_COMMAND      ; Is message a WM_COMMAND?
         jne     DlgDone               ; No, then just return
         mov     eax, wparam           ; Otherwise, see if CANCEL
         cmp     eax, IDCANCEL         ; that was pressed
         je      CancleIt
      .if eax > 4001 && eax < 4017
            sub     eax, 4000
            mov     BaseVal, eax
            jmp     DlgDone
      .endif

         cmp     eax, IDOK
         jne     DlgDone

      INVOKE     GetDlgItemText, hdlg, 4001, addr szBuff, 64
        test     eax, eax
          jz     DlgDone
       finit

;**************************************************************
; N O T E !  You can use either of the two process groups below
;**************************************************************

;---------- [#1 These two instructions process a REAL10 number] ----------
      INVOKE     AsciiToFloat, addr szBuff ; Convert Ascii string to a real 10 number
         fld     RNum10                    ; Load the real 10 number

;---------- [#2 These two instructions process a QWORD number] ----------
;      INVOKE     AsciiToBase, addr szBuff, addr w1, BaseVal  ; Convert Ascii string to a QWORD
;        fild     QWO                      ; Load the QWORD

;---------- [Do the square root] ----------
       fsqrt                               ; Do the square root

;---------- [#1 Convert the REAL10 number to ascii] ----------
        fstp     RNum10                    ; Store the result to a REAL10 number
         mov     edx, offset RNum10
        call     FloatToAscii              ; Convert the REAL10 number to Ascii
      INVOKE     SendMessage, hEdit, WM_SETTEXT, NULL, addr ConvO

;---------- [#2 Convert the DWORD to ascii] ----------
;        fist     Base4                    ; Store the result to a DWORD
;      INVOKE     BaseToAscii, Base4, addr szOut, 0, BaseVal, 1, 0, 1 ; Convert the DWORD to Ascii
;      INVOKE     SendMessage, hEdit, WM_SETTEXT, NULL, addr szOut

CancleIt:
      INVOKE     EndDialog, hdlg, wparam
         mov     eax, TRUE             ; Return with TRUE
         jmp     DlgRet

DlgDone:
         mov     eax, FALSE            ; Return with FALSE
DlgRet:
         RET
SqRoot ENDP

;=========================================================================
; Converts ascii string of Dec, Hex, Oct or Bin to a REAL10 value.
;=========================================================================
AsciiToFloat PROC InPut:DWORD
LOCAL    Min:DWORD  ;, Work

      pushad
         and     Min, 0
      INVOKE     lstrlen, InPut     ; Input
         cmp     eax, 0
         je      GetOut
         xor     ecx, ecx

         mov     edx, InPut
      .while (eax)
      .if byte ptr [edx] > 60h
            sub     byte ptr [edx], 57h
      .elseif byte ptr [edx] > 40h
            sub     byte ptr [edx], 37h
      .elseif byte ptr [edx] == 2eh
            mov     byte ptr [edx], 2eh
      .elseif byte ptr [edx] == 2dh
            or     Min, 1
      .else
            sub     byte ptr [edx], 30h
      .endif
         inc     ecx
         inc     edx
         dec     eax
      .endw

      .if ecx == 0
            inc     ecx
      .endif    
         mov     ebx, InPut         ; Ascii string
         mov     esi, ebx
         add     esi, ecx           ; Set esi at the end of szBuff
         dec     esi
      .if Min == 1
            dec     ecx
            inc     ebx
      .endif 
       finit
        fldz                        ; Initialize ST(0) = 0

Loop1:                              ; Loop before the decimal point
         xor     eax, eax           ; Set eax=0 for later
         mov     al, byte ptr[ebx]
         inc     ebx
         cmp     al, '.'
         je      Loop2
         mov     Work, eax          ; Set Work to number for loading
        fild     BaseVal            ; Load base for adding next digit
       fmulp     ST(1), ST          ; ST(1)=ST(1)*ST & pop ST(0)
        fild     Work               ; Load Work integer to ST(0)
       faddp     ST(1), ST          ; ST(1)=ST(1)+ST & pop ST(0)
        loop     Loop1              ; Next part of loop
        fldz                        ; Load a zero for decimal places
         jmp     NoMore             ; No more characters

Loop2:                              ; Now esi is used for an index
        fldz                        ; Load another zero for the decimal portion

Loop3:                              ; The actual loop after the decimal point
         dec     ecx
         jz      NoMore             ; if out of characters or last one was a '.'
         mov     al, byte ptr[esi]  ; get next character   *******************
         dec     esi
         mov     Work, eax          ; Store to Work
        fild     Work               ; Load Work
       faddp     ST(1), ST          ; Add new char to old value
        fild     BaseVal            ; Load base
       fdivp     ST(1), ST          ; Divide by base to retain decimal
         jmp     Loop3

NoMore:
       faddp     ST(1), ST          ; Add integer & decimal
      .if Min == 1
           fchs
      .endif
        fstp     tbyte ptr[RNum10]  ; Store real
GetOut:
       popad
         RET
AsciiToFloat ENDP

;========================================================================
; Converts a Dec, Hex, Oct or Bin ascii string to a 64 bit num value.
;========================================================================
AsciiToBase PROC Input:DWORD, Output, Base

      pushad
         mov     esi, Input
         mov     edi, Output
      INVOKE     lstrlen, Input
         xor     ecx, ecx
      .while (eax)
         .if byte ptr[esi+ecx] > 60h
               sub     byte ptr[esi+ecx], 57h
         .elseif byte ptr[esi+ecx] > 40h
               sub     byte ptr[esi+ecx], 37h
         .else
               xor     byte ptr[esi+ecx], 30h
         .endif
            dec     eax
            inc     ecx
      .endw

       finit
        fld1                           ; Load 1
       fistp     QWB                   ; Set base accumulater to 1
        fldz                           ; Load a zero
       fistp     QWO                   ; Set output accumulater to 0
         mov     esi, Input
         add     esi, ecx
         dec     esi
         xor     edx, edx

      .while (ecx)
            mov     al, byte ptr[esi]  ; Extract byte for conversion
            and     eax, 000000ffh
            mov     Work, eax
          finit
           fild     Work               ; Load byte
           fild     QWB                ; Load base accumulater
          fmulp     ST(1), ST          ; ST(1)=ST(1)*ST & pop ST(0)
           fild     QWO                ; Load output accumulater
          faddp     ST(1), ST          ; ST(1)=ST(1)+ST & pop ST(0)
          fistp     QWO                ; Store output accumulater
           fild     Base               ; Load base
           fild     QWB                ; Load base accumulater
           fmul     ST(0), ST(1)       ; ST(0)=ST(0)*ST(1)
          fistp     QWB                ; Store base accumulater
            dec     esi
            dec     ecx 
      .endw
       popad
         RET
AsciiToBase ENDP

;=========================================================================
; Converts a 32 bit num value to a Dec, Hex, Oct or Bin ascii string.
;=========================================================================
;INVOKE     BaseAscii, Num, offset szOut, 2, 10, 0, 1, 0
BaseToAscii PROC InPut:DWORD, OutPut, LEN, Base, Comma, Fill, TermA
LOCAL    LBuff[32]: BYTE
      pushad
         xor     esi, esi
         mov     eax, InPut                ; Input
         mov     ebx, OutPut
         mov     byte ptr [ebx], '0'
      .while (eax)
            xor     edx, edx
            div     Base                   ; Base 10, 16, 8, 2
         .if dl > 9h
               add     dl, 37h             ; Convert to hex ASCII
         .else
               add     dl, 30h             ; Convert to dec ASCII
         .endif
            mov     LBuff[esi], dl
            inc     esi
         .if Comma == 1 && Base == 10 && eax > 0
            .if esi == 3 || esi == 7 || esi == 11
                  mov     LBuff[esi], 2ch  ; Insert commas
                  inc     esi
            .endif
         .endif
      .endw
         xor     edi, edi
         mov     ecx, esi
      .if LEN > ecx && Fill == 1           ; Zero fill
            xor     eax, eax
         .while (eax < LEN)
               mov     byte ptr [ebx+eax], '0'
               inc     eax
         .endw
            sub     LEN, ecx
            add     edi, LEN
      .endif
      .while (ecx)
            mov     al, byte ptr LBuff[esi-1]
            mov     byte ptr [ebx+edi], al
            inc     edi
            dec     esi
            dec     ecx
      .endw
      .if TermA
         mov     byte ptr [ebx+edi], 0h
      .endif
       popad
          RET
BaseToAscii ENDP

;=========================================================================
; Converts a REAL10 value to a Dec, Hex, Oct or Bin ascii string.
;=========================================================================
FloatToAscii  PROC  uses ebx esi edi
LOCAL     sw1:DWORD

         mov     PLBuff, 0
         mov     byte ptr PRBuff, 0
         mov     esi, offset PRBuff
         mov     ebx, edx          ; Input
       fldcw     CWNoRound
         fld     tbyte ptr[ebx]    ; Load number
         fst     Work
         and     Work, 80000000h
         cmp     Work, 80000000h
         jnz     PlusNum
         mov     Work, 1
        fchs                       ; Changes sign 
PlusNum:
         fld     ST(0)             ; Duplicate
       fistp     Base4
      .if Base4 > 7fffffffh
            jmp     DoError
      .endif
      INVOKE     BaseToAscii, Base4, addr PLBuff, 0, BaseVal, 1, 0, 1 ; Convert the DWORD to Ascii
        fild     Base4             ; ST(0) : xxxxx,  ST(1) : xxxxx.yyyyy
       fsubp     ST(1), ST(0)      ; ST(0) = 0.yyyyy
         fst     Work
         cmp     Work, 0
         jz      Buildit           ; No decimal
         mov     byte ptr[esi], 2eh
         mov     byte ptr[esi+1], 0
         inc     esi
         mov     dx,sp             ; Save stack pointer
         xor     ecx,ecx
         mov     edi,edx

CalcDec:
        fild     BaseVal           ; Base 10, 16, 8, 2
       fmulp     ST(1), ST(0)
         fld     ST(0)             ; Duplicate
        call     Extend
        fist     Work              ; looks good at this point first int after dec
       fsubp     ST(1), ST(0)
         mov     eax, Work
      .if eax == 19999999h
         mov     ebx, esp
         jmp     GetOut
      .endif
      .if al > 9h
            add     al, 37h        ; Convert to hex ASCII
      .else
            add     al, 30h        ; Convert to dec ASCII
      .endif
         mov     byte ptr[esi], al ; Ascii output
         mov     byte ptr[esi+1], 0
         inc     esi
         inc     ecx
         cmp     ecx, 12 ;19 ;20  ;12  ;15
         jnz     CalcDec
         mov     ebx, esp

GetOut:
         mov     edx, edi
         mov     SP, DX            ; Restore SP
         mov     byte ptr[esi], 0

Buildit:
      INVOKE     lstrcpy, addr ConvO, addr PLBuff      ; Non decimal number
      INVOKE     lstrcat, addr ConvO, addr PRBuff      ; Decimal number
        fstp     Work              ; Get rid of ST(0)
         cmp     PRBuff, 0
         je      Exit
      INVOKE     lstrlen, offset PLBuff
      .if eax > 11
DoError:
         INVOKE     lstrcpy, addr ConvO, addr ErrorMsg ; Error
            mov     PLBuff, 0
            mov     PRBuff, 0
           fldz
           fstp     RNum10     
            jmp     Exit
      .endif
jmp     Exit

;---------- [If you want to do some type of rounding] ----------
         and     sw1, 0
      INVOKE     lstrlen, offset ConvO
         mov     edx, offset ConvO
         add     edx, eax
      .while (eax)
         .if byte ptr [edx]-1 == 39h   
               mov     byte ptr [edx]-1, '0'
               mov     sw1, 1
         .elseif sw1
               inc     byte ptr [edx]-1
            .break
         .endif
            dec     eax
            dec     edx
      .endw

Exit:
         RET
FloatToAscii  ENDP

;*************************************************************************************      
Extend   PROC
        fild     BaseVal           ; base 10, 16, 8, 2
       fmulp     ST(1), ST(0)
       fistp     w1
         mov     eax, w1
         xor     edx, edx
         div     BaseVal           ; base 10, 16, 8, 2
         mov     w1, eax
        fild     w1
         RET
Extend   ENDP

end start
;INVOKE     MessageBox, NULL, addr szOut, addr AppName, MB_OK
