Win32 hooks: a refresher
The Win32 hook is a mechanism by which user-defined functions can be intercepted before an event reaches the target application. Hooks decreases system performance due to the additional processing required for each message. So, they should be installed only when necessary and uninstalled as soon as possible.
Microsoft Windows supports many types of hooks, like
WH_KEYBOARD, which can be used for hooking the keyboard. Each type of hook provides access to different types of messages. The system maintains a data structure called a hook chain for each type of hook. This chain is a list of pointers to functions called hook procedures. Some types of hooks can only monitor messages; others can modify messages or stop their progress through the chain, preventing them from reaching the next hook procedure or the destination window.
The prototype of the hook procedure varies a bit according to the type of message it is expected to catch. Applications install hooks using the
SetWindowsHookEx API and
UnhookWindowsHookEx is used for uninstalling the same.
HHOOK SetWindowsHookEx (int idHook,
HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
The first parameter above specifies the hook ID, e.g.
WH_KEYBOARD for hooking the keyboard,
WH_MOUSE for hooking the mouse. The second parameter is the hook procedure that will be called when the particular message gets fired. The third parameter is the instance/module handle where the hook procedure is defined. The last parameter specifies the window thread to be hooked. This can be retrieved using the API
GetWindowThreadProcessId for passing the window handle. If this parameter is empty, then this will install a system hook. For more information, refer to this MSDN article.
Global hooks are not supported in .NET. This behavior requires a DLL export and .NET Framework does not support DLL exports.
Hooks in .NET
There is no built-in support for hooks in Microsoft .NET;
P/Invoke is used to handle such things.
P/Invoke is a method of calling unmanaged APIs. In .NET, the smallest units of processing are Application Domains -- called AppDomains for short -- whereas in Win32, the smallest unit of processing is a process. So, we make use of the
SetWindowsHookEx API through the
P/Invoke method to install hooks and we use
UnhookWindowsHookEx for uninstalling the hooks.
How the code works
The sample application with this article contains a class called
Win32Hook that is a simple wrapper for handling the hook. The function
InstallHook installs a
WH_GETMESSAGE type hook.
public bool InstallHook()
This function returns
true if the hook is installed successfully. Next, the function...
public bool UninstallHook ()
...uninstalls the hook. Don't forget to call this after you have done with it.
Here, the method
m_oHookManager_OnHookMessage will be called whenever an event is fired on the target window. The function prototype is:
void m_oHookManager_OnHookMessage (object sender, HookEventArgs hea)
HookEventArgs is defined in the same file and contains all of the messages related to a message, such as the identifier, whether it is going to be removed from the queue (
private static extern IntPtr SetWindowsHookEx(HookId hookId, HProc hookProc,
IntPtr hInstance, Int32 threadId);
private static extern Int32 UnhookWindowsHookEx(IntPtr hHook);
private static extern Int32 CallNextHookEx(IntPtr hHook, Int32 nCode,
IntPtr wParam, IntPtr lParam);
DllImport attribute specifies the DLL where the function is defined. This attribute is defined in
System.Runtime.InteropServices. For more information, refer to this MSDN article. It might take a long time to implement hooks in Microsoft .NET due to the architectural changes introduced in the native to managed code transition.
- 27 June, 2007 -- Original version posted