EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

winabi.htm
Enumerations
%FastCall64
Macros
GetArg
GetArgCount
StdInput
StdOutput
TerminateProgram
WinAPI

MS Windows x64 Application Binary Interface macros.

This library contains macros for 64bit MS Windows ABI invocations, retrieving command-line arguments, standard I/O and program termination.

Macro names in this 64bit library winabi.htm are identical with macros from 32bit library winapi.htm . I don't expect to include both 32bit and 64bit version in the same source.
.
 winabi HEAD
        INCLUDE1 winansi.htm ; Make sure that %WinANSI is assigned before WinAPI invocation.
↑ %FastCall64
This assignments define preprocessing %variables useful to refer stack frame in 64bit FastCall calling convention.
See also
fastcall.htm
 %Param8    %SET RBP+72
 %Param7    %SET RBP+64
 %Param6    %SET RBP+56
 %Param5    %SET RBP+48
 %Param4    %SET RBP+40
 %Param3    %SET RBP+32
 %Param2    %SET RBP+24
 %Param1    %SET RBP+16
↑ WinAPI   Function, Argument1, Argument2,,,Lib=

This macroinstruction invokes Function exported by [WindowsAPI] in the calling convention which conforms with [WinABI64].

The macro is similar to FastCall's Invoke with two minor differences:

64bit WinAPI functions do not keep the original contents of Rflags, RAX, RCX, RDX, R8..R11, XMM0..XMM5.
They require and keep Direction Flag on zero.

ABI specification requires that stack is OWORD-aligned at the moment when CALL instruction is just about to begin. This means that when the CALL has just been executed and RIP points to the first instruction of called function, RSP is OWORD-misaligned by QWORD, in other words its least significant bits are 1000b.
After invocation of macro WinAPI the stack pointer is returned to equilibrum. This is achieved by pushing one or two copies of original RSP contents. The number of pushed copies depends on RSP alignment at run-time.

Although Windows ABI specifies fastcall convention with %1..%4 delivered in RCX,RDX,R8,R9, arguments of this WinAPI macro may be supplied in those registers too, for instance WinAPI MessageBox,RDX,R8,R8,MB_OK in arbitrary order, because arguments are pushed on stack (to shadow space) by this macro before being loaded to input registers RCX,RDX,R8,R9.

ABI requires the first four floating-point arguments be passed in XMM0,XMM1,XMM2,XMM3 instead of RCX,RDX,R8,R9. This is supported by this macro on demand only, if the keyword parameter SIMD= is nonzero. Default value of SIMD= copies current SIMD level specified in EUROASM, which is off (0) by factory-default. Ordinary programs, which do not use Windows function with floating-point numbers, usually do not change SIMD= value, and copying of the first four arguments to XMM registers is not emitted in this case.
Recapitulation: The called function has its arguments available as
%1 in [RBP+16] alias [%Param1], RCX (always), XMM0 (if SIMD=enabled)
%2 in [RBP+24] alias [%Param2], RDX (always), XMM1 (if SIMD=enabled)
%3 in [RBP+32] alias [%Param3], R8  (always), XMM2 (if SIMD=enabled)
%4 in [RBP+40] alias [%Param4], R9  (always), XMM3 (if SIMD=enabled)
%5 in [RBP+48] alias [%Param5]
%6 in [RBP+56] alias [%Param6]
and so on.

Argument can be anything which is allowed as an operand of machine instruction PUSH, i.e. 64bit register, address of memory variable, or immediate integer 32bit numeric value, which will be sign-extended to 64 bits by CPU.

