EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

winapi.htm
Enumerations
%StdCall32
Macros
GetArg
GetArgCount
PutArg
PutEnv
StdInput
StdOutput
TerminateProgram
WinAPI

MS Windows 32bit Application Programming Interface macros.

This library contains macros for some basic OS interactions: retrieving of environment and command-line arguments, standard I/O, program termination, invocation of 32bit MS Windows Application Programming Interface.

Most macro names in this 32bit library winapi.htm are identical with macros from 64bit library winabi.htm and other API libraries. If you really need to include both libraries in one common source file, definitions of those macros should be forgotten before inclusion of the other library with %DROPMACRO GetArg,GetArgCount,PutEnv,StdInput,StdOutput,TerminateProgram or with %DROPMACRO * in order to prevent warning W2512 Overwriting macro "!1S" previously defined at !2@.

 winapi HEAD
        INCLUDE1 winansi.htm ; Make sure that %WinANSI is assigned before WinAPI invocation.
↑ %StdCall32
This assignments define preprocessing %variables useful to refer stack frame in 32bit StdCall calling convention.
See also
stdcal32.htm
 %Param6    %SET EBP+56
 %Param5    %SET EBP+52
 %Param4    %SET EBP+48
 %Param3    %SET EBP+44
 %Param2    %SET EBP+40
 %Param1    %SET EBP+36
 %ReturnEAX %SET EBP+28
 %ReturnECX %SET EBP+24
 %ReturnEDX %SET EBP+20
 %ReturnEBX %SET EBP+16
 %ReturnESP %SET EBP+12
 %ReturnEBP %SET EBP+08
 %ReturnESI %SET EBP+04
 %ReturnEDI %SET EBP+00
↑ WinAPI   Function, Argument1, Argument2,,, Fastmode=No, Lib=

This macroinstruction invokes Function exported from 32bit MS Windows by [WindowsAPI].

The macro is similar to StdCall's Invoke with two subtle differences:

WinAPI functions require Direction Flag be zero on input and they do not change its value.
32bit Windows functions do not keep the original contents of flags, ECX, EDX, but when this macro WinAPI is invoked with keyword Fastmode=No (default), it preserves all registers except for EAX.

Input
Function is the name of invoked WinAPI function. Amphibious functions, which have both ANSI and WIDE variant, may be specified with or without explicit suffix A or W.
Function may also be provided as a GPR with RVA of the function (pointer to its thunk in [.idata]).
Argument* Zero or more DWORD pushable arguments may follow the function name.
It is programmer's responsibility to provide exactly that many argument as specified in Function documentation.
Fastmode=No is Boolean argument. When disabled or omitted (default), the WinAPI macro preserves all registers except for EAX which returns the result of Function.
Fastmode=Yes: if switched on, WinABI does not save scratch registers ECX, EDX, the invokation is faster and 4 bytes shorter.
When you want to switch on the Fastmode for all WinAPI invokations, you don't have to append ,Fastmode=Yes to every invokation of WinAPI if you set preprocessing %variable in the beginning of your program: %Fastmode %SETB On.
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
EAX= returns the value of the API function,
EBX,EBP,ESI,EDI,ESP keep their previous contents (calee-saved),
ECX,EDX are undefined (scratch registers) when Fastmode=Yes
DF=0, other CPU flags are undefined.
Depends on
WinANSI
Documentation
Windows functions are documented in [WindowsSDK] and in [WindowsAPI].
Example
; GetEnvironmentVariable ("PATH",PathBuffer,MAX_PATH_SIZE) // C syntax. WinAPI GetEnvironmentVariable,="PATH",PathBuffer,MAX_PATH_SIZE ; €ASM syntax.
See also
64bit version WinABI in winabi.htm.
WinAPI %MACRO Function, Argument1, Argument2,,,,Lib=, Fastmode=%Fastmode, Lib=
        %IF %Fastmode            ; Do not save scratch registers in fast mode.
        %ELSE
          PUSH ECX,EDX           ; Save scratch registers when Fastmode=off.
        %ENDIF
%ArgNr  %SETA %#                 ; Number of ordinal operands.
        %WHILE %ArgNr > 1
          PUSHD %*{%ArgNr}       ; Push Function arguments on stack, begin with the last.
%ArgNr    %SETA %ArgNr-1
        %ENDWHILE
%suffix %SET                     ; Assume no A|W suffix (variable %suffix is empty).
 noreg  %IF TYPE#%Function != 'R'; If the function is specified by name (not in GPR).
 fn       %FOR %WinANSI ; Examine whether %Function is on the list %WinANSI.
            %IF "%fn" === "%Function"
