More on devenv.exe /resetaddin not removing permanent commandbars

I think I forgot to blog about the resolution of this bug:

devenv.exe /resetaddin doesn’t fully reset the add-in

whose Microsoft Connect bug report is:

The problem is, you see, that devenv.exe /resetaddin doesn’t remove permanent commandbars, only commands and buttons on commandbars. That means that if you are using permanent commandbars and not temporary ones, at the very least your uninstaller needs to take care of removing permanent commandbars explicitly because devenv.exe /resetaddin won’t do it. This can be done creating an instance of EnvDTE.DTE, locating the commandbar and calling EnvDTE.DTE.Commands.RemoveCommandBar (see HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation). And not only the uninstaller: when debugging you may need to remove the commandbar too because VS 2005 and higher fire a new UISetup phase each time that you debug, so you get duplicated commandbars.

The temporary vs permanent approaches for commandbars is a nightmare for two reasons:

  • First, their own existence. A single approach would be much better. And the temporary one would be preferable. The reason for the permanent one is that for add-ins with a large number of commandbars and buttons, it takes less time to persist the UI on disk and retrieve it from there when launching VS than recreating the UI. I think that there aren’t many add-ins with lots of commandbars and buttons (certainly my MZ-Tools add-in is one with such large number of buttons, but I keep using the temporary approach). But if performance is a problem, then it is better to fix that rather than inventing a new approach. Some ideas for Microsoft to increase the performance of add-ins using the temporary approach are:

    • Provide a EnvDTE.Commands.Exist(commandName) method to test if a command exists or not (to create it only if it doesn’t exist). Currently you have to call the Item method which causes an (expensive) exception if the command doesn’t exist.
    • Provide a EnvDTE.AddInCommands collection that returns only the commands of add-ins, not the hundreds of commands of Visual Studio.
    • Make EnvDTE.Command.AddControl to behave as follows: if you are adding a button to a menu, set the CommandBarButton.Style to msoButtonIconAndCaption (VS already does this), but if you are adding it to a toolbar, set the CommandBarButton.Style to msoButtonIcon since it is more likely that style (without caption) on a toolbar. Currently VS defaults to msoButtonIconAndCaption also in this case, which means that after getting the CommandBarControl, you have to cast it to CommandBarButton and then change the Style property, which means that the button needs to be redrawn (a performance hit). I already reported this two years ago to no avail: Wrong default vsCommandStyle for CommandBarButtons created from add-ins. Even more, Visual Studio doesn’t work as supposed to do: Problems with ContextUIGUIDs and vsCommandDisabledFlagsValue in EnvDTE.Commands.AddNamedCommand (a bug yet to be acknowledged and fixed).
    • Simplify the way of getting transparent pictures for commands. The transparent color has been RGB=0,254,0 for long time which means that a color remapping must be performed. Hopefully this has been addressed in VS 2010 with support for 32-bit bitmaps with transparency in the alpha channel.
  • Second, the APIs are not consistent, which creates a lot of confusion. If both approaches need to exist, at least they would have to use the same methods with just one boolean parameter indicating if a commandbar is permanent or temporary. Currently you have:

    • CommandBars.Add to add temporary commandbars
    • CommandBar.Delete to remove temporary commandbars
    • Commands.AddCommandBar to add permanent commandbars (even if the CommandBars.Add method above has a Temporary parameter!)
    • Commands.RemoveCommandBar to remove permanent commandbars

Anyone can see that that mix of methods to add commandbars is bound to cause problems (why is there a AddCommandBar method in the Commands collection?) and certainly it is: the bug of devenv.exe /resetaddin can’t be fixed because the Commands.AddCommandBar method lacks a fundamental piece of information: the AddIn instance that is adding the commandbar. Without that information the IDE doesn’t know which add-in is the owner of a permanent commandbar and therefore can’t remove it.