I am attempting to use vararg but I cant seem to figure out how to use it properly.
I notice there is a macro argcount, but it always returns 1 regardless of how many params i passed.
.386
.model flat, stdcall
option casemap:none ;case sensitive
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\macros\macros.asm
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
.data?
.code
varargtest proc C arg1:dword, args:VARARG
mov eax, argcount(args) ; argcount returns 1, even though there is 5!?
ret
varargtest endp
main proc public
invoke varargtest, 99, 1,2,3,4,5
invoke ExitProcess, 0
ret
main endp
end
argcount counts macro arguments. What you need is arg1, see below
include \masm32\include\masm32rt.inc
argcount MACRO args:VARARG
LOCAL cnt
cnt = 0
FOR item, <args>
cnt = cnt + 1
ENDM
EXITM %cnt ;; return as a number
ENDM
.code
varargtest proc C arg1:dword, args:VARARG
; mov eax, argcount(args) ; argcount returns 1, even though there is 5!?
mov eax, arg1
ret
varargtest endp
main proc public
invoke varargtest, 99, 1,2,3,4,5
MsgBox 0, str$(eax), "Hi", MB_OK
invoke ExitProcess, 0
ret
main endp
end main
Your example will return 99 everytime, regardless of how many parameters are passed in the varargtest proc.
Are you saying I need to explicitly inform the proc how many params I am passing?
Quote from: Matthew on May 18, 2012, 09:31:23 AM
Are you saying I need to explicitly inform the proc how many params I am passing?
Yep, that's it... and that's where the macro steps in: You can use argcount in a macro that pushes your params "by hand" and passed the count as last para.
Because basically I was writing some logging functionality which uses crt_sprintf.
I was hoping I could just wrap crt_sprintf format and vararg parameters, whilst giving an opportunity to modify the output of crt_sprintf before i used it (e.g append a timestamp).
after your response regarding the macros, I came up with this which seems to work, but I am always thinking could I have done it better...
I was also wondering in the macros in \masm32\macros\macros.asm I see some mangled variable names in the macros, so i mangled my logbuffer variable, is this common practice?
WriteLogMessage proc szMessage:LPSTR, bWriteTimeStamp:BYTE
local dwBytesWritten:DWORD
local dwMessageLength:DWORD
local systemTime:SYSTEMTIME
local dateTimeBuffer[64]:BYTE
.if bWriteTimeStamp == 1
invoke GetLocalTime, addr systemTime
invoke crt_sprintf, addr dateTimeBuffer, chr$("%04d-%02d-%02d %02d:%02d:%02d.%03d : "), systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds
invoke StrLen, addr dateTimeBuffer
mov dwMessageLength, eax
invoke WriteFile, hFile, addr dateTimeBuffer, dwMessageLength, addr dwBytesWritten, NULL
.endif
invoke StrLen, szMessage
mov dwMessageLength, eax
invoke WriteFile, hFile, szMessage, dwMessageLength, addr dwBytesWritten, NULL
invoke WriteFile, hFile, chr$(13,10), 2, addr dwBytesWritten, NULL
ret
WriteLogMessage endp
LogMessage macro szFormat,bWriteTimeStamp:req, args:vararg
local l_o_g_b_u_f_f_er
.data?
l_o_g_b_u_f_f_er BYTE 2048 dup(?)
.code
invoke crt_sprintf, addr l_o_g_b_u_f_f_er, chr$(format), args
invoke WriteLogMessage, addr l_o_g_b_u_f_f_er, bWriteTimeStamp
EXITM <>
endm
main proc
LogMessage "%d,%d%d", TRUE, 100, 200, 300
ret
main endp
If your procedure uses the C calling convention, and the variable arguments are of a uniform size, and you don't mind using a hack, then the procedure can determine the number of arguments by examining the instruction at the return address that removes the arguments from the stack. Note that this code is limited to 255 bytes for the arguments = 63 dwords. Tested with ML 6.15.8803 only.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
.data
.code
;==============================================================================
testproc proc C args:VARARG
xor eax, eax ; assume zero args
mov edx, [ebp+4] ; get return address
cmp WORD PTR[edx], 0C483h ; opcode for add esp,n
je @F
ret
@@:
movzx eax, BYTE PTR[edx+2] ; get value added to esp
shr eax, 2 ; divide by 4 for arg count
ret
testproc endp
;==============================================================================
start:
;==============================================================================
invoke testproc
printf("%d\n",eax)
invoke testproc,1
printf("%d\n",eax)
invoke testproc,1,2
printf("%d\n",eax)
invoke testproc,1,2,3
printf("%d\n",eax)
invoke testproc,1,2,3,4
printf("%d\n",eax)
invoke testproc,1,2,3,4,5
printf("%d\n",eax)
invoke testproc,1,2,3,4,5,6
printf("%d\n\n",eax)
inkey
exit
;==============================================================================
end start