Home   .......

Using Windows API in VB Tutorial

SubClassing

Products  
eXamples  
Files  
e-Mail Us  
 

 

When you have already used the maximum VB offers you and want to do something more, or just want to know something more about what's going on with your window, now or then you will find the advantages of subclassing.

Subclassing refers to changing the active window procedure with a new one. Now this new procedure will receive all messages coming to your window before the old one. But the old procedure still exists, it's not lost. If you do not process a given message, you should call the old procedure to process it.

Subclassing is done by calling SetWindowLong. This function changes a specified attribute of the given window. Here is its declaration:

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

The first parameter specifies the window to be subclassed, the second should be GWL_WNDPROC (-4) and the third should be the address of the new window procedure. See Callbacks and The Window Procedure. This function will be called literally every time your window has the focus and something is going on and in some other cases (like changing some system parameter by another process).

SetWindowLong return 0 if an error occurs, or the address of the old window procedure. This address is especially important and you should save it in a variable or else. It is used to call the old function when you do not process a message (in fact you will process less than 1% of all message and will let the old procedure handle the rest).

Calling the old window procedure is accomplished by CallWindowProc API function. Here is the declaration:

Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

The first parameter is the address of the old procedure and rest are just the same as the four parameters you receive. Note that you may change some of the values to control the message process. For example, when you receive WM_MOUSEMOVE, you get the coordinates of the mouse from lParam and change them to some other coordinates. Then the old window procedure will think the mouse is not where it is actually and may for example show a tooltip of some distant control or do some other funny things.

The return value you specify is also meaningful. It depends on the message sent.

It is very important to return the original window procedure before ending your program. It is usually done in Form_Unload. Here is how:

Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProcAddress)

If you miss this line when starting your program through VB, the result is a crash of VB and loss of any unsaved data. Be careful.

Here is a simple example of subclassing:

(in a module)

Public Const GWL_WNDPROC = -4

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal Hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal Hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public oldWndProc As Long

Public Function MyWndProc(ByVal Hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Debug.Print wMsg & " " & wParam & " " & lParam
MyWndProc = CallWindowProc(oldWndProc, Hwnd, wMsg, wParam, lParam)

End Function

(in a form module)

Private Sub Form_Load()
oldWndProc = SetWindowLong(Me.Hwnd, GWL_WNDPROC, AddressOf MyWndProc)
End Sub

Private Sub Form_Unload(Cancel As Integer)
Ret& = SetWindowLong(Me.Hwnd, GWL_WNDPROC, oldWndProc)
End Sub

This will display all messages sent to your window in the Immediate Window. As a message is sent on each mouse move over the form, the application will slow down because it has to display several lines in the Immediate Window per second.

 
Copyright (c) 1998, Billy&George Software and Peter Dimitrov
Revised March 2000