Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Forget PowerPoint – Make a Slideshow in… a Debugger :)

0.00/5 (No votes)
24 Nov 2011 1  
The article describes how to make a slideshow in a debugger. It may help you understand the PDB API in System.Reflection.Emit as well as impress listeners on any debugging-related presentations. :)

Few days ago, I had a presentation in the Warsaw .NET Group about PDB files. To make the slideshow more attractive (or rather original:)), I decided to replace the PowerPoint with something more connected with the subject, such as… the Visual Studio debugger. The only question was how to actually achieve this. The idea grew in my head after reading a brilliant Mike Stall’s post about debugging dynamically generated code. Mike shows in it how to emit sequence points for a text file of your choice and so bind this file with the generated MSIL. If done correctly, the debugger will load the text file, allowing you to step through its content and at the same time, execute the emitted MSIL. So what if we could use the presentation table of contents as our source file and for each title (line of the table of contents) emit MSIL which will present a corresponding slide in the console window? This will actually make the debugger play the role of the PowerPoint. :)

Prepare the Content

Let’s start from a table of contents for a hypothetical 3-slides presentation:

Welcome

1. Slide1
1.1 Slide1.1
2. Slide2

Thank you

Save this content as a toc.txt file – this will be our source file. Now let’s prepare slides. You may create a sub-directory slides or even create separate directories for each group of slides – as you will shortly see, there is no restriction here. In our case, let’s stay with the one-directory-for-all approach. Let’s now assume that we want some contents to be presented for slides entitled: Welcome, 1.1 Slide1.1, 2. Slide2 and Thank you (we omit 1. Slide1 on purpose). As mentioned previously, the slides will be presented on the console so we may safely store their contents in text files named adequately: welcome.txt, slide1.1.txt and slide2.txt. Example content for a welcome.txt might be as follows:

       SAMPLE PRESENTATION
       ===================

        Sebastian Solnica

http://lowleveldesign.wordpress.com

Now, we need to prepare a mapping file that will map the slide title with its corresponding content. Create a new text file and fill it with the following text:

Welcome
 slides\welcome.txt
1.1 Slide1.1
 slides\slide1.1.txt
2. Slide2
 slides\slide2.txt
Thank you
 thank-you.txt

Each indented line stores a path to the content of the slide with the title above it. The titles must be the same as in the toc.txt file and the file paths must be valid (however, as you can see, not all titles need to be mapped).

Create the Presentation Compiler

Having the presentation content ready, we now need to create an EXE file that will be run by the debugger. I suppose that the easiest approach is to use classes from the System.Reflection.Emit namespace. The pseudo code for the compiler (or rather emitter) will be as follows:

var asm = new DynamicAssembly()
MakeDebuggable(asm)

var mappingsContent = ReadFile(toc_slides.txt)
var mappings = StoreMappingsInDictionary(mappingsContent) // slide title -> slide file

for each slideTitle in GetContent(toc.txt) {
  if (mappings.Contains(slideTitle)) {
    EmitMsilCodeThatWillReadAndPrintTheSlide(mappings[slideTitle]);
    MarkSequencePoint(currentLineNum); // binds a line of the source code with the emitted MSIL
  }
}

SaveAssembly(asm)

I will now explain few methods that occur in the code above that might have confused you (the C# source code that implements the above logic can be downloaded from here). MakeDebuggable is responsible for adding a DebuggableAttribute to the assembly. This attribute informs the JIT compiler that it should produce assembly code that will be debuggable (more here). To make the debugging process possible, we also need to create a PDB file that will store the debug information for our module. ModuleBuilder contains a special method called DefineDocument that will do this for us. Here’s a C# code that implements all the logic described:

Type daType = typeof(DebuggableAttribute);
ConstructorInfo daCtor = daType.GetConstructor
(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] { 
    DebuggableAttribute.DebuggingModes.DisableOptimizations | 
    DebuggableAttribute.DebuggingModes.Default });
assemblyBuilder.SetCustomAttribute(daBuilder);

ModuleBuilder module = assemblyBuilder.DefineDynamicModule
(outputFileName, true); // <-- pass 'true' to track debug info.

// Tell Emit about the source file that we want to associate this with. 
ISymbolDocumentWriter doc = module.DefineDocument
(tableOfContentsPath, Guid.Empty, Guid.Empty, Guid.Empty);

EmitMsilCodeThatWillReadAndPrintTheSlide emits MSIL that will open the slide file, read it at once and print the content to the console. Ildasm the code below and you will get it :) (or check emitReadAndPrintSlideMethod in Program.cs from the slide compiler source code):

using (StreamReader reader = new StreamReader
(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
   Console.Clear();
   Console.Write(reader.ReadToEnd());
}

To make the assembly smaller, you may consider putting this logic in a separate method and emit just calls to this method with adequate parameters (this is what I do in the sample code). For each slide printed, we need to inform the debugger which line of the source code (or table of contents in our case:)) should be highlighted. For this purpose, we use MarkSequencePoint method of the ILGenerator instance:

ilGenerator.MarkSequencePoint(doc, currentLineNum, 1, currentLineNum, 100);

To make the debugging even more feasible, I emit System.Diagnostics.Debugger.Break() call after the first sequence point (so even when starting with F5, the debugger should stop on the first slide).

Compile and Show :)

By now, we should have the presentation compiler and the presentation content (table of contents, slide files and slide title <-> slide file mapping file) ready. So it’s time to compile it and debug it. :) If you are using my compiler, run the following in the command window:

SlideCompiler.exe -files toc_slides.txt -o toc.exe toc.txt

This should produce a toc.exe file (and toc.pdb) that you can now open in Visual Studio (File->Open->Project/Solution…). After pressing F5, you should see something like:

By pressing F11 or F10, you may advance the slides. To move back, just select the line before the slide you want to show, press Ctrl+Shift+F10 and then F10. You may also place breakpoints on your slides.

The code (and the sample presentation as well as my symbol presentation from WG.NET) can be found on my blog samples site.

Have fun and surprise your listeners on your next presentation! :)

Filed under: CodeProject, Debugging, Visual Studio

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here