Making a type visualizer for a custom array class
In this tutorial we will create a type visualizer for our own vector-like array class. Before you begin, please follow the getting started tutorial to make a very basic "dummy" visualizer and ensure that it works and can be debugged.
- Open the MyTypeVisualizer project (C# visualizer from the previous tutorial) and run it. A new instance of Visual Studio will start (and will be debugged by the first instance of Visual Studio).
- Open the C++ project from the previous tutorial 
					and replace the main file with the following:#include <stdio.h>
 #include <assert.h>
 template <class _Type> class VeryBasicArray
 {
 private:
 size_t m_Count;
 _Type *m_pData;
 public:
 VeryBasicArray(size_t count)
 : m_Count(count)
 , m_pData(new _Type[count])
 {
 }
 
 ~VeryBasicArray()
 {
 delete[] m_pData;
 }
 
 _Type &operator[](size_t index)
 {
 assert(index <= m_Count);
 return m_pData[index];
 }
 
 size_t GetCount()
 {
 return m_Count;
 }
 };
 
 int main()
 {
 VeryBasicArray<int> test(3);
 for (int i = 0; i < test.GetCount(); i++)
 test[i] = i * 100;
 return 0;
 }
- Build the project. Place a breakpoint at the "return 0" line and start 
					debugging. When the breakpoint is hit, hover the mouse over 
					"test" to see its value: Notice 
					how the value of "test" has been changed to "Hello, Visual 
					Studio" by the basic visualizer from the previous tutorial. Notice 
					how the value of "test" has been changed to "Hello, Visual 
					Studio" by the basic visualizer from the previous tutorial.
- Carefully look at the values displayed by Visual Studio 
					when you hover your mouse over "test" (or add it to the 
					Watch window). Each tree node corresponds to the VisualGDB
					IExpression interface. The annotated screenshot below 
					shows which element of IExpression corresponds to the main 
					displayed elements: 
- The type visualizers are based on the Expression Filter mechanism. Expression Filters can replace arbitrary IExpression objects with their own implementations. In most of the cases creating an instance of StaticExpressionFilter and specifying which fields to override should be sufficient. We will now make a visualizer that will use the m_Count value to display the collection elements.
- The first step will be to query the m_Count 
					value as an integer to know how many elements to query. 
					Replace the body of the DoAttach() method 
					with the following:protected override IExpression DoAttach(IExpression expr,Note that you can use "Break All" command in the outer Visual Studio to stop the inner Visual Studio, and then edit the visualizer code directly. Edit-and-continue will patch the visualizer on-the-fly, so you won't need to restart Visual Studio or even restart the debugged C++ program!
 IExpressionEvaluator evaluator)
 {
 string countExpression = string.Format("({0}).m_Count",
 expr.FullNameForEvaluator);
 var value = evaluator.EvaluateExpression(countExpression, "int")
 as ExpressionValue.Integral;
 if (value == null)
 return null;
 ulong count = value.Value;
 
 return new StaticExpressionFilter(expr)
 {
 ValueOverride =
 new ExpressionValue.Custom(
 string.Format("An array with {0} items",
 count)
 )
 };
 }
- Hover the mouse over "test" again. You will see the : 
- Note how we have queried the element count: first, we derived the GDB expression for it using IExpression.FullNameForEvaluator (would be 'test.m_Count' in this case). Then we evaluated it using the IExpressionEvaluator interface. Finally we ensured that the returned value is a valid integral number (VisualGDB parses it automatically and returns ExpressionValue.Integral) and extracted the integral value (of type ulong) from it.
- Now when we know the count and know that i-th 
					element of the array can be accessed as test.m_pData[i] 
					it's time to create IExpression 
					objects for all those values. Replace the return statement 
					in the DoAttach() method with the following 
					code:List<IExpression> children = new List<IExpression>();
 for (ulong i = 0; i < count; i++)
 {
 string itemExpression = string.Format("({0}).m_pData[{1}]",
 expr.FullNameForEvaluator, i);
 var item = evaluator.CreateExpression(itemExpression);
 if (item != null)
 children.Add(item);
 }
 
 var result = new StaticExpressionFilter(expr)
 {
 ValueOverride = new ExpressionValue.Custom(
 string.Format("An array with {0} items", count))
 };
 
 result.ChildrenOverride = new StaticChildProvider(
 children.ToArray());
 return result;
- Hover the mouse over "test" again: 
- The problem now is that the user won't be able to 
					access/modify the original m_Count and
					m_Data values. To provide this possibility 
					we will add an "Actual members" node. Instead of making our 
					own implementation of IExpression we will 
					simply reuse the
					
					VirtualExpressionNode class provided by VisualGDB:children.Insert(0, new VirtualExpressionNode("[Actual members]",Note that we have simply "moved" the IExpressionChildProvider from the original expression node to the newly created node. We did not have to query any actual members at this point.
 "", expr.Children));
- Add the "test" to the Watch window and expand the 
					results: 
- Note that the element names still have the format "(test).m_pData[i]" that corresponds to the raw GDB expressions, but is not very user-friendly. To fix this, we could wrap the child expressions returned by IExpressionEvaluator.CreateExpression() using StaticExpressionFilter and override the ShortName.
- Furthermore, when dealing with a 1000-element array, our 
					implementation would call CreateExpression() 
					1000 times even if the user just hovered the mouse over the 
					array or had the "Autos" window open. To fix that we could 
					make our own implementation of 
					
					IExpressionChildProvider creating child nodes on demand. 
					To facilitate that VisualGDB provides the
					
					ArrayChildProvider class that does everything 
					automatically:protected override IExpression DoAttach(IExpression expr,
 IExpressionEvaluator evaluator)
 {
 string countExpression = string.Format("({0}).m_Count",
 expr.FullNameForEvaluator);
 var value = evaluator.EvaluateExpression(countExpression, "int")
 as ExpressionValue.Integral;
 if (value == null)
 return null;
 
 ulong count = value.Value;
 var actualMembers = new VirtualExpressionNode(
 "[Actual members]", "", expr.Children);
 
 var result = new StaticExpressionFilter(expr);
 
 result.ValueOverride = new ExpressionValue.Custom(
 string.Format("An array with {0} items", count));
 
 string format = "(" +
 expr.FullNameForEvaluator +
 ").m_pData[{0}]";
 
 result.ChildrenOverride = new ArrayChildProvider(evaluator,
 format, 0, (int)count, actualMembers);
 
 return result;
 }
 
- Delete "test" from the Watch window and add it once 
					again: 
- You can get an overview of the raw commands that are 
					being sent to GDB when your expressions are evaluated by 
					selecting "All GDB interaction" in the GDB Session window: 
Source code
You can download the source code for the example in this tutorial here. The code in the archive is provided under the BSD license (no restrictions, no warranty).
