Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Schongar P.VBScript unleashed.1997

.pdf
Скачиваний:
46
Добавлен:
23.08.2013
Размер:
1.59 Mб
Скачать

Listing 12.12. Adding a form text area input control to capture debug trace statements.

<FORM NAME="frmPace">

<PRE>

<FONT COLOR=BLUE FACE="Comic Sans MS" SIZE=6>

Distance: <INPUT NAME="txtDistance" VALUE="" MAXLENGTH="5" SIZE=5>

<INPUT TYPE="RADIO" NAME="Dist" CHECKED VALUE="Miles"

onClick=SetDistance("Miles") > Miles

<INPUT TYPE="RADIO" NAME="Dist" VALUE="Kilos"

onClick=SetDistance("Kilos")>Kilos

Time:

<INPUT NAME="txtTime" VALUE="" MAXLENGTH="11" SIZE=11>

in minute:second format

 

<INPUT TYPE=BUTTON VALUE="Display Pace" SIZE=30 NAME="Calc">

Pace per Mile: <INPUT NAME="txtPaceMiles" VALUE=""

MAXLENGTH="5"

SIZE=5>

Pace per Kilo:

<INPUT NAME="txtPaceKilos" VALUE="" MAXLENGTH="5" SIZE=5>

Debug Window: <TEXTAREA NAME="txtDebug" ROWS="10" COLS="60" >

</TEXTAREA>

</FONT>

</PRE>

</FORM>

The textarea control, which is named txtDebug in this example, provides a convenient place to log trace information. You can add code to your script to display debug information in this control wherever you want logging to take place in your program. As a matter of fact, if you want, you can print debug information after each and every script statement. This logging takes place in an unobtrusive manner and doesn't require the interaction of the message box. You can even provide variable and code-location information when you display information in the txtDebug control. Listing 12.13 shows an example of PacePal modified to use this style of tracing.

Listing 12.13. Tracing program flow and variables with form text area input control.

document.frmPace.txtDebug.Value = document.frmPace.txtDebug.Value & _

"Prior to assignment, vSeconds =" & vSeconds & vbCrLF

' Return total seconds value

ConvertStringtoTotalSeconds = CInt(vHours) + CInt(vMinutes) _

+ CInt(vSeconds)

document.frmPace.txtDebug.Value = document.frmPace.txtDebug.Value & __

"After assignment, vSeconds =" & vSeconds & vbCrLf

When Pace-Pal is run with these modifications, a clear trace appears in the txtDebug textarea control as the program progresses. Figure 12.13 shows a sample of the trace.

Figure 12.13 : Output from the textarea trace.

This trace can provide great insight into code behavior. Another advantage of storing trace output in the txtDebug control is that you can use this information to review your program history even after your script execution completes. Suppose that your script generates 200 lines of trace information in response to a button click. After the block of code associated with the button click completes, all this information still is available in the txtDebug control. You can scroll through the data and reconstruct what happened to the script by looking at this trace. Notice that the variable vbCrLf is used here. This is declared to contain the standard line-separator characters-specifically, Chr$(10) & Chr$(13).

Building Your Own Tracing Routines

The technique of placing trace statements in a textbox control is handy, but you can make it even more convenient. The statements that log information are not difficult to understand, but they are a bit lengthy. Also, you want to ensure that you take the same approach with every log statement. If you generate one type of trace information in one area of code, and then generate trace information in another format somewhere else in your script, it will be more confusing to analyze the trace results. So it is more convenient to simply call an easy-to-use subroutine every time you want to log trace messages. That way, the subroutine can contain the code to handle all aspects of logging the trace information. Listing 12.14 shows a sample trace debug subroutine.

Listing 12.14. The definition for a simple trace routine.

Sub DebugMsg(Info)

'--------------------------------------------------------

' Print debug message to textarea used for debug display

Document.frmPace.txtDebug.Value = _

Document.frmPace.txtDebug.Value & info & vbCrLf

End Sub

This procedure takes a string, which is provided as a parameter at the time the procedure is called, and adds that string to the current contents of the textbox control. This procedure may be called many times from different locations in the program. The string, which is provided as data to this procedure, should describe the program from which the call is made in order to provide a meaningful trace history. For clear output, new information provided by the trace procedure should be displayed as a new line in the text box. That is the purpose of the vbCrLf constant variable in Listing 12.14. vbCrLf is a variable for the intrinsic VBScript constant containing the carriage-return/line-feed characters that cause a new line to be generated. The assignment statement appends the new information after the existing contents of the textbox control. Then, a carriage return/ line feed is appended to the end of that. Any information that follows appears on a new line.

