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
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632593%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632593%28v=vs.85%29.aspx)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573%28v=vs.85%29.aspx)
hope that helps
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.
WndProc proc hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
invoke SendMessage, hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
;-)
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.
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.
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?
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:
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
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?
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
I thought that was exactly what I had said :icon_confused:
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
"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?
it's fairly well documented in the links i provided in reply #1 :redface:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633573%28v=vs.85%29.aspx)
hamper,
The format of a WndProc style procedure is dictated by its function in the operating system design. First and foremost it is a system defined CALLBACK which means that the system expects the address passed to it as the CALLBACK location to accept 4 DWORD sized arguments that occur in the order HANDLE, MESSAGE WPARAM, LPARAM, the format itself being a leftover from 16 bit where you had to distinguish between a WORD sized argument and a signed LONG argument.
Now going backwards from a WndProc style procedure, you have a standard message loop that is again dictated by the OS which is primarily there for manually processing key strokes as it avoids the lag of a WndProc.
Windows is basically a message driven windowing system and to provide those facilities, Windows specifies the format of how a user defined window interacts with the operating system. The CALLBACK technique is common to many Windows techniques, WndProc, DialogProc, Subclass procs, system hooks and the like and it is how an application interfaces with the functionality provided by the OS.
Quote from: hamper on October 16, 2013, 11:42:07 AMadding 268435456 into the dwStyle
bad programming practices! Use the corresponding equate: WM_VISIBLE
Quote from: hamper on October 16, 2013, 11:42:07 AMit's pointless, silly and doesn't do anything[...]It only adds[...]local variables
a wise programmer prefers local variables, because it can be assumed that they are always cached.
Quote from: hamper on October 16, 2013, 11:42:07 AMI 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
as already said, that won't work reliable! please read this article:About Messages and Message Queues (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927%28v=vs.85%29.aspx)
Quote from: qWord on October 16, 2013, 12:03:22 PM
a wise programmer prefers local variables...
Essential in a multi-threaded app. Globals need spinlocks and such.