Input
Function is the name of invoked WinAPI function. Ambiguous functions, which have both ANSII and WIDE variant, may be specified with or without explicite suffix A or W.
Function may also be provided as a GPR (other than RCX,RDX,R8,R9) with RVA of the function (pointer to its thunk in [.idata]).
Argument* Zero or more QWORD-pushable arguments may follow the function name (r64, segreg, imm, [mem]).
It is programmer's responsibility to provide exactly that many argument as specified in Function documentation.
SIMD=%^SIMD. This parameter specifies if the first four argument should be passed in XMM registers, too. When WinAPI is invoked with keyword SIMD=0, arguments are not copied to XMM registers.
Lib= is the name of dynamic linked library (quoted or unquoted, always without path) which exports the invoked Function. This parameter may be empty or omitted
Output
RAX= returns the value of the API function. Some Windows functions return the result in XMM0.
RBX,RBP,RSI,RDI,R12..R15,XMM6..XMM15 keep their previous contents (calee-saved),
RCX,RDX,R8..R11,XMM0..XMM5 are undefined (scratch registers),
RFlags as they were returned by the WinABI function.
Example
; GetEnvironmentVariable ("PATH",PathBuffer,MAX_PATH) // C syntax. WinAPI GetEnvironmentVariable,="PATH",PathBuffer,MAX_PATH ; €ASM syntax.
See also
32bit version WinAPI in winapi.htm.
WinAPI %MACRO Function, Argument1, Argument2,,, SIMD=%^SIMD, Lib=
  %IF %# = 1              ; If no arguments.
     %ArgList %SET RCX,RDX,R8,R9
  %ENDIF
  %IF %# = 2              ; If one argument.
     %ArgList %SET %2,RDX,R8,R9
  %ENDIF
  %IF %# = 3              ; If two arguments.
     %ArgList %SET %2,%3,R8,R9
  %ENDIF
  %IF %# = 4              ; If three arguments.
     %ArgList %SET %2,%3,%4,R9
  %ENDIF
  %IF %# >= 5             ; If four or more arguments.
     %ArgList %SET %*{2..}
  %ENDIF
  %ArgNr %SETL %ArgList    ; Number of arguments, at least 4.
  PUSH RSP                 ; Save original stack pointer value.
  TEST SPL,1000b           ; Test stack OWORD alignment at run-time.
  %IF %ArgNr & 1b          ; When the number of arguments is odd,
     JNZ .WinAPI%.:        ;   skip padding if RSP is unaligned.
  %ELSE                    ; When the number of arguments is even,
     JZ .WinAPI%.:         ;   skip padding if RSP is OWORD aligned.
  %ENDIF
  PUSH RSP                 ; Save and update copy of original stack pointer value.
  ADDQ [RSP],8
.WinAPI%.:
  %WHILE %ArgNr > 0
    PUSHQ %ArgList{%ArgNr} ; Push all arguments on stack, begin with the last one.
    %ArgNr %SETA %ArgNr-1
  %ENDWHILE
  %IF '%ArgList{1}' !== 'RCX'
    MOV RCX,[RSP+0]        ; Load first four arguments to registers to satisfy FastCall convention.
  %ENDIF
  %IF '%ArgList{2}' !== 'RDX'
    MOV RDX,[RSP+8]
  %ENDIF
  %IF '%ArgList{3}' !== 'R8'
    MOV R8,[RSP+16]
  %ENDIF
  %IF '%ArgList{4}' !== 'R9'
    MOV R9,[RSP+24]
  %ENDIF
  %IF "%SIMD" !=== "0"  ; If arguments should be passed in XMM registers (required for floating- point values).
    MOVQ XMM0,RCX
    MOVQ XMM1,RDX
    MOVQ XMM2,R8
    MOVQ XMM3,R9
  %ENDIF
reg %IF TYPE# %Function = 'R'; Test if the Function is specified in register.
       %IF '%Function'=='RCX'||"%Function"=="RDX"||"%Function"=="R8"||"%Function"=="R9"
         %ERROR ID=5956,'WinAPI function cannot be supplied in scratch register %Function.'
         %EXITMACRO WinAPI
       %ENDIF
       CALL %Function
    %ELSE reg                ; The Function is specified by its name.
       %suffix %SET          ; First assume there is no A|W suffix.
   fn  %FOR %WinANSI         ; Examine if Function is on the list %WinANSI.
          %IF '%fn' === '%Function'
             %suffix %SETC ('W' & (%^UNICODE)) + ('A' & ~(%^UNICODE))
             %EXITFOR fn     ; No need for further investigation of the list.
          %ENDIF
       %ENDFOR fn            ; %suffix is now A or W or empty.
       IMPORT %Function%suffix, Lib=%Lib
       CALL %Function%suffix
    %ENDIF reg
    %ArgNr %SETL %ArgList    ; Reload the number of arguments.
    LEA RSP,[RSP+8*%ArgNr]   ; Let RSP skip all pushed arguments
    POP RSP                  ;  and restore its original value.
 %ENDMACRO WinAPI
