10

I'm setting a low-level mouse hook with SetWindowsHookEx:

HANDLE handle = SetWindowsHookEx(WH_MOUSE_LL, 
                                 &callback, 
                                 GetModuleHandle(NULL), 
                                 NULL);

Because this is a low-level callback, it will be executed inside my own process; no DLL injection is performed.

Now, I've noticed that the callback sometimes (indirectly) gets invoked from standard API functions such as GetAncestor, GetWindowRect and such. It seems that these can cause some message queue to be flushed.

Actually, my question is threefold…

  1. When is the callback called?

    Can it be called from inside any API function? How do I tell?

  2. On what thread is the callback executed?

    Will it only be run on the thread that installed the hook, or can the system call it on any thread?

  3. Why are hooks implemented as a callback in the first place?

    (Does Raymond Chen hang around here?) It would seem much more sensible to me to implement hooks simply as (sent) messages, like pretty much all the rest of Windows. For messages, at least I know which functions can cause pending sent messages to be processed (GetMessage, PeekMessage and a handful of others), and I would know on which thread they are processed (the thread that received the message in the first place).

Community
  • 1
  • 1
Thomas
  • 174,939
  • 50
  • 355
  • 478

1 Answers1

11
  1. See 3.

  2. It's written quite clearly in the documentation:

[...] However, the WH_MOUSE_LL hook is not injected into another process. Instead, the context switches back to the process that installed the hook and it is called in its original context. Then the context switches back to the application that generated the event. [...] This hook is called in the context of the thread that installed it.

  1. Actually it is implemented like that:

[...] The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

AFAIK, when your hook must be called Windows puts a special message in your thread's message queue. Your code in the message pump calls Peek/GetMessage, which checks if it's the special message and, if it is, it calls your hook procedure (some evidence here, whence I took the image). Hook dispatching call stack
(source: cprogramming.com)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 3
    If you will excuse me, I'll go bang my head against the wall for a while. Thank you so much! – Thomas Jan 14 '10 at 21:18
  • My question would be "why do they have different behavior for WH_MOUSE_LL vs. WH_MOUSE?" (one requires a dll, runs in the applications thread, one can work in an exe, in its own thread) like...is this to make it easier on us, but then it's only for those particular events, huh? – rogerdpack Sep 10 '13 at 20:10
  • @rogerdpack: that's mostly unrelated to the original problem, you should post your own question about it. – Matteo Italia Sep 10 '13 at 20:47