[Previous] [Table of Contents] [Next]

# Advanced Features

The following sections describe some of the advanced features in VBScript. Some are supported only in the version 5 scripting engines (which ship with WSH 2).

## Error Handling

Any run-time error that occurs in a script is fatal; that is, an error message is displayed and script execution terminates. However, you can change this behavior in all VBScript versions using this statement:

    On Error Resume Next

This statement tells the script engine to suppress the error message, recover from a run-time error, and resume with the statement following the statement that caused the error.

To disable inline error handling, you can insert this statement in your script code:

    On Error GoTo 0

You need to disable inline error handling as early as possible to avoid unexpected results (as you can see in Listing 4-7). During inline error handling, your script must catch and explicitly report run-time errors. Listing 4-7 establishes run-time error handling in a VBScript script.

Listing 4-7 RunTimeError.vbs

    '****************************************************
    ' File:    RunTimeError.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Simulating a run-time error to demonstrate
    ' run-time error handling and a pitfall
    '****************************************************
    Option Explicit

    Sub Test1()
        Err.Raise 6  ' Raise an overflow error.
        WScript.Echo "Test1 executed"
    End Sub

    Sub Test2()
        ' Here we have no run-time error handling.
        On Error Resume Next

        Err.Raise 6  ' Raise an overflow error.
        WScript.Echo "Level: Test2" & vbCrLf & "Errorcode: " & _
                     Err.Number & "=" & Err.Description
        Err.Clear    ' Clear error code.
    End Sub

    ' The main part
    WScript.Echo "Testing in progress"
    On Error Resume Next

    Test1
    WScript.Echo "Level: Main (back from Test1)" & vbCrLf & _
                 "Errorcode: " & Err.Number & "=" & Err.Description
    Test2
    WScript.Echo "Level: Main (back from Test2)" & vbCrLf & _
                 "Errorcode: " & Err.Number & "=" & Err.Description

    ' Here's the pitfall: the next statement contains an
    ' undeclared variable but doesn't cause a run-time
    ' error because of On Error Resume Next.
    WScript.Echo "Hello" & world  ' Dialog box is never shown!

    On Error Goto 0 ' Disable run-time error handling at script level.

    Test2           ' Inline error handling is done in the procedure.
    Test1           ' A run-time error terminates the script.
    WScript.Echo "Ready"

    '*** End

The script calls two procedures, Test1 and Test2. No run-time error handling is activated in Test1, so the script engine falls back to the caller if a run-time error occurs. The run-time error is simulated using this statement:

    Err.Raise 6  ' Raise an overflow error.

The Raise method of the Err object raises the run-time error of the number submitted to the method. This example uses code 6, which simulates an overflow error. Because Test1 doesn't contain run-time error handling, the following statement is never reached and execution falls back to the script level, where run-time error handling is activated.

    WScript.Echo "Test1 executed"

The following statement displays the current error in a dialog box:

    WScript.Echo "Level: Main (back from Test1)" & vbCrLf & _
                 "Errorcode: " & Err.Number & "=" & Err.Description

The error code is obtained from the Number property of the Err object, and the description is retrieved from Err.Description.

After the user closes the dialog box, the script calls Test2, which also simulates a run-time error using the Err.Raise method. Because run-time error handling is activated in this procedure, the execution continues in the procedure and a dialog box is displayed, showing the current error. Execution of the procedure resumes after the user closes the dialog box.

The following statement clears the error code:

    Err.Clear

As a result, the next message box invoked on the script level doesn't show an error code. After calling both procedures with active error handling, the script disables run-time error handling on the script level. Test2 results in a run-time error, but this error is handled within the procedure, so the script continues after the user closes the dialog box. The script then calls Test1 again. Because inline run-time error handling is disabled, the execution falls back from Test1 to the script level and then back to the built-in error handling routine. As a result, the default error dialog box is shown and the script terminates.

## Regular Expressions (in VBScript 5.0 and Later)

In versions 5.0 and later, VBScript supports regular expressions, which you can use to find patterns in strings or replace one pattern with another in a string. You create a regular expression object in the script by using the following statement:

    Set regEx = New RegExp

After this statement is executed, the object variable regEx contains a reference to the regular expression object. You can then use the methods of this object to force pattern matching, replacement operations, and so on.

Let's look at a simple example that detects all occurrences of the letter b in a given text. In this case, the pattern is defined as the letter b. To tell the object this fact, you use the Pattern property as follows:

    regEx.Pattern = "b"

The name of the object variable is used with the name of the property. The property is set to the pattern value, b.

