News:

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

Main Menu

Re: problems with a window

Started by jj2007, August 26, 2014, 09:26:01 AM

Previous topic - Next topic

dedndave

it is inefficient to repeat the INVOKE DefWndProc call, over and over
but, i might also remind you that it is inefficient to repeat the RET code

in those rare instances where i need to "break" into the default, i might do...
    .if eax==WM_SOMEMESSAGE
        .if something
            ;do stuff
        .else
            jmp     DefPrc
        .endif

DefPrc: INVOKE  DefWndProc,,,,


of course, the WM_KEYDOWN documentation tells us...
QuoteAn application should return zero if it processes this message.
but, i know you're trying to give a non-specific example

jj2007

Quote from: dedndave on August 28, 2014, 04:49:31 AM
but, i might also remind you that it is inefficient to repeat the RET code

            ;do stuff
            xor eax, eax
            jmp RetEax
   ...

DefPrc:  INVOKE  DefWndProc,,,,
RetEax:  ret

Tedd

You can tell an argument is going wayward when it starts to devolve into nit-picking over certain points, so let's state the facts:

  • The official Microsoft (the same company that developed the operating system) development documentation says to process a message or pass it to DefWindowProc, not both;
  • Raymond Chen's blog post that you pointed at to justify your point says to process a message or pass it to DefWindowProc, not both (even where you want default processing for some situations);
  • Reputable members of this board say to process a message or pass it to DefWindowProc, not both;
  • Every piece of code I've seen by anyone with a clue what they're doing processes a message or passes it to DefWindowProc, not both.
But obviously the masses are wrong and JJ is right. Microsoft purposely create misleading development examples in order to trick people so they can't produce correct software. Event Raymond Chen is in on the conspiracy.

JJ, really, I wasn't being 'smart' - go back and re-read the blog post carefully. If you still think it suggests calling DefWindowProc after you have already fully processed a message, I will go through it in patronising detail to make sure there is no misinterpretation.
Potato2

jj2007

#33
Quote from: Tedd on August 28, 2014, 07:50:24 AM
  • Reputable members of this board say to process a message or pass it to DefWindowProc, not both;

That includes me, indeed. On numerous occasions above I have written that, if the processed part of a message (search for what?! inside this page) does return something useful, this implies that you would not invoke DefWindowProc.

We are basically discussing two options here:

A: default handler calls DefWindowProc (standard C practice)
WndProc proc hWnd, uMsg, wParam, lParam
  SWITCH uMsg
  CASE WM_CHAR
    .if wParam==VK_SPACE      ; all other chars will go to DefWindowProc !!!
      MsgBox 0, "You hit space", "Hi", MB_OK
      xor eax, eax            ; this message was handled, and we decide
      ret                     ; that it will NOT be passed to DefWindowProc
    .else
      return rv(DefWindowProc, hWnd, uMsg, wParam, lParam)
    .endif
  CASE WM_DESTROY
    invoke PostQuitMessage, NULL
    xor eax, eax  ; RETURN ZERO
  DEFAULT
    ; default processing for all other messages
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
  ENDSW

  ret
WndProc endp


B: no default handler, handled messages either return or end up calling DefWindowProc
WndProc proc hWnd, uMsg, wParam, lParam
  SWITCH uMsg
  CASE WM_CHAR
    .if wParam==VK_SPACE      ; all other chars will go to DefWindowProc !!!
      MsgBox 0, "You hit space", "Hi", MB_OK
      xor eax, eax            ; this message was handled, and we decide
      ret                     ; that it will NOT be passed to DefWindowProc
    .endif
  CASE WM_DESTROY
    invoke PostQuitMessage, NULL
  ENDSW

  ; default processing for all messages that do NOT return,
  ; including WM_CHAR if it is not a space
  invoke DefWindowProc, hWnd, uMsg, wParam, lParam

  ret
WndProc endp


Both versions perform exactly the same tasks, with one notable exception: My handling of WM_DESTROY performs a call to DefWindowProc before returning. That is a superfluous step because we all know that DefWindowProc will return zero for that message, so we might as well add return 0, as all C programmers would instinctively do, but why do you think Raymond Chen chooses a loooong title like Even if you have code to handle a message, you're allowed to call DefWindowProc, because you were doing that anyway after all? And what do you think will be the value of eax after invoke DefWindowProc, hWnd, WM_DESTROY, wParam, lParam?

EDIT: Attached a crispy example, with sources. They differ only by C_style=1.

qWord

jj, you did claim that we must call DefWindowProc even when the message has been processed!



EDIT: just remove stupid example.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on August 28, 2014, 03:20:56 PM
jj, you did claim that we must call DefWindowProc even when the message has been processed!
Where?

QuoteEDIT: just remove stupid example.
??

P.S.: See EDIT/attachment in reply #41 above. Let me know if you can close the app with Alt F4 in the C_style=1 version ;)

qWord

Quote from: jj2007 on August 28, 2014, 05:22:20 PMWhere?
Quote from: jj2007 on August 27, 2014, 09:15:49 AMIf I had a case where an explicit return value was needed (a brush, ...), it would indeed RET that value. All other cases can handle the message, and then continue with DefWindowProc. By not passing DefWindowProc, you are blocking Windows' default processing, which may or may not work.

Quote from: jj2007 on August 28, 2014, 05:22:20 PMLet me know if you can close the app with Alt F4 in the C_style=1 version ;)
That is simply a wrong message handling, but this has nothing do with your above statement.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Quote from: qWord on August 28, 2014, 05:46:54 PMThat is simply a wrong message handling

Yes indeed, but with a few lines more you can "improve" it to make it work (and make it look more like proper C code):

WndProc proc hWnd, uMsg, wParam, lParam
  SWITCH uMsg
  CASE WM_SYSKEYDOWN
    .if wParam==VK_F1      ; all other chars will go through DefWindowProc !!!
          MsgBox 0, "Click OK", "Hi", MB_OK
    .else
          invoke DefWindowProc, hWnd, uMsg, wParam, lParam
          ret
    .endif
  CASE WM_DESTROY
    invoke PostQuitMessage, NULL
    xor eax, eax      ; if an app processes this message, it should return zero
    ret      ; if it would pass DefWindowProc, it would indeed return zero
  DEFAULT      ; Microsoft, Tedd and qWord say this is the right way to do it
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
  ENDSW
  ret
WndProc endp

MichaelW

