News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Question about returning values for processed msgs

Started by Rainstorm, October 06, 2007, 05:14:14 AM

Previous topic - Next topic

Rainstorm

When using the winapi's for many messages it says that the application should return 0 if it processes the said message. - however in the code I've tried.. the app still seems to work okay if i don't have a 'return 0' at the end od the processed message.

In the sample code in the SDK too, they don't always use a 'return 0' after processing a message, even though the documentation for the Message may say otherwise.

So is it compulsory.. or is there a downside to not having 'return 0' at the end ?

thx.

~

Mark Jones

Hi Rainstorm, it is necessary. What the Window API means by "the application should return zero if it processes the message successfully" is that the EAX register should contain zero before returning if your code processed the message successfully, or something non-zero to indicate that your code did not handle it successfully. This is just a simple way to pass a value to Windows to let it know to try some other method of processing that message. The EAX register is also commonly used as the return value from most procedures. Take for instance the GetCommandLine function -- no parameters are passed to it, it is simply called (Call or Invoke GetCommandLine) and it returns with the address of the command-line string in the EAX register.

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

sinsi

Quote from: Rainstorm on October 06, 2007, 05:14:14 AM
So is it compulsory.. or is there a downside to not having 'return 0' at the end ?
Here's one downside from CreateWindowEx
Quote
Return Value

If an application processes this message, it should return zero to continue creation of the window. If the application returns –1, the window is destroyed and the CreateWindowEx or CreateWindow function returns a NULL handle.

From what I've seen, most WM_* say to return 0 in EAX - maybe it's to stop any further processing? (a bit like Delphi's "inherited")?
Just to be contrary, some require that you return TRUE if you process it...fckn windows eh?
Light travels faster than sound, that's why some people seem bright until you hear them.

Rainstorm

mark & sinsi,
       thanks that was a big help!!
mar jones wrote..
QuoteWhat the Window API means by "the application should return zero if it processes the message successfully" is that the EAX register should contain zero before returning if your code processed the message successfully..

so i just need to put something like mov eax, 0  at the end or the msg procesing;.. not something like 'return 0'

I've got code in a window that seems to work proper even without putting a 0 in eax..
; --- Processes the WM_SETFOCUS msg & accordingly displays the Caret ----

          cmp uMsg, WM_SETFOCUS
          je showcaret
          jmp defaultprocessing

        showcaret:
          invoke CreateCaret, hWnd, NULL,1,16
          invoke SetCaretPos, 100, 350
          invoke ShowCaret, hWnd
;-------- next message --------


Actually that one would have a nonzero value in eax at the end, i think since after ShowCaret succeeds it would return a nonzero value.

~~

Tedd

You generally return zero to indicate that you've processed the message (except for messages where you don't ::)) If you do end up returning a different value, all it means to windows is that you haven't processed that message, and so windows will do something (sensible?) to take care of it instead. You can even process the message and then return 1 to say you didn't, and all will be fine, except that the extra handling might mess up whatever you did.
As for return values, when you say "return 0" it just translates to "mov eax,0","ret". So, whatever value is left in eax at the point of returning is the return value -- wherever it actually came from. So you could end up returning the return value of another function simply by calling it and then returning. Which is what's happening with your code that doesn't (explicitly) return a value. I'd try to avoid doing this though, unless you called your own function and want to return that value. It's not much effort to insert "mov eax,1" to make sure you return the correct value and avoid any problems.
No snowflake in an avalanche feels responsible.

Mark Jones

#5
...double post. Whoops, removed. Was the same as the below.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Mark Jones

 Hmm, you left out some important parts of that clip. But here's a typical WndProc for comparison:

WndProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    mov eax,uMsg
   
    .if eax==WM_CREATE
        ; do stuff here before everything else
    .elseif eax==WM_INITDIALOG
        ; do stuff before window is drawn
    .elseif eax==WM_HOTKEY
        ; maybe process some hotkeys

    .elseif eax==WM_COMMAND
        mov eax,wParam
        mov edx,eax
        shr edx,16
        and eax,0FFFFh
        .if edx==BN_CLICKED                       ; if something was clicked
            .if eax==IDC_BTN1                     ; if first button
                ; do something from 1st button
            .elseif eax==IDC_BTN2
                ; process 2nd button, etc...
            .endif
        .endif

    .elseif eax==WM_CLOSE
        invoke DestroyWindow,hWin
    .elseif uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .else
        invoke DefWindowProc,hWin,uMsg,wParam,lParam
        ret
    .endif
    xor eax,eax
    ret
WndProc endp


When execution reaches the main .IF eax== statement, it will branch to the sent message (WM_CREATE, WM_INITDIALOG, etc.) Say this program was sent a WM_HOTKEY message -- the main .IF and .ELSEIF statements would be skipped until we came to .elseif eax==WM_HOTKEY, at which point this would be true and whatever listed under that would be executed. Since this is inside an if/elseif/endif block, code execution would now exit the if/elseif/endif block at the .endif statement near the bottom, and execute xor eax,eax (which is the same thing as mox eax,0 only faster) and return. This lets windows know that we processed that message.

Now imagine this WndProc were sent a WM_SIZE message. Since we are not processing it (it is not defined anywhere in the if/elseif/endif block), the .else statement would be executed. To be concise about what we want windows to do, we specifically call the Windows default window procedure handler here and return (but in some cases mov eax,1 would suffice.)

Perhaps all of this can be made even more clear with a GoAsm example. GoAsm does not have .if/elseif/endif capability, so WndProcs must be made using low-level instructions. This particular code is for a DialogBoxParam, which is handled a little differently than other window types, but the same basic methodology remains:

DlgProc FRAME hWnd,uMsg,wParam,lParam
mov eax,[uMsg]
cmp eax,WM_INITDIALOG
jne >.WMCOMMAND
; init code here
jmp >.EXIT

.WMCOMMAND
cmp eax,WM_COMMAND
jne >.WMSIZE
mov eax,[wParam]
mov edx,eax
shr edx,16
and eax,0FFFFh
cmp edx,BN_CLICKED
jne >.EXIT
cmp eax,IDC_OK
jne >.B2
; button 1 code...
.B2
cmp eax,IDC_HLP
jne >.EXIT
; button 2 code...

.WMSIZE
cmp eax,WM_SIZE
jne >.WMCLOSE
; window resizing code here
jmp >.EXIT

.WMCLOSE
cmp eax,WM_CLOSE
jne >.DEFPROC
invoke EndDialog,[hWnd],0

.DEFPROC
mov eax,0
ret
.EXIT
mov eax,1
ret
ENDF


Here we return with a 1 in eax when a message was processed successfully, and a 0 if not.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Rainstorm

tedd, thanks for the explanation

mark, much appeciate the examples..that was a big help

& when I use 'ret'  after mov eax, 0 in the MSG processing, where does the program flow return to ? - back to the message loop in the winmain ? - is this correct ?
like if this is my message loop..    MessageLoop:
      invoke GetMessage,addr msg,NULL,0,0
     
      .if eax == -1                         ;  check for an error
        push eax
        fn MessageBox,0,"error","Title",MB_OK
        pop eax
        jmp ExitMsgLoop
      .endif

      cmp eax, 0                    ; check for WM_QUIT message retrieved by GetMessage
      je ExitMsgLoop                ; if 0 (WM_QUIT msg retrieved), then exit the Loop.
      invoke TranslateMessage, addr msg
      invoke DispatchMessage,  addr msg
      jmp MessageLoop     ; <---- Program Flow returned back here ?

   ExitMsgLoop:
      mov eax, msg.wParam
      ret

  WinMain endp


it would go back to the jmp MessageLoop statement  ?

Tedd

Short answer: yes :bg

Longer explanation:
When you call GetMessage, your program actually stops - it's put on hold until there is a message for your window(s). Then, when a message comes along (or if there was already one waiting), the message details are copied into the 'msg' structure, and your progam is allowed to continue - getmessage returns.
So then you check if it was WM_QUIT and exit, or translate (turns virtual-key presses into character messages) and dispatch it. When you call DispatchMessage, windows does a little fiddling around and your WndProc is called with the message details. So you handle the message and return true/false/anything, and ret back to the windows message dispatcher. It does whatever it does, and eventually returns from DispatchMessage - with a copy of the return value (in eax, of course.) And you go on your merry way.
No snowflake in an avalanche feels responsible.

Rainstorm

hi tedd,

thanks for the explanation.. that cleared a few other queries i had in my mind too.

just one more question. - what you said about getmessage stopping, that happens with just with GetMessage or for all calls ? - i mean for like calls to any other functions/WinAPIs... does the program stop for those too, till it gets a return value,..& then procceeds to the next instruction in the program only when it has recieved a return from the previous call ?

many thanks

Rainstorm.
~

Tedd

When you call a function, execution jumps to that function and continues there, until return, where it gets back to where it left off, and continues on. So your program hasn't 'stopped' it's just currently inside a function.
What I meant about GetMessage stopping - your process thread is actually stopped, i.e. windows continues a different thread (all threads don't run at once, they're run for short periods in turn -- task switching.) So, at that point, your thread isn't doing anything - no cpu usage. When there's a message ready for your window, then your thread is activated again, and it can continue.
No snowflake in an avalanche feels responsible.