News:

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

General Windows questions

Started by NoCforMe, October 06, 2011, 08:27:26 AM

Previous topic - Next topic

NoCforMe

Couple- "top-level" Windoze questions. Feel free to point me to tutorials, other posts, etc., as appropriate.

  • DefWindowProc(): When should this be called in the message-handling proc? Only for stuff you don't handle yourself? or for everythng?
    As I understand it, this is a kind of "none of the above" handling routine for things that fall out the bottom of your message selector.
  • What registers are guaranteed to be unmolested by Windows? I assume everything except [E]AX, but not sure. (Well, and SP and flags. And I'm not even messing with the segment regs at all at this point.)

ToutEnMasm


Samples of windows are numerous in the masm32 examples nd in this forum.
DefWindowProc is a function who answer to the messages you haven't processed in  window loop.
Preserved registers are     ESI EDI and EBX.You must follow this rule,:
When using one of this , you must preserve it .
MonProc PROC uses esi edi ebx parm1:DWORD ...
or
MonProc PROC  parm1:DWORD ...
           Push esi
           push edi
           push ebx
          ...........
           pop ebx
           pop edi
          pop  esi
           ret
MonProc endp

jj2007

Quote from: NoCforMe on October 06, 2011, 08:27:26 AM
  • DefWindowProc(): When should this be called in the message-handling proc? Only for stuff you don't handle yourself? or for everythng?
DefWindowProc does standard processing for controls and windows. Do not call it only in special cases.
Example: If you draw the background yourself, don't let Windows do it again.
Another example:
- call DefWindowProc in your WM_PAINT handler: Windows will draw the background and contents of your controls
- draw something on top
- validate the rect, telling Windows hands off
- return without calling DefWindowProc again.

As to register preservation, see my signature.

dedndave

likewise, there are special cases where you should exit via DefWindowProc, even if you do process it
for example, when you process a system-key message (WM_SYSKEYDOWN, WM_SYSKEYUP)

notice also that the parameters for DefWindowProc are the same as those for WndProc
those parms are already on the stack, then the return address
after that, the prologue pushes EBP, if you have it enabled, along with any other registers you declare in PROC
but, you can do something like this...
        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

WndProc PROC    hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

        mov     eax,[esp+8]
        cmp     eax,WM_SomeMessage1
        JZ      SM1

        cmp     eax,WM_SomeMessage2
        JZ      SM2

        JMP     DefWindowProc

;handle WM_SomeMessage1

SM1:
        ret     16

;handle WM_SomeMessage2

SM2:
        ret     16

WndProc ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

or
        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

WndProc PROC    hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

        cmp dword ptr [esp+8],WM_SomeMessage
        JNZ     DefWindowProc

;handle WM_SomeMessage

        ret     16

WndProc ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef


or, with the default prologue and epilogue
WndProc PROC    hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

        mov     eax,uMsg
        cmp     eax,WM_SomeMessage1
        JZ      SM1

        cmp     eax,WM_SomeMessage2
        JZ      SM2

        pop     ebp
        JMP     DefWindowProc

;handle WM_SomeMessage1

SM1:
        ret     16

;handle WM_SomeMessage2

SM2:
        ret     16

WndProc ENDP

NoCforMe

Quote from: jj2007 on October 06, 2011, 12:54:13 PM
Quote from: NoCforMe on October 06, 2011, 08:27:26 AM
  • DefWindowProc(): When should this be called in the message-handling proc? Only for stuff you don't handle yourself? or for everythng?
DefWindowProc does standard processing for controls and windows. Do not call it only in special cases.
Example: If you draw the background yourself, don't let Windows do it again.

OK. It took me a minute to parse that ("Do not call it only in special cases"), which I take to mean "only omit calling it in special cases". Fine. I can see why you would not call it after doing something that Windows would do redundantly if you called it.

Is there any general rule of thumb which defines those "special cases"? Or a short list of things like the examples you gave?

QuoteAnother example:
- call DefWindowProc in your WM_PAINT handler: Windows will draw the background and contents of your controls
- draw something on top
- validate the rect, telling Windows hands off
- return without calling DefWindowProc again.

So to be clear, do you mean this?



case WM_PAINT:
DefWindowProc()
draw something on top
ValidateRect()
RET


(pseudocode)

dedndave

in most cases, you want to return either TRUE (=1) or FALSE (=0) in EAX

it depends on the message
each message has documented behaviour for different return values
if you want to learn about WM_PAINT, for example, google "WM_PAINT"
one of the first search results listed will be the MSDN page for that message (or function)
http://msdn.microsoft.com/en-us/library/dd145213%28v=vs.85%29.aspx

scroll down to the Return Value section and read away   :bg
QuoteReturn value
An application returns zero if it processes this message.

9 times out of 10, you will return a zero in EAX
this does not include all the messages that you do not wish to process - they all go to DefWindowProc

jj2007

Here is a snippet to play with, almost identical to Iczelion's tut 9. Replace if 1 with if 0 and vice versa to see what happens.

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   .If uMsg==WM_ERASEBKGND
      if 1
         invoke DefWindowProc, hWnd, uMsg, wParam, lParam
      endif
      invoke TextOut, wParam, 5, 5, chr$("We paint something on top"), 25
      if 0
         return 1      ; An application should return nonzero if it erases the background; otherwise, it should return zero.
      endif

   .ElseIf uMsg==WM_

NoCforMe

I'll have to try that. For now I'll take your word for it.

My current puzzle is this (this is my current code):



childpaint:
; INVOKE DefWindowProc, hWin, uMsg, wParam, lParam ;THIS MADE THINGS WORSE (no text painted)

; Determine which text to place depending on which child is active:
MOV EAX, hWin
CALL FindChild ;Sets EBX--> child structure
MOV ESI, [EBX + $CW.$CW_text] ;Point to text to put.
cp30: INVOKE BeginPaint, hWin, ADDR paintStruct
MOV hDC, EAX ;Save handle to DC
        INVOKE GetClientRect, hWin, ADDR paintRect
INVOKE DrawText, hDC, ESI, -1, ADDR paintRect, DT_SINGLELINE or DT_CENTER or DT_VCENTER
INVOKE EndPaint, hDC, ADDR paintStruct
MOV EAX,  TRUE
RET



It works (text  gets put in the child window), but with problems as noted earlier.

However, if I uncomment the  call to DefWindowProc(), then no text gets  drawn (or it  gets obliterated). WTF?????

dedndave

that's because you return TRUE at the end of WM_PAINT code   :P
see how things are different if you return FALSE (0)

NoCforMe

Quote from: dedndave on October 06, 2011, 08:56:29 PM
that's because you return TRUE at the end of WM_PAINT code   :P
see how things are different if you return FALSE (0)

Nope, no difference (and calling DefWindowProc() before still wipes out the text in the boxes).

I'm sure you're correct, but there must be another problem.

dedndave

yah - you definately do not want to call DefWindowProc
especially before everything else - it is an exit mechanism
i will be able to look at your program in more detail in a few hours

Tedd

#11
1. Call DefWindowProc only if you do no other processing of the given message;
2. Return zero for WM_PAINT, if you handle it (otherwise pass it on to DefWindowProc, and return what it returns.)


Working example attached..
[edit: fixed redraw]
No snowflake in an avalanche feels responsible.

NoCforMe

Quote from: Tedd on October 08, 2011, 11:37:03 AM
1. Call DefWindowProc only if you do no other processing of the given message;

OK, got that, makes sense, but just to be crystal clear: by "no other processing", what do you mean exactly?
I take that to mean "no calls into the Windows API". Is that correct? (Meaning, for instance, that it would be OK to look at, say, wParam and lParam values; that wouldn't fall under the heading of "processing" in this case.)

Quote
2. Return zero for WM_PAINT, if you handle it (otherwise pass it on to DefWindowProc, and return what it returns.)

Yep, got that too (that's what the documentation for WM_PAINT says on MSDN.)

dedndave

every message type is vastly different from the next
WM_PAINT, for example, passes to the next level of child window if DefWindowProc is executed
i.e., if a main window does not process it, then the OS sends WM_PAINT to any children that have an update region
if you do go to DefWindowProc for WM_PAINT, then it does not matter what you "pass" - EAX is ignored
WM_PAINT is particularly finicky because of the relationship DefWindowProc has with BeginPaint/EndPaint

in contrast, let's take WM_KEYDOWN
there is little difference between returning 0 and calling DefWindowProc
if you got that message, it also means that your window has keyboard focus
so no other windows will receive that keypress
i.e., if you do or don't process a keypress, nothing else happens
quite often, a 0 is returned for keys that are ignored - that is ok - you processed it

petezl

Guys been some time since last post!

Think your being too complicated in the approach to handling messages....

The paint example is pretty simple. What is important is the last call, no need to return true as call Endpaint will always return non zero. Most problems with paint handling in my experience was where to place the code, main loop most commonly, or in a sub window proc...

Only want message effect on one or more controls then

Message handling in subclass procs are much the same but now your in control and must at some point ret to defWindowProc

Example would be key filtering:

message trapped
Did this unacceptable key get pushed? yes? then
xor eax, eax
ret
(winProc doesn't process this message) keypress is bypassed...

message trapped
Did this acceptable key get pushed? yes? then
call CallWindowProc
ret
(allow winProc to process this call) keypress is acted on..
Cats and women do as they please
Dogs and men should realise it.