When I described what the HINSTANCE parameter to the
SetWindowsHookEx function is for, I neglected to mention why the low-level hooks are not injected.
But then again, it should be obvious.
The low-level hooks let you see input as it arrives at the window manager. At this low level of processing, the window manager hasn't yet decided what window will receive the message. After all, that's the whole point of the low-level hook: to filter the input before the window manager does anything with it. "Deciding what window should get the message" counts as "anything". Consequently, it can't inject the call into the destination window's context even if it wanted to. There is no destination window yet!
So, for lack of a better choice, it uses the context that registered the hook. Of course, all this context-switching does come at a cost. Low-level hooks are consequently very expensive; don't leave them installed when you don't need them.