Trap Windows Messages by Subclassing your Form
It is easy to subclass your form to hook into the stream of messages Windows
sends to your form. This lets you customize your form by reacting to or
ignoring events that Visual Basic does not normally give you control over. Be
forewarned, however, that subclassing removes much of the stability and
robustness built into Visual Basic.
Subclassing can be accomplished through the use of the SetWindowLong
and CallWindowProc API calls. These functions are
described in detail in the source code.
Download Source Code
First off, forms are really windows. Any time you click a form, move it, size
it, or do anything at all to it, Windows generates one or more messages and
sends them to the target window. Associated with every window is a message
handling procedure, called a window procedure,
that runs whenever a message is sent to it.
To subclass a form you must replace the standard window procedure with
your own custom procedure. This causes Windows to call your procedure instead
of the standard one. That is why your procedure is referred to as a
Callback procedure. Windows passes the message and its associated
parameters to your callback procedure. You can then watch for certain messages
and handle them in a fashion that suites your needs. Any messages that you are
not interested in must be passed to the original window procedure.
To replace the standard window procedure with your own you use the
SetWindowLong API function with the GWL_WNDPROC
flag. This creates a subclass of the window class used to create your
form. SetWindowLong returns a value which is the
address of the original window procedure. Looking at the sample program, the
click event for the SubClass button calls the fSubClass function. fSubClass
then calls SetWindowLong and uses Visual Basic's
AddressOf operator to pass the address of our new window procedure
which I have called pMyWindowProc.
pMyWindowProc is the callback procedure used when a message is received
by the form. The desired message, based on the option selected, is processed
and all others are passed back to the original window procedure. This step is
very important. To pass a message to the original window procedure
CallWindowProc is issued with the address of the original procedure.
Recall that this address was returned by the SetWindowLong
API and was stored in the glPrevWndProc variable.
Before your application terminates, you must remove any subclassing. Failure to
do so will bring Visual Basic crashing down horribly. To remove the subclassing
issue SetWindowLong using the original window
procedure's address which was stored in the glPrevWndProc variable.
Whenever you employ subclassing, you should always start your application with a
full compile. Stepping through the code while subclassed can sometimes prove
impossible. Try to work out as many bug as possible first then use a full
compile to start.
Subclassing lets you watch for messages sent to any object. In this case it was
the form. It could have been a textbox, toolbar, etc. Although the two are very
similar, do not confuse subclassing with using hooks.
Briefly, a hook allows you to see all messages sent to an entire thread,
regardless of the active window. When using hooks, you do not replace the
window procedure with your own. Instead, you add your procedure to the top of a
chain of procedures. Each hook procedure is responsible for calling the next
procedure in the chain. Failure to do so does not cancel the message but merely
prevents the other procedures in the chain from seeing the message. To see how
to use a hook, see my Owner Drawn Controls program.
Download the source code and press Ctl-F5 to run the program. Make sure the
Immediate window is open so you can see the displayed messages. Pick a Window's
message to trap then click the SubClass button and perform the indicated