News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Suggestion with MSVCRT code.

Started by hutch--, June 06, 2005, 04:59:13 AM

Previous topic - Next topic

hutch--

Yes,

Its a good point, if it tests up as a problem, it would require the FlushConsoleInputBuffer() API call to be made both before and after to be safe.

LATER :

I changed the test piece with a Sleep,3000 and pressed a key a number of times and it allowed the first following wait_key procedure to fall through so adding the extra API call seems to fix that potential problem fine.  This is the proc with the added API call.


wait_key proc

    LOCAL hConsole  :DWORD

    mov hConsole, rv(GetStdHandle,STD_INPUT_HANDLE)

    invoke FlushConsoleInputBuffer,hConsole

  @@:
    invoke Sleep,10
    call crt__kbhit
    test eax, eax
    jz @B

    invoke FlushConsoleInputBuffer,hConsole

    ret

wait_key ENDP


Damn, all this incredible bloat.  :bg
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

I have been playing with the idea of a proc that returns the scancode of the key pressed but I cannot improve on a slight modification of Greg's version. This is what it looks like. About the only complaint is it returns garbage with the F keys.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL var   :DWORD
    LOCAL pinp  :DWORD              ; pointer for input buffer
    LOCAL inbuffer[8]:BYTE          ; input buffer

    mov pinp, ptr$(inbuffer)

    cls

    print "Press a key to display its ASCII value or ESC to quit",13,10

  backin:
    call ret_key

    mov ecx, pinp
    mov [ecx], al               ; write AL to 1st BYTE of buffer

    .if al != 27                ; if not ESC
      push eax
      print pinp," = "
      pop eax
      print str$(eax),13,10
      jmp backin
    .endif

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

ret_key proc

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    call crt__getch
    test eax, eax
    jz @F
    cmp eax, 0E0h
    jnz quit
  @@:
    call crt__getch
  quit:
    ret

ret_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

#32
Hutch,

It seems to be working correctly on my system.

F1:  ; = 59
F2:  < = 60
F3:  = = 61
F4:  > = 62
F5:  ? = 63
F6:  @ = 64
F7:  A = 65
F8:  B = 66
F9:  C = 67
F10: D = 68
F11: à = 133
F12: å = 134

Later: I should say it's returning the correct scan codes. My F11 and F12 codes are strange though.


GregL

Hutch,

I took your code and played with it a bit.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include c:\masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL acode :DWORD              ; ASCII code
    LOCAL scode :DWORD              ; Scan code
    LOCAL vcode :DWORD              ; Virtual-key code
    LOCAL outbuffer[64]:BYTE
       

    cls

    print "Press a key (ESC to quit): ", 13, 10

  backin:
    call ret_key
    .if al != 27                ; if not ESC
        .if edx == 0
            mov acode, eax
            print SADD("ASCII code = ")
            print hex$(acode)
            print SADD("h, ASCII character  = ")
            mov eax, acode
            mov outbuffer[0], al
            mov outbuffer[1], 0
            print ADDR outbuffer, 13, 10
        .else
            mov scode, eax
            print SADD("Scan code  = ")
            print hex$(scode)
            print chr$("h, Virtual-Key code = ")
            invoke MapVirtualKey, scode, 1
            mov vcode, eax
            print hex$(vcode)
            print chr$("h, Key name = ")
            shl scode, 16
            invoke GetKeyNameText, scode, ADDR outbuffer, SIZEOF outbuffer
            print ADDR outbuffer, 13, 10
        .endif   

        jmp backin
   
    .endif

    ret

main endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
ret_key proc
; returns code in EAX
; EDX is 0 if ASCII, 1 if Scan Code

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)
       
    call crt__getch                 ; it's an ASCII Code
    mov edx, 0
    .if (eax == 0) || (eax == 0E0h)
        call crt__getch             ; it's a Scan Code
        mov edx, 1
    .endif
   
    ret

ret_key endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


hutch--

Thanks Greg, using a register to flag an extended key is a good idea. This is the modded version.