%suffix       %SETC ('W' & (%^UNICODE)) + ('A' & ~(%^UNICODE))
              %EXITFOR fn        ; Break further examination when the %Function name was found.
            %ENDIF
          %ENDFOR fn
          IMPORT %Function%suffix, Lib=%Lib
        %ENDIF noreg
        CALL %Function%suffix
        %IF  %Fastmode
        %ELSE
          POP EDX,ECX            ; Restore scratch registers when Fastmode=off.
        %ENDIF
       %ENDMACRO WinAPI
↑ GetArg   ArgNumber, Unicode=%^UNICODE

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 returns 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. If you need to modify it, make a copy in local memory or use PutArg. Quotes surrounding the argument are kept but white spaces and commas which separate arguments on cmd-line are stripped off.

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

Input
ArgNumber is ordinal number of the required parameter. The 0-th parameter specifies the executable file itself. ArgNr can be immediate number, 32bit GPR or memory variable.
Unicode=%^UNICODE is Boolean keyword specifying if the returned string is ANSI or WIDE.
Output
CF=0,
ESI is pointer to the first byte of argument,
ECX is size of argument in bytes. It will be zero if the argument is empty.
Error
CF=1 if odd number of quotes or if requested argument was not provided.
ESI=ECX=0
Depends on
WinAPI
Tested by
twinapi.htm
See also
GetArgCount
Example
GetArg 1 ; Assume that our program should specify a filename. JC .BadArgument: ; Report error if no file was provided. StripQuotes ESI,ECX ; Use this macro to get rid of quotes if they were used. MOV EDI,InputFileName$ ; Room for the filename in [.bss] segment. REP MOVSB ; Copy the filename. SUB EAX,EAX STOSW ; Zero terminate the string.
GetArg %MACRO ArgNumber, Unicode=%^UNICODE
     PUSHD %ArgNumber
AorW %IF %Unicode
       CALL GetArgWin32W@RT
GetArgWin32W@RT:: PROC1 ; Stdcalled with %Param1=ArgNumber.
   PUSHAD
    MOV EBP,ESP
    CMPD [%Param1],-1
    ADCD [%Param1],0
    IMPORT GetCommandLineW
    CALL GetCommandLineW
    MOV ESI,EAX
    MOV EDI,EAX
    MOV EBX,EAX
    XOR EAX,EAX
    CMP EAX,ESI
    STC
    JE .90:           ; If GetCommandLine returned FALSE.
    XOR ECX,ECX
    DEC ECX
    REPNE SCASW
    LEA EDX,[EDI-2]   ; EDX points to the end of command line.
    SUB ECX,ECX       ; ECX will keep the ordinal number of parsed cmdline argument.
.10:MOV EDI,ESI       ; EDI is brutto end of current argument.
    CMP ECX,[%Param1] ; %Par1 is the number of requested argument.
    JAE .50:
.20:CMP ESI,EDX
    JNB .50:          ; No more arguments available.
    LODSW
    CMP AX,' '
    JBE .20:
    DEC ESI,ESI
    INC ECX
    MOV EBX,ESI       ; EBX is brutto beginning of ECX-th argument.
    MOV EDI,ESI
.30:CMP ESI,EDX
    JNB .10:
    LODSW
    CMP AX,'"'
    JNE .40:
.35:CMP ESI,EDX
    CMC
    JC .90:           ; Syntax error - unpaired quotes.
    LODSW
    CMP AX,'"'
    JNE .35:
    JMP .30:
.40:CMP AX,','
    JE .10:
    CMP AX,' '
    JA .30:
.45:CMP ESI,EDX
    JNB .10:
    LODSW
    CMP AX,' '
    JNA .45:
    CMP AX,','
    JE .10:
    DEC ESI,ESI
    JMP .10:
.50:CMPD [%Param1],-1 ; Test if invoked from GetArgCount with ArgNr= -1.
    JNE .60:
    DEC ECX           ; Omit the 0-th argument (the executable itself).
    MOV [%ReturnECX],ECX
    JMP .80:
.60:MOVD [%ReturnECX],0
    CMP ECX,[%Param1]
    STC
    JNE .90:
    MOV ESI,EBX       ; Brutto ECX-th argument found at ESI..EDI. Trim spaces and commas.
.65:CMP ESI,EDI
    JNB .75:
    LODSW
    CMP AX,' '
    JBE .65:
    CMP AX,','
    JE .65:
    DEC ESI,ESI
.70:DEC EDI,EDI
    MOV AX,[EDI]
    CMP AX,' '
    JBE .70:
    CMP AX,','
    JE .70:
    INC EDI,EDI       ; Netto argument is now at ESI..EDI.
