EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

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

MS Windows Application Programming Interface macros.

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

Macro names in this 32bit library winapi.htm are identical with macros from 64bit library winabi.htm . It's not expected to include both 32bit and 64bit version in the same source.
.
 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
stdcall.htm
 %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,,, Lib=

This macroinstruction invokes Function exported by [WindowsAPI].

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

WinAPI functions do not keep the original contents of flags, ECX, EDX. They require Direction Flag be zero on input and they do not change its value.

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.
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 keep their previous contents (calee-saved),
ECX,EDX are undefined (scratch registers),
DF=0, other CPU flags are undefined.
Example
; GetEnvironmentVariable ("PATH",PathBuffer,MAX_PATH_SIZE) // C syntax. WinAPI GetEnvironmentVariable,="PATH",PathBuffer,MAX_PATH_SIZE ; €ASM syntax.
See also
64bit version WinAPI in winabi.htm.
WinAPI %MACRO Function, Argument1, Argument2,,,Lib=
       %ParNr %SETA %# ; Number of ordinal arguments + 1.
       %WHILE %ParNr > 1
         PUSHD %*{%ParNr} ; Put ordinal operands on stack, begin with the last.
         %ParNr %SETA %ParNr-1
       %ENDWHILE
   reg %IF TYPE# %Function = 'R' ; If the function is specified in register.
          CALL %Function
       %ELSE reg ; The function is specified by its name.
          %suffix %SET  ; First assume no suffix (variable %suffix is empty).
      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 if found.
             %ENDIF
          %ENDFOR fn
          IMPORT %Function%suffix, Lib=%Lib
          CALL %Function%suffix
       %ENDIF reg
    %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 EAX=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
     PUSHAD
      MOV EBP,ESP
   %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 ESI,EAX ; ESI now points to the command-line ANSI zero-terminated string.
      SUB EAX,EAX
      SUB EDX,EDX ; DL will be used as a parsing flag register.
      MOV [%ReturnEAX],EAX
      CMP ESI,EAX
      JZ .80: ; If API returned FALSE.
      MOV EBX,-1 ; EBX will keep the ordinal number of parsed cmdline argument.
 .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 EBX
      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 EBX
 .70: CMP AL,0
      JNE .10:
 .80: TEST DL,%GetArgInQuotes
      JZ .90:
      STC ; If premature end of command line.
 .90: MOV [%ReturnEAX],EBX
     POPAD
     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 is ordinal number of the required parameter. The 0-th parameter is the executable file itself.
