After completing this topic, you should be able to identify key debugging enhancements in Visual Studio 2005.
Visual Studio 2005 includes enhanced debugging features to enable easy, secure, and flexible debugging of code.
It supports debugging of 32-bit and 64-bit managed and unmanaged applications. It also supports remote debugging of code on any platform compatible with Visual Studio.
Visual Studio 2005 uses the new Microsoft Build Engine (MSBuild) as its build system. This system differs from the system used in previous versions of Visual Studio in that it's written using managed code and is built into .NET Framework 2.0. As a result, it no longer requires installation of Visual Studio.
The new build system makes it easier to customize build processes, and to debug code across platforms.
New features of the Visual Studio 2005 debugger that make it easier to debug code include
DebuggerNonUserCodeAttribute
– to identify system-created code that the debugger must step throughDebuggerStepThroughAttribute
– to identify code that the debugger must step through, but that may contain breakpointsDebuggerHiddenAttribute
– to hide code from the debugger completely, even when the Just My Code feature is disabledTrace
feature for similar purposes, but tracepoints don't require that you make changes to the source code. Tracepoints run only under the debugger.Suppose you want to prevent the Visual Studio 2005 debugger from displaying a section of code which you already know functions correctly. To do this, you've already enabled the Just My Code debugging feature. You then need to define the code as system – rather than user-created – code.
Which attribute do you use to do this?
Options:
You use DebuggerNonUserCodeAttribute
to identify system code, which won't display if the Just My Code feature is enabled.
Option 1 is incorrect. You use DebuggerHiddenAttribute
to identify code that must be hidden from the debugger, even if the Just My Code feature is disabled.
Option 2 is correct. You use DebuggerNonUserCodeAttribute
to identify system-created code. With the Just My Code feature enabled, the debugger will step through this code rather than displaying it, unless the code contains an error it detects.
Option 3 is incorrect. You use DebuggerStepThroughAttribute
to identify code that the debugger must step through, but that may include breakpoints. This attribute doesn't specifically identify the code as non-user code.
Suppose an application you're designing includes a dialog box that contains a Calculate button. To debug the code for the button in Visual Studio 2005, you simply start debugging and then click the button you want to test. The Exception Assistant will then alert you to any errors in the code.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int a;
int b;
int c;
a = 5;
b = 0;
c = a / b;
}
}
}
First you start the debugging process from the code window.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int a;
int b;
int c;
a = 5;
b = 0;
c = a / b;
}
}
}
You select Debug - Start Debugging.
Alternatively, you press Alt+D, S.
The debugging process opens the dialog box that you've designed the source code to create.
To check the code for the Calculate button, you click this button.
The debugger checks the code for the button. When an exception occurs, the Exception Assistant highlights the cause of the problem in the script and provides information about the exception. You can now alter the script to fix the problem and try debugging again.
private void button1_Click(object sender, EventArgs e)
{
int a;
int b;
int c;
a = 5;
b = 0;
c = a / b;
}
}
}
Now suppose you need to be able to alter the value specified in a line of code when you debug the code. To enable you to do this, you've added a breakpoint to the appropriate line.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 90000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You begin debugging the code by clicking the Play button on the toolbar.
The debugger advances through the code until it reaches the breakpoint, which pauses execution.
You can now select the code you want to change and then alter it, before resuming the debugging process.
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 90000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You select 90000
in the code, type 85000
to replace this value, and click the Play button on the toolbar to resume debugging.
Debugging of the code, which now includes the changes you've made, continues until a new breakpoint is encountered.
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
The process completes without any errors, and Visual Studio 2005 opens the form you created for the code. You have now used the Edit and Continue feature to modify code without having to exit the debugging process.
Next suppose the values in your source code must depend on the result of another process. You therefore want to attach the other process to the debugger for the application.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You select Debug - Attach to Process.
Alternatively, you press Alt+D, P.
The Attach to Process dialog box lists available processes you can set the debugger to attach to the source code.
You select the required process and click Attach.
This returns you to the source code.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You continue debugging the active application, and it pauses at the breakpoint in the script. You now want to check for processes to which the application is attached.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You select Debug - Windows - Processes.
Alternatively, you press Alt+D, W, P.
The Processes window now lists details of the processes attached to the application.
Using the icons in this window, you can set the active process, detach processes, or break execution of a process for debugging.
To set the debugger windows to show only user-created code, you first select Tools - Options to open the Options dialog box.
The Options dialog box includes a tree pane, which enables you to access option settings in different categories. A settings pane displays settings in the selected category.
You scroll down, access general debugging settings, and then enable the Just My Code feature.
You expand the Debugging node, select General, and then select the Enable Just My Code checkbox from the list of general debugging options that displays in the settings pane, and click OK.
You have now enabled the Just My Code feature. During debugging, debugging windows will now display only user-created code.
You are running a program that organizes quarterly sales figures for January through April. You want to attach the program to another managed process, named validate.exe, for validation purposes.
How do you attach the program to the validate.exe process and then open the Process window to check that the attachment succeeded?
Options:
To attach the process and then open the Process window to verify the attachment, you select Debug - Attach to Process, select validate.exe from the Available Processes list, click the Attach button, and select Debug - Windows - Processes.
Alternatively, you press Alt+D, P to open the Attach to Process dialog box and Alt+D, W, P to open the Process window.
Visualizers provide a new way of exploring what particular variables contain by creating a more appropriate interface. They provide a type-specific alternate view of objects or variables, based on their data type, and allow the user to interact with the Debugger. Visual Studio 2005 has four new standard visualizers – a DataSet visualizer that shows DataSets in a grid, an XML visualizer, a text visualizer, and an HTML visualizer.
The XML, HTML, and text visualizers refer to string variables. If a string supports multiple visualizers, you can select which to use.
In addition to providing standard visualizers, Visual Studio 2005 enables you to create your own, custom visualizers.
To do this, you need to
Microsoft.VisualStudio.DebuggerVisualizers.DLL
and then import the referenceDialogDebuggerVisualizer
base classShow
method to specify how the visualizer's user interface must displayThe code for a visualizer you create needs to be in the form of a DLL file so that the debugger can read it. So to begin, you create a new C# class library project, in this case named MyVisualizer2
. The Class1.cs page for the new project opens automatically.
using System;
using System.Collections.Generic;
using System.Text;
namespace MyVisualizer2
{
public class Class1
{
}
}
Using the Solution Explorer, you rename the Class1.cs file as DebugSide.cs
.
Next you need to create a reference to the Microsoft.VisualStudio.DebuggerVisualizers.DLL
file, so that you can use the classes defined in it. To access the References folder for the project, however, you first need to set the Solution Explorer to list all of the project's components.
You click the Show All icon.
All files and folders for the project, including a References folder, are now listed.
To begin creating the required reference, you right-click the References folder and select Add Reference.
In the Add Reference dialog box, you scroll down the list of component names, select Microsoft.VisualStudio.DebuggerVisualizers.DLL, and click OK.
This adds the reference to the expanded References folder.
You then use a using
statement to import the reference into your code.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.DebuggerVisualizers;
namespace MyVisualizer2
{
public class DebugSide
{
}
}
Next you specify the base class – in this case DialogDebuggerVisualizer
– from which the DebugSide
class you've created must inherit methods.
You then override the Show
method for the DialogDebuggerVisualizer
class, and add the required Show
method for the visualizer you're creating. This method creates the visualizer interface and enables it to display information.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.DebuggerVisualizers;
namespace MyVisualizer2
{
public class DebugSide : DialogDebuggerVisualizer
{
protected override void Show(
IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider) { }
}
}
You now need to create the dialog box in which the visualizer will display data. You decide to use a Windows Forms message box for this purpose, so you need to create a reference to the System.Windows.Forms
class. To enable you to do this, you open the Add Reference dialog box using the Solution Explorer.
You add the System.Windows.Forms
reference to the References folder in the Solution Explorer.
You select System.Windows.Forms and click OK.
You have successfully added the System.Windows.Forms
reference to the References folder.
You use a using
statement to import the reference in the code.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Windows.Forms;
namespace MyVisualizer2
{
public class DebugSide : DialogDebuggerVisualizer
{
protected override void Show(
IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider) { }
}
}
You now need to add code to tell Visual Studio how you want the interface for the visualizer to look and act. To do this, you use a MessageBox.Show
method.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Windows.Forms;
namespace MyVisualizer2
{
public class DebugSide : DialogDebuggerVisualizer
{
protected override void Show(
IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider)
{
MessageBox.Show(objectProvider.GetObject().ToString());
}
}
}
To check for any build errors in the code you've written, you select Build - Build MyVisualizer2.
No build errors occurred, and you can now return to the code. You need to add code that will tell the debugger side – the side where users work – which classes make up the visualizer.
To inform Visual Studio of the classes your visualizer will use and identify their source, you add an Assembly
attribute prior to the DebugSide
class definition.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Windows.Forms;
[assembly: System.Diagnostics.DebuggerVisualizer(
typeof(MyVisualizer2.DebugSide),
typeof(VisualizerObjectSource),
Target=typeof(System.String),
Description="My First Visualizer")]
namespace MyVisualizer2
{
public class DebugSide : DialogDebuggerVisualizer
{
protected override void Show(
IDialogVisualizerService windowService,
IVisualizerObjectProvider objectProvider)
{
MessageBox.Show(objectProvider.GetObject().ToString());
}
}
}
You have now created a visualizer, which you can test and then install in Visual Studio 2005.
Suppose you want to create a custom visualizer in Visual Studio 2005.
Place the steps you perform to do this in the correct order.
Option | Description |
---|---|
A | Identify the debugger-side classes that the visualizer must use |
B | Open a new class library project file |
C | Reference Microsoft.VisualStudio.DebuggerVisualizers.DLL
|
D | Set debugger-side code to inherit from the DialogDebuggerVisualizer base class
|
E | Use a Show method to specify how the visualizer must display
|
Option | Description |
---|---|
B | Open a new class library project file
To read the code for a visualizer, the debugger requires that it be stored in a DLL file. To create a visualizer, you therefore start by creating a class library project file, which uses this format. |
C | Reference Microsoft.VisualStudio.DebuggerVisualizers.DLL
Once you've opened a new class library project file, you create a reference to Microsoft.VisualStudio.DebuggerVisualizers.DLL and import the reference, so that the visualizer you create can use the classes it contains. |
D | Set debugger-side code to inherit from the DialogDebuggerVisualizer base class
Once you've referenced Microsoft.VisualStudio.DebuggerVisualizers.DLL , you need to specify the base class from which the visualizer you're creating must inherit methods and properties. |
E | Use a Show method to specify how the visualizer must display
After referencing the required classes, you override the Show method in the base class and then add a new Show method to specify how the user interface for the new visualizer must display. |
A | Identify the debugger-side classes that the visualizer must use
Finally, you need to specify which classes – in addition to the base class you've already referenced – the debugger side of the visualizer you're creating must use. Once you've done this, you can create a test harness and then test the visualizer before installing it in Visual Studio 2005. |
The DataTips feature in Visual Studio 2005 now provides a view of important properties and attributes while in break mode. You can view and edit these properties and attributes using the source editor in which you type your code.
You can't, however, edit read-only files using the DataTips feature.
Suppose you have an application in break mode and you want to use the DataTips feature to
check the type of visualizer being used for an entryedit a value
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You decide to check the e1
variable in the code. You hover your cursor over e1
, and a small DataTip displays.
When you move your cursor over the + (plus sign) icon, an extension of the entry displays to list the attributes of the e1
code item.
You now want to check the visualizer that the code Ben Stoller
is using.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You click the magnifying glass icon alongside the name entry in the DataTip, and a drop-down list of visualizers displays. A tick indicates the visualizer currently in use.
If the entry had been using the incorrect visualizer, you could have changed it easily by selecting the correct visualizer.
Next you want to use the DataTip to change the salary value assigned to the e1
variable from 57,000 to 90,000. To do this, you simply select the salary value in the DataTip and then type the new, required value.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
You type 90000.
You have now successfully used the new extended DataTips feature to edit an entry's attributes while in break mode.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//Application.EnableVisualStyles()
Employee e1 = new Employee("Ben Stiller", 57000);
Employee e2 = new Employee("Big Foot", 85000);
Employee e3 = new Employee("Tucan Sam", 87000);
}
}
}
While in break mode, you decide to edit multiple entries using the extended DataTips feature. However, entries you select don't have extended DataTips associated with them.
Why would some entries not have extended DataTips?
Options:
To use the extended DataTips feature on a data type, the data type must be complex and cannot be read-only.
Option 1 is incorrect. Complex data entries aren't separate files but object types of data with multiple properties and attributes.
Option 2 is incorrect. Visualizers provide a type-specific alternate view of objects or variables, based on their data type. However, the visualizer that an entry uses doesn't affect the DataTips feature.
Option 3 is correct. You cannot use the extended DataTips feature to edit files that are read-only.
Option 4 is correct. You can edit only complex data types – types with multiple properties – using the DataTips feature.
Suppose you want to change the price property of the p1
variable, which represents a complex data type, to 75.
What steps do you perform to do this?
Options:
To change the price value for the p1
DataTip, you click the + sign, click the price entry, type 75
, and press Enter twice.
Debugger display attributes enable you to specify what a type you've created will look like when displayed in a debugger.
A type class represents type declarations, and is the primary way to access metadata. You use the members of a type to find information about a type declaration. A type is an abstract base class that allows multiple implementations.
C# 2005 offers three attributes that you can use to alter how a type displays:
DebuggerDisplay
DebuggerTypeProxy
DebuggerBrowsable
The DebuggerDisplay
attribute resides in the System.Diagnostics
namespace, and can be used to control how a type or member is displayed in the debugger variable windows. It is applied at class level and the members can be private or public.
The DebuggerDisplay
constructor only has a single argument – a string that is displayed in the value column when the type occurs.
The string can contain brackets – round or curly – and the text within a pair is assumed to be the name of a property, method, or field. It is evaluated as an expression.
Suppose you want to structure the DebuggerDisplay
attribute so that you can examine numerator and denominator properties. To do this, you reference the attribute in the code.
[MISSING CODE("Value = {Numerator} / {Denominator}")]
class Fraction
{
private int m_Numerator;
private int m_Denominator;
public int Numerator
{
get
{
return m_Numerator;
}
set
{
m_Numerator = value;
}
}
public int Denominator
{
get
{
return m_Denominator;
}
set
{
m_Denominator = value;
You type DebuggerDisplay
to complete the code.
You have set DebuggerDisplay
attribute for the Fraction
class.
[DebuggerDisplay("Value = {Numerator} / {Denominator}")]
class Fraction
{
private int m_Numerator;
private int m_Denominator;
public int Numerator
{
get
{
return m_Numerator;
}
set
{
m_Numerator = value;
}
}
public int Denominator
{
get
{
return m_Denominator;
}
set
{
m_Denominator = value;
When you debug instances of the class, the Debug
ger
Display
attribute determines the output shown in the Watch window and when the mouse is hovered over instances. In this case, you have used the attribute to reveal the values of the testfraction
type's properties.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Fraction testfraction = new Fraction();
testfraction.Denominator = 20;
testfraction.Numerator = 5;
}
}
Selecting the link title opens the resource in a new browser window.
View a full example of code that uses the DebuggerDisplay
attribute.
The DebuggerTypeProxy
attribute is similar to the DebuggerDisplay
attribute but enables you to change the view of the type without changing the type itself. To do this, you specify a display proxy to use when debugging the type.
The input parameter for the DebuggerTypeProxy
constructor specifies the proxy to use.
[DebuggerTypeProxy(typeof(Fraction.Check))]
public class Fraction
{
private int m_Numerator;
private int m_Denominator;
public int Numerator
{
get
{
return m_Numerator;
}
set
{
m_Numerator = value;
}
}
public int Denominator
{
get
{
return m_Denominator;
}
set
{
m_Denominator = value;
}
The debugger variable window displays only the public members of the DebuggerTypeProxy
proxy class.
private void Form1_Load(object sender, EventArgs e)
{
Fraction testfraction = new Fraction();
testfraction.Denominator = 20;
testfraction.Numerator = 5;
}
}
}
The DebuggerTypeProxy
attribute can be used at the assembly level. At this level, you use its Target property to specify the type to which the proxy must apply.
Selecting the link title opens the resource in a new browser window.
View a full example of code that uses the DebuggerTypeProxy
attribute.
If a field or property is to be displayed in the Debugger variable windows, the DebuggerBrowsable
attribute is used to determine how it will appear.
The DebuggerBrowsableState
enumeration is used when utilizing this attribute, which has the following values:Never
, meaning the field or property the attribute is applied to is not displayed.Collapsed
, meaning the field or property the attribute is applied to is shown in a minimized displayRootHidden
, meaning only the child objects of the field or property the attribute is applied to are shown.
using System.Collections
public class AttClass
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public int myInt = 5;
[DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
public Stack myFirstStack;
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public Stack mySecondStack;
//...
}
While working in Visual Studio 2005, you decide to change how the application displays a type, but without changing the characteristics of the type itself.
Which attribute do you use to do this?
Options:
You use the DebuggerTypeProxy
attribute to change the display properties of a type, without changing the type itself.
Option 1 is incorrect. The DebuggerDisplay
determines how a type or member is displayed in the debugger variable window. The constructor contains a single argument in the form of a string, and the text within the string is assumed to be the instance name of the type.
Option 2 is incorrect. The DebuggerHidden
attribute is used to hide code from the debugger, even when the Just My Code feature is disabled.
Option 3 is incorrect. You would use the DebuggerStepThrough
attribute to tell the debugger to step through certain code to the next set of code relevant to you.
Option 4 is correct. The DebuggerTypeProxy
attribute enables you to change the view for a type by specifying its display proxy, without altering the type in any way.
Enhanced debugging features of Visual Studio 2005 include the Exception Assistant, the Edit and Continue feature, the Just My Code feature, the introduction of tracepoints, and support for multiprocess debugging.
Visual Studio 2005 provides four new standard visualizers – a DataSet visualizer that shows DataSets in a grid, an XML visualizer, a text visualizer, and an HTML visualizer. It also enables you to create custom visualizers.
The extended DataTips feature enables you to edit the properties of complex data types while in break mode.
Debugger display attributes – DebuggerDisplay,
DebuggerTypeProxy
and DebuggerBrowsable
– enable you to specify how the debugger variable windows must display types.
| Top of page |
| 1. Enhanced debugging features |
| 3. Using the DataTips feature |
| 4. Setting debugger display attributes |
| Summary |
Copyright © 2006 SkillSoft. All rights reserved.
SkillSoft and the SkillSoft logo are trademarks or registered trademarks
of SkillSoft in the United States and certain other countries.
All other logos or trademarks are the property of their respective owners.