↑ GetArgCount
counts arguments provided on the command line of the executed program. Arguments may be separated with unquoted spaces or commas. Multiple white spaces are treated like a single space. Comma-separated empty arguments are counted, too. Single apostrophe cannot be used as a quote.
Input
is taken from the command line which launched the program.
Output
CF=0
EAX=number of arguments on the command line which launched the program.
Error
CF=1 if odd number of quotes detected.
See also
GetArg
Example
All examples of the command lines below will return ArgCount=4.
Program.exe arg1 arg2 arg3 arg4 Program.exe arg1,arg2, ,arg4 Program.exe , , , , , Program.exe arg1, "arg2,arg2" arg3 arg4
GetArgCount %MACRO
       CALL GetArgCount@RT
GetArgCount@RT PROC1
     PUSH RCX,RDX,R8,R9,R10,R11
      MOV RBP,RSP
   %GetArgWithin    %SETA 1 ; Boolean parsing flags will be kept in DL.
   %GetArgInQuotes  %SETA 2
   %GetArgCommaTerm %SETA 4
      WinAPI GetCommandLineA
      MOV RSI,RAX ; RSI now points to the entire command-line ANSI zero-terminated string.
      SUB RCX,RCX ; RCX will keep the ordinal number of parsed cmdline argument.
      SUB DL,DL   ; Flags in DL will be used as a parsing status register.
      TEST ESI,ESI
      JZ .80: ; If API returned FALSE.
      DEC RCX
 .10: LODSB
      CMP AL,' '
      JBE .30:
      CMP AL,','
      JE .30:
      AND DL,~%GetArgCommaTerm
      CMP AL,'"'
      JNE .20:
      XOR DL,%GetArgInQuotes
 .20: TEST DL,%GetArgWithin
      JNZ .10:
      OR DL,%GetArgWithin
      INC RCX
      JMP .10:
 .30: TEST DL,%GetArgInQuotes
      JZ .40:
      CMP AL,0
      JNE .10:
      JMP .80:
 .40: TEST DL,%GetArgWithin
      JZ .50:
      AND DL,~(%GetArgWithin|%GetArgCommaTerm)
      CMP AL,','
      JNE .70:
      OR DL,%GetArgCommaTerm
      JMP .70:
 .50: CMP AL,0
      JE .80:
      CMP AL,','
      JNE .10:
      TEST DL,%GetArgCommaTerm
      JNZ .60:
      OR DL,%GetArgCommaTerm
      JMP .10:
 .60: INC RCX
 .70: CMP AL,0
      JNE .10:
 .80: TEST DL,%GetArgInQuotes
      JZ .90:
      STC ; If premature end of command line.
 .90: MOV RAX,RCX
     POP R11,R10,R9,R8,RDX,RCX
     RET
   ENDPROC1 GetArgCount@RT
  %ENDMACRO GetArgCount
↑ GetArg   ArgNumber

Macro GetArg retrieves ArgNumber-th parameter provided on command line.
Parameters on the command line may be separated with unquoted white spaces or commas. Single aphostrophe cannot be used as quote.
Macro returnes the executable name itself when ArgNumber is 0. It is taken verbatim from the console window or, if launched from Explorer, it may be expanded to a full pathname.

The returned argument is not zero terminated and it is not writable. Make a copy in local memory if you need to modify it. Quotes surrounding the argument are returned, too.

Value of EUROASM UNICODE= option specifies whether the returned string will be ANSI or WIDE.

