Subclassing With The SSubTmr6 DLL
This page describes how to use the SSubTmr6 DLL in your
VBA projects to implement subclassing. Other pages on this site
describe how to use subclassing in general to extend your applications and
the existing Excel objects to accomplish tasks that are not available
directly from VBA. The SSubTmr6 component is the subclassing component of
choice that I use throughout this site.
You can't really write your own subclassing component in VBA. Technically speaking, it can be done -- there isn't anything in VBA that prevents you from doing so. With the right Windows API functions, you could make it happen. But VBA, being an interpreted language and not compiled to machine code, just isn't fast enough to handle the flood of messages sent by Windows. VBA would expend all its resources simply reading the input messages, leaving no time to do actual work.
Thus the need for a third-party subclassing component written in compiled VB or C/C++. There are a number of ActiveX components and DLLs available on the Internet that implement the actual subclassing of a window. I am most familiar with, and most pleased with, the free SSubTmr6.dll subclassing component available at Steve McMahon's www.vbaccelerator.com site. I have used it quite successfully in both VBA6 and VB6. The other pages on this site that describe subclassing techniques use the SSubTmr6.dll to accomplish the task at hand. You will find that most of the subclassing components available on the Internet provide a similar interface, so if you choose to use a different subclassing component, you will find that the code I use with SSubTmr6 will be similar to the code you will use with another subclassing component. The code as written, though, is for use with the SSubTmr6 component, and this is the component I recommend.
This page is not meant to replace the descriptions and documentation provided at the official SSubTmr6 site. I would very strongly recommend you read those pages, preferably two or three times. They provide much more information than is provided here. This page is intended to get you started quickly using the SSubTmr6 DLL to implement subclassing in your applications without having to know the dirty details. It assumes that you are familiar, at least at a conceptual level, with what subclassing a window is all about. Subclassing is not for novices. It is a fairly advanced technique, and requires that you understand the concepts of Windows messages and window handles. Subclassing is also unforgiving. You can and will crash Excel as you learn and experiment with subclassing. Be sure to save your work before running the code.
The first step is to download the SSubTmr6.dll zip file from http://www.vbaccelerator.com/codelib/ssubtmr/ssubtmr.htm . Download the zip file described as SSubTmr6.DLL for VB6. Even though the page says For VB6, the component will work fine in VBA6. Save the zip file in the folder of your choice and unzip the file. The zip file contains Visual Basic 6 example files in addition to SSubTmr6.dll file itself. Copy the SSubTmr6.dll file to your "C:\Windows\System32" folder.
The next step is to register the DLL file with
Windows. Close any open applications and then go to the Windows Start Menu,
choose Run, and enter the following, including the quotes, and click OK.
For your VBA Project to use the DLL, you must set a reference in your project to the DLL. In the VBA Editor, go to the Tools menu, choose References, and scroll down to vbAccelerator VB6 Subclassing and Timer Assistant and put a check next to this item. This adds a reference in your project to the DLL. Your code now has access to the objects and their properties and methods that are in the SSubTmr6.dll.
The implementation of subclassing must be done in an object module (a class module, a Userform's code module, a worksheet's code module, or the ThisWorkbook module). It is up to you to determine the most appropriate location for the subclassing code. In whatever module you decide to work in, you must Implement the ISubclass interface defined in the SSubTmr6 component. This is done with the following code:
When you Implement an interface, you must include in your object module all of the methods and properties of that interface, even if you don't use them. The ISubclass interface has three procedures that you must include in your code. The first two are the Property Get and Property Let procedures for the MsgResponse property. Even if you don't use these procedures, they must be declared in your module. This is a requirement of Implements.
Private Property Let ISubclass_MsgResponse(ByVal RHS As SSubTimer6.EMsgResponse) ' we don't use this property by it must be declared for Implements. End Property Private Property Get ISubclass_MsgResponse() As SSubTimer6.EMsgResponse ISubclass_MsgResponse = SSubTimer6.emrPreprocess End Property
The third procedure you must include in your code is the ISubclass_WindowProc procedure. This is the procedure that does all the work, and where we will put code to react to the messages passed in to this procedure.
Private Function ISubclass_WindowProc(ByVal HWnd As Long, ByVal iMsg As Long, _ ByVal WParam As Long, ByVal LParam As Long) As Long ''''''''''''''''''''''''''''''''''''''''''''''''' ' The code that runs based on the values of iMsg, ' WParam, and LParam. ''''''''''''''''''''''''''''''''''''''''''''''''' End Function
Now, your code must configure SSubTimer6 to subclass a
particular window and particular messages. To do this, you call the
AttachMessage procedure, passing it the HWnd of the window whose messages
you want to receive and the windows message number you want to receive. The
ISubclass_WindowProc will be called only for HWnds and messages that you
specify in the
AttachMessage method. To receive messages for more than one
window and/or to receive more than one message type, call
each Hwnd/Msg pair. It is assumed here than you know how to find the HWnd of
the window you want to subclass, using the FindWindow and possibly the
FindWindowEx Windows API procedures. For example, the following code will
subclass the Userform in which the code appears, listening for the
When a WM_ACTIVATE message is sent by Windows to this userform, SSubTimer6 will call the ISubclass_WindowProc procedure, passing it the HWnd of the userform, the message number (WM_ACTIVATE = 6), and the additional WParam and LParam parameters. Your code would then take action based on these values.
When your object module is unloaded or terminated, you must call the DetachMessage method to configure SSubTimer6 to stop subclassing. There must be a corresponding DetachMessage for each AttachMessage you called.
Private Sub UserForm_Terminate() ''''''''''''''''''''''''''''''''''''''''' ' Call DetachMessage to correspond to the ' AttachMessage call in Initialize. ''''''''''''''''''''''''''''''''''''''''' SSubTimer6.DetachMessage Me, MeHWnd, WM_ACTIVATE End Sub
That's about all you need to know to get started with subclassing with the SSubTmr6.dll component.