EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

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

MS Windows 32bit Application Programming Interface macros.

This library contains macros for some basic OS interactions: retrieving of 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,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 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, but separating white spaces and commas 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
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 ; Get rid of quotes if they were used. MOV EDI,InputFileName$ ; Room for the filename. 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
    JZ .Err:          ; 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
    JZ .90:           ; If GetCommandLine returned FALSE.
    XOR ECX,ECX
    DEC 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
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
↑ 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.

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 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.

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
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, 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
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▲