Sep
25
2008
--

Implementing elegant if else

A typical if else condition in VBScript would look like below

If (message = "ok") Then 
    Msgbox "I am calling ok"
Else
    Msgbox "I am calling not ok"
End if

VB provides a elegant function named IIf for such small if else conditions. The function can be easily witten in VBScript

Public Function IIf(ByVal pCondition, ByVal trueValue, ByVal falseValue)
    If pCondition Then
        IIf = trueValue
    Else
        IIf = falseValue
    End If
End Function

Now the same code be written in single line of code

Msgbox "I am calling " & IIf(message="ok","ok", "not ok")
Rating: 6.5/10 (11 votes cast)
Written by Tarun Lalwani in: VBScript | Tags: , , , , , , ,
Sep
23
2008
--

Implementing Callback in VBScript

Callback is a function which is executed on completion of a registered event. VBScript is not a event driven language, which means we are limited in terms of events for which callback can be implemented.

This article will demonstrate how to implement a callback on finish/terminate event. This finish/terminate event could be one of the following

  • The script finishes/terminates
  • A function finishes/terminates
  • A class finishes/terminates

CallBack implementation

We will create a special CallBack class for this

Class Callback
	'The object which called
	Dim Caller
 
	'Code to be executed during callback
	Dim CallBackCode
 
	'When the class ends execute the callback code
	Sub Class_Terminate()
		Execute CallBackCode
	End Sub
End Class

Executing code when script ends
If we want a Finalize function to be called when the script ends we can use the below code

Dim OC
Set OC = New Callback
OC.CallBackCode = "Call Finalize(0)"
 
Function Finalize(ByVal ExitCode)
	Msgbox "The code end with exit code - "  & ExitCode
End Function
 
Msgbox "Script ends here"

Executing code when a function ends

Function Test()
	Dim OC
	Set OC = New CallBack
	OC.CallBackCode = "Msgbox ""Function Test ended"""
 
	x = 2/0
	Msgbox "Unreachable code"
End Function
 
Call Test()

The advantage of implementing this call back is that they are guaranteed to be executed even in case the script end with a error or the function ends with an error. In QTP we can similarly execute a code at the end of the Test by declaring the variable in one of the associate global libraries.

Note: The approach works on the concept that all variables are destroyed once the scope in which they exist ends. It is important to make sure the CallBack object is always taken in a variable declared (as shown in code “Dim OC”)

Executing the Callback on a Class method

In case we want a class method to be called on a class object we can use the caller property

Class Test
     Function CallMe()
            Msgbox "You called me"
     End Function
End Class
 
Dim oTest
Set oTest = new Test
 
Dim OC
Set OC = New CallBack
Set OC.Caller = oTest
OC.CallBackCode = "Call Caller.CallMe"
Rating: 7.2/10 (6 votes cast)
Written by Tarun Lalwani in: VBScript | Tags: , , , , , , , , , , , ,
Sep
21
2008
0

VBScript Part 2 - Variables

What is variable?
Variable is a named container used to store values

Declaring a variable
There are three possible ways to declare a variable

Dim <VariableName>
Public <VariableName>
Private <VariableName>

Ex –

Dim x, y, z
Dim a
Dim b, c

Variable naming rules
Variable names should following the below rules

  • Must not exceed 255 characters.
  • Must be unique in the scope in which it is declared.
  • Must begin with an alphabetic character.
  • Cannot contain an embedded period.

Though these are the naming conventions specified by Microsoft. But we will be breaking the last 2 rules later in this article
Assigning values to variables
Variables can be assigned values why using the “=” to operator. Below code shows how different types of values can be assigned to a variable

Dim myVar
myVar = "Assigning a string value"
'Assigning a integer value
myVar = 2
'Assigning a double value
myVar = 3.3

Data Type of variables
All variables declared in VBScript are of Data type VARIANT. A VARIANT data type can store any types of value listed below

  • Boolean
  • Byte
  • Date (Time)
  • Double
  • Error
  • Integer
  • Long
  • Object
  • Single
  • String

