News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Why the window procedure's arguments?

Started by hamper, October 16, 2013, 08:12:48 AM

Previous topic - Next topic

hamper

According to the API reference information, the window procedure (which I'm calling WndProc) is a user-defined procedure for processing messages, and any messages that the user doesn't personally process have to be carried out by calling DefWindowProcA. Fine, no problem, I understand all that.

But what I cannot understand is why the API and every example/tutorial I have ever seen declares/defines the window procedure prototype/definition to have the following four arguments:
      window handle
      message number
      w parameter
       l parameter

Once a message has been retrieved from the message queue (and checked in the loop) it is passed to the window procedure for processing by using the function DispatchMessageA. But DispatchMessageA only passes the address (offset) of the msg structure variable that contains the details of the message.

The window procedure is never called directly from anywhere within the program - only indirectly by functions such as DispatchMessageA.
SO WHY DOES THE WINDOW PROCEDURE HAVE THE ARGUMENTS/PARAMETERS IT HAS. WHAT INITIALISES THEM? WHAT IS THEIR PURPOSE IF I CAN SIMPLY ACCESS THE WHOLE msg STRUCTURE VARIABLE ANYWAY FROM WITHIN THE PROCEDURE (since I have its address)?

I realise that the window procedure is also used by Windows (e.g. non-queued messages) and by a variety of functions, but I cannot see how any of them use arguments - they seem to revolve around passing the address of the msg structure (which makes sense to me).

Has anyone an answer on the role/need/purpose of the "standard" arguments for the window procedure?

Regards, and thanks in anticipation


hamper

Thanks dedndave, but no - no real help, they just both repeat the same mantra.
Neither actually explain why the window procedure needs the arguments it always seems to have, what their purpose is (bearing in mind that the argument values and more are immediately readily available anyway from the address of the msg structure variable, which is always there - the window handle, message number, w, l, cursor x and y etc.), and what actually passes their values as parameters (since all of the standard routines seem to just pass the address of msg - which is far more useful anyway). It just seems like a lot of complicated duplication, and the need to think up even more names for the same data, which is already there and can be immediately used anyhow, without passing any arguments at all.
So, no answer really.
But thanks anyway.


jj2007

WndProc proc hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
invoke SendMessage, hWnd, uMsg, wParam:WPARAM, lParam:LPARAM

;-)

hamper

Thanks jj2007.
Starting to get somewhere now.
So if I use SendMessageA to send a non-queued message direct to the window procedure, it passes the arguments I've been talking about. OK, that makes sense. And I suppose the theoretical alternative approach of SendMessageA sending the address of msg is no use in that case, because nothing will have actually made a copy of msg and initialised it (normally only done when it's added to the queue, right?). So you can use SendMessageA so long as you only want the limited message information it provides - no cursor info for example?
Whereas using PostMessageA sends the full story via a copy of the msg structure variable, with everything in it, but it is queued right?
So here's the big question...
If I never want/need to use SendMessageA (or its ilk), and only ever use either PostMessageA (or its ilk) or default processing, do I HAVE to declare the window procedure with all the standard arguments? Or can I simply write a window procedure with no arguments and use direct access to the message structure variable msg to do everything that I could possibly want to do, including calling DefWindowProcA?
Or is there something lurking around somewhere that I don't know about that will say NO WAY - can't function without you declaring the four arguments, even though you're not actually using them yourself.
That's what I'm getting at, and trying to figure out.

qWord

for your own code, you could do what ever you want. The problems came up if you trying to interact with components of windows, which sends nonqueued messages (which means no copy goes to your MSG structure!) and assumes a window procedure with four arguments.
It is hard to understand your problem, especially when taking into account that the message queue it self is an "expensive" resource due the needed synchronization mechanisms.
MREAL macros - when you need floating point arithmetic while assembling!

hamper

Thanks qWord.
So I guess what you're saying is that I HAVE to declare the window procedure with the standard four arguments because there IS something lurking around in Windows (default processing) that expects them to be there, even though my program code itself doesn't need them or use them in any way?
Is that correct?

dedndave

you should declare the procedure with 4 arguments because they are on the stack when WndProc is called
common structure of a StdCall routine dictates that you clean up the 4 arguments when done

furthermore, you'd have a mess on your hands if you tried to sort out messages via the MSG structure
it may or may not contain the current message (the same message as the one sent to WndProc)
and - some messages may not be sent to the window - some may not be queued
heaven forbid you were using accelerators   :redface:

qWord

Quote from: hamper on October 16, 2013, 10:23:58 AMI HAVE to declare the window procedure with the standard four arguments because there IS something lurking around in Windows [...] that expects them to be there [...]
Is that correct?
yes
MREAL macros - when you need floating point arithmetic while assembling!

hamper

I appreciate what you say dedndave, but as I understand it the window procedure is a "user-defined" procedure (at least if we believe what the API tells us), and as such the arguments are only created on the stack if we say so. StdCall requires that the procedure clears up the stack for us, but only for arguments (and local variables) that we have defined to be there. Is that not correct?
So if I define the window procedure to have no arguments and no local variables, StdCall should not pop any doublewords off the stack by its own volition, surely, and if it does, what orders is it following?

dedndave

no - the caller pushes the arguments on the stack
when the StdCall convention is used, it is the responsibility of the callee to clean up the stack
i.e., the routine must be designed for a specific number of arguments

if you disassemble a WndProc routine...

WndProc PROC

    push    ebp
    mov     ebp,esp
;
;
;
    leave
    ret     16      ;return and pop 4 dwords

WndProc ENDP

any other RET method could make a mess   :biggrin:
you could pop the return address into a register, pop the 4 arguments (or add esp,16), then JMP REG

hamper

I thought that was exactly what I had said  :icon_confused:

dedndave

Quote from: hamper on October 16, 2013, 10:43:45 AM
...but as I understand it the window procedure is a "user-defined" procedure ...., and as such the arguments are only created on the stack if we say so.

not the same thing

WndProc is user-defined, but the number of arguments and StdCall are dictated by the OS

hamper

"not the same thing" ?? any information, or possibly some explanation?

Anyway...

As I understand it at the moment, based upon everyone's feedback and my own notes...

I declare a point structure prototype.
I declare a message structure prototype, including the nested point structure.
I define a global message structure variable (msg).
As you can see, I'm not adopting the "usual" WinMain approach, as it's pointless, silly and doesn't do anything that a more direct approach can do. It only adds another layer of complexity with all its arguments and local variables etc. - none of which are actually needed. So, just do all the usual stuff in the correct sequence...
I do all the usual windows-type stuff, defining strings etc.
I create a window using CreateWindowExA (adding 268435456 into the dwStyle parameter so that the window is made visible automatically, so I don't need to bother with ShowWindow or UpdateWindow)
I do the message loop immediately thereafter.
I define a window procedure 'WndProc', reluctantly including the four arguments, even though they're all useless to me because I can get more information from examining the (global) msg structure variable msg directly, which is automatically initialised with data for the current message copied into the message queue.
Within the window procedure I examine msg.message etc. and act upon the integer value it holds.

Have I gone wrong anywhere here?
If so, where exactly?

dedndave