Creating a Debugger Visualizer Using Visual Studio 2005 Beta 2
Updated April 2005
Summary: This article describes how to create a visualizer, using the Visual Studio 2005 Beta 2 release, which enables you to customize the way data is displayed when you are debugging through managed code. (7 printed pages)
Microsoft Visual Studio 2005 Beta 2; C#, Visual Basic, J#
Creating a Simple Visualizer
Adding Some Useful Code
Testing the Visualizer
Installing the Visualizer
Using the Visualizer
Visual Studio IDE Support
Debugger visualizers enable advanced, customized data display while you are running your application under the Visual Studio Debugger. Today's data windows have their limitations; they are text-only, hierarchical, and spatially constrained. They are not the best way to view an image, for example. Visualizers enable you to create completely custom views using Windows Forms to best show the data within any managed object.
A visualizer is associated with a particular type. Whenever a variable of that type is included in a data window like the Watch window (as shown in Figure 1) or DataTips, a little magnifying glass will be shown next to its entry.
Figure 1. The magnifying glass visualizer button in the Watch window
Multiple visualizers can be associated with one type, and a visualizer can be associated with multiple types. A class derived from a class with visualizers associated with it will inherit those associations, but visualizers cannot be associated with interfaces.
A debugger and the application being debugged are two separate processes. Because of that, a visualizer runs in two separate places: within the debugger, and also within the program being debugged itself. The visualizer infrastructure provides System.IO.Streams through which these two components communicate.
All data to be visualized must be serialized to System.IO.Streams to be transported between the program being debugged and the visualization code on the debugger side. To simplify things, Microsoft.VisualStudio.DebuggerVisualizers.dll provides a class called VisualizerObjectSource that does the most basic type of serialization for you. It serializes the entire object, making it easy to extract on the debugger side. This requires that the object in question have the Serializable attribute.
Performance will suffer as large classes are visualized using this method, so it is recommended to develop some sort of on-demand communication mechanism beyond the default monolithic implementation. For example, a List visualizer might only transfer the elements initially in view. Once the user scrolls, the visualizer could request the data necessary to draw the new view.
Once the data has reached the debugger side, it needs to be shown to the user somehow, preferably graphically. Additionally, the visualizer interfaces provide the capability to change the original object, enabling visualizers to be sophisticated run-time editors as well as viewers.
The following basic example shows how to use one simple class beyond the default VisualizerObjectSource object to show a string in an exceedingly simple message box.
Note There is a possibility that visualizers may change in some minor ways after Beta 2. You can submit feedback about this article and Visual Studio 2005 Beta 2 at http://lab.msdn.microsoft.com/productfeedback/.
- First, create a new Class Library Project, named FirstVisualizer. To start off, you'll want to add a reference to the assembly containing the visualizer interfaces. Right-click on the project name, and select Add Reference. In the Add Reference dialog box, on the .NET tab, scroll down and select Microsoft.VisualStudio.DebuggerVisualizers.
- Next, open the auto-generated Class1.cs file. In the Solution Explorer tool window, right-click on Class1.cs, and rename it to DebuggerSide.cs. Note that the IDE asks you if you would like to rename the class along with the file name. DebuggerSide is an appropriate name because this is the class that is loaded into Visual Studio to do the actual data display.
- Now add
using Microsoft.VisualStudio.DebuggerVisualizers;to the set of using statements at the top of the file.
- Next type
class DebuggerSideto derive from the DialogDebuggerVisualizer base class defined in Microsoft.VisualStudio.DebuggerVisualizers.
- Click on
DialogDebuggerVisualizer. A small glyph, or SmartTag, is displayed under the 'D' as shown in Figure 2.
Figure 2. The SmartTag enables you to tell the IDE exactly when to auto-generate method stubs.
- Hover over the SmartTag, click on the resulting larger icon, and select to implement the abstract class from the menu. The IDE auto-generates the appropriate stubs to implement the simple abstract class DialogDebuggerVisualizer.
protected override void Show
(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
The Show method you now see in the code is what is called when you click to see the visualizer while debugging.
- Add System.Windows.Forms to your references. This visualizer needs to put up some sort of window to show the data. To make it easy to use classes from the System.Windows.Forms namespace, add
using System.Windows.Formsat the top of the file.
- Now change the line reading
throw new Exception("The method or operation is not implemented.");
MessageBox.Show(objectProvider.GetObject().ToString());, which of course lacks necessary error-checking for possible nulls. This line pulls the entire original object out of the stream using the provided GetObject method. The GetObject method is a perfect companion to the default
As a reference, here are some in-depth descriptions of the Show method's parameters:
windowService: This interface is used to provide information specific to the type of user interface this visualizer is to display. Because this visualizer is derived from DialogDebuggerVisualizer, the user interface is of the modal dialog form. This is the only type of visualizer user interface supported by Visual Studio 2005.
- IVisualizerObjectProvider objectProvider: The interface through which access is given to streams populated by and sent to the debugged program-side class. Some helper functions beyond simple stream access are provided as well, like
The classes for the visualizer have been created. Now Visual Studio needs to be told about the new visualizer. A number of debugging-related attributes have been added for Visual Studio 2005 that will allow you to customize your debugging experience. DebuggerVisualizer is the only one involved in the creation of debugger visualizers.
- Copy the following code into DebuggeeSide.cs:
[assembly:System.Diagnostics.DebuggerVisualizer( typeof(FirstVisualizer.DebuggerSide), Target = typeof(System.String), Description = "My First Visualizer")]
The above DebuggerVisualizerAttribute tells the debugger about the collection of classes that make up the visualizer. As a reference, its parameters are described in detail here:
- System.Type visualizer: The type of the debugger-side class, which is responsible for catching the data thrown to it by the debugged program-side class and showing it in a meaningful way.
- System.Type Target (named parameter): This specifies the type this visualizer will visualize. Normally this is specified by putting the attribute directly on the target class. This named parameter allows the attribute to be used without the need for access to the source of the target class.
- string Description (named parameter): This is the text shown in the drop-down list in the Watch window. It is specified using the attribute to avoid loading any visualizer code before the user actually invokes it.
Other constructors of this attribute enable you to specify your own debugged program-side class instead of the default VisualizerObjectSource class, or to specify types in string form.
- Testing a visualizer takes some effort due to the fact that it is hosted within Visual Studio. You must either launch a second Visual Studio instance under the debugger, or start a second instance and then attach. VisualizerDevelopmentHost was developed to remove this hassle from the visualizer development process — it replicates the way Visual Studio loads visualizers directly in your test application.
- Right-click on your current solution in Visual Studio, point to Add, click New Project, and add a Console Application project. Right-click the new project, and then click Set as StartUp Project.
- Right-click your project or its References node, and click Add Reference to add a reference to your visualizer project. Your FirstVisualizer project should be listed under the Projects tab of the Add Reference dialog.
- On the .NET tab of the Add Reference dialog box, select Microsoft.VisualStudio.DebuggerVisualizers.
- Add a
using Microsoft.VisualStudio.DebuggerVisualizersstatement to the top of the file, as done in the FirstVisualizer project.
- Create a local string variable testString and initialize it to some interesting value.
- Copy this code after your
VisualizerDevelopmentHost host = new VisualizerDevelopmentHost( testString, typeof(FirstVisualizer.DebuggerSide)); host.ShowVisualizer();
- The constructor of VisualizerDevelopmentHost mirrors the constructors of the DebuggerVisualizer attribute. You are now able to step into your visualizer as you would any other application you create with Visual Studio.
- Build the solution.
- The newly-built class library needs to be copied to a location where Visual Studio looks for visualizers. Copy the DLL to:
- <VS Install Dir>\Common7\Packages\Debugger\Visualizers
Here you'll see Microsoft.VisualStudio.Debugger.DataSetVisualizer.dll, the dataset visualizer provided by default. Visualizers put here will be available to all users on the machine.
- My Documents\Visual Studio\Visualizers
Putting your DLL here will install the visualizer for the current user only.
- <VS Install Dir>\Common7\Packages\Debugger\Visualizers
Right-click your current solution in Visual Studio, point to Add, click New Project, and add a Console or Windows Application project. Make sure it is the Startup Project, add some code that uses a string, set a breakpoint there, and press F5.
Figure 3. "My First Visualizer" is included in the visualizer drop-down list for the string type.
Now the list of visualizers available for strings should include your new visualizer, shown with whatever you put for the Description field in the DebuggerVisualizer attribute.
Figure 4. "My First Visualizer" puts up a simple message box
When you invoke the visualizer, a message box pops up with the contents of the string in it.
Visual Studio includes a project item that can easily set up everything that has been discussed in this article. Right-click your C# project, point to Add, click New Item, then find Debugger Visualizer in the list. A file will be added to your project containing a class that can easily be customized to visualize one of your classes. It contains comprehensive inline comment documentation to help you in that quest.
This item is currently only available for C# projects, though visualizers can be written in any managed language.
Now that you understand the general idea behind visualizers and the overall process of creating one, the possibilities are endless. You can easily build on top of these steps to create more advanced, useful visualizers.