Input
ArgNumber (64bit register or memory or immediate number) is ordinal number of the required parameter. The 0-th parameter is the executable file name itself.
Output
CF=0,
RSI is pointer to the first character of argument,
RCX is the size of argument in bytes.
Error
CF=1 if odd number of quotes or if requested argument was not provided.
RSI=RCX=0
Example
GetArg 1 ; Assume that our program should specify a filename. JC .BadArgument: ; Report error if no file was provided. StripQuotes RSI,RCX ; Get rid of quotes if they were used. MOV RDI,InputFileName$ ; Room for the filename. REP MOVSB ; Copy the filename. SUB AL,AL STOSB ; Zero terminate the string.
GetArg %MACRO ArgNumber
          PUSHQ %ArgNumber
          %IF %^UNICODE
             CALL GetArgW@RT
 GetArgW@RT PROC1
     PUSHQ RAX,RDX,R8,R9,R10,R11
 %GetArgNumber    %SET RSP+56
 %GetArgWithin    %SETA 1 ; Parsing within argument string. Boolean flags will be kept in DL.
 %GetArgInQuotes  %SETA 2 ; Parsing within quoted argument string.
 %GetArgCommaTerm %SETA 4 ; Previous argument was comma-terminated.
      WinAPI GetCommandLineW
      MOV RSI,RAX ; RSI now points to the entire command-line WIDE zero-terminated string.
      SUB RCX,RCX ; RCX will keep the ordinal number of parsed cmdline argument.
      SUB R8,R8   ; R8 will be pointer to argument.
      SUB R9,R9   ; R9 will be pointer to the end of argument.
      SUB DL,DL   ; DL will be used as a parsing flag register.
      CMP RSI,R8  ; Is the pointer valid?
      JZ .80      ; If API returned FALSE, abort with CF.
      DEC RCX     ; This first argument has ordinal 0 (executable name).
      MOV R8,RSI
 .10: LODSW       ; Parse the next character.
      CMP AX,' '
      JBE .30
      CMP AX,','
      JE .30:
      AND DL,~%GetArgCommaTerm
      CMP AX,'"'
      JNE .20:
      XOR DL,%GetArgInQuotes
 .20: TEST DL,%GetArgWithin
      JNZ .10:
      OR DL,%GetArgWithin
      INC RCX        ; Started to parse RCX-th argument now.
      LEA R8,[RSI-2] ; Remember in R8 where this argument begins.
      JMP .10:
 .30: TEST DL,%GetArgInQuotes
      JZ .40:
      CMP AX,0
      JNE .10:
      JMP .80:
 .40: TEST DL,%GetArgWithin
      JZ .50:
      AND DL,~(%GetArgWithin|%GetArgCommaTerm) ; Character in AX (comma or space or 0) terminates the argument.
      LEA R9,[RSI-2] ; End of argument.
      CMP AX,','
      JNE .70:
      OR DL,%GetArgCommaTerm
      JMP .70:
 .50: CMP AX,0
      JE .80:
      CMP AX,','
      JNE .10:
      TEST DL,%GetArgCommaTerm
      JNZ .60:
      OR DL,%GetArgCommaTerm
      JMP .10:
 .60: LEA R9,[RSI-2]   ; Pointer to the end of argument.
      INC RCX
 .70: CMP RCX,[%GetArgNumber] ; Have we reached the desired argument?
      JE .90:
      CMP AX,0
      JNE .10:
 .80: STC              ; If premature end of command line.
 .90: PUSHF            ; Temporarily save CF.
       MOV RCX,R9      ; Return string R8..R9 as RSI,RCX.
       MOV RSI,R8
       JNC .95:
       MOV R8,RCX      ; Force RCX=0 on error.
 .95:  SUB RCX,R8
      POPF             ; Restore CF.
     POP R11,R10,R9,R8,RDX,RAX
     RET 8
   ENDPROC1 GetArgW@RT
          %ELSE        ; It not %^UNICODE.
            CALL GetArgA@RT
 GetArgA@RT PROC1
     PUSH  RAX,RDX,R8,R9,R10,R11
 %GetArgNumber    %SET RSP+56
 %GetArgWithin    %SETA 1 ; Parsing within argument string. Boolean flags will be kept in DL.
 %GetArgInQuotes  %SETA 2 ; Parsing within quoted argument string.
 %GetArgCommaTerm %SETA 4 ; Previous argument was comma-terminated.
      WinAPI GetCommandLineA
      MOV RSI,RAX ; RSI now points to the entire command-line ANSI zero-terminated string.
      SUB RCX,RCX ; RCX will keep the ordinal number of parsed cmdline argument.
      SUB R8,R8   ; R8 will be pointer to argument.
      SUB R9,R9   ; R9 will be pointer to the end of argument.
      SUB DL,DL   ; DL will be used as a parsing flag register.
      CMP RSI,R8  ; Is the pointer valid?
      JZ .80      ; If API returned FALSE, abort with CF.
      DEC RCX     ; This first argument has ordinal 0 (executable name).
 .10: LODSB       ; Parse the next character.
      CMP AL,' '
      JBE .30:
      CMP AL,','
      JE .30:
      AND DL,~%GetArgCommaTerm
      CMP AL,'"'
      JNE .20:
      XOR DL,%GetArgInQuotes
 .20: TEST DL,%GetArgWithin
      JNZ .10:
      OR DL,%GetArgWithin
      INC RCX        ; Started to parse RCX-th argument now.
      LEA R8,[RSI-1] ; Remember in R8 where this argument begins.
      JMP .10:
 .30: TEST DL,%GetArgInQuotes
      JZ .40:
      CMP AL,0
      JNE .10:
      JMP .80:       ; Abort if the closing quote is missing.
 .40: TEST DL,%GetArgWithin
      JZ .50:
      AND DL,~(%GetArgWithin|%GetArgCommaTerm) ; Character in AL (comma or space or 0) terminates the argument.
      LEA R9,[RSI-1] ; End of argument.
      CMP AL,','
      JNE .70:
      OR DL,%GetArgCommaTerm
      JMP .70:
 .50: CMP AL,0
      JE .80:
      CMP AL,','
      JNE .10:
      TEST DL,%GetArgCommaTerm
      JNZ .60:
      OR DL,%GetArgCommaTerm
      JMP .10:
 .60: LEA R9,[RSI-1]   ; Pointer to the end of argument.
      INC RCX
 .70: CMP RCX,[%GetArgNumber] ; Have we reached the desired argument?
      JE .90:
      CMP AL,0
      JNE .10:
 .80: STC              ; If premature end of command line.
 .90: PUSHF            ; Temporarily save CF.
       MOV RCX,R9      ; Return string R8..R9 as RSI,RCX.
       MOV RSI,R8
       JNC .95:
       MOV R8,RCX      ; Force RCX=0 on error.
 .95:  SUB RCX,R8
      POPF             ; Restore CF.
     POP R11,R10,R9,R8,RDX,RAX
     RET 8
  ENDPROC1 GetArgA@RT
 %ENDIF
