Looking at various code examples on the forum, I see that people use different exits on IF ELSEIF. I have seen xor eax,eax and ret used.
.ELSEIF uMsg==WM_COMMAND
mov eax, lParam
.IF eax==hStatic ; if from hypertext window
invoke ShellExecute, 0, 0, chr$("http://www.shasti.ca"), 0, 0, SW_SHOWDEFAULT ; goto web site
xor eax,eax
.ENDIF
movzx edx, word ptr wParam+2 ; check command parameter
.IF edx==BN_CLICKED ; was button pressed
movzx eax, word ptr wParam
.IF eax==BUTTON_ID ; was the button pressed
.IF AdminFlaq==1 ; if in Admin mode
mov dw_Text_Flag, 1 ; flag to update files cleared
CALL Get_ELog_List ; creates Event Log text file and dumps to buffer
CALL Count_ELogs ; count the number of log files and calcs progress increment
CALL Create_Progress_Bar ; create progress bar
mov eax,OFFSET Clear_ELogs ; set for CreateThread call
invoke CreateThread,NULL,NULL,eax,\
NULL,NORMAL_PRIORITY_CLASS,\
ADDR dw_Clear_ELogs_ID ; create thread for clearing logs
invoke CloseHandle,eax ; close the thread
xor eax,eax ; return 0
.ELSE
invoke MessageBox, NULL,addr sz_MsgBoxAdminText, addr sz_MsgErrorCaption, MB_OK
invoke PostMessage,hWnd,WM_SYSCOMMAND,SC_CLOSE,NULL
xor eax,eax
.ENDIF
.ENDIF
or could you simple use one at the end of the conditional branch.
.ELSEIF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax ; clear message
ret
here is one i recently wrote
i think it is a good example, because one of the messages returns something other than 0
another case that comes to mind are the WM_CTLCOLORxxx messages, where you want to return a brush handle
notice that, for DefWindowProc, the value returned from that function is used
also notice that, for WM_SETCURSOR, i want DefWindowProc to handle messages that i do not intercept
mov eax,uMsg
.if eax==WM_MOUSEMOVE
movsx ecx,word ptr lParam
mov eax,dwDivFlags
movsx edx,word ptr lParam+2
.if al&DIVFLG_DRAG
push esi
mov esi,offset cg
.if al&DIVFLG_WE
sub ecx,[esi].CoordGroup.h.dwDivRef
mov [esi].CoordGroup.h.rcDiv.left,ecx
add ecx,DIV_WIDTH
mov [esi].CoordGroup.h.rcDiv.right,ecx
.endif
.if al&DIVFLG_NS
sub edx,[esi].CoordGroup.v.dwDivRef
mov [esi].CoordGroup.v.rcDiv.top,edx
add edx,DIV_WIDTH
mov [esi].CoordGroup.v.rcDiv.bottom,edx
.endif
pop esi
call ClientSize
call wmSize
.else
call MseMove
.endif
xor eax,eax
.elseif eax==WM_SETCURSOR&&(ah!=byte ptr dwDivFlags)
INVOKE SetCursor,hcurCurrent
mov eax,TRUE
.elseif eax==WM_SIZE
.if !(wParam&(NOT SIZE_MAXIMIZED))
movzx ecx,word ptr lParam
movzx edx,word ptr lParam+2
mov cg.v.rcDiv.right,ecx
mov cg.h.rcDiv.bottom,edx
call MinAdjust
call wmSize
.endif
xor eax,eax
.elseif eax==WM_GETMINMAXINFO
mov edx,offset cg
mov eax,[edx].CoordGroup.v.uMinSize
mov ecx,[edx].CoordGroup.h.uMinSize
mov edx,lParam
mov [edx].MINMAXINFO.ptMinTrackSize.y,eax
mov [edx].MINMAXINFO.ptMinTrackSize.x,ecx
xor eax,eax
.elseif eax==WM_PAINT
INVOKE PaintLines,hWnd
xor eax,eax
.elseif eax==WM_CAPTURECHANGED
push ebx
mov edx,dwDivFlags
xor ebx,ebx
.if edx
.if dl&DIVFLG_DRAG
INVOKE ClipCursor,ebx
.endif
mov dwDivFlags,ebx
INVOKE SetCursor,wc.hCursor
.endif
xchg eax,ebx
pop ebx
.elseif eax==WM_LBUTTONUP
.if byte ptr dwDivFlags&DIVFLG_DRAG
INVOKE ReleaseCapture
.endif
xor eax,eax
.elseif eax==WM_LBUTTONDOWN
mov eax,dwDivFlags
and al,DIVFLG_BOTH
.if !ZERO?
movsx ecx,word ptr lParam
movsx edx,word ptr lParam+2
call LBtnDn
.endif
xor eax,eax
.elseif eax==WM_CREATE
mov edx,hWnd
mov hwndMain,edx
INVOKE GetStockObject,BLACK_PEN
mov hpenBlack,eax
INVOKE CreatePen,PS_SOLID,1,CREF_DkGray
mov hpenDkGray,eax
xor ecx,ecx
INVOKE CreateWindowEx,ecx,offset szDiv1Class,ecx,
WS_VISIBLE or WS_CHILD,
ecx,ecx,ecx,ecx,hWnd,CID_DIV1WIN,wc.hInstance,ecx
mov chs.hwndDiv1,eax
xor ecx,ecx
INVOKE CreateWindowEx,ecx,offset szDiv2Class,ecx,
WS_VISIBLE or WS_CHILD,
ecx,ecx,ecx,ecx,hWnd,CID_DIV2WIN,wc.hInstance,ecx
mov chs.hwndDiv2,eax
xor ecx,ecx
INVOKE CreateWindowEx,ecx,offset szDiv3Class,ecx,
WS_VISIBLE or WS_CHILD,
ecx,ecx,ecx,ecx,hWnd,CID_DIV3WIN,wc.hInstance,ecx
mov chs.hwndDiv3,eax
xor ecx,ecx
INVOKE CreateWindowEx,ecx,offset szDiv4Class,ecx,
WS_VISIBLE or WS_CHILD,
ecx,ecx,ecx,ecx,hWnd,CID_DIV4WIN,wc.hInstance,ecx
mov chs.hwndDiv4,eax
xor eax,eax
.elseif eax==WM_CLOSE
INVOKE DestroyWindow,hWnd
INVOKE DeleteObject,hpenDkGray
xor eax,eax
.elseif eax==WM_DESTROY
INVOKE PostQuitMessage,NULL
xor eax,eax
.else
INVOKE DefWindowProc,hWnd,uMsg,wParam,lParam
.endif
ret
i played a little trick with WM_CAPTURECHANGED :biggrin:
it also returns 0
Thanks. :t
The use of RET should be only at the end of your procedure. Using it multiple times e.g. in .IF branches, it will bloat your code.
It's way better to create a label at your RET instruction and then use JMP to exit the procedure.
This is a bad example:
someProc PROC parm, parm, ...
LOCAL locVar
.IF someCondition
MOV eax, 1
RET
.ELSEIF anotherCondition
XOR eax, eax
RET
.ELSE
MOV eax, someVal
RET
.ENDIF
; maybe some other code here
; ...
RET
someProc ENDP
This is a better example:
someProc PROC parm, parm, ...
LOCAL locVar
.IF someCondition
MOV eax, 1
JMP @F
.ELSEIF anotherCondition
XOR eax, eax
JMP @F
.ELSE
MOV eax, someVal
JMP @F
.ENDIF
; maybe some other code here
; ...
@@: RET
someProc ENDP
Edited the examples for metaphorical correctness ...
Greenhorn
Launch Olly and have a look at your better example.
he has a point
if the PROC generates a prologue, that is
(i.e., if it has USES or parms on the PROC line, or any locals)
in those cases, the assembler generates an epilogue everyplace you put a RET
otherwise, RETN is a nice single byte instruction :P
Sure, it saves some bytes:
CASE Whatever
jmp RetZero
...
invoke DefWindowProc
@@:
RetZero:
xor eax, eax
jmp @B
For bigger WinProcs, it's hardly efficient because the jmps need 5 bytes then.
Another trick:
WndProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL NoWndProc
SWITCH uMsg
...
CASE WM_CLOSE
invoke ChkSave, 1 ; wm_close, ask
.if eax==IDCANCEL
xor eax, eax
inc NoWndProc ; RetNull
...
ENDSW
dec NoWndProc ; 3 bytes
.if Sign? ; 2 bytes
invoke DefWindowProc, hWin, uMsg, wParam, lParam
.endif
ret ; 7 bytes(!)
yah - and the epilogue is typically
leave
ret 16
what is that - 4 bytes ?
Quote from: dedndave on December 15, 2012, 06:57:06 AM
he has a point
if the PROC generates a prologue, that is
(i.e., if it has USES or parms on the PROC line, or any locals)
in those cases, the assembler generates an epilogue everyplace you put a RET
otherwise, RETN is a nice single byte instruction :P
Thanx for the correction, Dave. That's what I ment.
Quote from: jj2007 on December 15, 2012, 06:50:59 AM
Launch Olly and have a look at your better example.
Sorry for my incorrectness. In your sample you're right.
No problem, we all got our surprises when seeing "simple" code through Olly's eyes ;-)
Jumps that never execute, mov eax, eax, to name the most frequent ones...