Creating a Debugger Visualizer Using Visual Studio 2005 Beta 2

 

Scott Nonnenberg
Visual C#
Microsoft Corporation

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)

Applies to:
   Microsoft Visual Studio 2005 Beta 2; C#, Visual Basic, J#

Contents

Introduction
Architecture
Creating a Simple Visualizer
Adding Some Useful Code
System.Diagnostics.DebuggerVisualizerAttribute
Testing the Visualizer
Installing the Visualizer
Using the Visualizer
Visual Studio IDE Support
Conclusion

Introduction

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.

ms379596.simplevisualizercreation-fig1(en-US,VS.80).gif

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.

Architecture

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 https://lab.msdn.microsoft.com/productfeedback/.

Creating a Simple Visualizer

  1. 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.
  2. 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.

Adding Some Useful Code

  1. Now add using Microsoft.VisualStudio.DebuggerVisualizers; to the set of using statements at the top of the file.

  2. Next type DialogDebuggerVisualizer after class DebuggerSide to derive from the DialogDebuggerVisualizer base class defined in Microsoft.VisualStudio.DebuggerVisualizers.

  3. Click on DialogDebuggerVisualizer. A small glyph, or SmartTag, is displayed under the 'D' as shown in Figure 2.

    ms379596.simplevisualizercreation-fig2(en-US,VS.80).gif

    Figure 2. The SmartTag enables you to tell the IDE exactly when to auto-generate method stubs.

  4. 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.

  5. 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.Forms at the top of the file.

  6. Now change the line reading throw new Exception("The method or operation is not implemented."); to 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 VisualizerObjectSource on the other side in that it assumes the entire object has been serialized into the stream.

    As a reference, here are some in-depth descriptions of the Show method's parameters:

    • IDialogVisualizerService 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 GetObject.

System.Diagnostics.DebuggerVisualizerAttribute

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 the Visualizer

  1. 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.
    1. 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.
    2. 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.
    3. On the .NET tab of the Add Reference dialog box, select Microsoft.VisualStudio.DebuggerVisualizers.
    4. Add a using Microsoft.VisualStudio.DebuggerVisualizers statement to the top of the file, as done in the FirstVisualizer project.
    5. Create a local string variable testString and initialize it to some interesting value.
    6. Copy this code after your testString declaration:

VisualizerDevelopmentHost host = new VisualizerDevelopmentHost( testString, typeof(FirstVisualizer.DebuggerSide)); host.ShowVisualizer();

  1. 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.

Installing the Visualizer

  1. Build the solution.
  2. 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.

      -Or-

    • *My Documents\Visual Studio\Visualizers
      *Putting your DLL here will install the visualizer for the current user only.

Using the Visualizer

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.

ms379596.simplevisualizercreation-fig3(en-US,VS.80).gif

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.

ms379596.simplevisualizercreation-fig4(en-US,VS.80).gif

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 IDE Support

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.

Conclusion

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.

© Microsoft Corporation. All rights reserved.