%ENDMACRO GetArg
↑ StdOutput String1, String2,,, Size=-1, Handle=-11, Eol=No, Console=No, Unicode=%^UNICODE

Macro StdOutput writes one or more concatenated strings to the standard output or to other equipment specified with the Handle identifier.

Strings are either zero-terminated, or the keyword Size= must specify its size in bytes. The terminating NUL character is never written.

If keyword Eol=Yes, macro writes CR+LF after all strings.

One of four possible runtime subprocedures is selected to emit, depending on the chosen ANSI/WIDE and File/Console options.
Input
StringX is pointer to ANSI or WIDE string.
Size=-1 is the maximal possible string size in bytes. If its left to -1 (default), strings must be zero-terminated. This parameter applies to all ordinal operads.
Handle=-11 is the Windows standard handle identifier. Possible output values are defined in winscon.htm: Eol=No. If Yes, two additional characters CR and LF will be written on output after all strings have been written.
Console=No (or Yes) is boolean specification whether if the macro should use WinAPI function WriteFile or WriteConsole.
Output of WriteFile (default) is redirectable, but it writes WIDE string as is; in OEM console are the UTF-16 encoded characters displayed as interlaced.
Output produced by WriteConsole (when Console=Yes) cannot be redirected by command-line operator > but it accepts WIDE Unicode strings and displays the text in TrueType console properly, including non-English characters.
Unicode= %^UNICODE is boolean specification whether the Strings are in WIDE (UTF-16) encoding.
Output
CF=0
Error
CF=1 if not all characters were written or if Handle was invalid.
Example
StdOutput Message, Eol=Yes StdOutput Eol=Yes ; Write new line (CR+LF) only. StdOutput ="Error writing to file ",FileName, Handle=STD_ERROR_HANDLE
StdOutput %MACRO  String1,String2,,,Size=-1, Handle=-11, Eol=No, Unicode=%^UNICODE, Console=No
     %IF %Unicode ; WIDE variant.
       %StdOutputRT %SET StdOutputW
     %ELSE        ; ANSI variant.
       %StdOutputRT %SET StdOutputA
     %ENDIF
     %IF "%Console[1]" == "N" ; WriteFile variant.
       %StdOutputRT %SET %StdOutputRT[]F@RT
     %ELSE                    ; WriteConsole variant.
       %StdOutputRT %SET %StdOutputRT[]C@RT
     %ENDIF ; %StdOutputRT is now the name of runtime PROC1.
OpNr %FOR 1..%#, STEP=1
       PUSHQ %Handle, %Size, %1
       CALL %StdOutputRT
       %SHIFT 1  ; The next string to output.
     %ENDFOR OpNr
     %IF "%Eol[1]"!=="N"
       %IF %Unicode ; Write EOL in WIDE variant.
         PUSHQ %Handle, 4, =D(0x000A000D)
         CALL %StdOutputRT
       %ELSE        ; Write EOL in ANSI variant.
         PUSHQ %Handle, 2, =W(0x0A0D)
         CALL %StdOutputRT
       %ENDIF
     %ENDIF