All actual type of the data stored in a VARIANT type is known as the sub-type of the variable.

Declaring constant variable
Constants can be declared using below syntax

Const  <ConstName> = <ConstValue>

Ex –

Const APP_ NAME = "Testing VBScript"
Const APP_VERSION = "1.01"

It is advised to use all caps variable name when declaring a constant.

Variable Naming conventions
Since variables can store various types of values it is always a good practice to name them with a consistent convention

Data Type

Prefix 1

Prefix 2

Prefix 3

Boolean

b

b_

bln_

Byte

by

by_

byt_

Date (Time)

dt

dt_

dt_

Double

Dbl

dbl_

dbl_

Error

err

err_

err_

Integer

i

i_

int_

Long

l

l_

lng_

Object

o

o_

obj_

Single

sng

sng_

sng_

String

s

s_

str_

Above table shows few prefixes that can be used during scripting. You should choose the ones you like and stick to them. I personally prefer the Prefix 2 column. Below is the list of other Prefixes that might be required

  • Function – fn
  • Sub – sub
  • Global variable – g
  • Class member – m
  • Class – cls

We would be discussing all above mentioned topics in the upcoming articles

Forcing variable declaration
VBScript allows a very poor programming practice which is not to declare the variable being used
Ex –

str_Message = "Tarun Lalwani"
Msgbox str_Message
Msgbox for a undefined variable

Msgbox for a undefined variable

Above code will work even when we haven’t declared the ” str_Message” variable using a Dim/Public/Private statement. VBscript when it looks at a variable name which is not yet declared it declares with an Empty value. In programming a typo when using the variable name is always a possibility. Ex –

str_Message = "Tarun Lalwani"
Msgbox str_Messge
Msgbox for undefined and unused variables

Msgbox for undefined and unused variables

The value above is empty message because we haven’t declared str_Messge variable and when used VBScript declares it with an empty value. Though it is pretty easy to spot the issue in above code but when the code size is huge, these issues become very difficult to debug as wrong variable name used at once place might cause an issue at different location of code. To avoid such a situation VBScript provides an “Option Explicit” statement which can be used at the top of the code as shown below

Option Explicit
str_Message = "Tarun Lalwani"
Msgbox str_Messge

Now above code would throw an error

Undefined variable error when Option explicit is used

Undefined variable error when Option explicit is used

Breaking the 2 rules of naming restriction
Let us reiterate the last 2 rules for variable naming in VBScript

  • Must begin with an alphabetic character.
  • Cannot contain an embedded period.

Thought this is pretty much true the normal way
All below declaration will give syntax errors

Dim 1A
Dim _AB
Dim A B
Dim A.B

Though the error might be different for above declarations but the source of the error is the same, bnot following the naming convention. Now VBScript provides a very less talked about square bracket “[]” declaration

Dim [9X]
Dim [_varName]
Dim [My Name]
Dim [this.A]
[My Name] = "Tarun Lalwani"
[this.A] = [My Name]
MsgBox [this.A]
Msgbox for a undefined variable

Breaking the variable declaration rules

Rating: 8.0/10 (5 votes cast)
Sep
21
2008
0

Extending Dictionary Object

Dictionary object allows storing key value pairs. A dictionary object can be used for easy lookup of values. Dictionary is a not a QTP specific functionality and is available in normal VBScript as well.

Creating the Dictionary

A dictionary object can be created using CreateObject for COM class “Scripting.Dictionary”. The code below shows how to create the dictionary object in QTP

'Create the Dictionary Object
Set oDict = CreateObject("Scripting.Dictionary")

Methods

Below table shows list of methods that dictionary objects supports

Method

Description

Add (key, item)

Adds a key and item pair to a Dictionary object.

Exists(key)

Returns true if a specified key exists in the Dictionary object, false if it does not

Items()

Returns an array containing all the items in a Dictionary object

Keys()

Returns an array containing all existing keys in a Dictionary object.

Remove(key)

Removes a key, item pair from a Dictionary object

RemoveAll()

The RemoveAll method removes all key, item pairs from a Dictionary object.

