Converting a Visual Studio plugin from 2012 to 2013

I’ve some little utilities for Visual Studio, born as a Macro and then converted to Plugin. Now that VS 2013 preview is out, I want to convert that addin to support the new version of Visual Studio, so I can use my utilities even in VS 2013.

The whole conversion process is really straightforward, first of all I create a branch of the original VS2012 version of the plugin, just to be able to compile again with VS 2012. This is nothing more than having a backup of the project.

image

Figure 1: 2013 version is just a branch of the 2012 version

Now if you open project file with VS 2013 it will ask to convert the project, just choose yes and you are done, the project is converted for VS 2013. Unfortunately if you compile the project and try to install the .vsix file you will find that it does not install on VS 2013. You should simply edit the source.extension.vsixmanifest file telling that the addin supports newer version of VS

image

Figure 2: Choose supported version of VS where this addin can be installed

Now you can simple uninstall the old version from your VS 2012 version and simply install the new version, that now supports from VS 2010 to VS2013. If if double click the vsix file I can install the addin on all installed and supported versions.

image

Figure 3: Your converted addin now support both 2012 and 2013 preview

Working with Visual Studio SDK is really simple, and the upgrade procedure is a further confirmation of this fact. You can simply open the addin with the new Visual Studio Version, change supported version list and your addin is ready to be used in the new version.

Gian Maria.

Visual Studio Plugin: stop build at first error

When it is time to work with big solutions composed by many projects, it is useful to have the ability to stop the build at the very first build error. There are several reason to do this, first of all probably many of the subsequent error can be caused by the fact that a base project does not compile, or simply the build process takes a long time that it is not useful to continue the build when a project does not build, (quite often we are interested only in build the whole solution, so there is no point in waiting for all the other project to compile, because at the end everything we want to do is fixing the project that does not compile and try again to rebuild).

Implementing this logic in a plugin is super easy, first of all I create a simple class that contains all the code needed by the plugin, and in constructor I register handlers for a couple of Visual Studio Events.

Boolean _enabled = false;
private Boolean _alreadyStopped = false;

public StopBuildAtFirstError(DTE2 dte)
{
    _dte = dte;
    dte.Events.BuildEvents.OnBuildProjConfigDone += OnBuildProjConfigDone;
    dte.Events.BuildEvents.OnBuildBegin += (sender, e) => _alreadyStopped = false;
}

As you can verify, once you have a reference to a DTE2 object you can simply access Events property that contains all useful events raised by Visual Studio, grouped by categories; in my plugin I’m interested to be notified when the build starts (OnBuildBegin) and when a project finishes compiling (OmBuildProjConfigDone). I use a simply private boolean field to verify if I already stopped the build, this is needed if the build goes in parallel so I can have two concurrent project that failed building, but I need to issue only one command to stop the build. Here is the logic to stop the build if a project fails.


private void OnBuildProjConfigDone(string project, string projectConfig, string platform, string solutionConfig, bool success)
{
    if (_alreadyStopped || success || !_enabled) return;

    _alreadyStopped = true;

    _dte.ExecuteCommand("Build.Cancel");

    var pane = _dte.ToolWindows.OutputWindow.OutputWindowPanes
                                .Cast<OutputWindowPane>()
                                .SingleOrDefault(x => x.Guid.Equals(AlkampferVsix2012.Utils.Constants.BuildOutput, StringComparison.OrdinalIgnoreCase));

    if (pane != null)
    {
        Int32 lastSlashIndex = project.LastIndexOf('\\');
        String projectFileName = project.Substring(lastSlashIndex + 1, project.LastIndexOf('.') - lastSlashIndex - 1);
        var message = string.Format("INFO: Build stopped because project {0} failed to build.\n", projectFileName);
        pane.OutputString(message);
        pane.Activate();
    }
}

Super Easy isn’t it? To know if the build of the project succeeded you can simply check a parameter called success; to stop the build you can simply send a Build.Cancel command to DTE2 object. The ExecuteCommand method is really useful, because you can check every command available in VS directly from the menu Tools->Customize press the button Keyboard to add shortcut to command, and you can browse to every command that is available in the system. Once you find the command you want to raise from a plugin you can simply use the ExecuteMethod of DTE2 object passing command string as single argument and you are done.

The rest of the handler simply grab a reference to the Build OutputWindow and add a message telling that the build was stopped because the specific project failed to build. Now you can simply press F5 and debug your plugin in Visual Studio experimental Hive.

image

Figure 1: New menu option created by the plugin

This plugin will create a couple of new Menu Items under Tools menu, the first one is the “Attach to IIS” discussed previously, the second one is the “Stop Build on 1st error” that is disabled by default, you can enable simply clicking on it. Now if you build a solution and a project failed to build you will receive a message like this one.

image

Figure 2: Here is error message of the build and the subsequent info that tells you that the build was stopped

The coloration of the build output is another feature of the same plugin that helps me to immediately hilight in red all lines that contains the word error and in blue everything that starts with INFO: (informational message of the plugin itself).

Code of the plugin can be found here (file AlkampferVsix2.zip)

Alk.

Converting Visual Studio Macro to Visual Studio plugin

Visual Studio 2012 is really faster than 2010, this is due to an excellent work of the team to maximize performance and because in this release some of the older and less used part of the IDE were removed. One of this part is the Macro editor that is not anymore available in Visual Studio. This is one of the feature I missed most because I’ve used it in the past to automate some basic task, like attach to IIS automatically with a keyboard shortcut. The Macro engine had some limitation, it supported only Visual Basic, it was old code that needs time to be maintained and finally everything you can do with a Macro can be done with Visual Studio Plugin so there was no need to maintain anymore in the product.

If you used macro with VS2010 and you want to use them in VS2012 you need to create an addin, the easiest way is to go for a Visual Studio Package:

image

Figure 1: Creating a Visual Studio Package

Choosing a Project type of “Visual Studio Package” will launch a wizard that asks you some information about the type of extension you want to create, the most important part is choosing the functions that the plugin want to implement, to convert a macro the simplest solution is implement one or more Commands.

image

Figure 2: Choose to implement Menu Command.

The default structure created by the wizard implements a simple command placed under the Tools menu, it can be invoked with the menu or you can assign shortcut to launch with a combination of keys. Once the project is created converting the macro is just a matter of copying the code of the macro inside the plugin and call inside the handler of the command.

Dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as DTE2;

// Add our command handlers for menu (commands must exist in the .vsct file)
_attachToIIS = new AttachToIIS(Dte);
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (null != mcs)
{
    // Create the command for the menu item.
    CommandID menuCommandID = new CommandID(GuidList.guidAlkampferVsix2012CmdSet, (int)PkgCmdIDList.attachToIIS);
    MenuCommand menuItem = new MenuCommand(_attachToIIS.MenuItemCallback, menuCommandID);
    mcs.AddCommand(menuItem);
}

This snippet of code is based on code generated by the wizard, I’ve only added line 1 to retrieve a reference to the DTE2 object needed by my AttachToIIS macro code and to keep the code clean I’ve moved all the code of the macro inside a dedicated class called AttachToIIS. This class has a method called MenuItemCallback that gots called when the user ask to execute the command (from the menu or from a shortcut).

I’ve then converted all of my old VB code to C# and pasted inside the class, then press F5 and an instance of VS2012 Experimental Hive started, permitting me to debug the plugin to verify if everything is ok.

image

Figure 3: My plugin is loaded correctly and the menu is there

The icon is the default one used by the wizard it is an aspect I do not care about because I just want to use my old macro code :), now it is time to use Tools –> Customize menu to assign a shortcut to this command.

image

Figure 4: My new command is loaded and is associated to the Tools namespace, so it is called tools.AttachToIIS

Et voilà, the game is done, the whole process of Macro Conversion took no more than 15 minutes and I’m able to use the same macro code in VS2012. This is my feedback of the process.

Advantages:

  • Creating a VS package is a matter of few clicks and you have a solution completely configure to create your plugin
  • The result is much more manageable, instead of having a bunch of macro code that you need to copy and paste inside the Macro IDE when you reinstall you have a vsix package that can be installed by everyone with a simple double click.
  • You are not forced to use Visual Basic

Disadvantages:

  • It is much simpler to experiment with macro, just write code, press F5 and you are immediately debugging the code, with a plugin when you press F5 another instance of VS starts, and it needs some seconds.

I’ll release the code the next week.

Gian Maria.

Location of your vsix files in experimental hive during plugin development

When you are developing Visual Studio plugin, your project is usually configured to launch a special instance of Visual Studio under the Visual Studio debugger (excellent example of dogfooding), this special instance is called experimental HIVE.

image

Figure 1: Configuration of a standard VSIX project to test your addin

As you can see the project is configured to start Visual Studio as external program to be debugged and it is started with the option /rootsuffix Exp to start in Experimental Hive. This permits to test plugin in a configuration of Visual Studio that is isolated from your standard instance, think as an example if you develop a plugin that makes Visual Studio instable and you cannot open Visual Studio due to this addin.

If you want to remove or look at current configuration of experimental hive you can go to folder

C:\Users\username\AppData\Local\Microsoft\VisualStudio\

You should see all configuration folder for the various editions of Visual Studio, those that ends with Exp are related to experimental hive.

image

Figure 2: Folders related to experimental hive.

You can now enter in experimental hive folder and in extensions folder you should see all of your plugin that are under development, now you can remove them if you want to restore everything to the original value.

