Supporting add-ins across multiple versions of Reflector

We’ve recently been working on an add-ins page to go on this site, which has been dangerously close to nearly ready to publish – forgive me if I sometimes sound a little jaded – for a few weeks now.

We’ve also been receiving a fair few questions about v7 add-in compatibility. I’ve finally had five minutes to think about this properly today and quickly came to the conclusion that every solution we’d considered thus far sucks balls in one way or another.

So here are some facts:

  • Users don’t care what version of Reflector they’re running, they just want their add-ins to work… and they want them to carry on working when they upgrade.
  • Add-in authors don’t want, and for the most part don’t need, to maintain different versions of their add-ins for different versions of Reflector.
  • We have, as far as possible, tried to change the add-in API only by adding new interfaces, not by changing existing ones (there are a couple of cases in the engine where that hasn’t been possible, but I’ll leave Clive to explain that).

The upshot is that most of the actively maintained add-ins should work with Reflector 7 unmodified with no problems, or at least with no more problems than they would under Reflector 6 – and remember, for those of you running .NET Reflector 6.8, the add-ins are still available, and it’s still possible to create new add-ins for 6.8.

The fix, which I implemented today, is actually pretty simple – albeit a bit grubby. Check this out:

using System;
using System.Reflection;
 
namespace Reflector
{
 
	/// <summary>
	/// Helper class for supporting Reflector 5 add-ins without requiring them to be recompiled.
	/// This is really simple: all it does is examine assembly resolution requests and, if a request
	/// is made to resolve Reflector 5.0.0.0, just returns a reference to the main Reflector 7
	/// assembly.
	/// </summary>
	internal class Reflector5AddinSupportAssemblyResolver
	{
		private static readonly byte []	Reflector5PublicKeyToken	= new byte[] { 0x18, 0xca, 0x6b, 0xb8, 0xdd, 0x6a, 0x03, 0xc3 };
 
		private static bool PublicKeyTokenMatchesReflector5s( byte [] possibleMatchingToken )
		{
			if ( possibleMatchingToken.Length != Reflector5PublicKeyToken.Length )
			{
				return false;
			}
 
			for ( int index = 0, size = Reflector5PublicKeyToken.Length; index < size; ++index )
			{
				if ( possibleMatchingToken [ index ] != Reflector5PublicKeyToken [ index ] )
				{
					return false;
				}
			}
 
			return true;
		}
 
		internal static Assembly ResolveAssembly( object sender, ResolveEventArgs args )
		{
			string	fullName	= args.Name;
			if ( null == fullName )
			{
				return null;
			}
 
			AssemblyName	name	= new AssemblyName( fullName );
			if ( name.Name == "Reflector"
				&& name.Version.Major == 5
				&& name.Version.Minor == 0
				&& name.Version.Build == 0
				&& name.Version.Revision == 0
				&& PublicKeyTokenMatchesReflector5s( name.GetPublicKeyToken() ) )
			{
				return typeof( IConfigurationManager ).Assembly;
			}
 
			return null;
		}
	}
}

 

And then I just insert this into the Reflector start-up sequence and jobs a good ‘un:

AppDomain.CurrentDomain.AssemblyResolve	+= Reflector5AddinSupportAssemblyResolver.ResolveAssembly;

Yep, that’s right, all this code does is return a reference to the main Reflector assembly when something (anything) asks for a reference to Reflector 5.0.0.0. I told you it was grubby, didn’t I?

The important thing is that it works, and it does so without the need for fragile config files, or multiple builds, or any other half baked solution that requires either the add-in authors, or you in turn to do something half-arsed to get add-ins working.

What it means is that, in theory, any add-in written for .NET Reflector 5.x, or 6.x will work in .NET Reflector 7.2.0.130 or later. It’s still possible to create add-ins that only work in .NET Reflector 7 or later, if you want to take advantage of some of the new API additions, which I’ll talk about in another post.

Let me emphasize once again that this isn’t absolutely foolproof. As I’ve said, we’ve tried to avoid changing interfaces, and have instead mostly derived new ones. In one or two cases, that shouldn’t affect most add-ins, this isn’t so. We’ve also tried to avoid changing behaviour so, for example, even though the decompilation view supports tabbing, if you’re using the add-in API, it’ll still look and act like the old decompilation view that could only hold one thing at a time. Again, it maybe that in all cases we haven’t succeeded, although I’m not aware of any specific problems at the moment.

So, if you want to be able to use all your add-ins against .NET Reflector 7, download the latest early access build from the bottom of our homepage at http://www.reflector.net/.

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *