Running the Program Using the Debugger

Running the Program Using the Debugger

Let's debug our program and get an idea of the wealth of information available to us. First set the breakpoint shown in Figure 7-8, and then press F5 (or select Start from the Debug menu) to run the program so that it will enter the debugger. If you accidentally press Ctrl+F5 or select Start Without Debugging, breakpoints will be ignored.

When the program displays its main form, you can enter a number. Add 123 to the text box, and then click the Calculate button. Because we set a breakpoint inside this event procedure, we can start stepping through our code only at this point. If the Locals window is not displayed, select Debug | Windows | Locals. The Locals window for our program is shown in Figure 7-10. In the Locals window you can see the local variables and the values they contain so far. Arabics.GetLowerBound(0) is 0 and Arabics.GetUpperBound(0) is 12. If you click the plus sign beside either the Arabics or Romans array, the display is expanded to show each of the array's elements and their contents. You can also see that 123 was the value entered by examining the sInput string variable. Go ahead and click the plus signs and spend a few minutes examining the contents of these variables. You can discover what's happening in your program in the Locals window.

Figure 7-10

The Locals window.

You can even change the value of a variable in the Locals window to test the variable. For example, click the Value column of sInput and change the value to 444, as shown in Figure 7-11. You have just modified the value in memory, and the program will continue on with the new value.

Figure 7-11

You can dynamically change variables in the Locals window.

Stepping Through Our Code

You can step through your code using the Start, Break All, Stop Debugging, and Restart buttons on the Debug toolbar in the IDE. If the Debug toolbar, shown in Figure 7-12, is not displayed, right-click the main menu and be sure that the Debug and Debug Location choices are selected. The last three buttons are used for stepping through the code. These buttons are the ones that you'll use most often.

Figure 7-12

The Debug toolbar.

When you click the Start button, the program executes. Clicking the Stop Debugging button halts execution, terminates the program you are debugging, and ends the debugging session. Don't confuse stopping the debugging session with breaking execution, which just temporarily halts execution of the program you're debugging but leaves the debugging session active.

The Step Into button displays an arrow pointing to the next line of code. Use this button to step through lines one by one. (Pressing F8 performs the same operation as the Step Into button and eliminates a mouse click.) As you click the Step Into button, the variables will change in the Locals window as they are updated. You can see what your code is doing at each and every line of code.

The Step Over button shows an arrow pointing to the bottom of a code block. As the name implies, this button is used to step over sections of code. Let's say you have a function that returns a value. You know the function is completely debugged and not part of a problem you're trying to solve. You can use the Step Into button until you get to the line that calls the function. Then, by clicking the Step Over button, the code in the function executes but the debugger continues on as if this block were only a single line of executable code. So Step Into and Step Over differ only in one respect—the way they handle function calls. Each command instructs the debugger to execute the next unit of code. If the next unit contains a function call, Step Into executes only the call itself and then halts at the first unit of code inside the function. Step Over executes the entire function and halts at the first unit outside the function. Use Step Into if you want to look inside the function call. Use Step Over if you want to avoid stepping into functions.

The third step button is the Step Out button. Use the Step Out button when you're working inside a function call and want to return to the calling function. Step Out resumes execution of your code until the function returns and then breaks at the return point in the calling function.

You cannot access any of the step commands if your application is running. They are valid only in break mode or before you start the application.

Helpful Debugging Windows

For a more detailed inspection of your program, the Visual Studio .NET debugger provides a variety of windows and dialog boxes. Select Debug | Windows to select any of the windows described in Table 7-1. Set a breakpoint in the program and step through each line to get a feel for what information the various windows provide.

Table 7-1 The Debugging Windows

Use this debugging window

To view

Autos

Variables in the current and previous statement

Locals

All local variables

QuickWatch

Variables, register contents, and any valid expression recognized by the debugger

Watch

Variables, register contents, and any valid expression recognized by the debugger

Register

Register contents

Memory

Memory contents

Call Stack

Names of functions on the call stack, with the parameter types and values

Disassembly

Assembly code generated by the compiler for your program.

Threads

Information on sequential streams of execution (threads) created by your program

Modules

Modules (DLLs and EXEs) used in your program

Running Documents

List of script code loaded in the current process

Let's take a look in more detail at what some of these windows do for you and at some other details about the debugger.

Disassembly Window

In the Disassembly window you can see how the compiler distills your Visual Basic .NET code into assembly language. The simple assignment of an empty string to the text property of the lblResult label generates eight lines of assembly code, ending with the no operation (nop) line, as you can see in Figure 7-13.

Figure 7-13

The Disassembly window.

