Issues with command names in Visual Studio packages

When creating a Visual Studio add-in, you had full control of the full name of its commands (command prefix + command short name, such as “MyAddIn.MyCommand”), as I explained in the article HOWTO: Create command names without ‘.Connect’ in Visual Studio add-ins. So, when I created my MZ-Tools add-in for Visual Studio, each version used a command prefix such as “MZTools6” or “MZTools7”, and I could provide that information to the end user to customize the keyboard shortcuts, for example:

keyboardshortcuts

Another nice consequence was that, given a Visual Studio version, two versions of the add-in (for example one purchased, next one evaluating) could be loaded at the same time without collisions of add-in command full names, because each one used a different command prefix.

With packages, you lack the control over the command prefix, as I explained in INFO: How a Visual Studio package command is named. So, the commands of a package cannot be named “MyPackage.MyCommand”. And it is perfectly possible that two packages (or two versions of the same package loaded side by side) create two commands with the same full name as in this example:

TwoCommands

This is possible because Visual Studio commands (as everything else in Visual Studio) are identified by Guids and Ids and not by names (the EnvDTE.Command interface exposes those two properties).

Therefore, given that a collision of command full names is not really a collision internally in Visual Studio (only in the user interface level), so far so good. But if your add-in assumes that its commands have unique full names (because the command prefix is unique for add-ins) and uses code like this:

EnvDTE.Command command = dte.Commands.Item("MyAddIn.MyCommand");

that will cause problems when migrating to a package:

EnvDTE.Command command = dte.Commands.Item("Tools.MyCommand");

You see, the command full name now uses “Tools” (for example) instead of “MyAddIn”. If you have two versions of your package loaded side by side, that call can return the command of the wrong package version. A similar problem to getting the correct CommandBar as explained in HOWTO: Get a CommandBar by Guid and Id rather than by name from a Visual Studio add-in.

The same can happen if you execute a command by name:

dte.ExecuteCommand("Tools.MyCommand");

The solution is to stop using command full names in the code to identify commands, and to use the command Guid / Id instead:

In my MZ-Tools extension I use a lot of command stuff, so I have to review/change several areas of the product as part of the migration to a package. Also, the user can create commands for each code template of the Code Library feature (notice the optional Command Name field):

codelibrary

In the code of the add-in, that is done using the EnvDTE80.Commands2.AddNamedCommand2 method. Although you can use automation (EnvDTE) from a package, you can’t use that method because its first parameter is of the type EnvDTE.AddIn. I guess that a package must use the AddNamedCommand methods of the IVsProfferCommands interface. I will post and provide a sample once I try it.