Question

Global Windows hooks must be in a DLL because the hook is going to be called in the context of a different process, so the hook procedure's code must be injected into that process. However, there are limitations:

SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.

For this reason, I'd rather use the low-level hooks WH_MOUSE_LL and WH_KEYBOARD_LL, instead of WH_MOUSE and WH_KEYBOARD. As seen from their documentation:

This hook is called in the context of the thread that installed it. 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.

This leads me to think that these particular hook procedures do not need to be in a separate DLL, and can just live inside the EXE that hooked them up. The documentation for SetWindowsHookEx, however, says:

lpfn

[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL.

No explicit exception for the two low-level hooks is mentioned.

I have seen several .NET applications that use the low-level hooks without having their hook procedures in a separate DLL. That is another hint that this is acceptable. However, I'm a bit scared to do this myself since the documentation forbids it.

Does anyone foresee any trouble if I don't use a DLL and just put these low-level hook procedures straight into my EXE?

Edit: For the bounty, I would like a definitive "yes, this is ok, because..." or "no, this can go wrong, because...".

Was it helpful?

Solution

There is one exception to the global hooking function in dll rule. Low level mouse and keyboard hooks are executed in the context of the calling process, not the process being hooked (internally, Windows notifies your hook via a windows message). Therefore the hook code is not executed in an arbitrary process and can be written in .Net. See http://www.codeproject.com/KB/cs/CSLLKeyboardHook.aspx for an example.

For other hooks you do need to call the 32 bit version of SetWindowsHookEx and pass a hook function in a 32bit process and call the 64bit version of SetWindowsHookEx and pass a hook function in a 64bit process, though.

OTHER TIPS

Turns out that this is actually in the documentation. Although not in the documentation of SetWindowsHookEx and friends, but in a .NET knowledge base article.

Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.

Global hooks, whether low or high level, have to be in a separate DLL that can be loaded into each process. The documentation you quoted makes that pretty clear, and if there was an exception that applied to the low-level hooks, that documentation would say so as well.

Rule of thumb: When the docs say not to do something, there's usually a pretty good reason for it. While it may work in some cases, that fact that it works may be an implementation detail, and subject to change. If that happens, then your code will be broken if the implementation is ever modified.

Edit: I take back my previous answer. It turns out that WH_MOUSE_LL and WH_KEYBOARD_LL are exceptions to the usual rule about global hooks:

What is the HINSTANCE passed to SetWindowsHookEx used for?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top