Properties

Property

Description

Count Returns the number of items in a Dictionary object. Read-only.
Item Sets or returns an item for a specified key in a Dictionary object. Read/write
Key(Key) Sets a key in a Dictionary object

Adding Items to Dictionary

There are two ways to Add items to dictionary. One is to use the Add method and another is to use the Item property. Both the methods are shown in code below

'Method 1 for Adding items to dictionary
  'Add items to dictionary
  oDict.Add "CA", "California"
  oDict.Add "LA", "Los Angeles"
 
  'The below line will throw an error as LA key already exist
  oDict.Add "LA", "Los Angeles 2"
 
'Method 2 for adding items to dictionary
  oDict.Item("CA") = "California"
 
  'Item is the default property so ".Item" is not required
  oDict("LA") = "Los Angeles"
 
  'No Error this time as we are actually using the
  'Item property and not the Add method
  oDict("LA") = "Los Angeles 2"

Removing Items from Dictionary

Remove and RemoveAll methods allow to remove specified or all key(s) respectively. There usage is illustrated in the below code

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
oDict("TX") = "Texas"
oDict("IND") = "India"
 
'Displays "Texas"
MsgBox oDict("TX")
 
oDict.Remove "TX"
 
'Displays "Empty". The keys has been deleted and
'does not exists and when we try to access a non
'existent key, a new Empty item is created
MsgBox oDict("TX")
 
'Displays "India"
MsgBox oDict("IND")
 
'Remove all the keys
oDict.RemoveAll
 
'Displays Empty
MsgBox oDict("IND")

Changing Keys

The key property can use to change key of any item

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
oDict("IN") = "India"
 
'Change the IN key to IND
oDict.Key("IN") = "IND"
 
'Displays "India"
MsgBox oDict("IND")
 
'Displays "Empty"
MsgBox oDict("IN")
 
'Displays an error as the key IND is already
'associated with the value "India"
oDict.Key("IN") = "IND"

Checking Existence of an Item

We can check if an item exists or not using the exists methods as shown in code below

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
oDict("IN") = "India"
 
'Change the IN key to IND
oDict.Key("IN") = "IND"
 
'Displays "India"
MsgBox oDict("IND")
 
'Displays "Empty"
MsgBox oDict("IN")
 
'Displays an error as the key IND is already
'associated with the value "India"
oDict.Key("IN") = "IND"

Enumerating contents of a Dictionary

Items and Keys method returns the array of Items and keys respectively. These methods cannot be directly used to access the values, there return array has to be first assigned to a variable and then accessed. The code below illustrates the enumerations

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
oDict.Add "CA" , "California"
oDict.Add "LA" , "Los Angeles"
oDict.Add "TX" , "Texas"
 
aItems = oDict.Items
 
'Print all the items in the dictionary
For i = LBound(aItems) To UBound(aItems)
    Print aItems(i)
Next
 
'Print all keys in the dictionary
'We can use For each loop also to access the array
aKeys = oDict.Keys
For Each Key in aKeys
    Print "Key - " & Key
    Print "Value - " & oDict(Key)
Next

Compare Mode

CompareMode property of the dictionary can be used to set the text comparison mode for key. By default it is set to 0 (vbBinaryCompare) which means keys “TX” and “Tx” are different. Changing the value for CompareMode to 1 (vbTextCompare) will make “TX”, “tx”, “tX” and “Tx” to be treated as the same key. CompareMode can only be changed when there are no items in the dictionary

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
oDict.Add "TX", "Texas"
 
'Will display Empty
MsgBox oDict("Tx")
 
'Remove all items
oDict.RemoveAll
 
'Changing the key comparison mode to text
oDict.CompareMode = vbTextCompare
 
oDict.Add "TX", "Texas"
 
'Displays Texas
MsgBox oDict("tx")
 
'The below line will throw an "Access is Denied" error
'As the property can only be changes when there are no
'items present in the dictionary
oDict.CompareMode = vbBinaryCompare

Using Dictionary to Hash Values

