Windows - hooks

Top  Previous  Next

Windows has an interesting set of APIs for creating Windows Hooks. These hooks are inserted into a chain of hooks and allow an application to monitor the system for certain types of events.

The hooks work by telling Windows to notify a specified callback function when a particular event occurs in the system. The events monitored can be specific to an application or system-wide. The only catch is that to install a system-wide hook, it must appear in a DLL.

The types of hooks that can be installed and their purpose are as follows:

·        WH_CALLWNDPROC - installs a hook procedure that monitors messages before the system sends them to the destination window procedure.  The callback function type is CallWndProc.

·        WH_CALLWNDPROCRET - installs a hook procedure that monitors messages after they have been processed by the destination window procedure. The callback function type is CallWndProcRet. (Note: this hook only works in Win95).

·        WH_CBT - Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. The callback function type is CBTProc.

·        WH_DEBUG - Installs a hook procedure useful for debugging other hook procedures. The callback function type is DebugProc.

·        WH_GETMESSAGE - Installs a hook procedure that monitors messages posted to a message queue. The callback function type is GetMsgProc.

·        WH_JOURNALPLAYBACK - Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. The callback function type is JournalPlaybackProc.

·        WH_JOURNALRECORD - Installs a hook procedure that records input messages posted to the system message queue. The callback function type is JournalRecordProc. (Note: this hook is useful for recording macros).

·        WH_KEYBOARD - Installs a hook procedure that monitors keystroke messages. The callback function type is KeyboardProc.

·        WH_MOUSE - Installs a hook procedure that monitors mouse messages. The callback function type is MouseProc.

·        WH_MSGFILTER - Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The callback function type is MessageProc.

·        WH_SHELL - Installs a hook procedure that receives notifications useful to shell applications. The callback function type is ShellProc.

·        WH_SYSMSGFILTER - Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The hook procedure monitors these messages for all applications in the system. The callback function type is SysMsgProc.

For more information about any of these hooks, look up help for the API function SetWindowsHookEx. This is the API call that enables a hook to be inserted into the chain. Alternatively,  UnhookWindowsHookEx removes the hook from the chain.

How Do I Use This?

To use these Windows hooks is actually fairly simple. The first step is to create a global variable that will receive a pointer to the newly created hook. Then you need to create a global function that will be used as the callback functionBoth of these steps can be accomplished with the following code:

type

  TForm1 = class(TForm)

  private

  . . .

  end;

 

  function myHookProc(code : Integer; wParam, 

                      lParam : LongInt) : LongInt; 

                      stdcall;

 

var

  Form1: TForm1;

  myHook : hHook;

 

implementation

. . . 

Next, we need to set the hook and assign the pointer to the hook variable and tell Windows what function to call when the hook is triggered.

  myHook := SetWindowsHookEx(WH_MOUSE, myHookProc,

            hInstance, GetCurrentThreadID);

And when we are done, we need to unhook the hook. The following code will do that:

  UnHookWindowsHookEx(myHook);

Finally, our main processing code goes in the global function we defined for our callback. Here is an example of a function 

procedure myHookProc(code : Integer; wParam, 

                     lParam : LongInt) : LongInt;

var

  X,

  Y : Integer;

 

begin

  X := PMouseHookStruct(lParam).pt.X;

  Y := PMouseHookStruct(lParam).pt.Y;

  Form1.Label1.Caption := IntToStr(X) + ' : ' + 

                          IntToStr(Y);

  // It is HIGHLY important that this next call be 

  // made if you want normal processing to occur. 

  // If you don't make this call, than the message 

  // is gone forever. 

 

  // To enable the system to process the message, 

  // the return value must be 0. To discard the 

  // message, the return value must be a nonzero 

  // value.

  result := CallNextHookEx(MyHook, Code, wParam, 

                           lParam);

end;

 

This simply reports the X and Y coordinates of the mouse to a label on the form. There are, obviously, many more useful purposes for these hooks, but this hopefully has served to show the power of Windows hooks.

Hooks can be used to create a message viewer application, similar to WinSight. The JournalRecord and JournalPlayback hooks can be used to make a macro recorder and player.

Many fun things can be done with hooks as well, simply by adding, removing, and/or manipulating messages. For example, you could randomly remove mouse move messages from the queue. This would cause the mouse to jerk as it is moved across the screen. You could then add to the fun and insert mouse click messages. Now, not only would the jerky mouse frustrate the user, but also they would be launching applications from the desktop as they move across it. These are just some examples to give you an idea of what can be done with Windows hooks. 

To download the source code, visit the file repository web-site (http://www.geocities.com/SiliconValley/Lakes/4339/)