Visual Basic doesn't come with a set of symbolic constants defined for its own errors so I thought I'd put one together for you. Here's a snippet:
Public Enum vbErrorCodes VBErrReturnWithoutGoSub = 3 VBErrInvalidProcedureCall = 5 VBErrOverflow = 6 VBErrOutOfMemory = 7 VBErrSubscriptOutOfRange = 9 VBErrThisArrayIsFixedOrTemporarilyLocked = 10 VBErrDivisionByZero = 11 VBErrTypeMismatch = 13 VBErrOutOfStringSpace = 14 VBErrExpressionTooComplex = 16 VBErrCantPerformRequestedOperation = 17 VBErrUserInterruptOccurred = 18 VBErrResumeWithoutError = 20 VBErrOutOfStackSpace = 28 VBErrSubFunctionOrPropertyNotDefined = 35 . . . End Enum
Once you've added it to your project, this snippet is browsable via Visual Basic's Object Browser. To see how you might define constants using a type library, see Chapter 7.
Tip 21: Keep error text in a resource file.
Resource files (RES files) are good things in which to keep your error text and messages, and most C developers use them all the time, especially if they're shipping products internationally. That said, Visual Basic itself uses resource files-recognize some of these sample strings taken from Visual Basic's own resources?
STRINGTABLE FIXED IMPURE BEGIN 3 "Return without GoSub" 5 "Invalid procedure call or argument" 6 "Overflow" 7 "Out of memory" . . . 13029 "Sa&ve Project Group" 13030 "Sav&e Project Group As..." 13031 "Ma&ke %s..." . . . 23284 "Compile Error in File '|1', Line |2 : |3" . . . END
In fact, Visual Basic 6 uses a total of 2,934 resource files.
The %s in string 13031 is used to indicate (to a standard C library function) where a substring should be inserted-the binary name (?.EXE, ?.DLL, ?.OCX) in this case. The |1, |2, and |3 in string 23284 shows where replacement strings should be inserted, this time using a different technique. In fact, this latter technique (which you can use even on the %s strings) can be seen operating if you look at ResolveResString in the Visual Basic source code for SETUP1.VBP. It looks more or less like this (this is slightly tidied up):
'----------------------------------------------------------- ' FUNCTION: ResolveResString ' Reads string resource and replaces given macros with given ' values ' ' Example, given a resource number of, say, 14: ' "Could not read '|1' in drive |2" ' The call ' ResolveResString(14, "|1", "TXTFILE.TXT", "|2", "A:") ' would return the string ' "Could not read 'TXTFILE.TXT' in drive A:" ' ' IN: [nResID] - resource identifier ' [vReplacements] - pairs of macro/replacement value '----------------------------------------------------------- ' Public Function ResolveResString( _ ByVal nResID As Integer _ , ParamArray vReplacements() As Variant _ ) As String Dim nMacro As Integer Dim sResString As String sResString = LoadResString(nResID) ' For each macro/value pair passed in ... For nMacro = LBound(vReplacements) To UBound(vReplacements) Step 2 Dim sMacro As String Dim sValue As String sMacro = CStr(vReplacements(nMacro)) sValue = vbNullString If nMacro < UBound(vReplacements) Then sValue = vReplacements(nMacro + 1) End If ' Replace all occurrences of sMacro with sValue. Dim nPos As Integer Do nPos = InStr(sResString, sMacro) If 0 <> nPos Then sResString = Left$(sResString, nPos - 1) & _ sValue & _ Mid$(sResString, nPos + Len(sMacro)) End If Loop Until nPos = 0 Next nMacro ResolveResString = sResString End Function
To see all this code work, compile the strings and add them to your project. (Save the strings as an RC file, and then run the resource compiler on the RC file like so: C:\rc -r ?.rc. Add the resulting RES file to your application by selecting Add File from the Project menu.) Then add this code to Form1's Load event:
MsgBox ResolveResString( _ 23284 _ , "|1" _ , "Fubar.bas" _ , "|2" _ , "42" _ , "|3" _ , ResolveResString(7) _ )
This will produce the following message box:
Keeping message text in a resource file keeps strings (which could include SQL strings) neatly together in one place, and also flags them as discardable data, stuff that Windows can throw away if it must. Don't worry about this-Windows can reload strings from your binary image if it needs them. Your code is treated in exactly the same way and you've never worried about that being discarded, have you? Keeping read-only data together like this allows Visual Basic and Windows to better optimize how they use memory. Resource files also provide something akin to reuse as they usually allow you to be "cleverer" in your building of SQL and error text-they might even provide a way for you to share data like this across several applications and components. (See the notes on using a ROOS earlier in this chapter.)