Carlos Quintero (MVP, and developer of MZ-Tools) recently wrote a blog post on debugging into Visual Studio’s assemblies. We liked it, and asked him to tell us a bit more…
Using .NET Reflector to understand and debug Visual Studio assemblies
As a developer of Visual Studio add-ins, I have been using .NET Reflector to understand the internals of Visual Studio assemblies since many years ago, and I consider it an invaluable tool for developers of Visual Studio extensions (add-ins, packages, etc.). In this guest post I will explain why.
Developing a somewhat complex Visual Studio extension, there are two scenarios where you may desire to have the Visual Studio source code and even to debug its assemblies:
- To understand how Visual Studio does some kind of things, because you need to do the same or similar ones in your own extension.
- To guess which code path inside a method is actually used at run-time. I mean: you may have the source code of a Visual Studio assembly with some complex logic, and it is difficult to guess which branches are actually executed for certain cases.
Microsoft has released the source code of the .NET Framework and you can even debug its assemblies, but it hasn't done the same with Visual Studio assemblies. This is where. NET Reflector comes to the rescue. You can use .NET Reflector for those two scenarios. I’ll illustrate this with a real case…
The first scenario is to decompile Visual Studio assemblies. Although Visual Studio was born as a native C++ application, with each release more and more of its code became managed (.NET). Visual Studio assemblies are stored in the GAC 2.0 (C:\Windows\assembly), GAC 4.0 (C:\Windows\Microsoft.NET\assembly) and in the Common7\IDE folder (and the PrivateAssemblies and PublicAssemblies sub-folders).
My MZ-Tools 7.0 add-in for Visual Studio provides a Control Explorer feature that is basically an enhanced version of the Document Outline built-in feature of Visual Studio. While adapting my add-in to the Dark / Light themes introduced by Visual Studio 2012 I wondered how the Document Outline got the gray bitmaps of components of System.Windows.Forms 126.96.36.199, for example the MonthCalendar:
If you decompile that assembly with .NET Reflector you will see that the bitmaps are the colored ones of previous versions:
I knew that in a previous beta the bitmaps of the
System.Windows.Forms 188.8.131.52 were gray. But that of course broke the Document Outline feature of Visual Studio 2010, showing the bitmaps of Visual Studio 2012 (gray) rather than the colored ones.
In Visual Studio 2012 RTM Microsoft fixed that problem using some approach, but which one? To discover which, I decompiled the Visual Studio assembly that contains the Document Outline feature. This happens to be
Microsoft.VisualStudio.Windows.Forms.dll (in the folder C:\Windows\Microsoft.NET\assembly\GAC_MSIL\). By the way, this is the only thing that .NET Reflector can't do for you: to guess which Visual Studio assembly contains some feature ;-).
Once you have loaded the version of the assembly that belongs to Visual Studio 2012 in .NET Reflector (v4.0_184.108.40.206__b03f5f7f11d50a3a sub-folder), if you search for “
DocumentOutline“, you get the type that contains the feature, which has an
AddComponent method with the hint to solve the problem:
So, there is a BitmapSelector that, if you load the version of the assembly that belongs to Visual Studio 2010 (v4.0_10.0.0.0__b03f5f7f11d50a3a sub-folder), didn't exist. How the BitmapSelector gets the correct bitmap is beyond the scope of this post, but if you are interested you can read my article HOWTO: Get the bitmap of a component type from Visual Studio add-in.
The second scenario is to debug Visual Studio assemblies. For years, I have used .NET Reflector only to decompile assemblies. Recently I was thrilled to discover that I could debug them too and I wish I had discovered it much earlier.
Continuing with the first scenario, suppose that you want to debug that
AddComponent method to learn how Visual Studio gets the correct bitmap. This is how you would proceed:
- In the debugger IDE (Visual Studio 2012), show the .NET Reflector Object Browser (".NET Reflector", "Show .NET Reflector Object Browser" menu).
- Create a Class Library project.
- Save the solution (so that the .NET Reflector Object Browser shows the
references of the project. It doesn’t show them with temporary solutions).
- In the Project properties window, "Debug" section, select the "Start external
program" radio button and select the Visual Studio 2012 IDE: C:\Program Files
(x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe.
- In the Solution Explorer, add a reference to the Visual Studio assembly that you want to debug. In this example using the Browse button add the following assembly:
- In the .NET Reflector Object Browser, select the
right-click the "Enable Debugging" context menu. Click the "Done" button when the
decompilation is complete.
- In the .NET Reflector Object Browser, expand the
Microsoft.VisualStudio.Windows.Forms.dllnode and go to the "
AddComponentmethod and double-click it to open its
source code. Put a breakpoint on that method.
- Click the "Debug", "Start Debugging" menu of Visual Studio to start debugging.
- Visual Studio 2012 should be launched and the breakpoint should show with an
exclamation mark which means that the debugged assembly is not loaded yet.
- Show the Document Outline toolwindow.
- Create a Windows Forms application. The exclamation mark should disappear indicating that the debugged assembly is loaded and the debugger is attached, and the breakpoint should be hit because Visual Studio needs to get the bitmap for the Form component.
- Add some control to the form from the toolbox. The breakpoint should be hit again.
These are two scenarios where .NET Reflector can save you a lot of time integrating your extensions within Visual Studio – because extensibility is tricky, and Visual Studio’s own features already do many things that you need to do with your own. So it’s worthwile to learn how Microsoft does it.
Carlos Quintero is a Microsoft Most Valuable Professional (MVP) in the Visual Developer / Visual Basic categories since 2004. He is the author of MZ-Tools (www.mztools.com), a family of popular add-ins for Visual Studio, VB6, VB5 and VBA. He loves Visual Studio extensibility and shares his knowledge in his blog, articles and answering questions in the MSDN Visual Studio Extensibility (VSX) forum.