ret_key proc

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    call crt__getch
    xor ecx, ecx
    test eax, eax
    jz @F
    cmp eax, 0E0h
    jnz quit
  @@:
    call crt__getch
    mov ecx, 1
  quit:
    ret

ret_key endp
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Zooba,

Quote from: GregNice code  :U,  that works better than the Win32 API version of "waitkey" I had.

Well, it's not perfect, your 'wait_key' procedure doesn't accept extended (non-ASCII) keys. I know, I'm being picky.  :bg




GregL

Some 'number to string' conversion procedures that use the sprintf CRT function.


; Greg Lyon · 2005
.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

ByToStr   PROTO byValue  :BYTE,   lpBuffer:PTR BYTE
SbyToStr  PROTO sbyValue :SBYTE,  lpBuffer:PTR BYTE
WdToStr   PROTO wdValue  :WORD,   lpBuffer:PTR BYTE
SwdToStr  PROTO swdValue :SWORD,  lpBuffer:PTR BYTE
DwToStr   PROTO dwValue  :DWORD,  lpBuffer:PTR BYTE
SdwToStr  PROTO sdwValue :SDWORD, lpBuffer:PTR BYTE
QwToStr   PROTO qwValue  :QWORD,  lpBuffer:PTR BYTE
SqwToStr  PROTO sqwValue :QWORD,  lpBuffer:PTR BYTE
FltToStr  PROTO fltValue :REAL4,  lpBuffer:PTR BYTE
DblToStr  PROTO dblValue :REAL8,  lpBuffer:PTR BYTE
LdblToStr PROTO ldblValue:REAL10, lpBuffer:PTR BYTE
WaitKey   PROTO

.CONST

    byTest    BYTE   0FFh
    sbyTest   SBYTE  0FFh
    wdTest    WORD   0FFFFh
    swdTest   SWORD  0FFFFh
    dwTest    DWORD  0FFFFFFFFh
    sdwTest   SDWORD 0FFFFFFFFh
    qwTest    QWORD  0FFFFFFFFFFFFFFFFh
    sqwTest   QWORD  0FFFFFFFFFFFFFFFFh
    fltTest   REAL4  123.4567890
    dblTest   REAL8  456.7890123
    ldblTest  REAL10 789.0123456
   
.DATA

    szBuffer  BYTE  96 dup(0)
    pszBuffer PBYTE szBuffer

.CODE

start:

    invoke ByToStr, byTest, pszBuffer
    invoke crt_puts, pszBuffer
       
    invoke SbyToStr, sbyTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke WdToStr, wdTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke SwdToStr, swdTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke DwToStr, dwTest, pszBuffer
    invoke crt_puts, pszBuffer
           
    invoke SdwToStr, sdwTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke QwToStr, qwTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke SqwToStr, sqwTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke FltToStr, fltTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke DblToStr, dblTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke LdblToStr, ldblTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    call WaitKey
   
    invoke ExitProcess, 0
     
;======================================================
ByToStr PROC byValue:BYTE, lpBuffer:PTR BYTE
    ; byValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%u"), byValue
    ret
ByToStr ENDP   
;======================================================
SbyToStr PROC sbyValue:SBYTE, lpBuffer:PTR BYTE
    ; sbyValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%d"), sbyValue
    ret
SbyToStr ENDP         
;======================================================
WdToStr PROC wdValue:WORD, lpBuffer:PTR BYTE
    ; wdValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%hu"), wdValue
    ret
WdToStr ENDP   
;======================================================
SwdToStr PROC swdValue:SWORD, lpBuffer:PTR BYTE
    ; swdValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%hd"), swdValue
    ret
SwdToStr ENDP         
;======================================================
DwToStr PROC dwValue:DWORD, lpBuffer:PTR BYTE
    ; dwValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%lu"), dwValue
    ret
DwToStr ENDP   
;======================================================
SdwToStr PROC sdwValue:SDWORD, lpBuffer:PTR BYTE
    ; sdwValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%ld"), sdwValue
    ret