.75 MOV [%ReturnESI],ESI
    SUB EDI,ESI
    JC .80:
    MOV [%ReturnECX],EDI
.80:CLC
.90:POPAD
    RET 4
  ENDP1 GetArgWin32W@RT
     %ELSE AorW
       CALL GetArgWin32A@RT
GetArgWin32A@RT:: PROC1 ; Stdcalled with %Param1=ArgNumber.
   PUSHAD
    MOV EBP,ESP
    CMPD [%Param1],-1
    ADCD [%Param1],0
    IMPORT GetCommandLineA
    CALL GetCommandLineA
    MOV ESI,EAX
    MOV EDI,EAX
    MOV EBX,EAX
    XOR EAX,EAX
    CMP EAX,ESI
    STC
    JE .90:           ; If GetCommandLine returned FALSE.
    STC
    SBB ECX,ECX
    REPNE SCASB
    LEA EDX,[EDI-1]   ; EDX points to the end of command line.
    SUB ECX,ECX       ; ECX will keep the ordinal number of parsed cmdline argument.
.10:MOV EDI,ESI       ; EDI is brutto end of current argument.
    CMP ECX,[%Param1] ; %Par1 is the number of requested argument.
    JAE .50:
.20:CMP ESI,EDX
    JNB .50:          ; No more arguments available.
    LODSB
    CMP AL,' '
    JBE .20:
    DEC ESI
    INC ECX
    MOV EBX,ESI       ; EBX is brutto beginning of ECX-th argument.
    MOV EDI,ESI
.30:CMP ESI,EDX
    JNB .10:
    LODSB
    CMP AL,'"'
    JNE .40:
.35:CMP ESI,EDX
    CMC
    JC .90:           ; Syntax error - unpaired quotes.
    LODSB
    CMP AL,'"'
    JNE .35:
    JMP .30:
.40:CMP AL,','
    JE .10:
    CMP AL,' '
    JA .30:
.45:CMP ESI,EDX
    JNB .10:
    LODSB
    CMP AL,' '
    JNA .45:
    CMP AL,','
    JE .10:
    DEC ESI
    JMP .10:
.50:CMPD [%Param1],-1 ; Test if invoked from GetArgCount with ArgNr= -1.
    JNE .60:
    DEC ECX           ; Omit the 0-th argument (the executable itself).
    MOV [%ReturnECX],ECX
    JMP .80:
.60:MOVD [%ReturnECX],0
    CMP ECX,[%Param1]
    STC
    JNE .90:
    MOV ESI,EBX       ; Brutto ECX-th argument found at ESI..EDI. Trim spaces and commas.
.65:CMP ESI,EDI
    JNB .75:
    LODSB
    CMP AL,' '
    JBE .65:
    CMP AL,','
    JE .65:
    DEC ESI
.70:DEC EDI
    MOV AL,[EDI]
    CMP AL,' '
    JBE .70:
    CMP AL,','
    JE .70:
    INC EDI           ; Netto argument is now at ESI..EDI.
.75 MOV [%ReturnESI],ESI
    SUB EDI,ESI
    JC .80:
    MOV [%ReturnECX],EDI
.80:CLC
.90:POPAD
    RET 4
  ENDP1 GetArgWin32A@RT::
     %ENDIF AorW
 %ENDMACRO GetArg
↑ GetArgCount Unicode=%^UNICODE
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.
Unicode=%^UNICODE specifies if the macro should treat cmd-line as ANSI or WIDE.
Output
CF=0
ECX=number of arguments on the command line which launched the program.
Error
CF=1 if odd number of quotes detected.
Depends on
GetArg
Tested by
twinapi.htm
Example
All examples of the command lines below will return ArgCount ECX=4.
Program.exe arg1 arg2 arg3 arg4 Program.exe arg1,arg2, ,arg4 Program.exe , , , , , Program.exe arg1, "arg2,arg2" arg3 arg4
GetArgCount %MACRO Unicode=%^UNICODE
      GetArg -1, Unicode=%Unicode
     %ENDMACRO GetArgCount
↑ PutArg   ArgNumber, BufPtr, BufSize, Unicode=%^UNICODE

Macro PutArg retrieves ArgNumber-th argument from command-line, copies its content to the memory specified by BufPtr, BufSize and appends one NUL character at its end.