Using this type of subroutine doesn't just save you from repeatedly typing the same trace code. It also ensures that all trace output is generated in a standard, consistent manner. After all, every trace message comes from the same place with this approach. Then the rest of the code simply uses this common subroutine wherever traces are needed. Listing 12.15 shows an example of Pace-Pal, modified to use calls to the trace procedure to carry out a trace.

Listing 12.15. The call to a simple trace routine.

DebugMsg "Prior to assignment, vSeconds =" & vSeconds

' Return total seconds value

ConvertStringtoTotalSeconds = CInt(vHours) + CInt(vMinutes) _

+ CInt(vSeconds)

DebugMsg "After assignment"

Because any expression can be passed for subsequent display to DebugMsg, you have the flexibility to send information about any variable and have that recorded with your program trace. Notice that in the first call to DebugMsg, the descriptive string passed to the procedure contains the contents of a variable as well as indicates the location where the call was made. The benefits of this type of flexible trace are tremendous. You can monitor the changes in variables as your program executes, and monitor the current location and progression of the code. You can gain very keen insights from the program-monitoring this trace procedure provides.

NOTE

You might have noticed that the calls to the debug trace procedure are not indented, unlike the rest of the program. This is a convention that can be used to make temporary calls stand out. All the debug trace calls here are temporary calls only. Normally, you add them just to aid your debugging efforts during design time and remove them prior to releasing your final product. The practice of leftaligning the debug statements makes it easy to spot the statements and remove them later.

Looking at a Sample Variable Analysis Routine

The information provided by the DebugMsg procedure is good, but even that might not tell you everything you want to know. If you're chasing a problem in a script, it might not be enough just to see the program flow. You might even use DebugMsg to display the contents of a variable and find that it still doesn't quite fill you in on the whole story of the state of your program.

One other piece of the picture that can be very important is determining what subtype of data a variable represents, as well as the current value of that data.

A variable that prints as 23 in the trace log, for example, may be stored in a variant variable with subtype string, or a variant variable with subtype integer. For some types of problems, it can be very important to understand which subtype data representation a variable currently has. If you write elegant code to look at the variant subtype and interpret it for logging, the code can be rather lengthy. It's certainly not something you want scattered all over your program. Fortunately, you can apply the same trace procedure solution to this problem. An expanded trace procedure can be defined to provide a "power trace." This procedure not only accepts a descriptive parameter indicating the program location, but it also accepts a parameter that contains a variable to analyze. The procedure then logs an informational string to the textbox control based on these parameters. Part of the information logged in the textbox control displays the program location. The other portion reflects the value and subtype of the variable. An analysis of the variable is carried out to determine the subtype of the variant. This type of debugging procedure provides a very detailed and powerful trace history. Listing 12.16 shows an example.

Listing 12.16. The definition for a variant variable analysis routine.

Sub VarAnalyzeMsg(InfoMsg, VarToAnalyze)

'--------------------------------------------------------

'Print debug info message to textarea used for debug display;

'print out type and value of VarToAnalyze

Dim VarMsg ' Used to build up info about VarToAnalyze

'Determine type of variable

'Note: If this code was in Visual Basic 4.0, the VB

'intrinsic constants such as vbEmpty could be

'used instead of the hardcoded values shown

'(not defined in beta VBScript)

Select Case VarType(VarToAnalyze)

Case 0

 

' vbEmpty

VarMsg

= "Empty"

Case 1

 

' vbNull

VarMsg

= "Null"

Case 2

 

' vbInteger

VarMsg

= "Integer, Value=" & VarToAnalyze

Case 3

 

' vbLong

VarMsg

= "Long, Value=" & VarToAnalyze

Case 4

 

' vbSingle

VarMsg

= "Single, Value=" & VarToAnalyze

Case 5

 

' vbDouble

VarMsg

= "Double, Value=" & VarToAnalyze

Case 6

'

vbCurrency

VarMsg

= "Currency, Value=" & VarToAnalyze

Case 7

'

vbDate

VarMsg

= "Date, Value=" & VarToAnalyze

Case 8

 

' vbString

VarMsg

= "String, Len=" & Len(VarToAnalyze) _

& "

Value=" & VarToAnalyze

Case 9

 

' vbObject

VarMsg

= "OLE Automation Object"

Case 10

 

' vbError

VarMsg

= "Error"

Case 11

 

' vbBoolean

VarMsg

= "Boolean, Value=" & VarToAnalyze

Case 12

 