SdwToStr ENDP   
;======================================================
QwToStr PROC qwValue:QWORD, lpBuffer:PTR BYTE
    ; qwValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%I64u"), qwValue
    ret
QwToStr ENDP
;======================================================
SqwToStr PROC sqwValue:QWORD, lpBuffer:PTR BYTE
    ; sqwValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%I64d"), sqwValue
    ret
SqwToStr ENDP
;======================================================
FltToStr PROC fltValue:REAL4, lpBuffer:PTR BYTE
    ; REAL4 must be converted to REAL8 for sprintf
    LOCAL dblValue:REAL8
    finit
    fld fltValue
    fstp dblValue
    fwait
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
FltToStr ENDP
;======================================================
DblToStr PROC dblValue:REAL8, lpBuffer:PTR BYTE
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
DblToStr ENDP
;======================================================
LdblToStr PROC ldblValue:REAL10, lpBuffer:PTR BYTE
    ; REAL10 must be converted to REAL8 for sprintf
    ; A 'long double' in MS C/C++ is a REAL8
    LOCAL dblValue:REAL8
    finit
    fld ldblValue
    fstp dblValue
    fwait
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
LdblToStr ENDP
;======================================================
WaitKey PROC
    invoke crt_printf, SADD(13,10,"Press any key to continue...")
    invoke crt__getch
    .if (eax == 0) || (eax == 0E0h)
        invoke crt__getch
    .endif
    invoke crt_printf, SADD(13,10)
    ret
WaitKey ENDP   
;======================================================
END start


hutch--

Thanks Greg,

This is great stuff and very useful.  :U
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,

You know, using the Pelle's C run-time library would have some advantages over the MSVC run-time library as Pelle's C supports most, if not all, of the new C99 functions and MSVC does not support them at all. There are several new and very useful C99 functions that could be used in MASM32.

I wonder if that would be OK with Pelle?



hutch--

Greg,

Let me try this out on you, the set of functions are very good as they make a very good range of functionality available but there is no good reason to place tem in a seperate procedure when almost all of them make a direct call to MSVCRT.DLL. What I think would be more useful as we already have the C runtime functions available would be to make a set of direct macros using this excellent range of functionality so they could be used in a closer to "function" format with return values much like a higher level language.

Its basically the idea that we have the preprocessor available so we may as well make use of it.

Now another question as you have the expertise in C runtime library functions, are the versions using the "sprintf" function as fast as the dedicated conversions in msvcrt like _ltoa or similar ?
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

Hutch,

Yeah, I know, macros would be better. I thought about writing these procedures as macros, but I'm lousy at macros. I guess I need to get better at them. I'm just passing along ideas.

As far as the speed compared to ltoa etc., I don't know, I would have to do some testing. I do know the floating-point conversion functions like fcvt are pretty lousy because they don't store the decimal point in the string, you would need an additional routine to insert the decimal point into the string. itoa and ltoa are fine.

I've never been greatly concerned about speed unless it's really needed in the routine. I'm more interested in the functionality, simplicity and elegance of the code.

I do need to learn how to write macros better ...


 

hutch--

Greg,

See what you think of these, I have not put them in a test piece but I think they are OK.


;; ----------------------------------------------
  byte$ MACRO bytevalue
    LOCAL buffer
    .data?
      buffer db 4 dup (?)
    .code
    fn crt_sprintf,OFFSET Buffer,"%u",bytevalue
    EXITM <OFFSET buffer>
  ENDM
;; ----------------------------------------------
  sbyte$ MACRO bytevalue
    LOCAL buffer
    .data?
      buffer db 4 dup (?)
    .code
    fn crt_sprintf,OFFSET Buffer,"%d",bytevalue
    EXITM <OFFSET buffer>
  ENDM
;; ----------------------------------------------
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

 :P
Here is my C run-time example :

.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include  crtdll.inc
includelib \masm32\lib\kernel32.lib
includelib  crtdll.lib

