Dear John, How Do I... Work with Predefined Constants?

There are actually several types of constants in Visual Basic, including some predefined constants provided by the system.

Compiler Constants

If you need to develop your applications in both 16-bit and 32-bit versions, you must use Visual Basic 4. This is the only version that provides a development environment for Windows 3.1 (16-bit), Windows 95 (32-bit), and Windows NT 3.51 (32-bit). To create applications that will run on both 16-bit and 32-bit operating systems, you'll need to use the Win16 and Win32 compiler constants. These constants indicate the system currently in use during development of your Visual Basic applications and let you select appropriate blocks of code to suit the conditions.

These constants are used with the #IfDear John, How Do I... ThenDear John, How Do I... #Else directives to select or skip over sections of code during compilation. Visual Basic versions 5 and 6 still support these constants, but Win32 is always True and Win16 is always False because these versions of Visual Basic run only on 32-bit versions of Windows.

Visual Basic Constants

A long list of predefined constants is provided automatically by Visual Basic for virtually every need. To see what's available, click the Object Browser button, select VBA or VBRUN from the top drop-down list, and click on the appropriate group of constants in the Classes list. A list of constants, each identifiable by the Constant icon and the vb prefix, is shown on the right side in the Members list, as you can see in Figure 3-7.

Notice that many components provide constants, and this is the place to find them when you need them.

You'll find that there are predefined constants for almost every control and function parameter imaginable—for example, vbModal and vbModeless for the form's Show method; vbRed, vbBlue, and vbGreen for color constants used in most graphics methods; and even vbCr, vbLf, vbCrLf, and vbTab for common text characters. The following code shows how to insert a carriage return/linefeed character into a string:

strA = "Line one" & vbCrLf & "Line two"

Click to view at full size.

Figure 3-7. Built-in constants, as shown in the Object Browser.

Anytime you find yourself starting to type a numeric value for a property or a method argument, you should stop yourself and check to see whether there is already a constant defined by the system that you could use instead. This can help make your programs self-documenting, easier to read, and easier to maintain.

User-Defined Constants

Like earlier versions of Visual Basic, Visual Basic 6 lets you define your own constants in your programs by using the Const keyword. You can also create conditional compiler constants using the #Const directive, which looks similar but is actually quite different. Constants created by #Const are to be used only with the #IfDear John, How Do I... ThenDear John, How Do I... #Else directives described earlier. Conversely, user-defined constants created with the Const keyword are not to be used as conditional compiler constants.

Some of the predefined constants are extremely helpful for building complex string constants. For example, the following code prints one constant to display digits in a column on a form. This same formatting was impossible without extra coding in earlier versions of Visual Basic. Now you can do all this formatting at design time. Note that only one executable statement is executed in the following procedure at runtime.

Option Explicit

Private Sub Form_Click()
    Const DIGITS = _
        "1" & vbCrLf & _
        "2" & vbCrLf & _
        "3" & vbCrLf & _
        "4" & vbCrLf & _
        "5" & vbCrLf & _
        "6" & vbCrLf & _
        "7" & vbCrLf & _
        "8" & vbCrLf & _
        "9" & vbCrLf
    Print DIGITS
End Sub

Use the Private and Public keywords to define the scope of constants declared at the module level. If declared Private, the constants will be local to the module only, whereas Public constants are available project-wide. These keywords cannot be used for defining constants inside procedures. A constant declared within a procedure is always local to that procedure.

Enumerations

An enumeration (Enum for short) is a way that you can associate integer values with names. This can be helpful with property procedures. For example, a SpellOption property might have these valid settings:

`MailDialog class module-level declarations
Public Enum CheckedState
    Unchecked            `Enums start at 0 by default
    Checked              `1
    Grayed               `2, and so on
    `CantDeselect = 255  (You can set specific values too)
End Enum

The properties that set or return the state of check boxes in a dialog box would then be defined using Enum in the property's parameter declaration:

Public Property Let SpellOption(Setting As CheckedState)
    `Set the state of the Check Spelling check box
    frmSendMail.chkSpelling.Value = Setting
End Property

Public Property Get SpellOption() As CheckedState
    `Return the state of the Check Spelling check box

    SpellOption = frmSendMail.chkSpelling.Value
End Property

You can use Enums in any type of module. They appear in the Object Browser in the Classes list box; their possible settings are shown in the Members list box. Only the public Enums in public class modules are visible across projects, however.

Flags and Bit Masks

The operators And, Or, and Not are most often used for logical comparisons in decision structures. For example, an If statement can test several conditions using the And operator, as shown here:

If blnExit And Not blnChanged Then End

Logic is great, but to be a really smooth operator you'd better be bitwise too. Bitwise operations are bit-by-bit comparisons of two numbers to create a result. Bitwise operations are used when you want to stuff more than one meaning into a single numeric value. These values are referred to as flags. A good example is the Print dialog box's Flags property:

dlgPrint.Flags = cdlPDCollate Or cdlPDNoSelection

In most cases, using Or to combine flags is equivalent to using the addition operator (+). However, when flags conflict you'll get a different result using addition—for example, 1 + 1 = 2, but 1 Or 1 = 1. This shouldn't happen if flag values are well thought out, but it's safer to use Or.

To reset flags to 0 or to check the value of a flag, use And. This code checks whether Print To File is selected in the Print dialog box:

`Check whether Print To File is selected
If dlgPrint.Flags And cdlPDPrintToFile Then

The And operation above checks whether bit 5 is on (&H20 is the value of cdlPDPrintToFile); if it is, the statement is True. Checking flags this way is known as using a bit mask. A bit mask is the collection of bits you are checking—for example, 01101101 (in binary; &H6D in hex). If the value in question has 1s in all the same bit positions as the mask, the mask "fits."

Masking is how a signed integer was converted to an unsigned number earlier in this chapter. Signed integers have values from &H8000 (-32,768 in decimal) to &H7FFF (+32,767 in decimal). By masking out the proper bits, you can convert a signed integer to an unsigned value:

intShort = (lngLong And &H7FFF&) - (lngLong And &H8000&)