WC   %IF "%StdOutputRT" === "StdOutputWC@RT"
StdOutputWC@RT:: PROC1 ; WIDE Console variant.
        PUSHQ RAX,RCX,RDX,R8,R9,R10,R11
         %StdOutputHandle %SET RSP+80
         %StdOutputSize   %SET RSP+72
         %StdOutputString %SET RSP+64
         MOV RAX,[%StdOutputHandle]
         WinAPI GetStdHandle,RAX ; Output handle identifier.
         MOV R10,RAX ; Save the (redirected) handle to R10.
         INC RAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV RDI,[%StdOutputString] ; String pointer.
         MOV RCX,[%StdOutputSize] ; String maximal size.
         SUB EAX,EAX
         SAR RCX,1   ; Convert size in bytes to characters.
         MOV R8,RDI  ; Remember start of string in R8.
         REPNE SCASW ; Find the end of string.
         JNE .10:
         SUB RDI,2   ; Skip the NUL character.
   .10:  SUB RDI,R8  ; RDI is now string size in bytes.
         PUSH RDX    ; Make room for the written-size DWORD.
          MOV RDX,RSP
          SHR RDI,1  ; RDI is now string size in characters.
          WinAPI WriteConsoleW,R10,R8,RDI,RDX,0
         POP RDX
         CMP RDX,RDI  ; Set CF if not all characters were written.
   .90: POP R11,R10,R9,R8,RDX,RCX,RAX
        RET 3*8
      ENDP1 StdOutputWC@RT::
     %ENDIF WC

WF   %IF "%StdOutputRT" === "StdOutputWF@RT"
StdOutputWF@RT:: PROC1 ; WIDE File variant.
       PUSHQ RAX,RCX,RDX,R8,R9,R10,R11
         %StdOutputHandle %SET RSP+80
         %StdOutputSize   %SET RSP+72
         %StdOutputString %SET RSP+64
         MOV RAX,[%StdOutputHandle]
         WinAPI GetStdHandle,RAX ; Output handle identifier.
         MOV R10,RAX ; Save the (redirected) handle to R10.
         INC RAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV RDI,[%StdOutputString] ; String pointer.
         MOV RCX,[%StdOutputSize] ; String maximal size.
         SUB EAX,EAX
         SAR RCX,1   ; Convert size in bytes to characters.
         MOV R8,RDI  ; Remember start of string in R8.
         REPNE SCASW ; Find the end of string.
         JNE .10:
         SUB RDI,2   ; Skip the NUL character.
   .10:  SUB RDI,R8  ; RDI is now string size in bytes.
         PUSH RDX    ; Make room for the written-size DWORD.
          MOV RDX,RSP
          WinAPI WriteFile,R10,R8,RDI,RDX,0
         POP RDX
         CMP RDX,RDI  ; Set CF if not all characters were written.
   .90: POP R11,R10,R9,R8,RDX,RCX,RAX
        RET 3*8
      ENDP1 StdOutputWF@RT::
     %ENDIF WF

AC   %IF "%StdOutputRT" === "StdOutputAC@RT"
StdOutputAC@RT:: PROC1 ; ANSI Console variant.
        PUSHQ RAX,RCX,RDX,R8,R9,R10,R11
         %StdOutputHandle %SET RSP+80
         %StdOutputSize   %SET RSP+72
         %StdOutputString %SET RSP+64
         MOV RAX,[%StdOutputHandle]
         WinAPI GetStdHandle,RAX ; Output handle identifier.
         MOV R10,RAX ; Save the (redirected) handle to R10.
         INC RAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV RDI,[%StdOutputString] ; String pointer.
         MOV RCX,[%StdOutputSize] ; String maximal size.
         SUB EAX,EAX
         MOV R8,RDI  ; Remember start of string in R8.
         REPNE SCASB ; Find the end of string.
         JNE .10:
         DEC RDI     ; Skip the NUL character.
   .10:  SUB RDI,R8  ; RDI is now string size in bytes.
         PUSH RDX    ; Make room for the written-size DWORD.
          MOV RDX,RSP
          WinAPI WriteConsoleA,R10,R8,RDI,RDX,0
         POP RDX
         CMP RDX,RDI  ; Set CF if not all characters were written.
   .90: POP R11,R10,R9,R8,RDX,RCX,RAX
        RET 3*8
      ENDP1 StdOutputAC@RT::
     %ENDIF AC