Input
ArgNumber is ordinal number of the required parameter. The 0-th parameter specifies the executable file itself. ArgNr can be immediate number, 32bit GPR or memory variable.
BufPtr is pointer to the caller-reserved memory for the argument value.
BufSize is size of the reserved memory in bytes. This 3rd parameter may be omitted, SIZE# %BufPtr will be used instead.
Unicode=%^UNICODE is extended Boolean value specifying if the string written to BufPtr should be ANSI or WIDE. By default it copies the value specified by EUROASM UNICODE=.
When the argument value expects e.g. not more than 10 characters and UNICODE=Yes, you should reserve BufSize at least 22 bytes (10+1 WIDE characters).
In €ASM you can define the output buffer as OutBuffer D (11 >> %^UNICODE) * BYTE , which will assemble as OutBuffer D 11 * BYTE when UNICODE=0 and as OutBuffer D (11 << 1) * BYTE when UNICODE= -1, always reserving room for 10+1 characters.
Output
CF=0 if the requested ASCIIZ value was successfully copied to Buffer.
ECX=number of bytes written to BufPtr, without the terminating NUL character.
ECX=0 when the ArgNumber-th argument does not exist.
Error
CF=1 if the value size overflowed BufSize and is therefore incomplete and not zero-terminated.
ECX=number of bytes written to BufPtr (never above BufSize).
Tested by
twinapi.htm
Depends on
GetArg
Example
; This example works with both ANSI and WIDE strings. EUROASM UNICODE=On ; or UNICODE=Off, no further intervention is necessary. [.bss] FileName$ DB (260 >> %^UNICODE) * BYTE ; Reserve 260 or 520 bytes. [.text] PutArg 1,FileName$
PutArg %MACRO ArgNumber, BufPtr, BufSize, Unicode=%^UNICODE
sized?  %IF %# = 2
mem?      %IF %^PASS > 1 && TYPE#(SEGMENT# %BufPtr) != 'A'
            %ERROR ID=5814, 'Please specify the size of output buffer.'
            %EXITMACRO PutEnv
          %ELSE mem?  ; BufPtr is specified as a memory variable with size.
            %PutArgSize %SETA SIZE# %BufPtr
          %ENDIF mem?
        %ELSE sized?  ; BufSize is explicitly specified.
           %PutArgSize %SET %BufSize
        %ENDIF sized?
        PUSH EDX,ESI,EDI
          SUB EDX,EDX
          GetArg %ArgNumber,Unicode=%Unicode
          JC PutArgY%.:
          MOV EDX,%PutArgSize
          MOV EDI,%BufPtr
          INC ECX
          %IF %Unicode
            INC ECX
          %ENDIF
          CMP EDX,ECX
          JAE PutArgX%.:
          MOV ECX,EDX
          REP MOVSB
          JMP PutArgY%.:
PutArgX%.:DEC ECX
          %IF %Unicode
            DEC ECX
            MOV EDX,ECX
            REP MOVSB
            MOV [EDI],CX
          %ELSE
            MOV EDX,ECX
            REP MOVSB
            MOV [EDI],CL
          %ENDIF
PutArgY%.:MOV ECX,EDX
        POP EDI,ESI,EDX
      %ENDMACRO PutArg
↑ PutEnv   EnvName$, BufPtr, BufSize, IgnoreCase=Yes, Unicode=%^UNICODE

Macro PutEnv retrieves environment-variable with specified zero-terminated name EnvName$ at run-time, and copies its content to the memory specified by BufPtr, BufSize, including the NUL character at its end.

Input
EnvName$ is pointer to zero-terminated string with environment-variable name (ANSI or WIDE).
BufPtr is pointer to the caller-reserved memory for the variable value.
BufSize is size of the reserved memory in bytes. This 3rd parameter may be omitted, SIZE# %BufPtr will be used instead.
IgnoreCase=Yes is extended Boolean value specifying if PutEnv should search for EnvName$ case-insensitively.
Unicode=%^UNICODE is extended Boolean value specifying if EnvName$ and the string written to BufPtr are both ANSI or WIDE. By default it copies the value specified by EUROASM UNICODE=.
When the environment value expects e.g. not more than 10 characters and UNICODE=Yes, you should reserve BufSize at least 22 bytes (10+1 WIDE characters).
In €ASM you can define the output buffer as OutBuffer D (11 >> %^UNICODE) * BYTE , which will assemble as OutBuffer D 11 * BYTE when UNICODE=0 and as OutBuffer D (11 << 1) * BYTE when UNICODE= -1, always reserving room for 10+1 characters.
Output
CF=0 if the requested ASCIIZ value was successfully copied to Buffer.
ECX=number of bytes written to BufPtr, without the terminating NUL character.
ECX=0 when the environment variable is empty or does not exist.
Error
CF=1 if the value size overflowed BufSize and is therefore incomplete.
ECX=number of bytes written to BufPtr (never exceeded BufSize).
Tested by
twinapi.htm
Example
; This example works with both ANSI and WIDE strings. EUROASM UNICODE=On ; or UNICODE=Off, no further intervention is necessary. [.bss] TempDir$ DB (260 >> %^UNICODE) * BYTE ; Reserve 260 or 520 bytes. [.text] PutEnv ="TEMP",TempDir$ ; Retrieve TEMP to TempDir$. LEA EDI,[TempDir$ + ECX] MOV ESI, ="\Cache.tmp" ; Netto 10 characters. MOV ECX, (10+1) >> %^UNICODE ; Size of the literal ="\Cache.tmp" in bytes. REP MOVSB ; Append the cache file name to TempDir$ name. ; TempDir$ now contains WIDE or ANSI string e.g. "C:\TMP\Cache.tmp",0.
PutEnv %MACRO EnvName$, BufPtr, BufSize, IgnoreCase=Yes, Unicode=%^UNICODE
sized?  %IF %# = 2
mem?      %IF %^PASS > 1 && TYPE#(SEGMENT# %BufPtr) != 'A'
            %ERROR ID=5814, 'Please specify the size of output buffer.'
            %EXITMACRO PutEnv
          %ELSE mem?  ; BufPtr is specified as a memory variable with size.
%PutEnvSize %SETA SIZE# %BufPtr
           %ENDIF mem?
        %ELSE sized?  ; BufSize is explicitly specified.
%PutEnvSize %SET %BufSize
        %ENDIF sized?
%PutEnvCase %SETB %IgnoreCase
        PUSHD %PutEnvCase, %PutEnvSize, %BufPtr, %EnvName$
ansi?   %IF %Unicode
          CALL PutEnvWin32W@RT::
PutEnvWin32W@RT::PROC1
        PUSHAD
         MOV EBP,ESP
%PutEnvNameSize %SET EBP-4
%PutEnvBlock    %SET EBP-8
         SUB ESP,2*4          ; Room for two local %variables.
         XOR ECX,ECX
         XOR EAX,EAX
         MOV EDX,[%Param2]    ; BufPtr.
         MOV EDI,[%Param1]    ; EnvName$.
         MOV [%ReturnECX],EAX
         MOV [EDX],AX         ; Prepare for the case when EnvName$ not found.
         NOT ECX
         MOV ESI,EDI
         REPNE SCASW
         NOT ECX
         MOV [%PutEnvNameSize],ECX ; Size in unichars including the terminating NUL.
         LEA EDX,[2*ECX+3]
         AND EDX,-4           ; Round EDX up to DWORD.
         SUB ESP,EDX          ; Room for lowercase EnvName.
         MOV EDI,ESP
.10:     LODSW
         CMP AX,'A'
         JB .20:
         CMP AX,'Z'
         JA .20:
         OR AL,'x'^'X'        ; Convert character to lowercase.
.20:     STOSW
         DEC ECX
         JNZ .10:
         IMPORT GetEnvironmentStringsW,FreeEnvironmentStringsW
         CALL GetEnvironmentStringsW::
         MOV [%PutEnvBlock],EAX
         MOV EBX,EAX
.30:     MOV EDI,EBX
         XOR ECX,ECX
         XOR EAX,EAX
         NOT ECX
         MOV ESI,EDI
         CMP [EDI],AX         ; Test the end of environment block.
         JZ .90:              ; Return with ECX=0, CF=0, ZF=1.
         REPNE SCASW
         MOV EBX,EDI
         NOT ECX              ; ESI..EDI is ASCIIZ string EnvName=EnvVal, brutto size in unichars=ECX.
         MOV EDI,ESI
         MOV AX,'='
         REPNE SCASW
         JNE .30:
         SUB EDI,ESI
         SHR EDI,1
         CMP EDI,[%PutEnvNameSize]
         JNE .30:
         LEA ECX,[EDI-1]      ; ECX is unichar-size of netto string EnvName.
         TESTB [%Param4],1    ; PutEnvCase.
         JNZ .40:
         MOV EDI,[%Param1]    ; Case sensitive search.
         REP CMPSW
         JNE .30:
         JMP .70:
.40:     MOV EDI,ESP          ; Case insensitive search.
.50:     LODSW
         CMP AX,'A'
         JB .60:
         CMP AX,'Z'
         JA .60:
         OR AL,'x'^'X'        ; Convert character to lowercase.
.60:     CMP AX,[EDI]
         JNE .30:
         INC EDI,EDI
         DEC ECX
         JNZ .50:
.70:     INC ESI,ESI          ; EnvName was found. ESI is now ASCIIZ EnvVal.
         MOV EDI,ESI
         XOR ECX,ECX
         XOR EAX,EAX
         NOT ECX
         REPNE SCASW
         SUB EDI,ESI          ; EDI= required-by-value brutto size of EnvVal in bytes.
         DEC EDI,EDI
         MOV [%ReturnECX],EDI ; Return ECX=netto size of EnvVal in bytes.
         INC EDI,EDI
         MOV ECX,[%Param3]    ; BufSize. EnvVal allocated-by-user brutto size in bytes.
         CMP ECX,EDI
         XCHG ECX,EDI
         JAE .80:
         XCHG EDI,ECX
.80:     MOV EDI,[%Param2]    ; BufPtr.
          REP MOVSB
.90:      PUSHFD
           PUSH [%PutEnvBlock]
           CALL FreeEnvironmentStringsW::
          POPFD
          MOV ESP,EBP
         POPAD
         RET 4*4
        ENDP1 PutEnvWin32W@RT::
       %ELSE ansi?
          CALL PutEnvWin32A@RT::
PutEnvWin32A@RT::PROC1
        PUSHAD
         MOV EBP,ESP
%PutEnvNameSize %SET EBP-4
%PutEnvBlock    %SET EBP-8
         SUB ESP,2*4          ; Room for two local %variables.
         XOR ECX,ECX
         XOR EAX,EAX
         MOV EDX,[%Param2]    ; BufPtr.
         MOV EDI,[%Param1]    ; EnvName$.
         MOV [%ReturnECX],ECX
         MOV [EDX],AL         ; Prepare for the case when EnvName$ not found.
         NOT ECX
         MOV ESI,EDI
         REPNE SCASB
         NOT ECX
         MOV [%PutEnvNameSize],ECX ; Including the terminating NUL.
         LEA EDX,[ECX+3]
         AND EDX,-4           ; Round EDX up to DWORD.
         SUB ESP,EDX          ; Room for lowercase EnvName.
         MOV EDI,ESP
.10:     LODSB
         CMP AL,'A'
         JB .20:
         CMP AL,'Z'
         JA .20:
         OR AL,'x'^'X'        ; Convert character to lowercase.
.20:     STOSB
         DEC ECX
         JNZ .10:
         IMPORT GetEnvironmentStringsA,FreeEnvironmentStringsA
         CALL GetEnvironmentStringsA::
         MOV [%PutEnvBlock],EAX
         MOV EBX,EAX
.30:     MOV EDI,EBX
         XOR ECX,ECX
         XOR EAX,EAX
         NOT ECX
         MOV ESI,EDI
         CMP [EDI],AL         ; Test the end of environment block.
         JZ .90:              ; Return with ECX=0, CF=0, ZF=1.
         REPNE SCASB
         MOV EBX,EDI
         NOT ECX              ; ESI..EDI is ASCIIZ string EnvName=EnvVal, brutto size=ECX.
         MOV EDI,ESI
         MOV AL,'='
         REPNE SCASB
         JNE .30:
         SUB EDI,ESI
         CMP EDI,[%PutEnvNameSize]
         JNE .30:
         LEA ECX,[EDI-1]      ; ESI,ECX is netto string EnvName.
         TESTB [%Param4],1    ; PutEnvCase.
         JNZ .40:
         MOV EDI,[%Param1]    ; Case sensitive search.
         REP CMPSB
         JNE .30:
         JMP .70:
.40:     MOV EDI,ESP          ; Case insensitive search.
.50:     LODSB
         CMP AL,'A'
         JB .60:
         CMP AL,'Z'
         JA .60:
         OR AL,'x'^'X'        ; Convert character to lowercase.
.60:     CMP AL,[EDI]
         JNE .30:
         INC EDI
         DEC ECX
         JNZ .50:
.70:     INC ESI              ; EnvName was found. ESI is now ASCIIZ EnvVal.
         MOV EDI,ESI
         XOR ECX,ECX
         XOR EAX,EAX
         NOT ECX
         REPNE SCASB
         SUB EDI,ESI          ; EDI= required-by-value brutto size of EnvVal.
         DEC EDI
         MOV [%ReturnECX],EDI ; Return ECX=netto size of EnvVal.
         INC EDI
         MOV ECX,[%Param3]    ; BufSize. EnvVal allocated-by-user brutto size.
         CMP ECX,EDI
         XCHG ECX,EDI
         JAE .80:
         XCHG EDI,ECX
.80:     MOV EDI,[%Param2]    ; BufPtr.
         REP MOVSB
.90:     PUSHFD
          PUSH [%PutEnvBlock]
          CALL FreeEnvironmentStringsA::
         POPFD
         MOV ESP,EBP
        POPAD
        RET 4*4
       ENDP1 PutEnvWin32A@RT::
      %ENDIF ansi?
   %ENDMACRO PutEnv
↑ StdOutput String1, String2,,, Size=-1, Handle=-11, Eol=No, Console=%StdConsole, 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.

The output device is by default treated as a file (when Console=No) Such output is redirectable, but it writes WIDE string as is; in OEM console are the UTF-16 encoded characters displayed as interlaced.
Output produced with Console=Yes cannot be redirected by command-line operators |, > or >but it accepts WIDE Unicode strings and displays the text in TrueType console properly, including non-English characters.

Input
StringX is pointer to ANSI or WIDE string.
Size=-1 is the maximal possible string size in bytes. If it is left to -1 (default when omitted), strings must be zero-terminated. This parameter applies to all ordinal operands.
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 the macro should use WinAPI function WriteFile or WriteConsole. Default is No.

When you want to use the Console (nondefault) mode in all StdOutput and StdInput invokations, you don't have to append ,Console=Yes to every invokation of StdOutput and StdInput if you set preprocessing %variable in the beginning of your program: %StdConsole %SETB Yes.

Unicode= %^UNICODE is boolean specification whether the Strings are in WIDE (UTF-16) encoding. By default (if omitted) it copies the global option EUROASM Unicode=.
Output
CF=0
Error
CF=1 if not all characters were written or if Handle was invalid.
Depends on
WinAPI
Tested by
twinapi.htm
Examples
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, Console=%StdConsole, Unicode=%^UNICODE
C     %IF %Console
U       %IF %Unicode
          %StdOutputFlags %SETA 2 + 1
        %ELSE U
          %StdOutputFlags %SETA 2 + 0
        %ENDIF U
      %ELSE C
W       %IF %Unicode
          %StdOutputFlags %SETA 0 + 1
        %ELSE W
          %StdOutputFlags %SETA 0 + 0
        %ENDIF W
      %ENDIF C
ArgNr %FOR 1..%#, STEP=1 ; Call the runtime for each String.
        PUSHD %StdOutputFlags, %1, %Size, %Handle
        CALL StdOutputWin32@RT
        %SHIFT 1         ; The next string to output.
      %ENDFOR ArgNr
Eol   %IF %Eol
U       %IF %Unicode
          PUSHD %StdOutputFlags+4, 0, 4, %Handle
        %ELSE U
          PUSHD %StdOutputFlags+4, 0, 2, %Handle
        %ENDIF U
        CALL StdOutputWin32@RT
      %ENDIF Eol
StdOutputWin32@RT:: PROC1 ; Invoked in stdcall convention with parameters Handle,Size,Addr,Flags.
      PUSHAD
       MOV EBP,ESP
       SUB ESP,4+4       ; Room for Eol and address of characters-written.
       MOV [ESP],ESP
       WinAPI GetStdHandle,[%Param1],Fastmode=Yes ; %Param1=Handle.
       MOV EBX,EAX
       INC EAX
       STC
       JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE (-1).
       MOV ECX,[%Param2] ; String maximal size.
       MOV EDI,[%Param3] ; String pointer.
       MOV EAX,[%Param4] ; Status flags. Bits 0=Unicode, 1=Console, 2=Eol.
       IMPORT WriteFile,WriteConsoleA,WriteConsoleW
       MOV EDX,WriteFile
       TEST AL,2         ; Select File or Console mode.
       JZ .10:
       MOV EDX,WriteConsoleA
       TEST AL,1
       JZ .10:
       MOV EDX,WriteConsoleW
   .10:TEST AL,4
       JZ .20:
       LEA EDI,[EBP-4]   ; EOL is requested instead of string.
       MOVD [EDI],0x000A_000D ; WIDE EOL.
       TEST AL,1
       JNZ .20:
       MOVW [EDI],0x0A0D ; ANSI EOL.
   .20:XOR EAX,EAX       ; EDI,ECX is string to write
       MOV ESI,EDI
       TESTB [%Param4],1 ; ASCII | WIDE.
       JZ .40:
       SHR ECX,1         ; Convert size to length in characters.
       REPNE SCASW       ; Find the WIDE zero terminator.
       JNE .50:
       DEC EDI,EDI       ; Omit the zero terminator.
       JMP .50:
   .40:REPNE SCASB       ; Find the ANSI zero terminator.
       JNE .50:
       DEC EDI
   .50:SUB EDI,ESI       ; EDI is now string size in bytes.
       MOV EAX,[%Param4] ; Status flags.
       AND AL,3
       XOR AL,3
       JNZ .60:
       SHR EDI,1         ; EDI is now string size in WIDE characters for Console.
   .60:WinAPI EDX,EBX,ESI,EDI,[EBP-8],0,Fastmode=on
       CMP [EBP-8],EDI   ; Set CF if not all characters were written.
   .90:MOV ESP,EBP
      POPAD
      RET 4*4
    ENDP1 StdOutputWin32@RT::
 %ENDMACRO StdOutput
