This article has been dead for over three months
You
; Message definition in .rdata
Errm01 dd MB_YESNO | MB_ICONSTOP | MB_DEFBUTTON2 | MB_APPLMODAL
db 'MESSAGE BOX DEMO', 0
db 13, 10, 9, 'Do you want to continue', 0
; Example of how you would call function
xor eax, eax ; hWnd, owners window handle
mov edx, Errm01 ; Message definition
call MsgBox
; ============================================================================================
; *** MSGBOX ***
; ENTRY: EAX = hWnd
; EDX = Base pointer ot message parameters
; LEAVE EAX = Users response as defined in MessageBox
; .............................................................................................
FMTM EQU FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
MsgBox push esi
push edi ; Save essential registers
push ebx
enter 0x1c8, 0 ; Frame for MessageBox parameters
mov ebx, esp ; Let EBX point to base of these params
add ebx, byte 24
mov esi, edx
cld ; Assure auto increment of indices
; Due to the two modes of operation of this procedure, default to simple message
; box without extended information from GetLastError.
mov [ebx], eax ; hWnd, handle of owner window
lodsd ; Get style
mov [ebx+12], eax ; uType, style of message box
mov [ebx+8], esi ; lpCaption, title of message box
push esi
call _lstrlenA@4 ; Determine length of title text
inc eax ; Bump past strings terminating byte
add esi, eax
mov [ebx+4], esi ; lpText, text in message box
; The single determining factor whether procedure operates in extended mode or not
; is return value from GetLastError. If it isn't null, then that means we want
; to show error code, address of offending call, systems text associated with error
; and message box text from parameter 2 of MessgeBox.
call _GetLastError@0 ; Get error code if it exists.
and eax, eax
jnz .Ext_Mode
; NOTE: I've choosen to use this method because Extended Mode code is
; greater than 128 bytes which puts it past a near jump.
; Display message box in either simple or extended mode, get response from
; operator and let calling procedure determine appropriate action.
.Done lea esp, [ebp - 0x1b0] ; Point to parameters intialized earlier.
call _MessageBoxA@16
leave
pop ebx
pop edi ; Restore essential registers
pop esi
ret ; EAX = Return value of MessageBox call.
; -------------------------------------------------------------------------------------------
; Normally I would put this in .rdata, but sake of this demonstration I'll leave it in
; this segment
.OutFmt db 9, 'Error < %d > @ [ %X ] ', 13, 10, 13, 10, '%s%s', 0
; -------------------------------------------------------------------------------------------
; To create the extended string contents for message box, establish the 6 params
; that are required by wsprint being; OutputBuffer, FormatStr, ErrorCode,
; CallAddress, ErrorCodeStr, MsgBoxText.
.Ext_Mode mov edi, esp ; Establish pointer to wsprintf params
push eax ; Save error code from GetLastError
mov eax, esp
add eax, byte 0x3c ; Base of Destination Ascii buffer
stosd ; 1st Param for wsprintf
mov eax, .OutFmt ; Formatting definition
stosd ; 2nd Param for wsprintf
pop eax ; Restore Error code
stosd ; 3rd Param for wsprintf
; Procedure assumes that the first occurence of E8 before the call to MSGBOX was
; the API function that generated this error.
mov esi, edi ; Save next pointer to wsprintf param
mov edi, [ebp+16] ; Get callers return
sub edi, byte 6 ; Point to just before call to MSGBOX
mov al, 0xE8 ; Searching for call instruction
xor ecx, ecx
dec ecx ; Kind of large but no matter
std ; We want to search backward
repnz scasb
inc edi ; Points to call to API
cld ; Re-establish direction to default
mov eax, edi
xchg esi, edi
stosd ; 4th Param for wsprintf (Offending call).
; Use FormatMessage to determine text associated with this error from system
xor eax, eax
push eax ; Arguments = NULL (No insertion points)
push eax ; nSize, not required
push edi ; We'll use this location temporaritly
push dword SUBLANG_DEFAULT << 10 | LANG_NEUTRAL
push dword [edi - 8] ; Error code
push eax
push dword FMTM
call _FormatMessageA@28
and eax, eax
jnz $+4
int 3 ; In the unlikely event FormatMessage fails.
mov eax, [edi+12]
add edi, byte 4 ; Jump over value just save by FormatMessage
stosd ; Save address to string
call _wsprintfA ; Format entire message
pop eax ; Point to newly created string
mov [edi+4], eax ; and save for MessageBox API
push dword [edi-8] ; Recover memory allocated by FormatMessage
call _LocalFree@4
jmp .Done ; Complete display and operators response.