Category Archives: Moving from add-ins to packages

MZ-Tools Articles Series: PRB: Button of package command cannot be initially invisible on Visual Studio toolbar

While migrating my MZ-Tools add-in to a package, I found an issue: I wanted a button to be initially invisible on my toolbar. By “initially” I mean before the package is loaded, that is, declaring the invisibility in the .vsct file using:

<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>DefaultInvisible</CommandFlag>

However, the button appeared initially disabled rather than invisible. Investigating I found this reported in the MSDN VSX forum as back as in 2006 (VS 2005 I guess) using the old .ctc file rather than the new .vsct file and, guess what, that behavior is “by design”. However, buttons on toolwindows toolbars (rather that on IDE toolbars) can be initially invisible.

I created a sample package to reproduce the problem. The package creates two commands (the first one initially invisible) that are placed in three locations: the Tools menu, the Standard toolbar and the Solution Explorer toolbar. Notice that the button on the Standard toolbar is disabled rather than invisible:

PackageCommandButtonNotInvisibleOnVSToolbar

And I have documented this behavior with code in this article:

PRB: Button of package command cannot be initially invisible on Visual Studio toolbar

MZ-Tools Articles Series: INFO: How a Visual Studio package command is named

Another very confusing thing when starting with packages and you have a background of creating add-ins is how to name a command.

With add-ins, the (full) name of a command was composed by two parts:

And one interesting consequence was that all the commands of your add-in used the same prefix. With packages this is not true. The prefix of a command created by a package follows some complicated rules that depend on the menu / toolbar / context menu where the command is mainly placed (because, you know, a command is not a UI item and you can create several UI items in different locations tied to the same command).

And even the (short) name of the command can vary depending on the values of <CommandName>, <LocCanonicalName> and, go figure, can even be inferred from the caption of the command (<ButtonText>) removing special characters, etc.

I have written this article to try to explain all rules:

INFO: How a Visual Studio package command is named

MZ-Tools Articles Series: HOWTO: Create a command without user interface items from a Visual Studio package.

One of the most confusing things when starting with packages and you have a background of creating add-ins is how to create and name commands, which are not user interface items.

With add-ins, commands are created by code, and there are two separate steps: one to create the command (Commands2.AddNamedCommand2 method) and other step to create UI items (either temporary or permanent) such as menu items, toolbar buttons, etc. See:

HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in.

However, commands in packages are created by declarations in a .vsct file, and the separation between command and UI items is very blurry (and how to name a command is a subject for another post). For example, you have a <Commands> section, but commands are actually declared inside a <Buttons> section using <Button> elements. I can’t insist enough that in Visual Studio a command is not a button (or a menu item), and, in fact, sometimes your extension may want to provide a command without a user interface item. For example, if you want the command to be executed by default only with a keyboard shortcut. Or for some reason you need an “internal” command. My MZ-Tools add-in does this with at least one command.

So, I have written this article to show how you would create a command in a package without UI items:

HOWTO: Create a command without user interface items from a Visual Studio package

MZ-Tools Articles Series: HOWTO: Execute a command by Guid and Id from a Visual Studio package

There are a few articles / samples that I wrote in July but I forgot to blog about because I have been busy tuning this new web site and also I was a couple of weeks on vacation. This is the first of them.

Some years ago I wrote about executing a command by Guid and Id (rather than by name) from a VS add-in:

HOWTO: Execute a command by Guid and Id from a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008013.aspx

As part of my strategy to moving from add-in to package for my MZ-Tools add-in, I want to get rid of EnvDTE as much as possible, so this is the equivalent using an automation-free approach to do the same:

HOWTO: Execute a command by Guid and Id from a Visual Studio package
http://www.mztools.com/articles/2014/MZ2014018.aspx

Strategies migrating from Visual Studio add-ins to packages

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:

MZTools8SolutionExplorer

And my object model has 30 interfaces approx.:

ObjectModel

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.