Using Visual Studio .NET to Debug Applications
Visual Studio .NET and the .NET Framework give you all the tools you need to debug your applications while you're designing them. In this section, you learn how to use the Debug object on the FCL. You also learn how to use all the output windows in Visual Studio .NET to track exactly what's happening to your application when it's running.
Understanding the Debug Class
The Debug class is specifically used to aid you in determining the runtime state of your code via user-defined output and alerts. At design time, you use the properties and methods of the Debug class to write debug code. The Debug class uses one or more listeners to output debug information to a stream. The default output stream in Visual Studio .NET is the Output window. So, for example, any time you use the Debug.Writeline method in a Windows Form or ASP.NET application, the data is sent to the Output window by default. If you want the stream to go somewhere other than the Output window, you can add a new listener to the Listener collection and direct the output elsewhere, such as an event log or a text file.
Note
The Debug class is found in the System.Diagnostics namespace.Note
Any code written using the Debug class shows up in the build only if the current build configuration is set to Debug. When the build configuration is set to Release, the compiler doesn't include the debug code in the built version.In Visual Basic 6, you used the Debug.Print statement all over your code to output specific information about variable values or message data. The Debug class takes this a step further and gives you a full range of capability for outputting debug information. Before we get into any code, let's examine the properties and methods of the Debug class as listed in Tables 7.2 and 7.3, respectively.Property | Description |
---|---|
AutoFlush | Gets or sets a value indicating whether Flush should be called on the listeners after every write |
IndentLevel | Gets or sets the indent level |
IndentSize | Gets or sets the number of spaces in an indent |
Listeners | Gets the collection of listeners that is monitoring the debug output |
Listing 7.4 Using the Debug Class to Output Debug Information

Private Sub Button3_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button3.Click
' Declare a generic variable for testing
Dim X As Integer = 5
' Create a new file stream
Dim fOut As Stream = File.Create("C:\ConsoleOutput.txt")
' Create a new listener using the file stream as the output
Dim textListener As New TextWriterTraceListener(fOut)
' Add the listener to the Listeners collection
Debug.Listeners.Add(textListener)
Debug.WriteLine("This is going to a text file")
' Increase the Indent level on the output by 1
Debug.Indent()
Debug.WriteLine(Date.Now)
Debug.WriteLine("The date was just sent to the file")
' Use the WriteLineIf to test for a value of False
Debug.WriteLineIf(X = 7, "X = 7")
' Use the WriteLineIf to test for a value of True
Debug.WriteLineIf(X = 5, "X = 5")
' Flush the listener out
textListener.Flush()
End Sub

private void button3_Click(object sender, System.EventArgs e)
{
int x = 5;
System.IO.Stream fOut = System.IO.File.Create(@"C:\csConsoleOut.txt");
System.Diagnostics.TextWriterTraceListener textListener = new
System.Diagnostics.TextWriterTraceListener(fOut);
System.Diagnostics.Debug.Listeners.Add(textListener);
System.Diagnostics.Debug.WriteLine("This is going to a text file");
System.Diagnostics.Debug.Indent();
System.Diagnostics.Debug.WriteLine(System.DateTime.Now);
System.Diagnostics.Debug.WriteLine
("The date was sent to the text file");
System.Diagnostics.Debug.WriteLineIf(x == 7, "X = 7");
System.Diagnostics.Debug.WriteLineIf(x == 5, "X = 5");
textListener.Flush();
}
Tip
The System.Diagnostics class is added to a new Visual Basic .NET project by default. If you create a C# project, you must add the using System.Diagnostics statement to avoid typing the fully qualified name as Listing 7.5 does.When you run the project, the default Output window displays the following:
This is going to a text file
7/21/2002 3:03:30 PM
The date was just sent to the file
X = 5
If you look at your C drive, you'll find the output text for the custom listener. Figure 7.6 shows what it should look like (other than the date and time being different).
Figure 7.6. Text file output of Listing 7.5.