You must be careful about case sensitivity. The character B is different from b. Fortunately, you can set the IgnoreCase property to True or False. The following statement forces the pattern matching process to be case insensitive:

    regEx.IgnoreCase = True

You can use the Global property to define whether the pattern should match all occurrences in an entire search string or just the first one. To retrieve all occurrences, you set the property to True:

    regEx.Global = True

After defining the regular expression object, the search pattern, and the Global property, you can invoke the following methods:

- Test Executes a regular expression search against a specified string and returns a Boolean (True or False) value that indicates whether a pattern match was found. The method uses the syntax object.Test(string), where string is the string on which the regular expression is executed.

- Execute Executes a regular expression search against a specified string. The method uses the syntax object.Execute(string), where string is the string on which the regular expression is executed.

- Replace Replaces text found in a regular expression search. The method uses the syntax object.Replace(string1, string2), where string1 is the text string in which the text replacement is to occur and string2 is the replacement text.

You can find details about these methods and properties in the VBScript Language Reference. Listing 4-8 illustrates the use of the RegExp object.

Listing 4-8 RegExpression.vbs

    '*******************************************************
    ' File:    RegExpression.vbs  (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Finding a pattern in a string using the RegExp object
    '*******************************************************
    Option Explicit

    Const Test = "The quick brown fox jumps over the lazy dog..."

    Function RegExpTest(patrn, strng)
        Dim regEx, Match, Matches    ' Create variable.
        Dim retStr                   ' Result

        Set regEx = New RegExp       ' Create a regular expression.
        regEx.Pattern = patrn        ' Set pattern.
        regEx.IgnoreCase = True      ' Set case insensitivity.
        regEx.Global = True          ' Set global applicability.
        Set Matches = regEx.Execute(strng)    ' Execute search.
        For Each Match in Matches    ' Iterate Matches collection.
            RetStr = RetStr & "Match found at position "
            RetStr = RetStr & Match.FirstIndex & ". Match Value is '"
            RetStr = RetStr & Match.Value & "'." & vbCrLf
        Next
        RegExpTest = RetStr          ' Return result.
    End Function

    WScript.Echo RegExpTest("b.", Test)

    '*** End

The function RegExpTest, obtained from the VBScript Language Reference, creates a regular expression object; sets the Pattern, IgnoreCase, and Global properties; and applies the Execute method to the string. This method returns a collection of matches to an object variable. You can separate the items of the collection in a For Each loop, as follows:

    For Each Match In Matches
        ...
    Next

This loop is executed until all members of the Matches collection are processed. The results are collected in a text variable, which is returned as the function value. The function is called within the main script, and the results are shown in a simple dialog box.

## Classes (in VBScript 5.0)

You can use classes to create objects internally to implement some new features in VBScript 5.0. You're probably familiar with structured, user-defined variable types in other languages. For example, in Visual Basic you define structured variables as follows:

    Private Type MyType
        MyName As String
        MyAge As String
    End Type

Using this type definition, you can create a variable based on MyType by using the following statement. (The customer variable has the members customer.MyName and customer.MyAge.)

    Dim customer As MyType

In VBScript, you can't work with user-defined variable types in this way. But in VBScript 5.0, you can use the class feature to define your own structured variables. For example, the customer data might consist of a name, an address, a phone number, and so on. To capture this data in a script, you can use a group of variables to describe a customer:

    Dim Name, Street, Zipcode, Phone

If you also have a supplier, you need a second set of variable names, as shown below. (The prefix s indicates that these variables are part of the supplier data.)

    Dim sName, sStreet, sZipcode, sPhone

Wouldn't it be much better to have a user-defined data type that describes an item more globally? The following code snippet uses the new Class construction to define the data structure:

    Class MyType
        Dim Name
        Dim Street
        Dim Zipcode
        Dim Phone
    End Class

Within your script, you can create an instance of the class MyType and assign it to a new object variable by using this statement:

    Set customer = New MyType

The object variable customer owns all members of the class (Name, Street, Zipcode, and Phone). To access the Phone item, you can write this:

    customer.Phone = "(555) 803-7892"

This approach is particularly handy if you also need a variable for a different entity, such as a supplier, which has all the same type of information as a customer. You can use the following statement to create a new instance of the class MyType, which you can use to store the supplier data:

    Set supplier = new MyType

This statement is used in Listing 4-9, which creates two instances of the class, assigns values to the class members, and shows them in a dialog box.