Dictionary objects support a HashVal method which can be used to get hashvalue for a text. This can be used when huge text arrays need to be compared. HashVal will always generate same values for same text.

'Create the dictionary object
Set oDict = CreateObject("Scripting.Dictionary")
 
'Displays 0
MsgBox oDict.HashVal("")
 
'Displays 570
MsgBox oDict.HashVal("Tarun Lalwani")

Extending the Dictionary Functionality

Dictionary object does not allow saving and loading dictionary to and from files. We can extend the dictionary object by using VBScript classes. The extended will provide the following new functionalities

  • LoadFromFile to load the dictionary from a CSV file. This will remove all previous items
  • AddFromFile to add the item to current dictionary from a CSV file.
  • ExportToFile to export the dictionarty to a CSV file.
  • LoadFromDictionary to load the dictionary from a dictionary object. This will remove all previous items
  • AddFromDictionary to add items from another dictionary object
  • AccessUsingIndex property with True/False value to allow item access using index also. The actual dictionary object only allows to access items based on keys. But some times it is required to access items or keys based on index.

The code below shows the extended dictionary class

Class DictionaryEx
    'The actual dictionary that we will
    Private oDict
 
    'Private variable for storing value of AccessUsingIndex property
    Private mAccessUsingIndex
 
    'Now we need add all functions that the Dictionary already supports
    Public Property Get HashVal(Text)
        HashVal = oDict.HashVal(Text)
    End Property
 
    'Method to add a Key Value Pair
    Public Sub Add(ByVal Key, ByVal Item)
        oDict.Add Key, Item
    End Sub
 
    'Return the array of keys
    Public Function Keys()
        Keys = oDict.Keys
    End Function
 
    'Property to change key
    Public Property Let Key(oldKey, newKey)
        oDict.Key(oldKey) = newKey
    End Property
 
    'Returns array of items
    Public Function Items()
        Items = oDict.Items
    End Function
 
    'Check if certain key exists or not
    Public Function Exists(Key)
        Exists = oDict.Exists(Key)
    End Function
 
    'Remove All keys
    Public Sub RemoveAll()
        oDict.RemoveAll
    End Sub
 
    'Remove a specified key
    Public Sub Remove (Key)
        oDict.Remove GetKey(Key)
    End Sub
 
    'Get count of items in dictionary
    Public Property Get Count()
        Count = oDict.Count
    End Property
 
    'Get Property for CompareMode
    Public Property Get CompareMode()
        CompareMode = oDict.CompareMode
    End Property
 
    'Let Property for CompareMode
    Public Property Let CompareMode(newMode)
        oDict.CompareMode = newMode
    End Property
 
    'AccessUsingIndex is a flag which can be set to True/False
    'If Set to True then Numeric Keys will be translated to index
    'values and there corresponding keys will be used.
    'In case the numeric value is an existing key in the dictionary
    'then it would not be translated
    Public Property Get AccessUsingIndex()
        AccessUsingIndex = mAccessUsingIndex
    End Property
 
    'Let property for AccessUsingIndex
    Public Property Let AccessUsingIndex(newValue)
        If newValue = True Or newValue = False Then
            mAccessUsingIndex = newValue
        Else
            'If anything other then True/False raise an error
            Err.Raise vbObjectError + 1, "DictionaryEx", _
                "AccessUsingIndex can only be set true/false."
        End If
    End Property
 
    'Returns the actual dictionary object. This allows to do pass dictionary
    'to function which might support the actual dictionarty object
    Public Function Object()
        Set Object = oDict
    End Function
 
    'Function to translate keys from Index to actual key
    Private Function GetKey(Key)
        'Return actual key in case we are not
        'able to translate index to key
        GetKey = Key
 
        If Me.AccessUsingIndex Then
            'If the key already exist we do not want to change
            'anything even if it is a numeric value
            If Not oDict.Exists(Key) And IsNumeric(Key) Then
                keyIndex = CInt(Key)
                'Check if index is within range
                If keyIndex < Me.Count Then
                    Dim aKeys
 
                    aKeys = Me.Keys
 
                    'Translate from Index to Key
                    Key = aKeys(keyIndex)
                    Exit Function
                End If
            End If
        End If
    End Function
 
    'Item is the Default property for dictionary. So we
    'need to use default keyword with Property Get
    'Default keyword can be used with a only one Function
    'or Get Property
    Public Default Property Get Item(Key)
        'If a object is stored for the Key
        'then we need to use Set to return the object
        If IsObject(oDict.Item(GetKey(Key))) Then
            Set Item = oDict.Item(GetKey(Key))
        Else
            Item = oDict.Item(GetKey(Key))
        End If
    End Property
 
    'Let property Item
    Public Property Let Item(Key, Value)
        'Check of the value is an object
        If IsObject(Value) Then
            'The value is an object, use the Set method
            Set oDict(GetKey(Key)) = Value
        Else
            'The value is not an object assign it
            oDict(GetKey(Key)) = Value
        End If
    End Property
 
    'Property Set Item
    Public Property Set Item(Key, Value)
        Set oDict(GetKey(Key)) = Value
    End Property
 
    'AddFromDictionary takes an actual dictionary object and
    'add all keys from it
    Public Sub AddFromDictionary(oldDict)
        aKeys = oldDict.Keys
        Me.AccessUsingIndex = False
 
        For Each sKey In aKeys
            oDict(sKey) = oldDict(sKey)
        Next
    End Sub
 
    'LoadFromDictionary function removes all keys
    'and then add the keys from dictionary. It is
    'equivalent of creating a clone from a existing
    'dictionarty object
    Public Sub LoadFromDictionary(oldDict)
        oDict.RemoveAll
        Me.AddFromDictionary oldDict
    End Sub
 
    'Function to read dictionary key/value from file
    Public Sub AddFromFile(FileName, Delimiter)
        Set FSO = CreateObject("Scripting.FileSystemObject")
        Set oFile = Fso.OpenTextFile (FileName)
 
        'Read the file line by line
        While Not oFile.AtEndOfStream
            sLine = oFile.ReadLine
            KeyValue = Split(sLine, Delimiter)
            oDict(KeyValue(0)) = KeyValue(1)
        Wend
 
        Set oFile = Nothing
        Set FSO = Nothing
    End Sub
 
    'Function to remove all keys and then load it from
    'file
    Public Sub LoadFromFile(FileName, Delimiter)
        oDict.RemoveAll
        Me.AddFromFile FileName, Delimiter
    End Sub
 
    'Export the dictionarty to a file and use Delimiter
    'to seperate Key and Value pairs
    Public Sub ExportToFile(FileName, Delimeter)
        Set FSO = CreateObject("Scripting.FileSystemObject")
        Set oFile = FSO.CreateTextFile(FileName, True)
 
        Dim aKeys
        aKeys = oDict.Keys
 
        'Write the key value pairs line by line
        For Each sKey In aKeys
            oFile.WriteLine sKey & Delimeter & oDict(sKey)
        Next
 
        'Close the file
        oFile.Close
 
        Set oFile = Nothing
        Set FSO = Nothing
    End Sub
 
    'Intialize event gets executed whenever a object is created
    Sub Class_Initialize()
        Set oDict = CreateObject("Scripting.Dictionary")
        Me.AccessUsingIndex = False
    End Sub
 
    'Executed when the object is destroyed
    Sub Class_Terminate()
        'Remove all the keys
        oDict.RemoveAll
 
        'Destroy the dictionary
        Set oDict = Nothing
    End Sub
