MS Windows Application Programming Interface macros.
This library contains macros for 32bit MS Windows API invokations, retrieving command-line arguments, standard I/O and program termination.
Macro names in this 32bit library.winapi.htmare 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 invokation.
%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
This macroinstruction invokes Function exported by [WindowsAPI].
The macro is similar to StdCall's Invoke with two minor differences:
Lib=
.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.
kernel32.dll, or
IMPORT Function, LIB=user32.dll
, orWinAPI %MACRO Function, Argument1, Argument2,,,Lib= %ParNr %SETA %# ; Number of ordinal arguments + 1. %WHILE %ParNr > 1 PUSHD %*{%ParNr} ; Put 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. 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 %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
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.
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 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
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.
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.Unicode= %^UNICODE is boolean specification whether the Strings are in WIDE (UTF-16) encoding.
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.
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
Macro StdInput reads a line terminated with CR from standard input specified by the Handle identifier.
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
Errorlevel=
, this value may also be specified as an ordinal operand.
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