The Windows Word and the Windows Long


Some of the juiciest chunks of window data are accessed through a somewhat bizarre system of functions and constants. In the original design, if the data you needed was 16 bits in size, you called GetWindowWord with a constant indicating the data you wanted. If the data was 32 bits, you called GetWindowLong with a constant. Similarly, you could use SetWindowWord and SetWindowLong to modify the data.


Thunder Classes


If you are familiar with programming for Windows in C or Pascal, you might notice that this chapter doesn’t stress window classes. In fact, window classes—so important to most Windows programmers—are almost irrelevant to Visual Basic programmers.


When programming Windows in C, you first define the classes for your windows by filling in the fields of a WNDCLASS structure and then passing this structure to RegisterClass. Windows provides default classes for control windows (such as the Edit and ComboBox classes), but there is no default class for “normal” windows. You must create and register your own class before you can call CreateWindow to create your windows. As a result, almost every application has a different name for the classes of its windows, even though those classes often contain the same attributes. Program Manager has the Progman class, Notepad has the Notepad class, Calculator has the SciCalc class, and so on.


Visual Basic programmers usually don’t need to worry about classes because Visual Basic creates and registers its own and then uses them to create its windows, all behind the scenes. Once you start calling API functions to play with windows, however, you might want to manipulate windows through their class names occasionally.


All the names of the predefined Visual Basic classes start with the word Thunder, which was the prerelease code name of Visual Basic 1. (Internally, the Visual Basic folks were distributing a stunning bitmap showing the night sky of Seattle split by lightning and the slogan “The power to crack Windows.”) Each Visual Basic program has a main window with class ThunderMain and one or more forms with class ThunderForm. Controls have class names such as ThunderCommand­Button, ThunderListBox, and so on. In some cases, Thunder classes are made up of standard Windows control classes. For example, the ThunderCombo­Box class consists of what Windows calls an Edit control and a Combo­Box control.


Although you don’t have to worry about classes in your applications, the downside is that you can’t use classes to find Visual Basic programs as you can with other programs. Classwise, if you’ve seen one Visual Basic application, you’ve seen them all.


This system makes no sense in 32-bit windows. The window word and the window long are both 32 bits. Win32 throws GetWindowWord and SetWindow­Word in the trash. You must use GetWindowLong and SetWindowLong for all data. Windows also provides GetClassLong and SetClassLong functions and constants, but they aren’t of much use to Visual Basic programmers.


Why aren’t these names Word and DWord? Or Short and Long? Why doesn’t Windows provide separate functions to get and set each chunk of data? Why have Set functions to modify data (such as the instance handle) that no one in their right mind would modify? What happens if you pass a constant other than the ones provided in WINDOWS.H? Why didn’t it occur to the designers of the first version of Windows that the name GetWindowWord would be obsolete if Windows ever became 32-bit? Don’t ask.


The required constants are in the Windows API type library, but for reference, I’ll show what they would look like in Visual Basic:

Public Const GWL_WNDPROC = -4       ‘ Windows procedure 
Public Const GWL_HINSTANCE = -6 ‘ Instance handle
Public Const GWL_HWNDPARENT = -8 ‘ Use GetParent instead
Public Const GWL_ID = -12 ‘ Window ID (whatever that is)
Public Const GWL_STYLE = -16 ‘ Window style
Public Const GWL_EXSTYLE = -20 ‘ Extended window style
Public Const GWL_USERDATA = -21 ‘ Window style

In addition, you can use the following constants for dialog boxes:

Public Const DWL_MSGRESULT = 0      ‘ Return value of dialog message
Public Const DWL_DLGPROC = 4 ‘ Dialog procedure
Public Const DWL_USER = 8 ‘ User-defined data

In previous versions of Visual Basic, there wasn’t much you could do with a window or with a dialog procedure address. In this version, the AddressOf operator makes it possible to subclass windows with SetWindowLong and GWL_WNDPROC. We’ll experiment later in this chapter


I haven’t tried all the options, but I’ve been told you need to read the fine print twice to figure out the difference between Get/SetParent and Get/SetWindow­Long with GWL_HWNDPARENT. Instance handles aren’t nearly as useful in 32-bit Windows as they were in 16-bit Windows, but you can get them. The style bits are the data you’re most likely to need, and we’ll talk more about them next.


Here is the syntax for getting data with GetWindowLong:

Dim afStyle As Long, afExStyle As Long, hInst As Long 
hInst = GetWindowLong (hWnd, GWL_HINSTANCE)
afStyle = GetWindowLong(hWnd, GWL_STYLE)
afExStyle = GetWindowLong(hWnd, GWL_EXSTYLE)

You can also set window long values with SetWindowLong, and you might want to set the style bits, but that’s another story.