Output
CF=0,
ESI is pointer to the first byte of argument,
ECX is size of argument in bytes.
Error
CF=1 if odd number of quotes or if requested argument was not provided.
ESI=ECX=0
Example
GetArg 1 ; Assume that our program should specify a filename. JC .BadArgument: ; Report error if no file was provided. StripQuotes ESI,ECX ; Get rid of quotes if they were used. MOV EDI,InputFileName$ ; Room for the filename. REP MOVSB ; Copy the filename. SUB EAX,EAX STOSB ; Zero terminate the string.
GetArg %MACRO ArgNumber
          PUSHD %ArgNumber
          %IF %^UNICODE
             CALL GetArgW@RT
 GetArgW@RT PROC1
     PUSHAD
      MOV EBP,ESP
 %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 ESI,EAX ; ESI now points to the command-line WIDE zero-terminated string
      SUB EAX,EAX
      SUB EDX,EDX ; DL will be used as a parsing flag register.
      MOV [%ReturnECX],EAX
      MOV [%ReturnESI],EAX
      CMP ESI,EAX
      JZ .80 ; If API returned FALSE.
      MOV EBX,-1 ; EBX will keep the ordinal number of parsed cmdline argument.
 .10: LODSW
      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
      LEA EDI,[ESI-2] ; begin Param
      INC EBX
      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)
      LEA ECX,[ESI-2] ; end Param
      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 EDI,[ESI-2]
      MOV ECX,EDI
      INC EBX
 .70: CMP EBX,[%Param1]
      JE .90:
      CMP AX,0
      JNE .10:
 .80: MOV EDI,ECX
      STC ; If premature end of command line.
 .90: LAHF
       SUB ECX,EDI
       MOV [%ReturnESI],EDI
       MOV [%ReturnECX],ECX
      SAHF
     POPAD
     RET 4
   ENDPROC1 GetArgW@RT
          %ELSE  ; If not UNICODE.
            CALL GetArgA@RT
 GetArgA@RT PROC1
     PUSHAD
      MOV EBP,ESP
 %GetArgWithin    %SET 1  ; Boolean parsing flags will be kept in DL.
 %GetArgInQuotes  %SET 2
 %GetArgCommaTerm %SET 4
      WinAPI GetCommandLineA
      MOV ESI,EAX ; ESI now points to the command-line ANSI zero-terminated string.
      SUB EAX,EAX
      SUB EDX,EDX ; DL will be used as a parsing flag register.
      MOV [%ReturnECX],EAX
      MOV [%ReturnESI],EAX
      CMP ESI,EAX
      JZ .80: ; If API returned FALSE.
      MOV EBX,-1 ; EBX will keep the ordinal number of parsed cmdline argument.
 .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
      LEA EDI,[ESI-1] ; begin Param
      INC EBX
      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)
      LEA ECX,[ESI-1] ; end Param
      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 EDI,[ESI-1]
      MOV ECX,EDI
      INC EBX
 .70: CMP EBX,[%Param1]
      JE .90:
      CMP AL,0
      JNE .10:
 .80: MOV EDI,ECX
      STC ; If premature end of command line.
 .90: LAHF ; Temporary save CF.
       SUB ECX,EDI
       MOV [%ReturnESI],EDI
       MOV [%ReturnECX],ECX
      SAHF
     POPAD
     RET 4
   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 subprocesures 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 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.
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
       PUSHD %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.
         PUSHD %Handle, 4, =D(0x000A000D)
         CALL %StdOutputRT
       %ELSE        ; Write EOL in ANSI variant.
         PUSHD %Handle, 2, =W(0x0A0D)
         CALL %StdOutputRT
       %ENDIF
     %ENDIF

WC   %IF "%StdOutputRT" === "StdOutputWC@RT"
StdOutputWC@RT:: PROC1 ; WIDE Console variant.
        PUSHAD
         MOV EBP,ESP
         WinAPI GetStdHandle,[%Param3] ; Output handle identifier.
         MOV EBX,EAX ; Save the (redirected) handle to EBX.
         INC EAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV EDI,[%Param1] ; String pointer.
         MOV ECX,[%Param2] ; String maximal size.
         XOR EAX,EAX
         SAR ECX,1   ; Convert size in bytes to characters.
         MOV ESI,EDI
         REPNE SCASW ; Find the end of string.
         JNE .10:
         DEC EDI,EDI ; Skip the NUL character.
   .10:  SUB EDI,ESI ; EDI is now string size in bytes.
         PUSH EDX    ; Make room for the written-size DWORD.
          MOV EDX,ESP
          SAR EDI,1  ; EDI is now string size in characters.
          WinAPI WriteConsoleW,EBX,ESI,EDI,EDX,EAX
         POP EDX
         CMP EDX,EDI  ; Set CF if not all characters were written.
   .90: POPAD
        RET 3*4
      ENDP1 StdOutputWC@RT::
     %ENDIF WC

WF   %IF "%StdOutputRT" === "StdOutputWF@RT"
StdOutputWF@RT:: PROC1 ; WIDE File variant.
        PUSHAD
         MOV EBP,ESP
         WinAPI GetStdHandle,[%Param3] ; Output handle identifier.
         MOV EBX,EAX ; Save the (redirected) handle to EBX.
         INC EAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV EDI,[%Param1] ; String pointer.
         MOV ECX,[%Param2] ; String maximal size.
         XOR EAX,EAX
         SAR ECX,1   ; Convert size in bytes to characters.
         MOV ESI,EDI
         REPNE SCASW ; Find the end of string.
         JNE .10:
         DEC EDI,EDI ; Skip the NUL character.
   .10:  SUB EDI,ESI ; EDI is now string size in bytes.
         PUSH EDX    ; Make room for the written-size DWORD.
          MOV EDX,ESP
          WinAPI WriteFile,EBX,ESI,EDI,EDX,EAX
         POP EDX
         CMP EDX,EDI  ; Set CF if not all characters were written.
   .90: POPAD
        RET 3*4
      ENDP1 StdOutputWF@RT::
     %ENDIF WF

