Hi all,

I just wanted to post a few of my macro's and procs!
Most are enhanced versions of common macros!
Some have become invaluable to me!
Please note that some Procs/Macros might depend on others, for example, Many use my mAlloc() macro to allocate memory!
Take them, modify them and use them freely!
Posted on 2004-03-10 00:44:48 by SubEvil
This macro is an enhancement to the commonly used return macro in the MASM package.
My version is more "intelligent" (I hope) and will somewhat "optimize" the coding depending on the value returned!
I kept my (untidy) comments which can be easily removed or replaced!



;; -----------------
;; return val in eax
;; -----------------
return MACRO val:REQ ;; .type == OPATTR
; LOCAL val ;; Declares val as a local variable only, used incase of name conflicts
IF (.type(val)) AND 00010000y ;; Register == 16
IFDIFI <val>, <eax> ;; No need to use ! before eax cause it's not a variable
mov eax, val
ELSE
;; if val == eax ... then all we need to do is use ret, no additional code!
;.err <return should not be used if the return value is already in eax>
ENDIF
ELSEIF (.type(val)) AND 00000010y ;; Memory Variable
mov eax, val
ELSEIF (.type(val)) AND 00000100y ;; Constant == 4
IF val EQ 0 ;; Test for zero
xor eax, eax ;; slightly more efficient for zero
ELSE
mov eax, val
ENDIF
ELSE
mov eax, val
ENDIF
ret
ENDM
Posted on 2004-03-10 00:45:21 by SubEvil



;; This is a simple macro to display a message in a message box.
;; Not really needed except for ... debuggin!
;; eg. mDebugMsg "Here"
;; I use it constantly to provide me with general/quick visual feedback of what code is currently being executed
;; Can theoretically sit anywhere in code as it preserves all registers and flags before calling the messagebox with my message
;; This macro is generally the same as mErrorMsg, but I usually remove this macro once I'm done and know what's going on in my code
;; I often use it in .if or while statements to check things out.
mDebugMsg MACRO Text:REQ
LOCAL szDebugMsgText
.const
szDebugMsgText db Text, 0
IFNDEF szDebugMsgTitle
szDebugMsgTitle db "Debug Message", 0
ENDIF
.code
pushad ; Push all registers
pushfd ; Push all flags
invoke MessageBox, NULL, addr szDebugMsgText, addr szDebugMsgTitle, MB_OK + MB_ICONWARNING
popfd
popad
ENDM
Posted on 2004-03-10 00:49:07 by SubEvil


;; Very similar to the above macro mDebugMsg but allows you to define a custom title instead of the standard "Debug Message" used above!
;; Also, I leave this macro in my code for error reporting!
mErrorMsg MACRO MsgText:REQ, MsgTitle
LOCAL MsgText
LOCAL MsgTitle
LOCAL szErrorMsgText
LOCAL szErrorMsgTempTitle
.const
szErrorMsgText db MsgText, 0
IFB <MsgTitle>
IFNDEF szErrorMsgTitle
szErrorMsgTitle DB "Error", 0
ENDIF
.code
invoke MessageBox, NULL, addr szErrorMsgText, addr szErrorMsgTitle, MB_OK + MB_ICONERROR
ELSE
szErrorMsgTempTitle db MsgTitle, 0
.code
invoke MessageBox, NULL, addr szErrorMsgText, addr szErrorMsgTempTitle, MB_OK + MB_ICONERROR
ENDIF
ENDM
Posted on 2004-03-10 00:51:50 by SubEvil


;; Allocates memory using HeapAlloc function
;; Used to directly return the memory location in code!
;; eg. mov Buffer, mAlloc(32)
;; The above will allocate 32 bytes of memory using the ProcessHeap

mAlloc MACRO AllocSize:REQ
IFNDEF szHeapAllocErrorTitle
.const
szHeapAllocErrorTitle DB "HeapAlloc Error", 0
szHeapAllocSTATUS_NO_MEMORY DB "STATUS_NO_MEMORY Message received after call to HeapAlloc", 0
szHeapAllocSTATUS_ACCESS_VIOLATION DB "STATUS_NO_MEMORY Message received after call to HeapAlloc", 0
.code
ENDIF
call GetProcessHeap
invoke HeapAlloc, eax, HEAP_GENERATE_EXCEPTIONS or HEAP_ZERO_MEMORY, AllocSize
.if eax == STATUS_NO_MEMORY
invoke MessageBox, NULL, addr szHeapAllocSTATUS_NO_MEMORY, addr szHeapAllocErrorTitle, MB_OK + MB_ICONERROR
.elseif eax == STATUS_ACCESS_VIOLATION
invoke MessageBox, NULL, addr szHeapAllocSTATUS_ACCESS_VIOLATION, addr szHeapAllocErrorTitle, MB_OK + MB_ICONERROR
.endif
EXITM <eax>
ENDM
Posted on 2004-03-10 00:59:23 by SubEvil