.data
msg db "Command=%s P1=%s P2=%s",0
errmsg db "Only two parameters!",0

.data?
argc dd ?
argv dd ?
env dd ?
.code
start:
invoke __GetMainArgs,ADDR argc,ADDR argv,ADDR env,0
cmp argc,3
jne error
mov edx,argv
invoke printf,ADDR msg,dword ptr [edx],dword ptr [edx+4],dword ptr [edx+8]
finish:
invoke ExitProcess,0
error:
invoke printf,ADDR errmsg
jmp finish

END start

[attachment deleted by admin]

hutch--

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

GregL

#44
'Number to string' macros that use the C Run-time sprintf function. I had nothing but problems using fn or invoke in these macros, I never figured out why, I did it the direct way and it worked. Any suggestions for improvement are welcome.


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib

;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov   al, ubytevalue
        movzx eax, al
        push  eax
        push  OFFSET ubfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov   al, sbytevalue
        movsx eax, al
        push  eax
        push  OFFSET sbfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov   al, xbytevalue
        movzx eax, al
        push  eax
        push  OFFSET xbfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   ax, uwordvalue
        movzx eax, ax
        push  eax
        push  OFFSET uwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   ax, swordvalue
        movsx eax, ax
        push  eax
        push  OFFSET swfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   ax, xwordvalue
        movzx eax, ax
        push  eax
        push  OFFSET xwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        push  udwordvalue
        push  OFFSET udwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt    BYTE "%ld", 0
    ENDIF   
    .code
        push  sdwordvalue
        push  OFFSET sdwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        push  xdwordvalue
        push  OFFSET xdwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        push  DWORD PTR [uqwordvalue+4]
        push  DWORD PTR [uqwordvalue+0]
        push  OFFSET uqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        push  SDWORD PTR [sqwordvalue+4]
        push  DWORD PTR  [sqwordvalue+0]
        push  OFFSET sqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt    BYTE "%I64X", 0
    ENDIF   
    .code
        push  DWORD PTR [xqwordvalue+4]
        push  DWORD PTR [xqwordvalue+0]
        push  OFFSET xqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL r8value, buffer
    .data?
        r8value REAL8 ?
        buffer  BYTE  52 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld   r4value
        fstp  r8value
        fwait
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL r8value, buffer
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld   r10value
        fstp  r8value
        fwait
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
WaitKey MACRO
    LOCAL crlf, pak
    .data
        crlf BYTE 13, 10, 0
        pak  BYTE 13, 10, "Press any key to continue...", 0
    .code   
        push OFFSET pak
        call crt_printf
        add esp, 4
        call crt__getch
        .if (eax == 0) || (eax == 0E0h)
            call crt__getch
        .endif
        push OFFSET crlf
        call crt_printf
        add esp, 4
ENDM
;; ----------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483647 - 1            ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775807 - 1    ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
       
    invoke crt_puts, ubyte$(ubyMax)
    invoke crt_puts, ubyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sbyte$(sbyMax)
    invoke crt_puts, sbyte$(sbyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xbyte$(ubyMax)
    invoke crt_puts, xbyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uword$(uwdMax)
    invoke crt_puts, uword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sword$(swdMax)
    invoke crt_puts, sword$(swdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xword$(uwdMax)
    invoke crt_puts, xword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, udword$(udwMax)
    invoke crt_puts, udword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sdword$(sdwMax)
    invoke crt_puts, sdword$(sdwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xdword$(udwMax)
    invoke crt_puts, xdword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uqword$(uqwMax)
    invoke crt_puts, uqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sqword$(sqwMax)
    invoke crt_puts, sqword$(sqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xqword$(uqwMax)
    invoke crt_puts, xqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real4$(r4Max)
    invoke crt_puts, real4$(r4Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real8$(r8Max)
    invoke crt_puts, real8$(r8Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real10$(r10Max)
    invoke crt_puts, real10$(r10Min)
           
    WaitKey
         
    invoke ExitProcess, 0

end start