The Disassembly window is helpful to view on occasion to remind us of how high level Visual Basic .NET really is. (I remember taking assembly programming back in grad school and actually liking its cold, clear logic, which I'm sure is some sort of personality disorder. Assembly language was actually the first high-level language in which programmers could use meaningful symbols instead of 0s and 1s.) The compiler translates the assembler generated from Visual Basic syntax into the common intermediate language (IL) file that is passed to the CLR.

note

Bill Gates is said to often use the term no-op in meetings when he determines that a plan of action is not useful. He will say that this or that idea is a "no-op," referring to the assembly instruction meaning "no operation."

The Debugger Provides an Illusion to the Programmer

In case you're wondering how a program can run in debug mode, most CPUs actually have a special instruction set that is provided explicitly for the debugger. You set a breakpoint and can then step through your running program one line at a time. Single stepping allows the debugger to control the processor executing the program at such a fine level that only a single machine instruction at a time can be executed. After executing a single statement, the processor's debug mode returns control to the debugger program in Visual Basic .NET. The .NET debugger follows the Heisenberg Principle, which means that the debugger must intrude on the debugee program in a minimal way. In other words, we don't want to view our program as it acts when it is being debugged but how it acts during run time. (A great bumper sticker seen around town is "Heisenberg might have been here.")

In the previous section, we looked at the Disassembly window, which contains the assembly code for our program. The Visual Basic .NET compiler's job is to convert the source code into machine instructions. Behind the scenes, the debugger has the nontrivial task of mapping the machine code back to the original source code for us. Because it's the source code and not the machine code that the developer is interested in, the debugger is really a master of illusion. Because the Visual Basic .NET compiler provides extensive debugging information about the source code and how it was mapped to machine code, when we're debugging code it appears to us that it's the Visual Basic code that's executing line by line. In reality, the machine code is executing. However, by opening the various debugging windows, you can see the low-level detail that's taking place. The illusion that the debugger is executing the originally typed source code directly is compelling, but it is completely false. Pay no attention to the man behind the curtain.

If you examine the directory structure of your project, you can see that a Debug subdirectory is created automatically and populated for you, as shown in Figure 7-14. This folder contains the symbol maps that the debugger uses to provide its illusion.

Figure 7-14

Each project contains a Debug subdirectory.

Configuring Your Debugger

In the course of writing any program, you will run into particularly hairy errors that are tough to track down. You can configure the debugger to break on any error, even if the error is handled. For example, you might have a default Catch statement such as the last Catch statement in our example earlier in the chapter. You might decide not to display a message box or other visible indication that an error has occurred; you include the statement because you simply don't want to crash the system. Having errors occur in these situations is common, but because you are catching the errors you never know they've happened. Not knowing about these errors is another "gotcha" that can result in you spending hours looking for something that won't show up because you protected yourself and the errors are being masked.

Select Exceptions from the Debug menu to display the Exceptions dialog box, shown in Figure 7-15. This dialog box includes four main groups of exceptions: C++, CLR, Native Run Time Checks, and Win32. Each main category can be expanded to show the types of exceptions in each. If you are using only Visual Basic .NET, you need to look at only the CLR exceptions. However, if you have added some unmanaged code such as an ActiveX control to your program, you will also be interested in the Win32 exceptions.

Figure 7-15

The Exceptions dialog box.

Notice the two frames at the bottom of the dialog box. The options in the upper frame configure how the debugger works when an exception is thrown. These options tell the debugger how to handle an exception immediately after it is thrown but before the program you are debugging has a chance to handle it. The options in the lower frame configure how the debugger reacts when an exception is not handled. An exception of this sort occurs after the program you are debugging has tried to handle it and failed.

The option you choose in either frame affects the exception chosen in the Exceptions list. If you were working with a program that does calculations, you would be interested in a divide-by-zero error, for example. If a category is chosen, the option selected will affect all the exceptions in that category, in this case all divide-by-zero errors. Here's more information on each of these options.

  • Break Into The Debugger   Causes the debugger to break execution of your program so that you can examine everything and handle the exception yourself. When this option is selected, the icon next to the exception or category name changes from gray to a large red ball with an X on it.

  • Continue   Allows execution to continue. When this option is selected, the icon next to the exception or category name looks like a large gray ball. This option will permit your exception handler to handle the error.

  • Use Parent Setting    Causes a specific exception to use the setting chosen for the parent node, which would be either Break Into Debugger or Continue. When this option is selected, the icon next to the exception or category name looks like a small gray ball.

The Find button opens a dialog box that allows you to search for an exception name in the Exceptions list. Using the Find button saves you from having to open each individual tree to find the exception name you're looking for. The Find Next button is used to find another occurrence of the exception. The Add button permits you to add a new exception to a selected category. The Delete button removes a user-added exception, and the Clear All button deletes all user-added exceptions.

The QuickWatch Window

Another handy window is the QuickWatch window, shown in Figure 7-16. Simply highlight the variable you want to watch while the debugger is running and press Shift+F9 or select QuickWatch from the Debug menu. You can check the variable you select one time or click Add Watch and the variable will be added to a list of variables on your watch list. This feature is particularly useful for keeping an eye on loop counters or variables that change often under certain circumstances. You can actually see the contents as the program executes.

Figure 7-16

The QuickWatch window.

For more complicated programs, you'll find it useful to open several debugging windows simultaneously. Because the Locals window shows you all the local variables, the window can become crowded. If you want to keep tabs on a few specific variables, add them to your watch list, as shown in Figure 7-17. Then, if you need to look at the variables in your watch list, simply click the Watch tab at the bottom of the IDE. Using the watch list lets you isolate specific variables but quickly jump to any object in the entire running program.

Figure 7-17

The watch list.



Coding Techniques for Microsoft Visual Basic. NET
Coding Techniques for Microsoft Visual Basic .NET
ISBN: 0735612544
EAN: 2147483647
Year: 2002
Pages: 123
Authors: John Connell

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net