;; Frees the above allocated memory

mFree MACRO FreeAddr:REQ
call GetProcessHeap
invoke HeapFree, eax, NULL, FreeAddr
.if eax == NULL
mGetLastError "Error Freeing Heap Memory", "HeapFree Error"
.endif
ENDM
Posted on 2004-03-10 01:02:16 by SubEvil
The next Macro is used after an API call that returns error messages and codes using GetLastError. The Macro will extract the error code, and message from the Windows Resource files, so the exact Windows message is displayed. For example:



invoke RegisterClassEx, addr wc
.if eax == NULL
mGetLastError "Error processing call to RegisterClassEx for new Window class", "RegisterClassEx Error"
.endif





;; Used to retrieve the GetLastError code for most Windows API's
;; I use this macro extensively and it's VERY useful.
;; It will automatically get the apropriate Windows Error code and description.
;; It will also add a custom message at the top.
;; I use it with the custom message to tell me where in my code it generated an error.
;; This macro is essential to error reporting and saves a lot of lines of code
;; eg. mGetLastError "A call to CreateWindowEx generated the following error", "CreateWindowEx Error"
;; I've tried to save some memory by doing several checks and only assigning memory to strings when neaded!

mGetLastError MACRO CustomMsg, CustomMsgTitle
LOCAL szCustomMsg
LOCAL szCustomMsgTitle
IFNB <CustomMsg>
IF @SizeStr(CustomMsg) NE 2
.const
szCustomMsg DB CustomMsg, 0Dh, 0Ah, "Error Code ", 0
ELSEIFNDEF szGetLastErrorMsgPrefix
.const
szGetLastErrorMsgPrefix DB "Error Code ", 0
ENDIF
ELSEIFNDEF szGetLastErrorMsgPrefix
.const
szGetLastErrorMsgPrefix DB "Error Code ", 0
ENDIF
IFNB <CustomMsgTitle>
.const
szCustomMsgTitle DB CustomMsgTitle, 0
ELSEIFNDEF szGetLastErrorMsgTitle
.const
szGetLastErrorMsgTitle DB "GetLastError", 0
ENDIF
IFNDEF hFullErrorMsg
.data
hFullErrorMsg DD 0
hGetLastErrorMsg DD 0
hGetLastErrorCode DD 0
.const
szGeneralErrorMsgSpacer DB ": ", 0
ENDIF
.code
mov hGetLastErrorCode, mAlloc(11)
push NULL
push NULL
push offset hGetLastErrorMsg
push NULL
invoke GetLastError
push eax
invoke dw2str, eax, hGetLastErrorCode
push NULL
push FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM
call FormatMessage
;; This is uncommented to show the general format of the above function call
; invoke FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM, NULL, eax, NULL, addr hGetLastErrorMsg, NULL, NULL
IFNB <CustomMsg>
IF @SizeStr(CustomMsg) NE 2
invoke lstrlen, hGetLastErrorMsg
add eax, @SizeStr(<CustomMsg>) + 2 + (11 + 11 + 2)
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szCustomMsg
ELSE
invoke lstrlen, hGetLastErrorMsg
add eax, 11 + 11 + 2
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szGetLastErrorMsgPrefix
ENDIF
ELSE
invoke lstrlen, hGetLastErrorMsg
add eax, 11 + 11 + 2
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szGetLastErrorMsgPrefix
ENDIF
invoke lstrcat, hFullErrorMsg, hGetLastErrorCode
invoke lstrcat, hFullErrorMsg, addr szGeneralErrorMsgSpacer
invoke lstrcat, hFullErrorMsg, hGetLastErrorMsg
IFNB <CustomMsgTitle>
invoke MessageBox, NULL, hFullErrorMsg, addr szCustomMsgTitle, MB_OK + MB_ICONERROR
ELSE
invoke MessageBox, NULL, hFullErrorMsg, addr szGetLastErrorMsgTitle, MB_OK + MB_ICONERROR
ENDIF
invoke LocalFree, hGetLastErrorMsg
invoke HeapFree, App.Heap, NULL, hFullErrorMsg
invoke HeapFree, App.Heap, NULL, hGetLastErrorCode
ENDM
Posted on 2004-03-10 01:09:54 by SubEvil
I have found the next procedure invaluable. For debuggin purposes, sometimes I want to display a register or variable's value, and SEE with my own eyes what the value is, and how it changed. The next proc was one of the first assembler procs I wrote. All it does is convert and display the 32bit value in a messagebox. But also, because I often want to do some calculation on the variable, it stores the string value in the clipboard. So be warned, using it will remove clipboard data, but the value can then simply be used to past in Calculator. Also, it will preserve all registers and flags, so it can theoretically be used ANYWHERE in code without affecting your algorithm.