So, to break down what happened in the code:
- execution of your application without having to use intrusive MessageBox.Show prompts or stopping code execution with breakpoints.
- Break Always
- Break when the hit count is equal to
- Break when the hit count is a multiple of
- Break when the hit count is greater than or equal to
- Name of the module (that is, .dll or .exe filename)
- Address in memory where the module is located (starts)
- Path of the module in the file system
- Order in which the modules were loaded
- Version number of the module that's loaded
- The ProgramID and name of the PE that owns the module
- Time that the module was created
- Whether or not debug information has been loaded for the module (symbols loaded means you can step through source code to debug; otherwise, you can only step through disassembly)
Using Breakpoints to Debug Code
Visual Studio .NET enables you to set predetermined points in your code that cause execution to stop so that you can examine the state of the application. Breakpoints stop your code only when you're running it in the Visual Studio .NET IDE; after the code is deployed, breakpoints are ignored.By default, a breakpoint stops executing code at the exact line at which it's set. The condition that causes the application to break can be set for a number of circumstances, which we look at in a second. Breakpoints can be set only on a line of executable code, which doesn't include empty lines or variable declarations that neither instantiate an object nor assign a value to the newly declared variable. You set breakpoints to examine what's going on with any running object in your code. They enable you to see what state variables are in, what information objects are holding, and what threads your application is running on. After you set a breakpoint and your code stops executing, you can modify certain variables to see how your code reactsthus minimizing that chance that errors will occur after your application is deployed.Breakpoints can be set in the following five ways:
- by a burgundy-colored line that spans the line. Figure 7.7 shows this in action.
Figure 7.7. Setting a breakpoint.

Breakpoints can also be either removed permanently, or disabled so that they don't break the running code but can be easily enabled at any time.To remove breakpoints, you can
Tip
If you haven't set a breakpoint, but still want to enter break mode, you canAfter you set a breakpoint, you might or might not want the code to break automaticallyyou might want to set some sort of condition. You can do so with the Breakpoint Properties dialog box, which you can open by right-clicking the breakpoint that you've set and selecting Properties from the contextual menu. By default, an enabled breakpoint always causes the application to break. Figure 7.8 shows the Breakpoint Properties dialog box.Figure 7.8. The Breakpoint Properties dialog box.

To set a condition for when the Breakpoint will break, use the Condition button or Hit Count button.
The Condition Button Details
Breakpoint conditions cause the execution to break only when the condition has been met. The condition can be any expression that can be evaluated in the current scope of the breakpoint. The condition is further evaluated for either being True or having changed since the breakpoint condition was last evaluated. When the expression or state condition is met, the breakpoint causes code execution to break on that line. Figure 7.9 is an example of setting a condition to break the code when the variable X is equal to 22. If the variable X never contains the value of 22, the condition is never met and the code execution never breaks.
Figure 7.9. Setting a condition for a breakpoint.

The Hit Count Button Details
In addition to (or instead of) specifying a condition that breaks execution, a breakpoint can be set to break only when the hit count expression is True. The expression must consist of one of the following options:
The Breakpoint Hit Count dialog enables you to set the expression and related value. Figure 7.10 shows a hit count condition being set.
Figure 7.10. Setting a hit count expression.

Effective use of breakpoints can accelerate debugging time because it allows your application to run normally and stop at the exact line of code (and with the proper conditions) that you're trying to debug. Therefore, time isn't wasted needlessly stepping through code and reviewing the state of every variable in the application. After you hit a breakpoint, you're in break mode, and you can use the Debug windows to examine the state of your application.
Using the Debug Windows in Break Mode
When your application hits a breakpoint, several very useful debug windows become available that enable you to view and update variables, run local methods, and evaluate expressions. Each of the Debug windows is available only while in break mode, and can be opened by selecting Debug, Windows from the main menu.
Note
When I refer to the current scope of the application in the following sections, it should be noted that, by default, the current scope is the line of executable code where the application entered break mode. Visual Studio .NET enables you to change the current scope at any time while in break mode to review application state at locations other than the scope of current execution.To change the current scope, simply set the program, thread, and stack frame values in the address toolbar. The Program list box displays all programs that are attached to the current debugger, the Thread list box displays all running threads for the program selected in the program list box (only one item for single-threaded applications). The Stack Frame list box displays the call stack for the thread selected in the Thread list box. When the current scope is changed to a location other than the current execution, the debugger highlights the last line that the application executed for that call stack in green. Otherwise, current execution code is highlighted in yellow by default. You can also change the current scope by using the Call Stack window.Now let's go through each of the Debug windows and describe how you can use each one to debug your application effectively.Using the Command Window
The Command window is perhaps the most valuable Debug window that Visual Studio .NET provides. The command window has two modes: command mode and immediate.When the Command window is in immediate mode, you can evaluate an expression, execute a statement, or print any variable's value in the current scope.By default, the command window is in command mode. To determine which mode the Command window is currently in, use the following table:
Caption | Command Prompt | |
---|---|---|
Command Mode | Command Window | > |
Immediate Mode | Command Window - Immediate | None |
Figure 7.11. Using the Command window.

