When debugging image-processing code, being able to view bitmaps directly in the debugger greatly helps understand what the code is actually doing.
Image Watch is the reference debugger extension when it comes to debugging C++ apps. For C# Desktop apps Visual Studio Visualizer APIs help build such debugger extensions. Those APIs do not currently support Store apps, but with a bit more work similar visualizers can be created to debug those apps too.
This blog gives an overview of the steps required to create such visualizers. For details see the full code in this GitHub repo.
First, we need to create a VSIX package which will let users install the debugger extension. Install the Visual Studio SDK and create a new solution using the solution template under ‘Templates > Extensibility > Visual Studio Package’. In the VSIX manifest, add an asset of type Microsoft.VisualStudio.MefComponent using the main project in the solution as source. This tells Visual Studio that we want to extend the editor.
Also add a few references which will help interact with the editor:
Next we need some UI to display the bitmaps. A basic XAML user control with an <Image>
element will do:
The bitmaps will be displayed when the mouse hovers on a variable, so we need the editor to notify us when that happens.
This is done in two parts. First a visualizer factory is registered with the editor using a set of attributes. The factory also implements IWpfTextViewCreationListener to give out visualizer objects – the second part – to the editor whenever it needs them.
The visualizer objects register for the MouseHover
event when they are created.
The MouseHover
event fires whether the app is being debugged or not, so the event handler performs an early check and exits if not in debug-break mode.
The event handler then looks up the variable under the mouse pointer and starts retrieving basic information from the debuggee. This part requires too much string parsing to copy/paste in a blog, so just refer directly to DebuggerVariable.FindUnderMousePointer() in the GitHub project.
A quick type check tells whether we should try to retrieve more data from the debuggee. Here we only handle Bitmap
objects from the Lumia Imaging SDK.
The bulk of data transfer happens next, when the buffer of the bitmap gets copied from the debuggee to the debugger. This part is a bit complex for two reasons: retrieving data is only possible via EnvDTE.Debugger.GetExpression() which treats everything as strings, and Store apps represent buffers using IBuffer instead of byte[]
which does not give direct access to the data.
The DebuggerVariable
class mentioned earlier encapsulates both issues inside its GetMemberIBuffer()
method: IBuffer
is converted to byte[]
, encoded to a base64 string
, copied to the debugger, and decoded back to byte[]
.
Some more metadata about the bitmap (width, height, pitch, color mode) is retrieved from the debuggee and the WriteableBitmap to be displayed in the adornment UI can be created.
Special thanks to Kfir Karmon who actually wrote most of the code.