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:
SetWindowsHookExcan 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
SetWindowsHookExto inject a 32-bit
DLL into 32-bit processes, and a
64-bit application call
SetWindowsHookExto 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
dwThreadIdparameter
is zero or specifies the identifier of
a thread created by a different
process, thelpfnparameter 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…”.
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.