Using the This/Me Window
The This/Me window enables you to view and modify data members of the object that's within the current scope. If code is currently being executed in something other than an object (BAS module in Visual Basic), the This/Me window is empty. The window is named This in C# and Me in Visual Basic.By double-clicking in the value cell of the data member, you can edit the current value of that member and it's changed for the existing execution scope. Figure 7.12 shows the Me window.
Figure 7.12. The Me window in action.

Using the Autos Window
The Autos window is similar to the This/Me window in that you can view and update application variables in the current scope. The difference is that the Autos window displays variables used in the current statement and the previous statement for C++ and C#, or the current statement and the three statements on either side of the current statement for Visual Basic. Only primitive values can be changed in the Autos window. Changing values is done in the same fashion as in the This/Me window: Double-click on the value cell of the variable to change and type the updated value.
Using the Locals Window
The Locals window is similar to the Autos window in every way except the variables that it displays. The Locals window displays all variables that are local to the current scope, whereas the Autos window displays a subset of those variables that appear around the current statement.
Using the Watch Window
The Watch window is similar to the Local and Autos window in its utility. Once again, the difference is in the variables it displays. By default, the Watch window doesn't display any variables. You're actually setting a variable or expression to watch. When a watch condition is met, the execution stops and your application enters break mode. Any variable or expression that you want to continuously review can be added to the Watch window by right-clicking on the item you want to add, and selecting Add Watch from the contextual menu. You may also type in the empty Name column of the Watch window to add your expression. To delete a watch, right-click on the watch to delete and click Delete Watch from the contextual menu, or select the watch to delete and press the Delete key.
Using the QuickWatch Dialog Box
The QuickWatch dialog box is similar to the Watch window, but is most useful in viewing or updating variable values only one time. By typing in the expression to evaluate and clicking Recalculate, you can view or change (primitives only) the value of the expression.
Using the Call Stack Window
The Call Stack window gives you a view into the call stack of the application. From this window, you can change the current scope of the application by double-clicking the item that you want to change to in the call stack, or by right-clicking the item and selecting Switch to Frame from the contextual menu.Another interesting capability of the Call Stack window is that you can right-click any item in the call stack, and select Run to Cursor from the contextual menu. Doing so runs the application until it gets to the point in the call stack at which you clicked. This capability makes it very easy to maneuver through the application when you're buried in the call stack.The information displayed in the Call Stack window can be turned on or off by right-clicking in the Call Stack window, and then choosing the appropriate column in the contextual menu to toggle. Your choices for the call stack are
Using the Disassembly Window
The Disassembly window displays the native assembler code of the current scope. For you hardcore programmers who like to know everything that's going on under the hood, the Disassembly window enables you to view processor-level commands for your application. Not only can you view your own code, but you can also view the assembly code running in your .NET debugger. The window enables you to show or hide information such as the memory address location relative to the beginning of the function, source code, code bytes (actual byte code used by the processor to execute the instruction), symbol names (associated with the memory address), and line numbers. The Disassembly window gives you the following functionality:
- the contextual menu.
Using the Threads Window
The Threads window displays information about all threads running in the debugger. Using this window, you can see which threads are running, their scheduling priority, and current state of the thread. By right-clicking in the Threads window and selecting Freeze, you can suspend activation of a running thread. You can also select Thaw on a suspended thread to resume normal activation. You can view the code associated with a thread by right-clicking on the thread and selecting Switch to Thread from the contextual menu. The Threads window is most useful when you're debugging multithreaded applications.
Using the Modules Window
The Modules window displays information regarding all currently loaded program files. The information displayed is
In addition to the information in the preceding list, the Modules window can be used to tune your application's performance. A module that appears in the Modules window with a red exclamation point and asterisk next to it has been loaded at a relocated base address because another module was already using its base address space. When this occurs, the processor must spend extra clock cycles to point itself to the adjusted address, which causes decreased performance. When this occurs, consider changing the base address of the module that has been relocated.Now that you understand what the Debug windows can offer you on your road to perfect code, let's take a look at how you can step through code after you're actually in break mode.
Stepping Through Code
While in break mode, the Visual Studio .NET IDE enables you to step through the code to see the actual execution path through the application. This is extremely useful because it gives you a chance to check for logic errors and view variable contents throughout execution. To step though code, you can use the Debugging toolbar shown in Figure 7.13, or you can right-click anywhere in the code window and select any of the options discussed next.
Figure 7.13. The Debugging toolbar.