' vbVariant

VarMsg

= "Non-OLE Automation Object"

Case 13

 

' vbDataObject

VarMsg

= "Byte, Value=" & VarToAnalyze

Case 17

 

' vbByte

VarMsg

= "Byte, Value=" & VarToAnalyze

Case 8194

' vbArray + vbInteger

VarMsg

= "Integer Array, Ubound=" & Ubound(VarToAnalyze)

Case 8195

' vbArray + vbLong

VarMsg

= "Long Array, Ubound=" & Ubound(VarToAnalyze)

Case 8196

' vbArray + vbSingle

VarMsg

= "Single Array, Ubound=" & Ubound(VarToAnalyze)

Case 8197

' vbArray + vbDouble

VarMsg

= "Double Array, Ubound=" & Ubound(VarToAnalyze)

Case 8198

' vbArray + vbCurrency

VarMsg

= "Currency Array, Ubound=" & Ubound(VarToAnalyze)

Case 8199

' vbArray + vbDate

VarMsg

= "Date Array, Ubound=" & Ubound(VarToAnalyze)

Case 8200

' vbArray + vbString

VarMsg

= "String Array, Ubound=" & Ubound(VarToAnalyze)

Case 8201

' vbArray + vbObject

VarMsg

= "Object Array, Ubound=" & Ubound(VarToAnalyze)

Case 8202

' vbArray + vbError

VarMsg

= "Error Array, Ubound=" & Ubound(VarToAnalyze)

Case 8203

' vbArray + vbBoolean

VarMsg

= "Boolean Array, Ubound=" & Ubound(VarToAnalyze)

Case 8204

' vbArray + vbVariant

VarMsg

= "Variant Array, Ubound=" & Ubound(VarToAnalyze)

Case 8205

' vbArray + vbDataObject

VarMsg

= "vbDataObject Array, Ubound=" & Ubound(VarToAnalyze)

Case 8209

' vbArray + vbByte

VarMsg = "Byte Array, Ubound=" & Ubound(VarToAnalyze)

Case Else

VarMsg = "Unknown"

End Select

VarMsg = "...Var type is " & VarMsg

'Print to textarea used for debug trace, must use vbCrLf

'to advance lines

Document.frmPace.txtDebug.Value = _

Document.frmPace.txtDebug.Value & InfoMsg & vbCrLf

Document.frmPace.txtDebug.Value = _

Document.frmPace.txtDebug.Value & VarMsg & vbCrLf

End Sub ' VarAnalyzeMsg

Style Considerations

If you're really alert, you might have noticed that a check is made to see whether the variable is represented in several storage types that VBScript does not support. These include currency and arrays of nonvariants that are supported by Visual Basic. Because it doesn't hurt to check for these extra types, and it could even provide added insight if there was an internal VBScript error that resulted in a bad type, these checks are left in here. This also makes for upward-compatible code that can be ported to VBA or Visual Basic 4.0 programs without change.

Listing 12.17 shows a modified sample of the familiar Pace-Pal example. Pace-Pal has been modified to make calls to the VarAnalyzeMsg routine. These calls have been added both before and after the statement that earlier samples indicated was the problem statement. Because three variables are involved in the problem statement (vHours, vMinutes, and vSeconds), all three should be inspected prior to the problem statement to help determine the cause of the problem. Therefore, three different calls to VarAnalyzeMsg are used-one to analyze each specific variable. Likewise, the same three calls to VarAnalyzeMsg are made after the problem statement. This is to ensure that none of the variables has unexpectedly changed value or subtype.

NOTE

You can pretty well determine by looking at the code involved in the incorrect section of Pace-Pal that no variables will be changed after the problem statement. The post-statement calls to VarAnalyzeMsg, however, ensure that you are not making any mistaken assumptions about values not changing. This is a good standard debugging practice to follow, and the calls are included here to illustrate that point. You should scientifically verify the contents of variables during debugging rather than making potentially faulty assumptions. If you've decided that a full trace is in order, you can never assume that a value will not change. It is always best to check debugging information before and after a given statement. Even if you think that nothing will have changed, there is always a chance that you're wrong, and the extra debugging procedure costs you only the time it takes to enter it.

Listing 12.17. The call to the variant variable analysis routine.

Call VarAnalyzeMsg("Analyzing vHours prior to ConvertString",vHours)

Call VarAnalyzeMsg("Analyzing vMinutes prior to ConvertString",vMinutes)

Call VarAnalyzeMsg("Analyzing vSeconds prior to ConvertString",vSeconds)