Alk.

Customize output windows in Visual Studio

I really like WPF for showing directly in the Visual Studio Output folder all binding errors, but one annoying stuff is that the output windows is usually crowded with all sort of stuff, so you have an hard life identifying the binding errors from all the other output contained in there. Since Visual Studio 2010 use WPF to render the output windows and use MEF for extension, modifying the aspect of the content of VS2010 is really simple. So I’ve created in few minutes a simple addin to hilite the databinding error in output windows, the example is based on the Diff Classifier SDK sample, that explains how to use the text classification feature of VS2010

First of all create a new Visual Studio Package project

image

Figure 1: Creating a Visual Studio Package

Now you should add a couple of classes to the project that actually does the coloring for you.

SNAGHTML2180854

Figure 2: The CustomClassifierProvider will provide the entry point for modifying aspect of output window

The OutputClassifierProvider implements the IClassifierProvider interface, used to create a classifier for a text buffer; basically its purpose is creating a classifier capable to format text, and the ContentType attribute specifies that it formats text for “output” window. Since VS 2010 uses MEF behind the scene to implements part of the plugin extension point, you should simply add the Export attribute telling MEF that this class exports the IClassifierProvider interface.

Then you need to go to the source.extension.vsixmanifest file and add the project as content for MEF exporting like shown in Figure 3.

image

Figure 3: Remember to add the whole assembly as MEF Component

To have this, simply press the “Add content” button and you can specify everything in the windows shown in Figure 4:

SNAGHTML221549f

Figure 4: Adding the project as MEF Component.

Now you only need to write the class that actually does the formatting, I called this “OutputClassifierProvider” and it is very simple. It simply implements the IClassifier interface, thus it can give classification to text in Visual Studio, here is the first part of the class.

   1: using System;

   2: using System.Collections.Generic;

   3: using Microsoft.VisualStudio.Text;

   4: using Microsoft.VisualStudio.Text.Classification;

   5: using System.ComponentModel.Composition;

   6: using Microsoft.VisualStudio.Utilities;

   7: using System.Windows.Media;

   8:  

   9: public class OutputClassifier: IClassifier

  10: {

  11:     IClassificationTypeRegistryService _classificationTypeRegistry;

  12:  

  13:     internal OutputClassifier(IClassificationTypeRegistryService registry)

  14:     {

  15:         this._classificationTypeRegistry = registry;

  16:     }

  17:  

  18:     #region Public Events

  19:  

  20:     public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;

  21:  

  22:     #endregion 

The real work is done into the GetClassificationSpans method.

   1: public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)

   2: {

   3:     ITextSnapshot snapshot = span.Snapshot;

   4:  

   5:     List<ClassificationSpan> spans = new List<ClassificationSpan>();

   6:  

   7:     if (snapshot.Length == 0)

   8:         return spans;

   9:  

  10:     var text = span.GetText();

  11:  

  12:     if (text.StartsWith("System.Windows.Data Error", StringComparison.OrdinalIgnoreCase))

  13:     {

  14:         IClassificationType type = _classificationTypeRegistry.GetClassificationType("output.wpfbindingalert");

  15:         spans.Add(new ClassificationSpan(span, type));

  16:     } else if (text.IndexOf("error", StringComparison.OrdinalIgnoreCase) >= 0)

  17:     {

  18:         IClassificationType type = _classificationTypeRegistry.GetClassificationType("output.alert");

  19:         spans.Add(new ClassificationSpan(span, type));

  20:     }

  21:  

  22:     return spans;

  23: }

Basically I simply check if the text inside the span starts with “system.windows.data error” and if true I add the classification output.wpfbindingalert, and if contains the text error somewhere I add the classification output.alert, but what is a classification? If you go further down the class code you can find the definition of those two classification

   1: [Export]

   2: [Name("output.alert")]

   3: internal static ClassificationTypeDefinition outputAlertDefinition = null;

   4:  

   5: ...

   6:  

   7: [Export(typeof(EditorFormatDefinition))]

   8: [ClassificationType(ClassificationTypeNames = "output.info")]

   9: [Name("output.info")]

  10: internal sealed class OutputInfoFormat : ClassificationFormatDefinition

  11: {

  12:     public OutputInfoFormat()

  13:     {

  14:         this.ForegroundColor =  Colors.Green;

  15:         this.IsBold = true;

  16:     }

  17: }

As you can see it is based on a simple static ClassificationTypeDefinition property then a class that inherit from ClassificationFormatDefinition and the game is done. Now you can press F5, start Visual Studio in Experimental Hive, open a wpf project with binding errors, run and look at you new colored output folder.

image

Figure 5: Binding errors are now hilited in the output folder.

It is amazing how simple is to extend VS 2010 thanks to MEF.

Code is downloadable here.

Gian Maria.