Step Into
While stepping through code, it will eventually happen that the next line of executable code is a property or method call. When you reach this point using the Step Into option, the debugger goes into the property or method call that's called.
Step Over
If you want to ignore what code is running inside a property or method call, it's useful to Step Over the call. In this way, the code that's called is run normally, and you re-enter break mode when execution gets to the next line of code after the call that you stepped over.
Step Out
If you find yourself in a property or method call that you don't care to be in and don't want to step through each line of code to get out, use Step Out. Doing so causes the application to execute normally, and re-enter break mode on the next line of code after the call of the property or method that you were in when you stepped out.
Run to Cursor
Run to Cursor enables you to choose a position at some point ahead of the current line of execution at which the application should re-enter break mode. That is to say, the application executes normally until it reaches the point of execution.
Set Next Statement
Sometimes you might find that you don't want to follow the standard execution path of the application. Perhaps you want to go back in the code execution or skip a line. This can be done by using Set Next Statement.
Continue
Continue enables you to exit break mode and execute the rest of the application as normal (until break mode is re-entered later).
Stop Debugging
Use Stop Debugging to end the debug session as well as close the application. When this occurs, the application stops, and the IDE is now in design time.
Restart
While in break mode, you can stop and restart the application. On restart, the application enters break mode at the first line of executable code in your application.
Detach All
Detach All detaches the debugger from all running threads currently used by the debugger. That means the threads continue to run as normal, without the use of the debugger.
Hovering
The debugger also enables you to view values of expressions and object types by hovering the cursor over the selected code. For example, if you have a local variable, i, whose value is 10, you can hover the cursor over the i and view the contents (i = 10). You can also highlight a line of code, say i = 50, and view the results of the expression (i = 50 = False). By hovering over objects, you can view the type name of the object or view the function prototype of procedure calls.
Edit and Continue - Not Supported
For those programmers familiar with Visual Basic 6.0 (and earlier), it will come as sad news to discover that Visual Studio .NET doesn't support the capability to edit and continue. Code can no longer be changed while the debugger is in break mode, and execute as normal using the newly entered code. You can change code while in break mode, but an attempt to run the code any further results in a dialog box that asks whether you want to restart the application.
Keyboard Shortcuts Visual Studio and Visual Basic Versions
Table 7.4 gives you an idea of what shortcuts are available in Visual Basic .NET and C#, and how they compare to Visual Basic 6 debugging shortcuts.
Keyboard Shortcut Layouts | Debug Menu | Context Menu | ||
---|---|---|---|---|
Default | VB6 | |||
Continue | F5 | F5 | Continue | |
Break All | Ctrl+Alt+Break | Ctrl+Break | Break All | |
Stop Debugging | Shift+F5 | Stop Debugging | ||
Restart | Ctrl+Shift+F5 | Shift+F5 | Restart | |
Detach All | Detach All | |||
Step Into | F11 | F8 | Step Into | |
Step Over | F10 | Shift F8 | Step Over | |
Step Out | Shift+F11 | Ctrl+Shift+F8 | Step Out | |
Run to Cursor | Run to Cursor | |||
Set Next Statement | Set Next Statement |