This procedure displays a MessageBox, but with additional information such as error #, address of call that caused the error and associated text.
I left the snippet in start so you can see how this is called. You'll need to include inc files and libraries to conform to your own system
.486
.model flat, stdcall
option casemap:none
.const
Caption db 'MsgBox Error', 0
Text db 'Please choose from the following', 0
FmtText db 'Error [%d] @ %X', 13, 10, 13, 10, '%s', 13, 10, '%s', 0
.code
; ============================================================================================
Start:
enter 0, 0 ; Empty procedure frame
BOX EQU MB_ABORTRETRYIGNORE or MB_ICONWARNING or MB_DEFBUTTON2 or MB_APPLMODAL
push 33
call SetLastError
push BOX ; uType
push offset Caption ; lpCaption
push offset Text ; lpText
push 0 ; hWnd = Desktop in this example
call MsgBox ; Display error message
leave
ret
; --------------------------------------------------------------------------------------------
MsgBox PROC uses ebx esi edi hWnd:DWORD, Msg:DWORD, Cap:DWORD, MsgType:DWORD
FMTM EQU FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM
LOCAL DispBuff [512] :BYTE
; Setup stack for MessageBox call at epilogue.
push MsgType ; uType
push Cap ; lpCaption
push Msg ; lpText
push hWnd ; hWnd
; As there may not be an error associated with this call make the determination first
call GetLastError
and eax, eax
jz ShowMsg
; Now CapText can be replaced with DispBuff
lea ecx, DispBuff
mov [esp + 4], ecx ; This way so we don't alter EAX
; Begin setting up stack for wsprintf call subject to format outlined in FmtText.
push Msg ; 4th parameter of FmtText
push 0 ; We don't know exactly where this is yet
push eax ; Save temporarily
; As this call is as a result of an error usually from an API, we need to search
; backward in code to find the address at which it occured.
mov edi, [ebp + 4] ; Get callers return address
sub edi, 6 ; Bump past this calls opcode
std ; Set auto decrement of EDI
mov al, 0E8H ; Intel's call instruction
xor ecx, ecx
dec ecx ; Ridiculously large
repnz scasb ; Search backward until found
inc edi ; Bump to proper position
cld ; Set to default again, auto increment
xchg [esp], edi
push edi
; Now we are ready to get formatted text from OS
xor eax, eax
push eax ; Arguments
push eax ; nSize, not required because ALLOCATE_BUFFER
lea eax, [esp + 16]
push eax ; lpBuffer, allocated by API
xor edx, edx
mov dl, SUBLANG_DEFAULT
shl edx, 10
or edx, LANG_NEUTRAL
push edx ; dwLanguageId
mov eax, [esp + 16]
push eax ; dwMessageID
push 0
push FMTM
call FormatMessage
and eax, eax
jnz $ + 3
int 3 ; Trap this if there is an error
; Take all the elements and format them into DispBuff as per FmtText specifications
mov eax, offset FmtText
push eax
lea eax, DispBuff
push eax
call wsprintf
add esp, 24 ; Waste parameters
; Recover memory from system that was allocated by FormatMessage
push dword ptr [esp - 8]
call LocalFree
; Display message message box with extended information if applicable
ShowMsg: call MessageBox
ret ; Return with response from operator
MsgBox ENDP
END Start
Hi,
Could you or somebody tell me why some codes have so many push instructions (specially to call library functions) and not equivalent pop instructions ?
Do these functions do the "pop" internally or the "push pop" simetry doesn't really care in those codes ?
Tks in advance
S A
Hi alemao,
Welcome to the Forum :thumbu
The pushs are "neutralised" by the ret at the end of the called function:
include \masm32\include\masm32rt.inc
.code
AppName db "Masm32 is great!", 0
Hello db "A message:", 0
MyTest proc arg1, arg2
MsgBox 0, arg1, arg2, MB_OK
ret
MyTest endp
start:
push offset Hello
push offset AppName
call MyTest ;invoke MyTest, offset AppName, addr Hello
exit
end start
If you check the ret with Olly (http://www.ollydbg.de/version2.html), you will find out that it is in fact a retn 8
those are parameters, passed to the function on the stack
as JJ mentioned, the function is responsible for removing them from the stack when using the "StdCall" convention
Thanks for all :cheekygreen: