How does the system call a window procedure directly?

I participated in this thread (http://www.cplusplus.com/forum/windows/14209/) and I read something that I just can't conceive: Most window messages are sent directly to the window procedure of the window.

If you visit the link provided by Grey Wolf in the original thread, all-knowing MSDN clearly states this is true. I don't understand how this can be possible.

I guess that if SendMessage() is called within the same thread that created the window, everything is good because SendMessage() probably retrives the WndProc function pointer and calls it, adding the window procedure to the stack:

WndProc()
SendMessage()
SameThreadCode()
...

Once WndProc() finishes, SendMessage() finishes, and then SameThreadCode() is back to the top of the call stack, being able to continue exactly where it left off. Nice.

But how in this world can the system call WndProc to process, say WM_SETFOCUS, if the window's thread is doing stuff, like counting sheep, or blocked by GetMessage()??? Is this one of those "Microsoft can do it because they have the OS source code" kind of thing?
Here goes a real amateur's assessment...

I think it's as simple as message priority. WM_SETFOCUS, for example, probably has a different priority than WM_PAINT. How that is specifically coded I couldn't begin to say. I'm not sure many people could. But there has to be a priority, otherwise every thread would conflict with each other.
Thanks for posting Lamblion, but that cannot be it. My problem here resides in the fact (I say fact, maybe it is not?) that an executing thread cannot suddendly be forced to execute an entirely different piece of code. This messes up the processor registries, RAM, etc. It just can't be done, or at least this is what I say.

The closest to "making a thread execute an arbitrary function all of the sudden" would be QueueUserAPC(), a function that posts an "asynchronous procedure call" request for a specific thread to execute. But APC will not work unless the thread that must execute it enters an alertable sleep state. This means that the thread must willingly stop doing any work and just wait to see "who needs it". I have never seen this coded anywhere in a Windows application.
You're obviously not taking into account the MicroSoft Gremlins, which are pervasive in every PC, whether you know it or not! -:)
If there are no messages in the queue when Getmessage() function is called , then windows goes off and does something else (I think the thread/app loses it time slice and windows goes off and service other threads that have messages waiting)

This will help you out
http://msdn.microsoft.com/en-us/library/ms644927%28VS.85%29.aspx
Last edited on
Another real amateur's assessment.

The whole thing blows my mind too. Can you just imagine the complications? Any given program is somewhat simultaneously processing messages sent directly to the programs WndProc (and dont forget that a program can have many window procedures - one for each registered Window Class it registers), and retrieving messages posted to its message queene - another rather complex structure no doubt.

Further, the Window Procedure is reentrant - at any given moment there may be many invocations of it on the stack. Microsoft's Programmers? That's why they make the big bucks!
Last edited on
Thanks guestgulkan for the link. I have already read it and it does not explain how the operating system can just invoke the window procedure without any regard of what the GUI thread is doing. I want to know how Microsoft can do this.

I have thought of a couple of possibilities:

1.
GetMessage() internally enters an alertable state if there are no messages in the queue. This allows the processing of window procedures in the same thread that created the window via an APC.

Note however, that functions like SleepEx(), MsgWaitForMultipleObjectsEx() and WaitForMultipleObjectsEx() can only be used from Windows 2000 and up, and I think this behavior is found prior to this OS. So this one might be a No No. Could be a Yes Yes if we think the APC technology was already in place, but not publicly available via the SDK and Windows header files as it is today.

2.
Microsoft uses preemptive algorithms to save the state of the thread that created the window, and then resume it from an "artificial" state that would correspond to the call of the desired window procedure, and would then restore the thread to the point where it was interrupted. This one would be possible since Windows 95, but it sounds a major pain.


Geez, I was way better when I knew nothing about this!! :-(
Messages can interrupt messages.
Your windows procedure be in the middle of processing a message and it can get called again with another one.
Yes, another one that was generated by the code already running. But imagine a worker thread obtaining the text of a listbox item, a listbox not owned by the worker thread. It would use SendMessage() with LB_GETTEXT (if I remember correctly). That call to SendMessage() would send the message directly, no message loop, right? But the window procedure needs to be called in the thread context of the thread that owns the listbox. What if the owning thread is doing something? I would imagine that SendMessage() would then block the execution of the worker thread. Cool, but at which point will the owning thread execute the Window procedure? When it reaches... what point? I can only imagine when it reaches GetMessage(). I am starting to think that GetMessage() also pumps messages to the window procedures "directly". But if that is the case, what difference would it make to bypass a short loop like a message pump?

Also consider the case where an external application uses SendMessage() to get a message processed by another executable. This is the case of applications that "remember" desktop icon position. There is no API to get or set the desktop icons in a particular place programatically, so a hack with Read/WriteProcessMemory() is used over the underlying ListView. These guys normally use SendMessage() with LVM_GETITEMTEXT to read the icon's captions and build a database.

I understand that WindProc is reentrant, I do, so long the reentrancy is caused by the same thread. In my head, reentrancy from a different thread requires another message pump. Actually, COM proxies indeed use a second message pump.
Why don't you write a program to track the message que? You could do this with a number of different messages executing at specific points in the program, just like breakpoints in a debugger. You could output to the screen, sort of like Petzold in his sysmets program, or you could pop message boxes at each execution point.

Might be a fun exercise. There are only two things preventing me from writing such a program. One, I'm working on something else, and two, I don't have the expertise to write such a program.
I wish I had the time. My work laptop has already 3 VS 2008 open permanently. My home computer's Windows 7 is now complaining about the license, which I will not activate yet because it is an out-of-the-box installation and I need (and want) to create my "standard" image first with all my apps and settings and domain-joined (I have my own domain controller @ home), which I haven't done it... not even started! So I have way too much in front of me right now to open yet another instance of VC 2008 to figure this one out.

If we can't figure this one out here, I guess I'll eventually write a test program to find out the answer, but it will then be months from now!

EDIT: And I will do Windows 7 first so I can activate and start my occasional gaming. I haven't installed Prototype yet. :-(
Last edited on
When calling SendMessage(hWnd,…) from the same thread that manages the window of hWnd, the system will directly call that window’s window procedure. The message will not enter the message queue at all. When SendMessage is called from a different thread, the message is written to the message queue, but has precedence over all queued messages. SendMessage will not return until the recieving thread treats the message.


Also:
If one thread T1 send a message to a window that belongs to another thread T2, the sending thread T1 is put to sleep until the receiving thread replies to the message. But if somebody else sends a message to thread T1, thread T1 is woken to process the message, then is returned to sleep.
Last edited on
Aha! So direct messages are not so direct anymore! I knew something didn't fit. I'll be able to sleep tonight after all. :-)

What document are you quoting, guestgulkan?
Last edited on
Thanks. I think it is now safe to say the topic is solved. :-)
Topic archived. No new replies allowed.