AF   %IF "%StdOutputRT" === "StdOutputAF@RT"
StdOutputAF@RT:: PROC1 ; ANSI File variant.
        PUSHQ RAX,RCX,RDX,R8,R9,R10,R11
         %StdOutputHandle %SET RSP+80
         %StdOutputSize   %SET RSP+72
         %StdOutputString %SET RSP+64
         MOV RAX,[%StdOutputHandle]
         WinAPI GetStdHandle,RAX ; Output handle identifier.
         MOV R10,RAX ; Save the (redirected) handle to R10.
         INC RAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV RDI,[%StdOutputString] ; String pointer.
         MOV RCX,[%StdOutputSize] ; String maximal size.
         SUB EAX,EAX
         MOV R8,RDI  ; Remember start of string in R8.
         REPNE SCASB ; Find the end of string.
         JNE .10:
         DEC RDI     ; Skip the NUL character.
   .10:  SUB RDI,R8  ; RDI is now string size in bytes.
         PUSH RDX    ; Make room for the written-size DWORD.
          MOV RDX,RSP
          WinAPI WriteFile,R10,R8,RDI,RDX,0
         POP RDX
         CMP RDX,RDI  ; Set CF if not all characters were written.
   .90: POP R11,R10,R9,R8,RDX,RCX,RAX
        RET 3*8
      ENDP1 StdOutputAF@RT::
     %ENDIF AF
 %ENDMACRO StdOutput
↑ StdInput Buffer, Size=, Handle=-10

Macro StdInput reads a line terminated with CR from standard input specified by the Handle identifier.

Input
Buffer is offset of memory where the input line will be stored.
Size= is the Buffer size. If omitted (default), macro will use SIZE# attribute of the Buffer.
Handle=-10 is the Windows standard input handle identifier. Possible input values are defined in winscon.htm:
Output
CF=0, RCX=number of bytes read.
Error
CF=1, RCX=0.
StdInput %MACRO Buffer, Size=, Handle=-10
    %IF "%Size"===""
      PUSHQ %Handle, SIZE# %Buffer, %Buffer
    %ELSE
      PUSHQ %Handle, %Size, %Buffer
    %ENDIF
    CALL StdInput@RT
StdInput@RT::PROC1
    PUSH RAX,RDX,R8,R9,R10,R11
     %StdInputHandle %SET RSP+72
     %StdInputSize   %SET RSP+64
     %StdInputBuffer %SET RSP+56
     MOV RAX,[%StdInputHandle]
     WinAPI GetStdHandle,RAX
     SUB ECX,ECX                  ; Clear RCX.
     MOV R10,RAX                  ; Save the handle to R10.
     INC RAX                      ; Test on INVALID_HANDLE_VALUE (-1).
     STC
     JZ .90:   ; Abort with CF when RAX=-1 (INVALID_HANDLE_VALUE).
     MOV R8,[%StdInputBuffer]
     MOV R9,[%StdInputSize]
     PUSH RCX  ; Make room for the read size.
      MOV RCX,RSP
      WinAPI ReadFile,R10,R8,R9,RCX,0
     POP RCX   ; Number of bytes read.
     SUB RAX,1 ; Return CF if ReadFile returned FALSE=0.
.90:POP R11,R10,R9,R8,RDX,RAX
    RET 3*8
   ENDPROC1 StdInput@RT::
  %ENDMACRO StdInput
↑ TerminateProgram Errorlevel=0
This macro provides exit from the running process and the return to the operating system.
It also specifies the Errorlevel (plain number) which can be used to inform the batch script which launched the program whether the program terminated normally or due to some error condition.
Input
Errorlevel= is the return code of the terminating program.
Beside the keyword Errorlevel=, this value may also be specified as an ordinal operand.
When this argument is omitted, it defaults to 0.
Output
is not applicable.
Example
TerminateProgram Errorlevel=[WorstErrLevel] ; Keyword value (from memory). TerminateProgram 8 ; Ordinal value.
TerminateProgram %MACRO Errorlevel=0
     IMPORT ExitProcess
     %IF %#=1 ; If ordinal provided.
       PUSHQ %1
     %ELSE    ; If keyword provided.
       PUSHQ %Errorlevel
     %ENDIF
     CALL ExitProcess::
   %ENDMACRO TerminateProgram
   ENDHEAD winabi

▲Back to the top▲