This entry is a little tutorial on how to write your own Reflector Addin. For the past weeks, I have been playing a lot with those and Lutz Roeder was backing me up on MSN for quick questions, so it's my time to return him the favor and write a tutorial about it. So let's get started.A Reflector Addin is basically only a control that gets notified when the browser changes of active items. Of course, the tricky part is to "inject" your Addin into Reflector and to "clean" up when it is unloaded. Once, you're addin is injected, the control you provided takes care of the rest. I will not focus on writing controls here but rather on the procedure to load and unload packages.
Reflector API is rather big, so this tutorial is just the "immerged" part of the iceberg.
Quick Semantics
In Reflector, an Addin is called a Package (IPackage interface). Each package can add multiple Windows (IWindow), which are the control appearing on the right, can add CommandBar items (ICommandBarItem, ICommandBarButton) to the context menus, and attach listeners to the event trigerred when the AssemblyBrowser changes of ActiveItem (IAssemblyBrowser.ActiveItemChanged). The ActiveItem is the item selected in the reflection tree.
Building a simple package (hard way)
The IPackage interface is defined as follows:
public interface IPackage
{
void Load(IServiceProvider serviceProvider);
void Unload();
}
As may already know, the Reflector API is exposed through a set of interfaces. The actual implementations are obfuscated. The IServiceProvider instance is a "facade" against the implementations and can be used to retreive IAssemblyBrowser instance (and others).
The Load method is where you will inject your Addin, while the Unload method is for cleaning. Implementing IPackage is rather boring and bug prone because you need to track all the window, menu item, etc.. that you inject to later remove them. Forgetting to remove a menu item is likely to happen often if you are in a rush. Moreover, using the serviceProvider is verbose in the sense that you access elements through a dictionary:
IAssemblyBrowser ab = (IAssemblyBrowser)serviceProvider.GetService(typeof(IAssemblyBrowser));
Let's implement a small package that displays a text box for assemblies. As mentionned above the steps are:
- create your control and add it to the IWindowManager instance (retreive from serviceProvider),
- add menu item and event handler,
- set control to visible when menu is clicked,
- add IAssemblyBrowser.ActiveItemChanged handler in your control
- Don't forget to prepare cleaning up!
The control: this control display the name of the assembly, otherwise nothing.
public class AssemblyNameWindow : TextBox
{
private IAssemblyBrowser assemblyBrowser=null;
public AssemblyNameWindow()
{
this.Dock = DockStyle.Fill;
this.Multiline=true;
}
public IAssemblyBrowser AssemblyBrowser
{
get
{
return this.assemblyBrowser;
}
set
{
if (this.assemblyBrowser!=null)
this.assemblyBrowser.ActiveItemChanged -= new EventHandler(activeItemChanged);
this.assemblyBrowser = value;
if (this.assemblyBrowser!=null)
this.assemblyBrowser.ActiveItemChanged += new EventHandler(activeItemChanged);
}
}
private void activeItemChanged(Object sender, EventArgs args)
{
// testing if current item is an assembly
IAssembly assembly = this.assemblyBrowser.ActiveItem as IAssembly;
if (assembly!=null)
this.Text=assembly.Name;
else
this.Text=null;
}
}
And now the package, which creates a window, and some menu items:
public class AssemblyNamePackage : IPackage
{
private IWindowManager windowManager=null;
private ICommandBar assemblyMenu=null;
private ICommandBarButton button=null;
public void Load(IServiceProvider serviceProvider)
{
this.windowManager=(IWindowManager)serviceProvider.GetService(typeof(IWindowManager));
IAssemblyBrowser assemblyBrowser = (IAssemblyBrowser)serviceProvider.GetService(typeof(IAssemblyBrowser ));
// create window
AssemblyNameWindow anw = new AssemblyNameWindow();
anw.AssemblyBrowser=assemblyBrowser;
// inject window into reflector
this.windowManager.Windows.Add("AssemblyName",anw,"Assembly Name");
// create menu item and attach handler
ICommandBarManager cbm = (ICommandBarManager)serviceProvider.GetService(typeof(ICommandBarManager));
// get assembly context menu
this.assemblyMenu = cbm.CommandBars["Browser.Assembly"];
// add button
this.button = this.assemblyMenu.Items.AddButton("Assembly name",new EventHandler(button_Click));
}
public void Unload()
{
// remove window
this.windowManager.Windows.Remove("AssemblyName");
// remove button
this.assemblyMenu.Items.Remove(this.button);
}
private void button_Click(Object sender, EventArgs args)
{
this.windowManager.Windows["AssemblyName"].Visible=true;
}
}
That's it. You have built your first Reflector Addin:

Now this is a lot of code to get thigs up and moreover, it is quite errorprone, so let's us another easier method.
Building a simple package (easier way)
This solution uses a few classes that I have written in order to handle all the "load/unload" code. The new way is mainly based on custom attributes. [Update:]Firstly, you need to make your controls implement IServiceComponent where you can register to Reflector events:
public class AssemblyNameWindow : UserControl,