↑ StdInput Buffer, Size=, Handle=-10, Console=No, Unicode=%^UNICODE

Macro StdInput reads a line of text terminated with CR (Enter) from standard input device (usually the keyboard) specified by the Handle identifier.

The input device is by default treated as a file (when Console=No). Such input is redirectable by command-line operators < or | but it treats input characters as bytes. Console mode uses console input buffer (no redirection works here) but it interprets WIDE characters properly.

Input
Buffer is offset of memory where the input string will be stored.
Size= is the Buffer size in bytes. 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: Console=No (or Yes) is boolean specification whether the macro should use WinAPI function ReadFile or ReadConsole.
When you want to use the Console (nondefault) mode in all StdOutput and StdInput invokations, you don't have to append ,Console=Yes to every invokation of StdOutput and StdInput if you set preprocessing %variable in the beginning of your program: %StdConsole %SETB Yes.
Unicode=%^UNICODE is boolean specification whether the characters read from console should be in WIDE (UTF-16) encoding.
Output
CF=0, ECX=number of bytes read from standard input.
Error
CF=1, ECX=0.
Depends on
WinAPI
Tested by
twinapi.htm
StdInput %MACRO Buffer, Size=, Handle=-10, Console=%StdConsole, Unicode=%^UNICODE
    %IF "%Size" === ""
      PUSHD %Handle, SIZE# %Buffer, %Buffer
    %ELSE
      PUSHD %Handle, %Size, %Buffer
    %ENDIF
    XOR ECX,ECX    ; ECX=0 when characters are 8bit ANSI.
    %IF %Console
      %IF %Unicode ; ReadConsole WIDE variant.
        IMPORT ReadConsoleW
        PUSHD  ReadConsoleW
        INC ECX    ; ECX=1 when characters are 16bit WIDE.
      %ELSE        ; ReadConsole ANSI variant.
        IMPORT ReadConsoleA
        PUSHD  ReadConsoleA
      %ENDIF
    %ELSE          ; ReadFile variant. Ignores Unicode.
      IMPORT ReadFile
      PUSHD  ReadFile
    %ENDIF         ; %StdInputRT is now the name of runtime PROC1.
    CALL StdInputWin32@RT
StdInputWin32@RT:: PROC1 ; StdCalled with parameters Function,Addr,Size,Handle,ECX.
     PUSHAD
       MOV EBP,ESP
       WinAPI GetStdHandle,[%Param4],Fastmode=on ; Get input handle.
       MOV ECX,EAX
       INC ECX
       STC
       JZ .90:   ; Abort with CF when EAX=-1 (INVALID_HANDLE_VALUE).
       MOV ESI,[%Param1]    ; Function.
       MOV EBX,[%Param3]    ; Size.
       MOV ECX,[%ReturnECX] ; 0=ANSI or 1=WIDE.
       LEA EDX,[%ReturnECX] ; Address of number of characters read.
       MOV EDI,ECX          ; Save 0 or 1 to EDI.
       SHR EBX,CL           ; Convert Size in bytes to length in characters.
       WinAPI ESI,EAX,[%Param2],EBX,EDX,0,Fastmode=on
       XCHG ECX,EDI         ; Restore 0 or 1 to CL.
       SHLD [%ReturnECX],CL ; Convert read length in characters to bytes.
       SUB EAX,1            ; Return CF if WinAPI returned FALSE (EAX=0).
 .90:POPAD
     RET 4*4
     ENDPROC1 StdInputWin32@RT::
  %ENDMACRO StdInput
↑ TerminateProgram Errorlevel=0
This macro provides exit from the running process and 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
     %IF %# = 1          ; If Errorlevel is provided as an ordinal.
       PUSHD %1
     %ELSE
       PUSHD %Errorlevel ; If Errorlevel is provided as a keyword.
     %ENDIF
     IMPORT ExitProcess, Lib="kernel32.dll"
     CALL   ExitProcess
   %ENDMACRO TerminateProgram
   ENDHEAD winapi

▲Back to the top▲