Holy cow, I wrote a book!
If an operation includes as part of its processing sending messages,
then naturally the target window for those messages must be
processing messages (or more precisely, the thread which owns the
target window must be processing messages) in order for the
operation to complete.
Because processing messages is the only way a window can receive messages!
It's sort of tautological yet not obvious to everyone.
Generally you run into this problem when you try to manipulate
a window from a thread different from the one which created
Since windows have thread affinity,
operations from off-thread
typically need to get moved onto the thread which owns the window
because that's where the window really "lives".
The window manager will often try to see how much it can do
without marshalling to the thread which owns the window,
but when message traffic is involved,
you are pretty much stuck.
Messages are delivered to a window on the thread to which the window
belongs, and there's no way around that.
There are subtle ways in which a function called off-thread
can result in message traffic.
Generally speaking, you should just assume that any operation on
a window may generate messages:
Even if they don't do so today, they may do so in the future.
For example, changing a window's style did not generate message traffic
in early versions of Windows, but in
Windows 95, it began generating
This isn't called out explicitly in the documentation for
but it's implied by the documentation for
WM_STYLECHANGING and WM_STYLECHANGED.
Why isn't there an explicit callout in the documentation for
At the time the SetWindowLong documentation was
originally written, the WM_STYLECHANGING and
WM_STYLECHANGED messages did not exist.
Therefore the documentation was complete at the time of writing.
Circumstances changed elsewhere in the system that had
secondary effects on SetWindowLong,
but nobody bothered to update the documentation,
probably because it didn't even occur to anybody
that these effects existed.
And then these secondary effects lead to tertiary effects:
SetScrollInfo may change the window style
to add or remove the WS_HSCROLL or
which in turn results in a call to
SetWindowLong which in turn results in sending
the WM_STYLECHANGING and WM_STYLECHANGED
Next come quaternary effects on functions like
since they call
SetScrollInfo as part of their functioning.
And so on, and so on.
Just tracking down the full ripple
effect of those two new messages is probably impossible.
But the root cause of all these ripple effects is
operating on a window (particularly modifying a window)
from a thread
different from the thread that owns the window.
Avoid that, and you'll avoid the whole issue of which operations
generate messages and which manage to sneak by without needing to
send any messages (at least not yet).