eg. invoke MsgDD, eax



;; MsgDD is somewhat similar to the dw2str function, it basically just converts the input falue to a string representation!
;; Then it copies the value to the clipboard, I did this cause I usually use this value in a calculation or to paste in Notepad
;; Then show the value in a messagebox. The function also preserves the registers and flags, so it can be used anywhere in code!
;; I use it extensivesly when debugging to check values as they go by.
;; eg. invoke MsgDD, eax
;; This will display the value in eax for me and won't affect the program so I can use it anywhere!

MsgDD PROC Val :DWORD ;USES eax ecx edx esi edi Val :DWORD
LOCAL hAlloc :DWORD

pushad ; Push all registers
pushfd ; Push all flags

;; NB Memory used for the clipboard is allocated with GlobalAlloc and NOT freed!
invoke GlobalAlloc, GMEM_MOVEABLE and GMEM_DDESHARE, 11
.if eax == NULL
mGetLastError "Error allocating memory for MsgDD", "GlobalAlloc Error"
.elseif
mov hAlloc, eax

mov edi, hAlloc ; edi stores the beginning offset of our string

mov eax, Val ; eax now contains input value for division later
mov esi, edi ; copy the offset of our string to esi (now both esi & ecx contain the offset)
mov ecx, 0Ah ; 0Ah == 10 == Decimal system (similar to Radix parameter of _itoa)

@@:
xor edx, edx ; Clear edx for division
div ecx ; Divide eax by 10 (Radix)
add dl, 30h ; Add 48 to the value (This is value for 0 (zero) on ASCII table)
mov byte ptr [edi], dl ; Move our new ASCII value into string position
inc edi ; Move to next string value
test eax, eax ; Test to see if we've reached 0 (zero)
jnz short @B ; If (!Zero?) Then ... Go Back to beginning
mov byte ptr [edi], 0 ; Place our terminating zero into position
dec edi ; Decrement ecx so we can begin reversing string

@@: ; This section reverses our string
mov dl, [esi]
mov al, [edi]
mov [edi], dl
dec edi
mov [esi], al
inc esi
cmp esi, edi
jb short @B

;;Clipboard
invoke OpenClipboard, NULL
.if eax == NULL
mGetLastError "", "OpenClipboard Error"
.else
invoke EmptyClipboard
.if eax == NULL
mGetLastError "", "EmptyClipboard Error"
.else
invoke SetClipboardData, CF_TEXT, hAlloc
.if eax == NULL
mGetLastError "", "SetClipboardData Error"
.endif
.endif
invoke CloseClipboard
.if eax == NULL
mGetLastError "", "CloseClipboard Error"
.endif
.endif

invoke MessageBox, NULL, hAlloc, sz("MsgDD"), MB_OK ; Finally display our message
.endif
popfd
popad
ret
MsgDD ENDP
Posted on 2004-03-10 01:19:20 by SubEvil
MsgHex is exactly the same as the above function, but displays the Hex value in a messagebox, instead of Decimal. I wrote this function while writing my GetPixel conversion to display RGB values which are usually better viewed as Hex values.



MsgHex PROC Val :DWORD
LOCAL hAlloc :DWORD

pushad ; Push all registers
pushfd ; Push all flags

;; NB Memory used for the clipboard is allocated with GlobalAlloc and NOT freed!
invoke GlobalAlloc, GMEM_MOVEABLE and GMEM_DDESHARE, 11
.if eax != NULL
mov hAlloc, eax

mov edi, hAlloc ; edi stores the beginning offset of our string

mov eax, Val ; eax now contains input value for division later
mov esi, edi ; copy the offset of our string to esi (now both esi & ecx contain the offset)
mov ecx, 10h ; 10h == 16 == Hex system (similar to Radix parameter of _itoa)

@@:
xor edx, edx ; Clear edx for division
div ecx ; Divide eax by 16 (Radix)
.IF (dl > 9)
sub dl, 9
add dl, 40h
.ELSE
add dl, 30h
.ENDIF
mov byte ptr [edi], dl ; Move our new ASCII value into string position
inc edi ; Move to next string value
test eax, eax ; Test to see if we've reached 0 (zero)
jnz short @B ; If (!Zero?) Then ... Go Back to beginning
mov byte ptr [edi], 0 ; Place our terminating zero into position
dec edi ; Decrement ecx so we can begin reversing string

@@: ; This section reverses our string
mov dl, [esi]
mov al, [edi]
mov [edi], dl
dec edi
mov [esi], al
inc esi
cmp esi, edi
jb short @B

;;Clipboard
invoke OpenClipboard, NULL
.if eax == NULL
mGetLastError "", "OpenClipboard Error"
.else
invoke EmptyClipboard
.if eax == NULL
mGetLastError "", "EmptyClipboard Error"
.else
invoke SetClipboardData, CF_TEXT, hAlloc
.if eax == NULL
mGetLastError "", "SetClipboardData Error"
.endif
.endif
invoke CloseClipboard
.if eax == NULL
mGetLastError "", "CloseClipboard Error"
.endif
.endif

invoke MessageBox, NULL, hAlloc, sz("MsgHex"), MB_OK ; Finally display our message
.elseif
mGetLastError "Error allocating memory for MsgHex", "GlobalAlloc Error"
.endif
popfd
popad
ret
MsgHex ENDP
Posted on 2004-03-10 01:23:49 by SubEvil


;; This function is an extention to MsgDD
;; I wrote it cause sometimes I want to display a message with my value,
;; cause perhaps I'm displaying several values and if I don't display a small message with it, I won't know where I am!
;; eg. invoke MsgTxtDD, eax, sz("WinSock generated the following Error: "), sz("WinSock Error")
;; Very useful to me when debugging! So the above will show a message and the value returned
;; Also preserves registers and flags! Only really useful during debugging stage!
MsgTxtDD PROC inVal :DWORD, pText:DWORD, pTitle :DWORD
LOCAL pAlloc :DWORD
LOCAL pFinalAlloc :DWORD

pushad ; Push all registers
pushfd ; Push all flags

;; NB Memory used for the clipboard is allocated with GlobalAlloc and NOT freed!
invoke GlobalAlloc, GMEM_MOVEABLE and GMEM_DDESHARE, 11
.if eax== NULL
mGetLastError "Error allocating memory for MsgTxtDD", "GlobalAlloc Error"
.elseif
mov pAlloc, eax

mov edi, pAlloc ; edi stores the beginning offset of our string

mov eax, inVal ; eax now contains input value for division later
mov esi, edi ; copy the offset of our string to esi (now both esi & ecx contain the offset)
mov ecx, 0Ah ; 0Ah == 10 == Decimal system (similar to Radix parameter of _itoa)

@@:
xor edx, edx ; Clear edx for division
div ecx ; Divide eax by 10 (Radix)
add dl, 30h ; Add 48 to the value (This is value for 0 (zero) on ASCII table)
mov byte ptr [edi], dl ; Move our new ASCII value into string position
inc edi ; Move to next string value
test eax, eax ; Test to see if we've reached 0 (zero)
jnz short @B ; If (!Zero?) Then ... Go Back to beginning
mov byte ptr [edi], 0 ; Place our terminating zero into position
dec edi ; Decrement ecx so we can begin reversing string

@@: ; This section reverses our string
mov dl, [esi]
mov al, [edi]
mov [edi], dl
dec edi
mov [esi], al
inc esi
cmp esi, edi
jb short @B

;;Clipboard
invoke OpenClipboard, NULL
.if eax== NULL
mGetLastError "", "OpenClipboard Error"
.else
invoke EmptyClipboard
.if eax == NULL
mGetLastError "", "EmptyClipboard Error"
.else
invoke SetClipboardData, CF_TEXT, pAlloc
.if eax == NULL
mGetLastError "", "SetClipboardData Error"
.endif
.endif
invoke CloseClipboard
.if eax == NULL
; mGetLastError "", "CloseClipboard Error"
.endif
.endif

