Note: On pages 32 and 33 of the Visual Basic 2 Programmer's Guide, Visual Basic has defined control naming conventions that will likely be adopted by many corporations and Visual Basic ISVs. As a result, it would take a very strong argument to justify deviating from the Visual Basic 2 standard without causing a lot of heartache and confusion. Lacking such a compelling argument, this document therefore is a superset of the published Visual Basic conventions.
"Option Explicit" must always be used to force proper variable declarations and aid good variable commenting. The time lost trying to track down bugs caused by typos (aUserNameTmp vs. sUserNameTmp vs. sUserNameTemp) far outweighs the time needed to Dim variables.
The following table defines our standard Control name prefixes. (These are consistent with those documented in the Visual Basic 2 Programmers Guide.)
Table 1. Standard Control Name Prefixes
Prefix | Control Type Description |
ani | Animation button |
bed | Pen Bedit |
cbo | Combobox and dropdown Listbox |
chk | Checkbox |
clp | Picture Clip |
cmd | Command Button |
com | Communications |
ctr | Control (Used within procs when the specific type is unknown) |
db | ODBC Database |
dir | Dir List Box |
dlg | Visual Basic Pro Common Dialog |
drv | Drive List Box |
ds | ODBC Dynaset |
fil | File List Box |
frm | Form |
fra | Frame |
gau | Gauge |
gpb | Group Push Button |
grd | Grid |
hed | Pen Hedit |
hsb | Horizontal Scroll Bar |
img | Image |
ink | Pen Ink |
key | Keyboard key status |
lbl | Label |
lin | Line |
lst | Listbox |
mpm | MAPI Message |
mps | MAPI Session |
mci | MCI |
mnu | Menu |
opt | Option Button |
ole | Ole Client |
pic | Picture |
pnl | 3d Panel |
shp | Shape |
spn | Spin Control |
txt | Text/Edit Box |
tmr | Timer |
vsb | Vertical Scroll Bar |
Because Menu handlers can be so numerous, Menu names require a little more attention. Menu prefixes therefore continue beyond the initial Mnu label by adding an additional (upper case) character prefix for each level of nesting, with the final menu caption being spelled out at the end of the name string. When there is ambiguity caused by character duplications, such as a menu having both main Format and File menus, use an additional (lower case) character to differentiate the items. Examples:
Menu Caption Sequence | Menu Handler Name |
Help.Contents | mnuHContents |
File.Open | mnuFiOpen |
Format.Character | mnuFoCharacter |
File.Send.Fax | mnuFSFax |
File.Send.Email | mnuFSEmail |
This results in all the family members of a particular menu group being listed right next to each other. This multi-tiered format provides a very direct way to find a menu handler, especially when there are a great many of them.
For new controls not listed above, try to come up with a unique 3-character prefix. However, it is more important to be clear than to stick to 3 characters. For derivative controls, such as an enhanced list box, extend the prefixes above so that there is no confusion about what control is really being used. For example, a control instance created from the Visual Basic Pro 1.0 3D Frame could use a prefix of fra3d to make sure there is no confusion over which control is really being used.
Variable and function names have the following structure:
<prefix><body><qualifier><suffix>
The prefix describes the use and the scope of the variable, as in iGetRecordNext and sGetNameFirst. The qualifier is used to denote standard derivatives of a base variable or function, as in iGetRecordNext and sGetNameFirst. The suffix is the optional Visual Basic type char ($, %, #, and so on).
Prefixes
The following table defines variable/function name prefixes that are based on Hungarian C. These must be used universally, even when Visual Basic suffixes (such as %, &, #, and so on) are also used.
Table 2. Prefixes for Variable and Function Names
Prefix | Variable Use Description (precedes Control prefix and body) |
b | Boolean (vb type = %) |
c | Currency - 64 bits (vb type = @) |
d | Double - 64 bit signed quantity (vb type = #) |
db | Database |
ds | Dynaset |
dt | Date+Time (vb type = variant) |
f | Float/Single - 32 bit signed floating point (vb type = !) |
h | Handle (vb type = %) |
i | Index (vb type = %) |
l | Long - 32 bit signed quantity (vb type = &) |
n | Integer (sizeless, counter) (vb type = %) |
s | String (vb type = $) |
u | Unsigned - 16 bit unsigned quantity (must use &) |
ul | Unsigned Long - 32 bit unsigned quantity (must use #) |
vnt | Variant (big and ugly to discourage use and make sure it gets the reader's attention) |
w | Word - 16 bit signed quantity (vb type = %) |
a | Array |
User defined type | |
Prefix | Scope or Use (precedes Use prefix above) |
g | Global |
m | Local to module or form |
st | Static variable |
v | Variable passed by value (local to a routine) |
r | Variable passed by reference (local to a routine) |
Hungarian is as valuable in Visual Basic as it is in C because the Visual Basic type suffixes alone do not provide standard (and valuable) information about what a variable/function is used for or where it is accessible. For example, iSend (which might be a count of the number of messages sent), bSend (which might be a flag/Boolean defining the success of the last Send operation), and hSend (which might be a handle to the Comm interface) all succinctly tell a programmer something very different. This information is fundamentally lost when the name is reduced down to Send%. Scope prefixes such as g and m also help reduce the problem of name contention, especially in multideveloper projects. Hungarian is also well known to Windows programmers and constantly referenced in Microsoft and industry programming books. Additionally, the bond between C programmers and Visual Basic programmers can be expected to become much stronger as Visual C++ begins to live up to its potential. This transition will result in many Visual Basic programmers moving to C for the first time and many programmers moving fluidly back and forth between each environment.
Body
The body of variable and routine names should use mixed case and should be as long as needed to describe their purpose. Function names should also begin with a verb, such as InitNameArray or CloseDialog.
For frequently used or long terms, abbreviations (such as Init, Num, Tbl, Cnt, and Grp for Initialization, Number, Table, Count, and Group) are suggested to help keep name lengths reasonable. Names greater than 32 characters generally begin to inhibit readability on VGA displays. When abbreviations are used, they must be used consistently throughout the application. Randomly switching between "Cnt" and "Count" within a project will greatly frustrate developers.
Qualifiers
Often related variables and routines are used to manage and manipulate a common object. In these cases it can be very helpful to use standard qualifiers to label the derivative variables and routines. Although putting the qualifier after the body of the name might seem a little awkward (as in sGetNameFirst, sGetNameLast instead of sGetFirstName, and so on), this practice will help order these names together in the Visual Basic editor routine lists, making the logic and structure of the application easier to understand.
The following table defines common qualifiers and their standard meaning.
Table 3. Common Qualifiers
Qualifier | Description (follows Body) |
First | First element of a set. |
Last | Last element of a set. |
Next | Next element in a set. |
Prev | Previous element in a set. |
Cur | Current element in a set. |
Min | Minimum value in a set. |
Max | Maximum value in a set. |
Save | Used to preserve another variable which must be reset later. |
Tmp | A "scratch" variable whose scope is highly localized within the code. The value of a Tmp variable is usually only valid across a set of contiguous statements. |
Src | Source. Frequently used in comparison and transfer routines. |
Dst | Destination. Often used in conjunction with Source. |
mnUSER_LIST_MAX | 'Max entry limit for User list (integer value, local to module) |
gsNEW_LINE | 'New Line character string (global to entire application) |
With the single exception listed below, variants should NOT be used. When a type conversion is needed, variant use would probably provide a slight performance win over the explicit basic type conversion routines (val(), str$(), and the like), but this gain is not sufficient to overcome the ambiguity and general sloppiness they allow in code statements.
Example:
vnt1 = "10.01" : vnt2 = 11 : vnt3 = "11" : vnt4 = "x4"
vntResult = vnt1 + vnt2 ' Does vntResult = 21.01 or 10.0111?
vntResult = vnt2 + vnt1 ' Does vntResult = 21.01 or 1110.01?
vntResult = vnt1 + vnt3 ' Does vntResult = 21.01 or 10.0111?
vntResult = vnt3 + vnt1 ' Does vntResult = 21.01 or 1110.01?
vntResult = vnt2 + vnt4 ' Does vntResult = 11x4 or ERROR?
vntResult = vnt3 + vnt4 ' Does vntResult = 11x4 or ERROR?
Additionally, the type conversion routines assist in documenting implementation details, which make reading, debugging, and maintaining code more straightforward.
Example:
(iVar1 = 5 + val(sVar2) 'use this
vntVar1 = 5 + vntVar2 'not this!
Exception
While working with databases, messages, DDE, or OLE, a generic service routine can receive data that it does not need to know the type of in order to process or pass on.
Example:
Sub ConvertNulls(rvntOrg As Variant, rvntSub As Variant)
'If rvntOrg = Null, replace the Null with rvntSub
If IsNull(rvntOrg) Then rvntOrg = rvntSub
End Sub
Note: The Project window inherently describes the list of files in a project, so this overview section only needs to provide information on the most important files and modules or files that the Project window doesn't know about, such as .INI or database files.
Because many programmers still use VGA displays, screen real estate must be conserved as much as possible while still allowing code formatting to reflect logic structure and nesting. For this reason:
Function iFindUser (rasUserList() as String, rsTargetUser as String) as Integer
'Search UserList and if found, return index of first occurrence of TargetUser,
' else return -1
Dim i as Integer 'loop counter
Dim bFound as Integer 'target found flag
iFindUser = -1
i = 0
While i <= Ubound(rasUserList) and Not bFound
If rasUserList(i) = rsTargetUser Then
bFound = True
iFindUser = i
End If
Wend
End Function
vntVar1 = "10.01"
vntVar2 = 11
vntResult = vntVar1 + vntVar2 'vntResult = 21.01
vntResult = vntVar1 & vntVar2 'vntResult = 10.0111