At least running under Windows 7 this coding works for me, and responds to Alt+F4 normally, with or without the return rv(DefWindowProc... statement.

WindowProc proc hwnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    SWITCH uMsg     
        CASE WM_CHAR
            .if wParam==VK_SPACE
                MsgBox 0, "You hit space", "Hi", MB_OK
                xor eax, eax
                ret
            .else
                return rv(DefWindowProc, hwnd, uMsg, wParam, lParam)
            .endif               
        CASE WM_CLOSE
            invoke DestroyWindow, hwnd
        CASE WM_DESTROY
            invoke PostQuitMessage, NULL
        DEFAULT
            invoke DefWindowProc, hwnd, uMsg, wParam, lParam
            ret
    ENDSW
    return 0
WindowProc endp

Well Microsoft, here's another nice mess you've gotten us into.

Tedd

Quote from: jj2007 on August 28, 2014, 02:36:45 PM
On numerous occasions above I have written that, if the processed part of a message (search for what?! inside this page) does return something useful, this implies that you would not invoke DefWindowProc.
This is not about return values - it's a very simple matter to return zero to indicate you've processed a given message, or another appropriate value where that is required (such cases are documented). The issue is with doing additional processing after you have already fully processed the message because that further processing could contradict the original processing you just performed.
Of course, now you will just argue that one shouldn't call DefWindowProc in those specific cases either, but this is the point - one should not call DefWindowProc in any cases where you have already fully processed the message.

Quote
We are basically discussing two options here:
...
This is an overly simplified example that handles 2 whole messages and does nothing useful. Of course it happens to work; though it fails to really demonstrate your argument. And I would argue that calling DefWindowProc after already handling WM_DESTROY is not only unnecessary, but incorrect. If the only reason is so you can return zero, why not just return zero?

Quote
why do you think Raymond Chen chooses a loooong title like Even if you have code to handle a message, you're allowed to call DefWindowProc, because you were doing that anyway after all?
So, is this is the source of your misunderstanding? Ignore the title and read the very first paragraph.
Quote from: RaymondChenJust because you write case WM_SOMETHING: doesn't mean that you have to handle all possible parameters for the WM_SOMETHING message. You're still allowed to call the DefWindowProc function. After all, that's what you did when you didn't have a case WM_SOMETHING: statement in the first place.
The "you were doing that anyway" means "you were doing that anyway [when you were not handling the message at all]", it does not mean "you were doing that anyway [when you had already fully handled the message and then returned so that windows could process the message yet again]"

Had you read carefully, this is what you should have understood:
Quote from: Tedd on August 27, 2014, 09:34:12 PM
1. If you do not handle a message at all, pass it to DefWindowProc;
2. If you do handle a message and complete all processing you require, do not pass it to DefWindowProc;
3. If you handle a message, but in some cases it will require further processing, pass it to DefWindowProc in those cases only.

Quote
And what do you think will be the value of eax after invoke DefWindowProc, hWnd, WM_DESTROY, wParam, lParam?
The return value is zero, where appropriate. The result is additional processing that was not required or wanted.
Potato2

jj2007

Quote from: Tedd on August 28, 2014, 10:30:21 PMThe issue is with doing additional processing after you have already fully processed the message because that further processing could contradict the original processing you just performed.

It doesn't get more convincing if you repeat the same stuff over and over, Tedd.

  CASE WM_CHAR
    .if wParam==VK_SPACE      ; all other chars will go to DefWindowProc !!!
      MsgBox 0, "You hit space", "Hi", MB_OK
      xor eax, eax            ; this message was handled, and we decide
      ret             ; that it will NOT be passed to DefWindowProc
    .endif

hutch--

Lets go for a short walk down memory lane here, for those of us who have been coding Windows since THE original SDK (which cost you over a grand here in OZ circa 1990) the basic logic of a system defined window (there are not any other type) has not changed since the 16 bit Win3.0/1 era. Differing from the 16 bit DOS era, the system is a message driven windowing system that provides the windowing system according to its specifications to any programmer who bothers to read the Windows API lists.

Now Win32 has been with us for close to 20 years and for the normal reasons of backwards compatibility, the basic mechanics of how to get a window going and how to process the messages that are sent through it have not changed over that period, it is still a lead in procedure (often called a WinMain) that refers to a callback procedure in its definition structure WNDCLASS and empties into a system defined message loop which has a system defined method of exiting the message loop and terminating the application.

The archetypal examples were Charles Petzold back in the middle 1990s and minus the dual 16/32 bit C compatibility code, nothing has changed in Win32 since then. The system defined callback procedure is often called a WndProc and it has a very specific format, 4 DWORD size variable are passed to it on the stack by the operating system which identify the bulk of the messages sent to the Window by the operating system. If you ever want to see the vast array of messages sent to a running window, set up a message spy utility that looks at all of them and you will see a flood of messages going past. This is what the default Windows procedure is routinely processing. Most people never need to process the non client hit test messages but they are still sent through the callback.

Many get confused by the many examples of layering that you find in different development environments, the simplified easy style of Windows, even the system defined dialogs are a system defined layering system but this much is true, the system layering STILL uses the same core that was defined as Win32 20 years ago because if it did not, it would not be backwards compatible.

Now while creative genius is virtuous and encouraged by most of the older members here, the Campus is not the best place for debates over inflicting deviations on folks who are trying to get the swing of what is originally complex code. We have enough places for custom code designs but the Campus is not the place for it. What I ask of members is keep the debates over technical details OUT OF THE CAMPUS as it simply confuses folks who are learning this style of coding. This is the place for core Win32 code defined by the operating system, you can play with message crackers, despatchers and a many other tricky variations elsewhere and once folks who are learning this stuff know enough, they can learn yours, mine and everyone else's bad habits as well as developing a range of their own.

dedndave

suggestion:
start with reply #8, and split the thread   :t

Tedd

Quote from: jj2007 on August 28, 2014, 11:34:15 PM
It doesn't get more convincing if you repeat the same stuff over and over, Tedd.
I could say the same to you. I'm repeating myself because you seem to be missing the point and I don't know how I can explain it any more clearly.
Also, moving the focus to examples on which we never disagreed does not hide the fact that your original statements which sparked this argument are still wrong.

Quote from: jj2007 on August 27, 2014, 06:48:55 AM
If you are giving special treatment to a message through e.g. a WM_CREATE handler, and you return a value (xor eax, eax / ret), it implies that you are not allowing Windows to perform the standard tasks required by WM_CREATE.
No. WM_CREATE is a 'notification' that the window has been created - to allow you to perform initialisation. That is all. There are no standard tasks required.

Quote
Of course, it might well be that the Windows developers are aware of the bad habit to use DefWindowProc only in a DEFAULT handler, and therefore do whatever needs to be done after the ret.
No. If there are things that need to be done after returning from processing a message, they will be done. If you call DefWindowProc to handle that message and then return, they will still be done. If you don't call DefWindowProc to handle that message and then return, they will still be done. If it happens that they won't be done when you return zero, then so be it, but calling DefWindowProc in that case will still not get them done.

Quote
...for the great majority [of messages], the safest assumption is that Windows may still have plans with that message, so put the invoke DefWindowProc after the Endsw.
No. This is wrong. This is where the actual argument is. The only purpose of DefWindowProc is handle those messages which you do not fully handle yourself. There is no secret processing that happens afterward. If you have processed it fully, that is it - there is no need to pass it on - it has been fully processed. The end. Fin.

Quote
BTW Raymond Chen supports this view, too: Even if you have code to handle a message, you're allowed to call DefWindowProc, because you were doing that anyway after all.
No. He doesn't. This is not what he says - as I have already explained. None of the code in this article falls through to call DefWindowProc after a message has been fully processed. DefWindowProc is called for some messages, but only when they will not be fully processed otherwise - which is the entire point of the article.
Potato2

Tedd

Quote from: hutch-- on August 29, 2014, 02:34:24 AM
Now while creative genius is virtuous and encouraged by most of the older members here, the Campus is not the best place for debates over inflicting deviations on folks who are trying to get the swing of what is originally complex code. We have enough places for custom code designs but the Campus is not the place for it. What I ask of members is keep the debates over technical details OUT OF THE CAMPUS as it simply confuses folks who are learning this style of coding. This is the place for core Win32 code defined by the operating system, you can play with message crackers, despatchers and a many other tricky variations elsewhere and once folks who are learning this stuff know enough, they can learn yours, mine and everyone else's bad habits as well as developing a range of their own.
Indeed. I did suggest splitting the argument off and moving it to The Colosseum; starting from reply #8.

Apologies to Ar0n for the thread hijacking; also welcome to board politics :icon_mrgreen:
Potato2