.if pText == NULL
.if pTitle == NULL
IFNDEF szMsgTxtDDTitle
.const
szMsgTxtDDTitle db "MsgTxtDD", 0
.code
ENDIF
invoke MessageBox, NULL, pAlloc, addr szMsgTxtDDTitle, MB_OK ; Finally display our message
.else
invoke MessageBox, NULL, pAlloc, pTitle, MB_OK ; Finally display our message
.endif
.else
invoke lstrlen, pText
add eax, 11
mov pFinalAlloc, mAlloc(eax)
invoke lstrcat, pFinalAlloc, pText
invoke lstrcat, pFinalAlloc, pAlloc

.if pTitle == NULL
IFNDEF szMsgTxtDDTitle
.const
szMsgTxtDDTitle db "MsgTxtDD", 0
.code
ENDIF
invoke MessageBox, NULL, pFinalAlloc, addr szMsgTxtDDTitle, MB_OK ; Finally display our message
.else
invoke MessageBox, NULL, pFinalAlloc, pTitle, MB_OK ; Finally display our message
.endif
mFree(pFinalAlloc)
.endif
.endif
popfd
popad
ret
MsgTxtDD ENDP
Posted on 2004-03-10 01:27:26 by SubEvil


;; Basically the same as the above mGetLastError except it retrieves the Winsock API error for most of the WinSock API functions

mWSAGetLastError MACRO CustomMsg, CustomMsgTitle
LOCAL szCustomMsg
LOCAL szCustomMsgTitle
IFNB <CustomMsg>
IF @SizeStr(CustomMsg) NE 2
.const
szCustomMsg DB CustomMsg, 0Dh, 0Ah, "Error Code ", 0
ELSEIFNDEF szGetLastErrorMsgPrefix
.const
szGetLastErrorMsgPrefix DB "Error Code ", 0
ENDIF
ELSEIFNDEF szGetLastErrorMsgPrefix
.const
szGetLastErrorMsgPrefix DB "Error Code ", 0
ENDIF
IFNB <CustomMsgTitle>
.const
szCustomMsgTitle DB CustomMsgTitle, 0
ELSEIFNDEF szWSAGetLastErrorMsgTitle
.const
szWSAGetLastErrorMsgTitle DB "WSAGetLastError", 0
ENDIF
IFNDEF hFullErrorMsg
.data
hFullErrorMsg DD 0
hGetLastErrorMsg DD 0
hGetLastErrorCode DD 0
.const
szGeneralErrorMsgSpacer DB ": ", 0
ENDIF
.code
mov hGetLastErrorCode, mAlloc(11)
push NULL
push NULL
push offset hGetLastErrorMsg
push NULL
invoke WSAGetLastError
push eax
invoke dw2str, eax, hGetLastErrorCode
push NULL
push FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM
call FormatMessage
IFNB <CustomMsg>
IF @SizeStr(CustomMsg) NE 2
invoke lstrlen, hGetLastErrorMsg
add eax, @SizeStr(<CustomMsg>) + 2 + (11 + 11 + 2)
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szCustomMsg
ELSE
invoke lstrlen, hGetLastErrorMsg
add eax, 11 + 11 + 2
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szGetLastErrorMsgPrefix
ENDIF
ELSE
invoke lstrlen, hGetLastErrorMsg
add eax, 11 + 11 + 2
mov hFullErrorMsg, mAlloc(eax)
invoke lstrcat, hFullErrorMsg, addr szGetLastErrorMsgPrefix
ENDIF
invoke lstrcat, hFullErrorMsg, hGetLastErrorCode
invoke lstrcat, hFullErrorMsg, addr szGeneralErrorMsgSpacer
invoke lstrcat, hFullErrorMsg, hGetLastErrorMsg
IFNB <CustomMsgTitle>
invoke MessageBox, NULL, hFullErrorMsg, addr szCustomMsgTitle, MB_OK + MB_ICONERROR
ELSE
invoke MessageBox, NULL, hFullErrorMsg, addr szWSAGetLastErrorMsgTitle, MB_OK + MB_ICONERROR
ENDIF
invoke LocalFree, hGetLastErrorMsg
invoke HeapFree, App.Heap, NULL, hFullErrorMsg
invoke HeapFree, App.Heap, NULL, hGetLastErrorCode
ENDM
Posted on 2004-03-10 01:29:44 by SubEvil
You need to zip the source files with a readme, and upload to this site, it would make it a neat and clean download for all those interested.
Posted on 2004-03-10 10:42:08 by DarkStar
You should use VKim debug macros for debugging purposes. Its much easier than using message box, even with your macros.
Posted on 2004-03-10 20:12:11 by Mikky