Listing 4-9 ClassSample.vbs

    '***************************************************
    ' File:    ClassSample.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Using the new class feature in VBScript 5 to
    ' create structured variables, which simulate user-
    ' defined types
    '***************************************************
    Option Explicit

    Dim customer, supplier

    ' Here comes a class definition.
    Class MyType
        Dim Name
        Dim Street
        Dim Zipcode
        Dim Phone
    End Class

    ' Now create a new variable for customer.
    Set customer = new MyType

    ' Assign values
    customer.Name = "Jo Brown"
    customer.Phone = "(555) 203-2466"

    ' Now create a new variable for supplier.
    Set supplier = new MyType

    ' Assign values.
    supplier.Name = "Northwind Traders"
    supplier.Phone = "(555) 203-3457"

    WScript.Echo "Customer: " & customer.Name & " " & _
                 customer.Phone & vbCrLf & _
                 "Supplier: " & supplier.Name & " " & _
                 supplier.Phone

    '*** End

### Example: Extending a class

You can also use classes to define your own properties and methods. The technique in VBScript is the same as in Visual Basic: you use the Public and Private keywords and the Property keyword. Here's an example derived from a sample I found in a Microsoft document. The class defines an address object.

    Class address
        Public FirstName, LastName
        Private strEmailName

        Property Get EmailName
            EmailName = strEmailName
        End Property
        Property Let EmailName(strName)
            StrEmailName = strName
        End Property

        Property Get FullName
            FullName = FirstName & " " & LastName
        End Property

        Sub Add(First, Last)
            FirstName = First
            LastName = Last
        End Sub
    End Class

The class has two public properties, FirstName and LastName, which are read/write. Neither property uses any code for the read/write process. The class also provides a read/write property named EmailName, which has code associated with it. The FullName property is read-only because it has only a Property Get statement. The class also defines the Add method, which adds a name to the object. All functions and subroutines in a class are public unless they are declared private by using the Private keyword.

After defining the class, you can create an object instance using the following statement:

    Set customer = New address

You can add the values to the object instance using the Add method:

    customer.Add "Frank", "Miller"

Listing 4-10 creates and uses this class.

Listing 4-10 ClassSample1.vbs

    '****************************************************
    ' File:    ClassSample1.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Using the new class feature in VBScript 5
    ' (Code derived from a sample by Andrew Clinick
    ' of Microsoft)
    '****************************************************
    Option Explicit

    Dim customer

    ' Here comes a class definition.
    Class address
        Public FirstName, LastName
        Private strEmailName

        Property Get EmailName
            EmailName = strEmailName
        End Property
        Property Let EmailName(strName)
            StrEmailName = strName
        End Property

        Property Get FullName
            FullName = FirstName & " " & LastName
        End Property

        Sub Add(First, Last)
            FirstName = First
            LastName = Last
        End Sub
    End Class

    ' Now create a new variable for customer.
    Set customer = New address

    ' Add a new customer.
    customer.Add "Douglas", "Groncki"

    ' Set e-mail address.
    customer.EmailName = "dgroncki@microsoft.com"

    ' Display the customer's data.
    WScript.Echo customer.FullName & "  " & customer.EmailName

    '*** End

## Using the With Statement (in VBScript 5.0)

The normal syntax for accessing properties or methods of an object is object.property or object.method. This syntax requires you to name the object explicitly in each statement. The following code (from the RegExpression.vbs sample file) demonstrates this behavior:

    Set regEx = New RegExp       ' Create a regular expression.
    regEx.Pattern = patrn        ' Set pattern.
    regEx.IgnoreCase = True      ' Set case insensitivity.
    regEx.Global = True          ' Set global applicability.

After you create the object instance, you assign it to the object variable regEx. In subsequent statements, you can use the RegExp object, but you have to type regEx repeatedly and the VBScript interpreter has to parse the name again and again, which is inefficient. Instead, you can use the With statement to qualify an object once for a series of statements. You can rewrite the preceding code snippet as follows:

    Set regEx = New RegExp      ' Create a regular expression.
    With regEx
        .Pattern = patrn        ' Set pattern.
        .IgnoreCase = True      ' Set case insensitivity.
        .Global = True          ' Set global applicability.
    End With

Inside the With block, the VBScript engine knows that all unqualified references to properties and methods belong to regEx. By using the With statement, the VBScript engine can optimize calls to an object, and your code will be much shorter and more manageable.

> NOTE

> The With statement isn't supported in versions of VBScript before version 5.0, so most of the samples in this book don't use the statement (in order to be compatible with WSH 1).

VBScript 5.0 comes with several other new features, including function pointers to bind a procedure to an event, the ability to call objects on other workstations, and the ability to execute statements to evaluate a string expression. We'll use some of these features later in this book. For detailed information about VBScript's advanced features, see the VBScript Language Reference and VBScript Tutorial.