An Introduction to (Keyboard) Hook Procedures

What Windows hooks are and how to use them within a Delphi application!

Delphi Windows Hook Example
Delphi Windows Hook Example.

Article submitted by Chris Cummings

This document describes what windows hooks are and how to use them. In order to use hooks properly you will need a copy of the windows SDK, that can be downloaded from the Microsoft web site. The project hooks.dpr contains all the code for the program used in this document and hookdll.dpr contains the DLL required. The actual code itself is shown and explained more thoroughly as remarks within the projects.

What Are Hooks?

Put shortly, a hook is a function you can create as part of a dll or your application to monitor the 'goings on' inside the windows operating system. The idea is to write a function that is called every time a certain event in windows occurs - for example when a user presses a key on the keyboard or moves the mouse.

Hooks were provided by Microsoft primarily to help program writers with the debugging of their applications, but they can be put to use in many different ways - for example, my first use of them was to write hidden key logging program to find out my mums password to the internet!

Local or Global Hook?

There are 2 types of hooks - global or local.

A local hook is one that monitors things happening only for a specific program (or thread).

A global hook monitors the entire system (all threads).

Both types of hooks are set up in the same way, the main difference being that for a local hook, the function to be called can be within the program it is monitoring, but with a global hook the function must be stored and loaded from a separate dll.

Hook Procedures

What follows is a quick description of each of the windows procedures required and also of the structure that your hook procedure should take.

The SetWindowsHookEx function
SetWindowsHookEx is the function provided by Microsoft to install a hook. It accepts the following arguments:

  • idHook (Integer) - A number representing the type of hook - eg WH_KEYBOARD.
  • lpfn (TFNHookProc) - The address in memory of the hook function.
  • hMod (Hinst) - The handle of the dll the hook function is in. If it is a local hook, this is 0.
  • dwThreadID (Cardinal) - The 'thread id' that the program is to monitor. If it is a global hook this is 0.

SetWindowsHookEx returns a handle (i.e. an identifier) for the current hook, so you can use UnhookWindowsHookEx to remove the hook later on.

The hook function
The hook function is the procedure to be called by windows when the event we specify happens. A hook for any event always takes the same form, but the values passed to it by windows can mean different things. For example if the hook is type WH_KEYBOARD, windows will pass information to it relating to which key was pressed. Your hook procedure should accept the following arguments:

  • Code (Integer) - Indicates what the next 2 arguments mean.
  • wParam (word) - A parameter of size 1 word.
  • lParam (longword) - parameter of size 2 words.

A hook function returns a value of type longword. What you should set it to depends on the type of hook, or you can just set it to the value that CallNextHookEx returns.

The CallNextHookEx function
This function is to do with 'hook chains'. When a hook is installed for a certain event, there may be others like it already installed - for example 2 programs at once might be trying to log keyboard input.

When you install a hook with SetWindowsHookEx it adds your hook procedure to the front of a list of hook procedures. CallNextHookEx simply calls the next procedure in the list. When your hook procedure is finished, it can run CallNextHookEx, and then return the value it gets from it or a different one depending on the type of hook. CallNextHookEx takes exactly the same form as a hook procedure plus one extra - the handle returned by SetWindowsHookEx identifying the hook. The other values you pass to it should be the values your hook procedure was called with. How you should use it depends on the type of hook.

The UnhookWindowsHookEx function
This is very simple! It simply removes your hook. The only argument you pass to it is the hook handle returned by SetWindowsHookEx.

A Local Hook

First up we will create a local hook.

The important code for this is in 'local.pas'. Hooks.exe when run will display a small form. Click the Add/Remove Local Hook Button on this form to use the local hook. When the local hook is installed correctly, you should find that pressing any key and releasing it makes the beep sound, providing hooks.exe has the focus (since it is a local hook).

The first function in local.pas is SetupLocalHook which creates a local hook, specifying the hook procedure as our KeyboardHook function. It simply calls SetWindowsHookEx, and if the handle returned is > 0, indicating the procedure works, it saves the handle in CurrentHook and returns true, otherwise it returns false. Next is RemoveLocalHook which takes the stored hook handle in CurrentHook and uses UnhookWindowsHookEx to remove it. Lastly is the hook procedure. The hook procedure simply checks if the key is being released, and if so beeps.

A Global Hook

The global hook is slightly more complicated. To create a global hook you need 2 projects, 1 to make the executable file and 1 to make a dll to contain the hook procedure. The global hook that is shown in the code records keydown events and every time 20 keys have been pressed it writes them to a file, log.txt. To use the global hook run hooks.exe and choose add/remove global hook. Then type something (say in notepad for example) that is more than 20 characters long. You will notice a file, log.txt appear that contains the text you wrote.

The Dll you write should contain 2 procedures.

The first, obviously being our hook procedure which in structure is identical to that defined for a local hook. The second is a simple procedure that you will find you need to do almost whenever you create a dll initialises a few variables in the dlls memory - these include the current number of the key that has been pressed and the handle for the hook that has been created.

The executable file must first load the procedures in the dll and then use SetWindowsHookEx to define a global hook.