Now you know how to subclass windows, but there’s something seriously wrong with the model so far. It’s missing encapsulation. There are lots of common problems that can be solved by capturing messages, but do you really want to write separate code for every possible message? Of course not. You want to modularize. You want to write classes that make subclassing safe, easy, and preferably invisible. There are two ways to do it.
One way to make subclassing more modular is by writing a generic subclassing control or component. Ed Staffin’s Message Blaster control and Matt Curland’s callback component are provided on the CD for this book (as they were in the first edition). You can use either of these tools to make subclassing easy and generic, but you do have to ship the extra component with your program. MessageBlaster has one big advantage over the AddressOf technique. It can handle messages between processes. Now that’s a hardcore accomplishment for which Ed has my admiration. But I’ve never subclassed a window outside my current process in a real project.
Personally, I think a generic subclassing control is the wrong way to modularize most projects. Subclassing is difficult, messy, and dangerous—no matter what the tools. This brings me to the second, better method of subclassing, which is wrapping different subclass tasks in classes or controls. For example, assume you want to put new items on the system menu and then handle clicks on them. You can do this at three levels:
I prefer the third approach for most subclassing tasks. It concentrates on the solution, not the problem. A programmer who wants to handle system menus wants to worry about item titles and menu events, not about the subclassing chain and window procedures.
There’s only one problem with this approach. Subclassing isn’t difficult to program; it’s just hard to encapsulate. You have to do things that Visual Basic ought to be doing for you. But if it won’t, you’ll just have to do them yourself.
The SubTimer component provides tools for encapsulating subclasses easily and with relative safety. It also provides two classes that use those tools. The CSysMenu class encapsulates the system menu code we saw earlier. The CMinMax class encapsulates the WM_GETMINMAXINFO message, which controls the
position and size of maximized windows, and the minimum and maximum size of normal windows.
I had to write at least two classes to test my subclassing code because the tricky part of encapsulating subclassed windows is to allow the tools to work for as many messages and as many windows as the user wants. The Test Messages program uses the CSysMenu and CMinMax classes to handle two different messages. It also has a New Form button that clones the form in order to test using both classes with multiple windows. Figure 6-3 shows the test program in action.