8
votes

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).

1

1 Answers

9
votes
  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)