Logo
INFO: Visual Studio .NET Add-In Commands Disappear On Next Session

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio .NET 2002
Date: May 2005   Microsoft Visual Studio .NET 2003
Updated March 2013   Microsoft Visual Studio 2005
      Microsoft Visual Studio 2008
      Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012
Introduction

This article describes why commands created by Visual Studio .NET add-ins disappear on the next session and how to restore them.

More Information

Using the wizard provided by Visual Studio .NET to create add-ins ("Other Projects", "Extensibility Projects", "Visual Studio .NET Add-in" project kind) the 4th step allows you to create a "Tools" menu item through the checkbox under the question "Would you like to create UI for the user to interact with your Add-in?". Selecting this checkbox will cause the following code to appear in your OnConnection method:

Language: VB.NET   Copy Code Copy Code (IE only)
Public Sub OnConnection(ByVal application As Object, _
   ByVal connectMode As Extensibility.ext_ConnectMode, _
   ByVal addInInst As Object, ByRef custom As System.Array) _
   Implements Extensibility.IDTExtensibility2.OnConnection
 
   applicationObject = CType(application, EnvDTE.DTE)
   addInInstance = CType(addInInst, EnvDTE.AddIn)

   If connectMode = Extensibility.ext_ConnectMode.ext_cm_UISetup Then

      Dim objAddIn As AddIn = CType(addInInst, AddIn)
      Dim CommandObj As Command
  
      Try
         CommandObj = applicationObject.Commands.AddNamedCommand(objAddIn, "MyAddin15", _
            "MyAddin15", "Executes the command for MyAddin15", True, 59, Nothing, 1 + 2)  
            '1+2 == vsCommandStatusSupported+vsCommandStatusEnabled

         CommandObj.AddControl(applicationObject.CommandBars.Item("Tools"))

      Catch e as System.Exception
      End Try
 
   End If

End Sub
Language: C#   Copy Code Copy Code (IE only)
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, 
  object addInInst, ref System.Array custom)
{
   applicationObject = (_DTE)application;
   addInInstance = (AddIn)addInInst;

   if(connectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup)
   {
      object []contextGUIDS = new object[] { };
      Commands commands = applicationObject.Commands;
      _CommandBars commandBars = applicationObject.CommandBars;

      try
      {
         Command command = commands.AddNamedCommand(addInInstance, "MyAddin1", "MyAddin1",
            "Executes the command for MyAddin1", true, 59, ref contextGUIDS, 
            (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
         CommandBar commandBar = (CommandBar)commandBars["Tools"];
         CommandBarControl commandBarControl = command.AddControl(commandBar, 1);
      }
      catch(System.Exception /*e*/)
      {
      }
   }
}

As you can see, the command is created only when the connectMode parameter value is ext_cm_UISetup, and that happens only once in the whole life of the add-in after installed on a computer: when the add-in is loaded for the first time for the current user. This is convenient because add-ins should not create commands on startup and destroy them on shutdown. Rather, they should be created only once to load faster and to preserve keyboard bindings created by the user for those commands.

Visual Studio .NET knows if it is the first time that the add-in is loaded (and therefore if it must pass the value ext_cm_UISetup in the connectMode parameter) through a Windows Registry key, as explained in the article HOWTO: Reset a Visual Studio add-in.

When Visual Studio .NET is closed, it persists add-in command information on disk. That information is stored for each user in the following file:

  • Windows XP: "C:\Documents and Settings\<user>\Application Data\Microsoft\VisualStudio\<version>\1033\CmdUI.PRF"
  • Windows Vista / Windows 7 / Windows 8 / Windows 8.1: "C:\Users\<user>\AppData\Roaming\Microsoft\VisualStudio\<version>\1033\CmdUI.PRF"

where <version> is:

  • 7.0 for Visual Studio .NET 2002
  • 7.1 for Visual Studio .NET 2003
  • 8.0 for Visual Studio 2005
  • 9.0 for Visual Studio 2008
  • 9.0 for Visual Studio 2010
  • 10.0 for Visual Studio 2012

This persistence mechanism causes the following issue when you debug an add-in for the first time:

  • You open a first instance of Visual Studio .NET and use the wizard to create an add-in as described above.
  • You debug the add-in. This opens a second instance of Visual Studio .NET where the add-in is loaded and the ext_cm_UISetup value is passed in the connectMode parameter of the OnConnection method. At this point, you can go to the "Tools", "Customize…" menu, "Commands" tab, "AddIns" category and check that the command of your add-in is there. You can also check that a menu item was added to the "Tools" menu with a smiley face.
  • You close the debugged (second) instance of Visual Studio .NET. At this point, the command information is persisted to disk.
  • You close the first instance of Visual Studio .NET. At this point, the command information of this instance is persisted to disk too, overwriting the information persisted by the second instance. As a consequence, the information about your command is lost, and since the ext_cm_UISetup value won't be used again since the add-in was already loaded, the add-in won't have the chance of recreating the command.

There are several ways to solve this problem, which are detailed here:

  • You can close all Visual Studio .NET instances, open a .NET DOS command prompt ("Microsoft Visual Studio .NET 2003", "Visual Studio .NET Tools", "Visual Studio .NET 2003 Command Prompt" and type:

devenv.exe /setup

That will reset the CommandPreload (per-user addins) or PreloadAddinState (all-user add-ins) flags in the Registry and will load Visual Studio .NET and its add-ins, closing again Visual Studio .NET and persisting command information for good. But be aware that some Visual Studio .NET customizations can be lost (buttons, command bars, etc.) using this approach.

  • You can close all Visual Studio .NET instances, reset the proper CommandPreload or PreloadAddinState flag by hand using the regedit.exe tool, load Visual Studio .NET, check that the command is there again, and close Visual Studio .NET to persist command information. See HOWTO: Reset a Visual Studio add-in.
  • You can avoid altogether the ext_cm_UISetup flag and the described mechanism and instead you can check if your command exists (using the DTE.Commands collection) every time that your add-in is loaded. If it does not exist, you create it. See: HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in

Note: Visual Studio 2005 and higher doesn't exhibit this problem because it introduced a new command-line switch /resetaddin <addin_namespace.Connect> for devenv.exe to reset those registry entries for the add-in, and the add-in project generated by the add-in wizard uses that switch in the property pages of the add-in project ("Debug" tab, "Start Options" section, "Command line arguments" field) to reset the add-in each time you debug it. This could lead to the false conclusion that ext_ConnectMode.ext_cm_UISetup is fired each time that the add-in runs. It is not. It only happens when you debug add-ins with Visual Studio 2005 or higher. It doesn't happen with Visual Studio .NET 2002/2003, it doesn't happen when the add-in is used on a final machine (without debugging) and if you remove the /resetaddin flag of the property page of your Visual Studio 2005 project, it won't happen too when you debug your add-in.

Related articles



Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)


Top