' Return total seconds value

ConvertStringtoTotalSeconds = CInt(vHours) + CInt(vMinutes) + _

CInt(vSeconds)

Call VarAnalyzeMsg("Analyzing vHours after call to ConvertString",vHours)

Call VarAnalyzeMsg("Analyzing vMinutes after call to ConvertString", vMinutes)

Call VarAnalyzeMsg("Analyzing vSeconds after call to ConvertString", vSeconds)

NOTE

The source file for the Pace-Pal program modified to contain the change shown here is available on the accompanying CD-ROM in the file Ppalerr5.htm.

The modified Pace-Pal program with the VarAnalyzeMsg trace statement generates the output shown in Figure 12.14.

Figure 12.14 : Output from the variant variable analysis routine.

The txtDebug text box trace area is filled with meaningful trace information that can help you understand the behavior of the program. Although this trace facility might not be as powerful as the trace capabilities built into other languages, such as Visual Basic 4.0, it does give you ample power to get to the root of just about any VBScript-generated error.

Looking at More Reasons Why VBScript Can Be Tough to Debug

As if all these debugging challenges weren't enough, there are still a few more that haven't been discussed yet. It's important to be aware of these additional challenges-not so that you will spend sleepless nights worrying about them, but so that you will have a broad view of what to expect as you start to chase VBScript-related problems.

VBScript is what sometimes is called a glue language. It is great at gluing many components together to provide a powerful programmatic interface. You easily can weave a masterpiece of ActiveX controls, Java applets, intrinsic form controls, and OLE automation components into one tapestry when building your script. Opening the door to such easy integration of components, however, also opens the door to potential problems with them. A third-party control might have a bug in it. The Java applet provided by your coworker might be riddled with hideous errors in logic. The possibilities for problems are endless. And if your VBScript program incorporates those pieces, the problems will be visible to the user through your program. When such a problem occurs, the user considers it your script's problem. Then it falls to you, the debugger, to isolate areas of code to prove that a problem is caused by one specific component.

And now the good news that will save you from those sleepless nights: The very same skills discussed in this lesson that will help you hone in on VBScript errors also will help you hone in on component-related errors. You still need to trace through the program, isolating the problem to one specific area of the code. You still might need to display the value of variables, or even component property values, to monitor the state of the program before and after the statements related to the components that might be causing the errors. You still might need to break down one large VBScript statement involving components into a series of smaller statements to isolate the problem. In every case, the same tools and techniques already discussed still apply.

The Moral of the Story

The best advice to give for debugging and error handling is, "Don't make mistakes!" The outcome is no more probable than if you told the sun to rise in the north and set in the south, though. Mistakes are an inherent and unavoidable part of today's programming model. If you're a programmer, you will make plenty of them. A big part of the task of producing VBScript programs is getting out the bugs and making your programs shield the user from the bugs. The real moral of the story, then, is to apply these debugging, tracing, and error-handling techniques vigorously. Make use of debug tracing and variable analysis routines like those provided in this chapter. They will add efficiency and consistency to your debugging. Keep your eyes open for good debugging tools. VBScript debug tools currently are far behind those for Visual Basic 4.0, but this language is still in its infancy, and you can expect support to increase. For now, scripts may take longer to debug than programs in other languages due to the lack of tools. But with patience, strategy, and some of the techniques discussed in this chapter, your debugging sessions still can be highly effective.

Review

This chapter provided important debugging techniques that can be applied to syntax and semantic errors. Syntax errors and semantic errors, both caused by incorrectly specifying your programs, were defined-and examples of both were illustrated. This chapter also demonstrated how VBScript provides the means to turn off the automatic generation of runtime error messages to the user and prevent the subsequent script termination. Tracing techniques can also be helpful in analyzing all types of errors. The various tracing techniques were summarized in this chapter.

If you're doing a lot of debugging, you'll probably want an even more powerful debug repertoire. You can obtain this by building your own debug routines. This chapter supplied several strategies you can incorporate in your own Web pages to analyze and prevent errors from occurring. While VBScript does not have a powerful set of debug tools like Visual Basic 4.0 does, there is enough in the language to craft your own effective debugging approach. The most important tools, however, are the same ones you supply for any language you must debug-your own persistence and patience.

In Chapter 13, "Dynamic Web Page Building," you will learn how to use Internet Explorer's Document object to create Web

pages that dynamically alter the content of a Web page. You will also learn other techniques, such as writing the current date and time to a Web page, or dynamically changing the colors on a page. These techniques are very useful and helpful in VBScripting arsenal.