The Unofficial Newsletter of Delphi Users - by Robert Vivrette


There's Method in My (Hook) Madness!

by Grahame Marsh - gsmarsh@aol.com

Recently I was experimenting with an application which used a hook to monitor events.  Hooks are really useful for a number of like tasks but they are unsupported directly in Delphi, so you use the (win 32) API calls, such as:

This puts a WH_CALLWNDPROC type hook in to the current application's instance and thread.  When the hook fires it calls the HookProc, which is declared like this: And finally, when you are finished with the hook you disconnect it: You'll find an example of these calls used in Borland's FORMS.PAS; also you can search the WIN32.HLP file for SetWindowsHookEx and this will show you the types of hooks available.  But in this simple example you'll have noticed that I have had to use a global variable and a stand-alone function.  This gives you a problem if you multiple hooks in the same application are a possibility, or if you want to refer to methods or variables inside a class, without going through yet another global variable (as in the case of FORMS.PAS).

The same problem arises when you want to write your own windows message procedures inside a class.  But Borland have provided the MakeObjectInstance (and a corresponding FreeObjectInstance) to allow message procedures to be methods.  So I wondered if the same technique could be used to make a hook function a method.  The resulting code used the Borland code for MakeObjectInstance but substituted a call suitable for hooks.  I came up with this code which is only a little modified from the Borland original (also in FORMS.PAS):

I'm sorry that this unit is not better documented, but although I understand the principle of what is happening, I've not worked out the details!  But it does work!

So how do you use it?

Let's say you want a WH_CALLWNDPROC hook in a class.  You define your hook function, a pointer variable (that will be a pointer to the method) and a hook handle (so you can correctly chain the hook events):

And in the class constructor, you create a pointer to the class method and set the hook running with a call to the API: And next you must define your hook function, which is now a method: Finally, in the destructor, you clean up: So, in conclusion...

No global variables!  No stand alone hook function!  The hook function can easily reference the class methods!