Adding Controls at Runtime, Part II

In this article, we will discuss "event handling" for runtime-added controls. If you haven't read the first part, I strongly recommend that you read it before part II. The technique that we’re going to use to react to events is called “Sub Classing”. We’re going to use two very important APIs for sub classing that are basically the backbone of this technique.
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nindex As Long, ByVal dwnewlong As Long) As Long
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, lParam As Long) As Long 
The “SetWindowLong” function changes an attribute of the specified window. The function also sets a 32-bit (long) value at the specified offset into the extra window memory of a window; The “CallWindowProc” function passes message information to the specified window procedure. First, we put these two API declarations in a code module, then we need to declare some constants for the messages. To know when an event has been fired, we first capture the message sent by windows, and then compare it with the list of message constants we declared. Here, I gatherd a list of the most common events, based on the control you have created you should declare some or all of these constants to use later on.
Public Const WM_MMOVE = &H200  		         ‘Mouse Move
Public Const WM_LBUTTONDOWN = &H201           ‘Left Button Down
Public Const WM_LBUTTONUP = &H202	         ‘Left Button Up
Public Const WM_LBUTTONDCLICK = &H203        ‘Left Button Double Click
Public Const WM_RBUTTONDOWN = &H204	         ‘Right Button Down
Public Const WM_RBUTTONUP = &H205	         ‘Right Button Up
Public Const WM_RBUTTONDCLICK = &H206        ‘Right Button Double Click
Public Const WM_MBUTTONDOWN = &H207	         ‘Middle Button Down
Public Const WM_MBUTTONDOWN = &H208	         ‘Middle Button Up
Public Const WM_MUTTONDOWN = &H209	         ‘Middle Button Double Click
Public Const WM_KEYDOWN = &H100		    ‘Key Down
Public Const WM_KEYUP = &H101			    ‘Key Up
Public Const WM_KEYPRESS = &H102		    ‘KeyPress
*A full list should be found in the MSDN library (http://msdn.microsoft.com) 
After adding the message constants in the code module, you should also add these declarations as well:
Public Const GWL_WNDPROC = (-4)
Global oldWndProc As Long 
After finding the event that has happened, we must handle it, or in other words, write a function to do what ever we want the control to do once the event has happened:
WndProc = SetWindowLong(CreatedControl.hWnd, GWL_WNDPROC, AddressOf HFunction)
This code must be put in the same event in which the control was created, Form_Load for example. “CreatedControl” is the control we crated at runtime, “HFunction” is our handler-function. “AddressOf HFunction” basically points to the address of the function. Now, we can write the handler function. Note that it must be in a code module.
Public Function HFunction(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, lParam As Long) As Long
If uMsg = WM_LBUTTONDOWN Then
    ‘What do you want your control to do ?
End If
newWndProc = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam)
End Function

We shall end this article with a complete example: '

-In a code module

Public Const WM_LBUTTONDOWN = &H201
Public Const WM_RBUTTONDOWN = &H204
Public Const GWL_WNDPROC = (-4)
Global WndProc As Long
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, lParam As Long) As Long
Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nindex As Long, ByVal dwnewlong As Long) As Long
Public Function HFunction(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, lParam As Long) As Long

   Select Case uMsg
        Case WM_LBUTTONDOWN
            Form1.Text1.Text = "Left Click"
        Case WM_RBUTTONDOWN
            Form1.Text1.Text = "Right Click"
        End Select
   HFunction = CallWindowProc(WndProc, hWnd, uMsg, wParam, lParam)
End Function

' -end of code module

' -In form ' Add a text box

 Dim tstButton As Object 
Private Sub Form_Load()
 Set tstButton = Form1.Controls.Add("VB.CommandButton", "tstButton", Form1)
 tstButton.Left = Text1.Left - Text1.Width / 2
 tstButton.Top = Text1.Top - Text1.Height / 2
 tstButton.Height = 375
 tstButton.Width = 1135
 tstButton.Visible = True
 tstButton.Caption = "Test"
 WndProc = SetWindowLong(tstButton.hWnd, GWL_WNDPROC, AddressOf HFunction)
End Sub

Note SetWindowLing has been superseded by the SetWindowLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Microsoft® Windows®, use the SetWindowLongPtr function. SetWindowLongPtr takes the exact same arguments, I used SetWindowsLongPtr since it’s a new function and many aren’t familiar with it.
Well I hope you enjoyed this article, be sure to catch my next articles!

July/27/2002
(Ziggy)3
ziggycubbe@yahoo.com
http://www.oocities.org/ziggycubbe