| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# winapi.htm
Enumerations
%StdCall32
Macros
GetArg
GetArgCount
MemAlloc
MemFree
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
            INCLUDEHEAD1 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:

  - If the Function name occurs on the %WinANSI list, it will be suffixed with `A` or `W` , depending on current %^UNICODE value.
  - The Function name will be declared as imported from library `Lib=`.

  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
  - if the library is kernel32.dll, or
  - if the Function is explicitly declared in current program, e.g. with `IMPORT Function, LIB=user32.dll`, or
  - if the Function is declared in some import library linked to the program.
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

↑ MemAlloc Size
  Macro MemAlloc allocates memory from Windows.
Input
  Size is the size of allocated memory in bytes, It will be rounded up to the multiply of pagesize (64 KiB).
Output
  CF=0,
  EAX is pointer to the first byte of the allocated memory.
Error
  CF=1
  EAX=0
Depends on
  WinAPI
See also
  MemFree

    MemAlloc %MACRO Size
         WinAPI VirtualAlloc, 0, %Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE, Fastmode=no
         CMP EAX,1  ; VirtualAlloc returns 0 on failure, otherwise the address.
        %ENDMACRO MemAlloc

↑ MemFree Address
  Macro MemFree unallocates memory from Windows.
Input
  Address as returned from MemAlloc which allocated it.
Output
  CF=0,
  EAX=0
Error
  CF=1
  EAX > 0
Depends on
  WinAPI
See also
  MemAlloc

    MemFree %MACRO Address, Size
         WinAPI VirtualFree, %Address, 0, MEM_RELEASE, Fastmode=no ; Returns 0 when failed.
         CMP EAX,1
        %ENDMACRO MemFree

↑ 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:
  - STD_OUTPUT_HANDLE = -11
  - STD_ERROR_HANDLE = -12
  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:
  - STD_INPUT_HANDLE = -10
  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▲