AC   %IF "%StdOutputRT" === "StdOutputAC@RT"
StdOutputAC@RT:: PROC1 ; ANSI Console variant.
        PUSHAD
         MOV EBP,ESP
         WinAPI GetStdHandle,[%Param3] ; Output handle identifier.
         MOV EBX,EAX ; Save the (redirected) handle to EBX.
         INC EAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV EDI,[%Param1] ; String pointer.
         MOV ECX,[%Param2] ; String maximal size.
         XOR EAX,EAX
         MOV ESI,EDI
         REPNE SCASB ; Find the end of string.
         JNE .10:
         DEC EDI     ; Skip the NUL character.
   .10:  SUB EDI,ESI ; EDI is now string size in bytes.
         PUSH EDX    ; Make room for the written-size DWORD.
          MOV EDX,ESP
          WinAPI WriteConsoleA,EBX,ESI,EDI,EDX,EAX
         POP EDX
         CMP EDX,EDI  ; Set CF if not all bytes were written.
   .90: POPAD
        RET 3*4
      ENDP1 StdOutputAC@RT::
     %ENDIF AC

AF   %IF "%StdOutputRT" === "StdOutputAF@RT"
StdOutputAF@RT:: PROC1 ; ANSI File variant.
        PUSHAD
         MOV EBP,ESP
         WinAPI GetStdHandle,[%Param3] ; Output handle identifier.
         MOV EBX,EAX ; Save the (redirected) handle to EBX.
         INC EAX     ; Test on INVALID_HANDLE_VALUE (-1).
         STC
         JZ .90: ; Abort with CF when INVALID_HANDLE_VALUE.
         MOV EDI,[%Param1] ; String pointer.
         MOV ECX,[%Param2] ; String maximal size.
         XOR EAX,EAX
         MOV ESI,EDI
         REPNE SCASB ; Find the end of string.
         JNE .10:
         DEC EDI     ; Skip the NUL character.
   .10:  SUB EDI,ESI ; EDI is now string size in bytes.
         PUSH EDX    ; Make room for the written-size DWORD.
          MOV EDX,ESP
          WinAPI WriteFile,EBX,ESI,EDI,EDX,EAX
         POP EDX
         CMP EDX,EDI  ; Set CF if not all bytes were written.
   .90: POPAD
        RET 3*4
      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, ECX=number of bytes read.
Error
CF=1, ECX=0.
StdInput %MACRO Buffer, Size=, Handle=-10
    %IF "%Size"===""
      PUSHD %Handle, SIZE# %Buffer, %Buffer
    %ELSE
      PUSHD %Handle, %Size, %Buffer
    %ENDIF
    CALL StdInput@RT
StdInput@RT::PROC1
     PUSHAD
      MOV EBP,ESP
      MOV EAX,[%Param3]  ; %Handle identifier (-10).
      WinAPI GetStdHandle,EAX
      MOV EBX,EAX
      INC EAX
      MOV [%ReturnECX],EAX
      STC
      JZ .90:   ; Abort with CF when EBX=-1 (INVALID_HANDLE_VALUE).
      LEA EDX,[%ReturnECX]
      WinAPI ReadFile,EBX,[%Param1],[%Param2],EDX,0
      SUB EAX,1 ; Return CF if ReadFile returned FALSE (EAX=0).
.90:POPAD
    RET 3*4
   ENDPROC1 StdInput@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
     IMPORT ExitProcess
     %IF %#=1 ; If ordinal provided.
       PUSHD %1
     %ELSE
       PUSHD %Errorlevel ; If keyword provided.
     %ENDIF
     CALL ExitProcess::
   %ENDMACRO TerminateProgram
   ENDHEAD winapi

▲Back to the top▲