News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

The correct way return IF ElSEIF ?

Started by Don57, December 15, 2012, 05:18:02 AM

Previous topic - Next topic

Don57

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

dedndave

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


Greenhorn

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

Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

jj2007

Launch Olly and have a look at your better example.

dedndave

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

jj2007

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(!)
 

dedndave

yah - and the epilogue is typically
    leave
    ret     16

what is that - 4 bytes ?

Greenhorn

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.
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

Greenhorn

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.
Kole Feut un Nordenwind gift en krusen Büdel un en lütten Pint.

jj2007

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...