When you use text editors such as Notepad to create long scripts, receiving error messages such as Error in line 162 from Windows Script Host (WSH) as it interprets the lines of code can be annoying. The messages are annoying not because the script has errors, but because you don't know which line is line 162. Now, I could have told you to buy SAPIEN Technologies' Primalscript or use Microsoft Script Debugger (which you can find in the Microsoft Windows 2000 Server Resource Kit or download from http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/001/731/msdncompositedoc.xml); instead, I decided to write a script to enumerate the line numbers in .vbs files.
Laying the Groundwork
I wanted to create a script that would add line numbers to the lines of code in a .vbs file. However, I didn't want to append the numbers to the code in the original .vbs file because the line numbers would cause the code to fail. So, I needed to create a temporary file and copy the .vbs file's code into it, appending line numbers to each line of code in the temporary file during the copy. To make the script easy to use, I wanted to use the WSH drag-and-drop technology that I showed you in "Scripting Solutions with WSH and COM: Using WSH Drag and Drop to Send Faxes in Win2K," December 2001, InstantDoc ID 23041. Using this WSH technology, I created a script called ShowLineNumbers.vbs onto which I can drag other scripts to generate and open a temporary file with the contents appended by line numbers. ShowLineNumbers.vbs, which Listing 1, page 14, shows, has four distinct sections:
- Initialization—I set up the constants and variables.
- Arguments—I make sure the user is passing only one argument (i.e., the pathname to one .vbs file) to the script (the code at callout A in Listing 1).
- New file creation—I create the temporary file that includes line numbers (the code at callout B in Listing 1).
- End—I view, then delete the temporary file (the code at callout C in Listing 1).
You can download ShowLineNumbers.vbs from the Code Library on the Windows Scripting Solutions Web site (http://www.winscriptingsolutions.com). Let's go through this simple script.
In the code at callout A, I use the value returned by the WScript::Arguments collection's Count property to make sure the user has dragged one .vbs file (i.e., passed in one argument). If this property's value is greater than 1, the script ignores all the passed-in arguments and displays an input box that tells the user only one file is allowed at a time and prompts the user to enter one pathname. I then use VBScript's Trim function to remove the leading and trailing spaces from the entered pathname before placing the name into the strInput variable. If the Count property's value is 0, the script hasn't received a drag-and-drop file. In other words, the user manually executed the script (e.g., by double-clicking it). In this case, the script displays an input box that prompts the user for a pathname. I again use the Trim function to remove the leading and trailing spaces from the entered pathname before placing the name into the strInput variable. If the Count property's value isn't greater than 1 and isn't 0 (i.e., the value is 1), I place the name of the drag-and-drop file into strInput.
Next, I verify that strInput actually contains a value. For example, the user could just have pressed Enter or clicked OK in the input box, which means that the pathname is blank. If such is the case, the script outputs an error message stating that the user hasn't specified a file and quits. If no error has occurred, I verify that a file with the specified name exists. To do so, I use the FileSystemObject::FileExists method to which I connected the fso variable during the initialization section of the script, then see what Boolean value the method returns. If the method returns the value of True, strInput contains a full, valid pathname and the script continues. If the method returns the value of False, the script issues another error message stating that the file doesn't exist and quits.
This pathname-retrieval process is quite cumbersome. Fortunately, you don't have to go through all this rigmarole. If you're sure that you'll always drag only one file onto ShowLineNumbers.vbs and that any mistakes you make will generate errors, you can simply replace the code at callout A with the code that Listing 2 shows. This new code states that if the number of arguments passed in to the script is anything other than 1, ShowLineNumbers.vbs quits. Otherwise, strInput is set to the value of the argument. When you drag this argument onto ShowLineNumbers.vbs, you know that the pathname is valid because the OS passed it in as part of the WSH drag-and-drop operation.
Writing the New File
Now that the strInput variable holds the name of the .vbs file to which I want to add line numbers, I need to open this file and read the contents line by line. To do so, I use the FileSystemObject::OpenTextFile method with the fso variable I created during initialization (the code at callout B in Listing 1). To ensure that the script opens the file in read-only mode, I defined during initialization a constant called ForReading, which I use as the second parameter to the OpenTextFile method. Then, I attach the open file to the filSource variable. Now I need to open a new temporary file that I can write to.
During initialization, I defined the TEMP_FILE constant, whose value is the temporary file's pathname, and the ForWriting constant, whose value lets you write to a file. To open the temporary file, I use the FileSystemObject::OpenTextFile method again—this time using the new filename, the ForWriting constant, and a value of True, which indicates that the file should be overwritten if it already exists.
Because the script must go through the entire .vbs file line by line, I use a While...Wend statement. The script checks the TextStream::AtEndOfStream property, which returns a value of True or False depending on whether the script is at the end of the file.
To actually write a line to the destination file, I use the TextStream::WriteLine method. The script writes to the file data that I pass to this method. The data consists of the line number (which I used the TextStream::Line property to retrieve), a string consisting of a colon (:) and a space, and the existing line read from the .vbs file. The result is a new line in the temporary file for every line in the .vbs file, but this time with the line number and a colon prefixing each line. Finally, I use the TextStream::Close method to close both files.
Bringing It All Together
So far, I've created a new file in the TEMP_FILE location without altering the original .vbs file. The last step is to open the temporary file on screen. The simplest way to open this file is to place the text file as a parameter to the WScript::Shell Run method (the code at callout C in Listing 1). This method forces the OS to use the default viewer to open the file. In this case, TEMP_FILE has a .txt extension, so the default viewer is Notepad. However, you could give TEMP_FILE a .lin extension, then use the code
wshShell.Run "notepad " & _TEMP_FILE
to force the file to open in Notepad or any other viewer.
The last two lines of code in ShowLineNumbers.vbs might seem a bit strange. When Notepad opens the text file, the application places the file in memory, which means that you can delete the underlying file without causing Notepad to crash or experience problems. With these two lines of code, I'm forcing the script to wait 10 seconds after Notepad opens the file with the line numbers, then to delete the underlying file.
Now that you know how to enumerate the line numbers in .vbs files, troubleshooting the scripts you use text editors to create will be much easier. In my next article, I'll follow up on "Scripting Solutions with WSH and COM: Scheduling Automated Tasks," March 2002, InstantDoc ID 23935, and show you how to have the WSH CScript engine call a VBScript file.