Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
MSDN Visual Basic Community
 
 
 
 
 
 
  Tutorial: Subclassing  
 
 

Subclassing in Visual Basic is the processing of intercepting Windows messages that a Visual Basic program normally wouldn't receive. The program uses the SetWindowLong API function to install a new WindowProc message handler for a form, control, or other object that has a window handle (hWnd). The new WindowProc must be the address of a function defined in a .BAS module.

Private Sub Form_Load()
    OldWindowProc = SetWindowLong( _
        hwnd, GWL_WNDPROC, _
        AddressOf NewWindowProc)
End Sub

Now when the object receives a Windows message, the system calls the new WindowProc. That function should examine the message and take whatever action is appropriate. If it isn't taking special action, it should pass the message on to the original WindowProc for normal processing. This is extremely important! If you don't pass the message along, the object will not be able to update its appearance when it is uncovered, correctly draw itself, and perform other standard Windows functions. The new WindowProc should return whatever code the original WindowProc returns.

The following code examines the message looking for WM_SYSCOMMAND. If it finds that message, it checks the wParam parameter for the SC_SIZE command. If it finds this command, the form is trying to resize. The function exits so this message is not passed to the original WindowProc (with address stored in the variable OldWindowProc) and the message is effectively ignored. The function passes all other messages to the original WindowProc.

Public Function NewWindowProc( _
    ByVal hwnd As Long, ByVal msg As Long, _
    ByVal wParam As Long, lParam As WINDOWPOS) As Long
Const WM_SYSCOMMAND = &H112
Const SC_SIZE = &HF000&

    ' See if this is a WM_SYSCOMMAND message.
    If msg = WM_SYSCOMMAND Then
        ' This is a WM_SYSCOMMAND message.
        ' If the command is SC_SIZE, ignore it.
        If (wParam And &HFFF0) = SC_SIZE Then Exit Function
    End If

    ' Continue normal processing. VERY IMPORTANT!
    NewWindowProc = CallWindowProc( _
        OldWindowProc, hwnd, msg, wParam, _
        lParam)
End Function

Before the program unloads the subclassed object, it should restore the original WindowProc.

Private Sub Form_Unload(Cancel As Integer)
    SetWindowLong _
        hwnd, GWL_WNDPROC, _
        OldWindowProc
End Sub

You can make this a bit more automatic by making the WindowProc automatically restore the original WindowProc when it sees the WM_NCDESTROY message.

Public Function NewWindowProc( _
    ByVal hwnd As Long, ByVal msg As Long, _
    ByVal wParam As Long, lParam As WINDOWPOS) As Long
Const WM_NCDESTROY = &H82
Const WM_SYSCOMMAND = &H112
Const SC_SIZE = &HF000&

    ' If we're being destroyed,
    ' restore the original WindowProc.
    If msg = WM_NCDESTROY Then
        SetWindowLong _
            hwnd, GWL_WNDPROC, _
            OldWindowProc
    End If

    ' See if this is a WM_SYSCOMMAND message.
    If msg = WM_SYSCOMMAND Then
        ' This is a WM_SYSCOMMAND message.
        ' If the command is SC_SIZE, ignore it.
        If (wParam And &HFFF0) = SC_SIZE Then Exit Function
    End If

    ' Continue normal processing. VERY IMPORTANT!
    NewWindowProc = CallWindowProc( _
        OldWindowProc, hwnd, msg, wParam, _
        lParam)
End Function

Warnings

Any time you subclass a program like this, you can easily crash the entire Visual Basic integrated development environment (IDE), losing any changes you have made. If you click the IDE's Halt button or select End from the Run menu, the IDE does not clean up the subclassed WindowProc properly and crashes. The basic problem is the object doesn't have a chance to process the teardown messages normally because the original WindowProc doesn't run.

To avoid serious inconvenience, save your program every time you run it so you don't lose a lot of work if you accidentally crash the IDE in this way.

Don't use the halt button. Instead close the form normally. If you close it by unloading it or by clicking on the little X button in the upper right corner, Visual Basic cleans up its mess and the IDE will not die.

It takes some practice to figure out how to jump out of a program in the middle without crashing. Use Ctrl-F9 to skip over statements you don't want to execute until you can get the program running again. Then close the form normally.

See Also:

Subclass a control to read Windows messages.

 

Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated