Since the next Visual Studio version (“14”) will remove add-ins, the time has come for those of us still providing our products as add-ins (such as my MZ-Tools productivity add-in) to move to Visual Studio packages. In my view, there are three strategies:
In the first one, you change the minimal number of things in your add-in to convert it to a package. For example, some areas that need to be changed are:
- Creation of commands (remember that commands are not UI items).
- Creation of UI items (toolbars, menus, context menus, buttons, etc.).
- Creation of toolwindows.
Although they are tricky, the Visual Studio package wizard will get you started about those areas. But there is another thing that your add-in surely does: to respond to events to perform some actions. And for that it uses events provided by the automation model (EnvDTE). Furthermore, add-ins are totally based on the automation objects (EnvDTE.DTE, EnvDTE.Solution, EnvDTE.Project and so on). Although you can get an instance of the root DTE object as explained in HOWTO: Get an EnvDTE.DTE instance from a Visual Studio package, there is a another way.
In the second strategy, you get rid of the Visual Studio automation (EnvDTE). The automation model was provided initially in Visual Studio .NET 2002 to support add-ins, macros and wizards. Macros were removed in Visual Studio 2012. And add-ins will be removed in Visual Studio “14”. Microsoft packages don’t use very much EnvDTE. So, which will be the future of EnvDTE? Not a brilliant one, I guess. Likely in some Visual Studio version it will be deprecated and in some other version it will be removed and then you will have to change again your package because of its heavy dependency on EnvDTE. So, you can leverage the migration from a Visual Studio add-in to a package to do things in the natural way of packages, using Visual Studio services and interfaces. They are not easy because 1) there are tons of services and are difficult to discover (in the automation model you can use the Object Browser to discover classes, methods, etc.) and 2) they still show its C++/COM nature in some cases (not a friendly API).
In the third strategy you realize that your Visual Studio extension has a strong dependency on the Visual Studio assemblies, either EnvDTE or the ones used by packages (Microsoft.VisualStudio.*). Furthermore, they can change on each Visual Studio version. To avoid this, my approach is to split my “plug-in” in two assemblies:
- One assembly has the features of my product and depends only on abstractions such as IHost, ISolution, IProject, IProjectConfiguration, etc. with the methods, properties and events that I define. This assembly only references some assemblies of the .NET Framework. In my case (for the future MZ-Tools 8.0), this assembly has 80% of the code and has only five references: System, System.Data, System.Drawing, System.Windows.Forms and System.Xml.
- The other assembly is an “adapter” for a Visual Studio version that provides the implementation of the interfaces IHost, ISolution, etc. In my case it has 20% of the code and I have adapters not only for Visual Studio (all versions as add-in), but for the VBA editor (32-bit & 64-bit) of Office, VB 6.0 and VB 5.0. I even have a stub adapter to be used in ultra-fast “integration” tests. So, I only have now to create an adapter for Visual Studio as a package. But the core of my product (80%) is not affected.
To get you the idea, this is the structure of the solution:
And my object model has 30 interfaces approx.:
Needless to say, my implementation of those interfaces in the adapter for VS as package will not use the automation model EnvDTE. In the next posts and articles of the MZ-Tools Articles Series I will explain how to do things in the native way of packages, as I learn about it.