End Class

Below code illustrates the usage of the extended dictionary.

Set xDict1 = New DictionaryEx
Set xDict2 = New DictionaryEx
xDict1("CA") = "California"
xDict1("IND") = "India"
xDict1("FL") = "Florida"
 
'Export the dictionary
xDict1.ExportToFile "C:\Dict.txt", "###"
 
'Load dictionarty from file
xDict2.LoadFromFile "C:\Dict.txt", "###"
 
'Displays India
MsgBox xDict2("IND")
 
Set oDict = xDict2.Object
 
'Display Florida
MsgBox oDict("FL")
 
xDict2.AccessUsingIndex = True
 
'Displays "California"
MsgBox xDict2(0)
 
'Displays "India"
MsgBox xDict2("IND")
 
'Displays "India"
MsgBox xDict2(1)

In case you add the DictionaryEx class to a VBS file and associate it to the Test; Trying to create a object of DictionaryEx class will cause an error. This happens because global libraries in QTP are loaded outside the action scope and the classes are not visible to the action scope. The workaround is to create a function in the VBS that creates the object and returns it reference

Public Function NewDictionaryEx()
    Set NewDictionaryEx = New DictionaryEx
End Function

Dictionaries as Reserved Object in QTP

QTP allows adding any COM object as reserved object by adding its information to the Registry. To add Dictionary as one of the objects, follow the below mentioned steps

  • Open Regedit.exe through windows run window
  • Browse to HKEY_CURRENT_USER\Software\Mercury Interactive\QuickTest Professional\MicTest\ReservedObjects
  • Create a new key under this key with Name as “Dictionary” and as String value “ProgID” with data as “Scripting.Dictionary” as shown in below screenshot

    Registry Editor

    Registry Editor

  • Start QTP, type “Dictionary.” and we will not get the intellisense for the same as shown in the image below

    Dictionary as Reserved object

    Dictionary as Reserved object

Summary

In this article we learned

  • How to use dictionary objects
  • Extending the dictionary objects
  • Using dictionary object as Reserved QTP objects
Rating: 10.0/10 (3 votes cast)
Sep
21
2008
0

VBScript Part 1 - Introduction

VBScript is a scripting language. A VBScript can be executed in various ways

  • Using Windows Script Host (wscript.exe and cscript.exe). Will cover this later
  • Inside HTML page for IE Browser.
  • Other host process which allows to execute code in VBScript format (ex - HP QuickTest Pro)

Internal methods and objects
VBScript provides method and objects that can be used in the script. Internal methods are one which not dependent on the Host running the script. For Ex, below code would run fine on any of scripting host

Dim myName
myName = "Tarun Lalwani"
Dim myNameLength
myNameLength = Len(myName)
WScript Message box

WScript Message box

Above code would run fine if run in standalone VBScript, HTML or QTP
Host specific methods and objects

These methods or objects are provided by the Host running the script. Scripts using such methods are specific to the Host and can only run by them. Consider the below VBScript

Dim myName
myName = "Tarun Lalwani"
WScript.Echo myName

In the above script we are using a special object named “WScript” and a method “Echo” of that object. The code would run fine when run as a standalone script file and would produce the below message

No if we paste the same code in an HTML file and try to open the file in a IE browser

<HTML>
<BODY>
<SCRIPT type="text\VBScript">
Dim myName
myName = "Tarun Lalwani"
WScript.Echo myName
</SCRIPT>
</BODY>
<HTML>

The IE browser will display an error (Make sure you have unchecked the Disable Script Debugging in IE Options…Advanced Tab)

WScript object required error

WScript object required error

The reason the error is thrown is that WScript is Host specific object which is defined by the WScript.exe or CScript.exe scripting hosts. When we run the same code in IE this Host specific object does not exists. It is important to understand which methods or objects are host specific when porting scripts from one host to another (Ex VBScript to QTP Script, VBScript to HTML web page etc…)

Executing a Script

Different scripting host have different ways of running the script. In windows we can write the script in a notepad file and then save it with “vbs” extension

Script written in Notepad

Script written in Notepad

Save script as VBS

Save script as VBS

Double clicking the “Demo.vbs” file in explorer execute the script. By default windows is configured to execute the script using WScript.exe

Running the script by double clicking in explorer

Running the script by double clicking in explorer

Another way to the run the script is through windows run window or command prompt. Below screenshot shows how to execute a script using cscript.exe from console.

Script executed using CScript thorugh DOS command line

Script executed using CScript thorugh DOS command line

For an IE host we would need to run the HTML file containing the code which in turn would.

Rating: 9.5/10 (4 votes cast)