Visualizing and Viewing Data
Type visualizers and custom viewers present data in a way that is quickly meaningful to a developer. The expression evaluator (EE) can support third-party type visualizers as well as supply its own custom viewers.
Visual Studio determines how many type visualizers and custom viewers are associated with the object's type by calling the IDebugProperty3::GetCustomViewerCount method. If there is at least one type visualizer or custom viewer available, Visual Studio calls the IDebugProperty3::GetCustomViewerList method to retrieve a list of those visualizers and viewers (actually, a list of CLSIDs that implement the visualizers and viewers) and presents them to the user.
Supporting Type Visualizers
There are a number of interfaces that the EE must implement to support type visualizers. These interfaces can be broken down into two broad categories: those that list the type visualizers and those that access the property data.
Listing Type Visualizers
The EE supports listing the type visualizers in its implementation of IDebugProperty3::GetCustomViewerCount and IDebugProperty3::GetCustomViewerList. These methods pass the call to the corresponding methods IEEVisualizerService::GetCustomViewerCount and IEEVisualizerService::GetCustomViewerList.
The IEEVisualizerService is obtained by calling IEEVisualizerServiceProvider::CreateVisualizerService. This method requires the IDebugBinder3 interface, which is obtained from the IDebugBinder interface passed to IDebugParsedExpression::EvaluateSync. IEEVisualizerServiceProvider::CreateVisualizerService also requires the IDebugSymbolProvider and IDebugAddress interfaces which were passed to IDebugParsedExpression::EvaluateSync. The final interface required to create the IEEVisualizerService interface is the IEEVisualizerDataProvider interface, which the EE implements. This interface allows changes to be made to the property being visualized. All property data is encapsulated in an IDebugObject interface, which is also implemented by the EE.
Accessing Property Data
Accessing property data is done through the IPropertyProxyEESide interface. To obtain this interface, Visual Studio calls QueryInterface on the property object to get the IPropertyProxyProvider interface (implemented on the same object that implements the IDebugProperty3 interface) and then calls the IPropertyProxyProvider::GetPropertyProxy method to obtain the IPropertyProxyEESide interface.
All data passed into and out of the IPropertyProxyEESide interface is encapsulated in the IEEDataStorage interface. This interface represents an array of bytes and is implemented by both Visual Studio and the EE. When a property's data is to be changed, Visual Studio creates an IEEDataStorage object holding the new data and calls IPropertyProxyEESide::CreateReplacementObject with that data object in order to obtain a new IEEDataStorage object that, in turn, is passed to IPropertyProxyEESide::InPlaceUpdateObject to update the property's data. IPropertyProxyEESide::CreateReplacementObject allows the EE to instantiate its own class that implements the IEEDataStorage interface.
Supporting Custom Viewers
The flag DBG_ATTRIB_VALUE_CUSTOM_VIEWER is set in the dwAttrib field of the DEBUG_PROPERTY_INFO structure (returned by a call to IDebugProperty2::GetPropertyInfo) to indicate that the object has a custom viewer associated with it. When this flag is set, Visual Studio obtains the IDebugProperty3 interface from the IDebugProperty2 interface using QueryInterface.
If the user selects a custom viewer, Visual Studio instantiates the custom viewer using the viewer's CLSID supplied by the IDebugProperty3::GetCustomViewerList method. Visual Studio then calls IDebugCustomViewer::DisplayValue to show the value to the user.
Normally, IDebugCustomViewer::DisplayValue presents a read-only view of the data. To allow changes to the data, the EE must implement a custom interface that supports changing data on a property object. The IDebugCustomViewer::DisplayValue method uses this custom interface to support changing the data. The method looks for the custom interface on the IDebugProperty2 interface passed in as the pDebugProperty argument.
Supporting Both Type Visualizers and Custom Viewers
An EE can support both type visualizers and custom viewers in the IDebugProperty3::GetCustomViewerCount and IDebugProperty3::GetCustomViewerList methods. First, the EE adds the number of custom viewers that it is supplying to the value returned by the IEEVisualizerService::GetCustomViewerCount method. Second, the EE appends the CLSIDs of its own custom viewers to the list returned by the IEEVisualizerService::GetCustomViewerList method.