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

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio .NET 2002
Date: June 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 provides a code sample to add commands, buttons, commandbars and toolbars to the Visual Studio .NET IDE from an add-in.

More information

Add-ins provide commands to execute actions. A command is not a user interface element, that is, it is not a button. It is a mechanism used by Visual Studio to execute actions. When an add-in creates a command using DTE.Commands.AddNamedCommand, no button is created. You can notice the existence of the command by the following ways:

  • The "Tools", "Customize" dialog, "Commands" tab, "Addins" category.
  • The "Tools", "Customize" dialog, "Keyboard" button.
  • The Command window, where you can type command names.

Commands can be executed:

  • Using the buttons (CommandBarButtons) that are created from them in the Visual Studio user interface (in built-in commandbars of Visual Studio or in commandbars created by the add-in). Several buttons can be created from the same command, on different commandbars (main menu, toolbar, context menu, etc.).
  • Using the keyboard shortcut associated.
  • Typing it in the Command window
  • Programmatically, using DTE.ExecuteCommand.

Visual Studio .NET allows add-ins to add commandbars of two kinds, permanent or temporary:

  • Temporary commandbars: the add-in creates these commandbars each time that it is loaded and removes them each time it is unloaded.

    To create a temporary commandbar:
    • Create it each time that the add-in is loaded, when the OnConnection method receives the values ext_ConnectMode.ext_cm_AfterStartup or ext_ConnectMode.ext_cm_Startup (but not when it receives the value ext_ConnectMode.ext_cm_UISetup).
    • Use the DTE.CommandBars.Add method for toolbars or the CommandBar.Controls.Add method for a commandbar inside other commandbar (which is called a commandbar popup).

    To remove a temporary commandbar:
    • Remove it when the add-in is unloaded.
    • Use the CommandBar.Delete method.
  • Permanent commandbars: these commandbars are always visible in the IDE, even if the add-in is unloaded through the Add-in Manager. The rationale for this behavior is to optimize the startup of the IDE and add-ins: the commandbars are created faster if they are persisted and retrieved from disk by Visual Studio than if an add-in has to create them and add all its buttons by code when the add-in is loaded.

    To create a permanent commandbar:
    • Create it only once, when the OnConnection method receives the value ext_ConnectMode.ext_cm_UISetup in the connectMode parameter, which happens only once after an add-in is installed on a machine (more on this later).
    • Use the DTE.Commands.AddCommandBar method.

    To remove a permanent commandbar:

    Since permanent commandbars remain visible in the IDE even if the add-in is unloaded through the Add-in Manager, this behavior will be confusing for many users and most add-ins use temporary commandbars instead. Also, permanent commandbars are complicated during development, because for their own nature they are not removed, and you can get duplicated commandbars if a new ext_ConnectMode.ext_cm_UISetup phase is executed (specially in Visual Studio 2005 and higher; more on this later). It is recomended that you use temporary commandbars if your add-in adds only a few buttons or commandbars.

    Since temporary commandbars are created by an add-in each time it is loaded, it is up to the add-in to store somewhere (in the registry, for example) the visibility of the commandbar when it was unloaded (CommandBar.Visible property), because the user may have choosen to hide it. Then, when the add-in is loaded, it can check the stored value to know if the commandbar should be made visible or not after creating it. See the article HOWTO: Handling buttons and toolbars user customizations from a Visual Studio add-in

Important notes

  • You should only use DTE.Commands.AddCommandBar to create permanent commandbars when connectMode has the value ext_ConnectMode.ext_cm_UISetup, and you should only use DTE.CommandBars.Add to create temporary commandbars when connectMode is ext_ConnectMode.ext_cm_AfterStartup or ext_ConnectMode.ext_cm_Startup. Do not mix both models.
  • In order to receive the ext_ConnectMode.ext_cm_UISetup flag in the OnConnection method, your add-in registration must specify that it wants "CommandPreload" (see HOWTO: Reset a Visual Studio add-in). When you use the add-in wizard to create an add-in project, you must check the option "Yes, create a "Tools" menu item. By default this will cause the Add-in to load when the button is clicked unless the Add-in is set to load on startup of the host application.". If you don't check that option and later you change your mind and want a ext_ConnectMode.ext_cm_UISetup phase, you need to change the Windows registry setting or XML tag value specified in that article.
  • Notice that ext_ConnectMode.ext_cm_UISetup is fired only once in the whole life of an add-in on the computer, that is, it is not fired each time that the add-in is loaded (keep on reading some bullets if you think otherwise because on your machine it is fired always when you debug your add-in in Visual Studio 2005 or higher). The flag ext_ConnectMode.ext_cm_UISetup is intended to create permanent user interface only once and forever.
  • If, while developing your add-in, you want to add new permanent user interface, in order to have a new ext_ConnectMode.ext_cm_UISetup phase to add it, you would need to reset some registry flags (see HOWTO: Reset a Visual Studio add-in).
  • Visual Studio 2005 introduced a handy new command-line flag to reset those registry entries to get a new ext_ConnectMode.ext_cm_UISetup phase:

    devenv.exe /resetaddin <AddInNamespace.Connect>
     
  • The add-in project generated by the add-in wizard of Visual Studio 2005 or higher (on the contrary to VS.NET 2002/2003) adds that command-line flag to devenv.exe 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 does not happen with Visual Studio .NET 2003, it does not 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/2008 project, it won't happen too when you debug your add-in.
  • The /resetaddin command-line flag of Visual Studio 2005 or higher removes commands and permanent buttons created by the add-in, but not permanent commandbars. So, you will get duplicated permanent commandbars in Visual Studio 2005 or higher each time that you debug your add-in, unless your code deletes a previous commandbar before adding it again.
  • Commands should be created only once and forever, and removed only when the add-in is uninstalled, rather than creating them when the add-in is loaded and removed when the add-in is unloaded. The reason for this is that if the user has associated keyboard shortcuts to them, they would be lost on each session. Therefore, commands can be created either:
    • When the connectMode has the value ext_ConnectMode.ext_cm_UISetup, which will happen only once in the whole life of the add-in on the computer.
    • When connectMode is ext_ConnectMode.ext_cm_AfterStartup or ext_ConnectMode.ext_cm_Startup if you detect that they do not exist yet. This approach is more robust (see INFO: Visual Studio .NET Add-In Commands Disappear On Next Session) at the cost of being somewhat more time-consuming. This approach will be used in the code of this article.

    However, when using the temporary user interface approach, if Visual Studio or the add-in crashes, there will be no chance of removing the temporary user interface and it will remain "dead", getting a duplicated user interface the next time the add-in is loaded. You can mitigate this problem to some extent re-creating commands preserving keyboard bindings when the add-in is unloaded to remove all its buttons (dead or not). See HOWTO: Prevent dead CommandBarButtons when Visual Studio or an add-in crashes.
  • Controls (buttons) are added to a CommandBar using Command.AddControl(commandBar). This function returns a CommandBarControl, which has properties to set the Caption, etc. Some properties, though, will require to cast it to a CommandBarButton, for example to set the BeginGroup or the Style (msoButtonIcon, msoButtonIconAndCaption, etc.) properties. The status of a CommandBarControl (visible, enabled, etc.) is controlled through its underlying Command, in the implementation of the IDTCommandTarget.QueryStatus method, not through the properties of CommandBarControl. The state of a command can be controlled also even when the add-in is not loaded. See: HOWTO: Controlling the state of command in a Visual Studio add-in.
  • There are a couple of bugs in the Visual Studio .NET 2002/2003 IDE that cause a an add-in to be reloaded after being unloaded if it has added a CommandBarControl to some built-in commandbar of the IDE (such as the "Tools" menu) and another add-ins has done the same, or if it has created a toolbar which is on the same row that the toolbar of other add-in.

Sample code

The following source code shows an add-in that creates an EnvDTE.Command and exposes it in the Visual Studio .NET IDE through the following UI elements:

  • A button on the "Standard" toolbar of Visual Studio .NET.
  • A menu entry on the "Tools" menu of Visual Studio .NET.
  • A submenu on the "Tools" menu of Visual Studio .NET.
  • A menu entry on the context menu of a code window.
  • A new menu on the main menu of Visual Studio .NET.
  • A new toolbar.

Both permanent and temporary approaches are shown, in VB.NET and C#.

For temporary commandbars:

Language: VB.NET   Copy Code Copy Code (IE only)
Public Class Connect
   Implements Extensibility.IDTExtensibility2
   Implements IDTCommandTarget

   ' Constants for command properties
   Private Const MY_COMMAND_NAME As String = "MyCommand"
   Private Const MY_COMMAND_CAPTION As String = "My command"
   Private Const MY_COMMAND_TOOLTIP As String = "My command tooltip"

   ' Variables for IDE and add-in instances
   Private applicationObject As EnvDTE.DTE
   Private addInInstance As EnvDTE.AddIn

   ' Buttons that will be created on built-in commandbars of Visual Studio
   ' We must keep them at class level to remove them when the add-in is unloaded
   Private myStandardCommandBarButton As CommandBarButton
   Private myToolsCommandBarButton As CommandBarButton
   Private myCodeWindowCommandBarButton As CommandBarButton

   ' CommandBars that will be created by the add-in
   ' We must keep them at class level to remove them when the add-in is unloaded
   Private myTemporaryToolbar As CommandBar
   Private myTemporaryCommandBarPopup1 As CommandBarPopup
   Private myTemporaryCommandBarPopup2 As CommandBarPopup

   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

      Try

         applicationObject = CType(application, EnvDTE.DTE)
         addInInstance = CType(addInInst, EnvDTE.AddIn)

         Select Case connectMode

            Case ext_ConnectMode.ext_cm_UISetup

               ' Do nothing for this add-in with temporary user interface

            Case ext_ConnectMode.ext_cm_Startup

               ' The add-in was marked to load on startup
               ' Do nothing at this point because the IDE may not be fully initialized
               ' Visual Studio will call OnStartupComplete when fully initialized

            Case ext_ConnectMode.ext_cm_AfterStartup

               ' The add-in was loaded by hand after startup using the Add-In Manager
               ' Initialize it in the same way that when is loaded on startup
               AddTemporaryUI()

         End Select

      Catch e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub

   Public Sub OnStartupComplete(ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnStartupComplete

      AddTemporaryUI()

   End Sub

   Public Sub AddTemporaryUI()

      ' Constants for names of built-in commandbars of Visual Studio
      Const VS_STANDARD_COMMANDBAR_NAME As String = "Standard"
      Const VS_MENUBAR_COMMANDBAR_NAME As String = "MenuBar"
      Const VS_TOOLS_COMMANDBAR_NAME As String = "Tools"
      Const VS_CODE_WINDOW_COMMANDBAR_NAME As String = "Code Window"

      ' Constants for names of commandbars created by the add-in
      Const MY_TEMPORARY_COMMANDBAR_POPUP1_NAME As String = "MyTemporaryCommandBarPopup1"
      Const MY_TEMPORARY_COMMANDBAR_POPUP2_NAME As String = "MyTemporaryCommandBarPopup2"

      ' Constants for captions of commandbars created by the add-in
      Const MY_TEMPORARY_COMMANDBAR_POPUP1_CAPTION As String = "My sub menu"
      Const MY_TEMPORARY_COMMANDBAR_POPUP2_CAPTION As String = "My main menu"
      Const MY_TEMPORARY_TOOLBAR_CAPTION As String = "My toolbar"

      ' The only command that will be created. We will create several buttons from it
      Dim myCommand As Command = Nothing

      ' Built-in commandbars of Visual Studio
      Dim standardCommandBar As CommandBar
      Dim menuCommandBar As CommandBar
      Dim toolsCommandBar As CommandBar
      Dim codeCommandBar As CommandBar

      ' Buttons that will be created on a toolbars/commandbar popups created by the add-in
      ' We don't need to keep them at class level to remove them when the add-in is unloaded 
      ' because we will remove the whole toolbars/commandbar popups
      Dim myToolBarButton As CommandBarButton
      Dim myCommandBarPopup1Button As CommandBarButton
      Dim myCommandBarPopup2Button As CommandBarButton

      ' The collection of Visual Studio commandbars
      Dim commandBars As CommandBars

      ' Other variables
      Dim toolsCommandBarControl As CommandBarControl
      Dim position As Integer

      Try

         ' ------------------------------------------------------------------------------------

         ' Try to retrieve the command, just in case it was already created, ignoring the 
         ' exception that would happen if the command was not created yet.
         Try
            myCommand = applicationObject.Commands.Item(addInInstance.ProgID & "." & MY_COMMAND_NAME)
         Catch
         End Try

         ' Add the command if it does not exist
         If myCommand Is Nothing Then

            myCommand = applicationObject.Commands.AddNamedCommand(addInInstance, _
               MY_COMMAND_NAME, MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, True, _
               59, Nothing, vsCommandStatus.vsCommandStatusSupported Or _
               vsCommandStatus.vsCommandStatusEnabled)

         End If

         ' ------------------------------------------------------------------------------------

         ' Retrieve the collection of commandbars
         ' Note:
         ' - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         '   DTE.CommandBars returns directly a CommandBars type, so a cast 
         '   to CommandBars is redundant
         ' - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         '   DTE.CommandBars returns an Object type, so we do need a cast to CommandBars
         commandBars = DirectCast(applicationObject.CommandBars, CommandBars)

         ' Retrieve some built-in commandbars
         standardCommandBar = commandBars.Item(VS_STANDARD_COMMANDBAR_NAME)
         menuCommandBar = commandBars.Item(VS_MENUBAR_COMMANDBAR_NAME)
         toolsCommandBar = GetCommandBarPopup(menuCommandBar, VS_TOOLS_COMMANDBAR_NAME)
         codeCommandBar = commandBars.Item(VS_CODE_WINDOW_COMMANDBAR_NAME)

         ' ------------------------------------------------------------------------------------

         ' Create the buttons from the commands
         ' Note:
         ' - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         '   Command.AddControl returns directly a CommandBarControl type, so a cast 
         '   to CommandBarControl is redundant
         ' - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         '   Command.AddControl returns an Object type, so we do need a cast to CommandBarControl

         ' ------------------------------------------------------------------------------------
         ' Button on the "Standard" toolbar
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Standard" toolbar
         myStandardCommandBarButton = DirectCast(myCommand.AddControl(standardCommandBar, _
            standardCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION
         myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon ' It could be also msoButtonIconAndCaption
         myStandardCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' Button on the "Tools" menu
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Tools" menu
         myToolsCommandBarButton = DirectCast(myCommand.AddControl(toolsCommandBar, _
            toolsCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myToolsCommandBarButton.Caption = MY_COMMAND_CAPTION
         myToolsCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' Button on the "Code Window" context menu
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Code Window" context menu
         myCodeWindowCommandBarButton = DirectCast(myCommand.AddControl(codeCommandBar, _
            codeCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myCodeWindowCommandBarButton.Caption = MY_COMMAND_CAPTION
         myCodeWindowCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' New toolbar
         ' ------------------------------------------------------------------------------------

         ' Add a new toolbar 
         myTemporaryToolbar = commandBars.Add(MY_TEMPORARY_TOOLBAR_CAPTION, _
            MsoBarPosition.msoBarTop, System.Type.Missing, True)

         ' Add a new button on that toolbar
         myToolBarButton = DirectCast(myCommand.AddControl(myTemporaryToolbar, _
            myTemporaryToolbar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myToolBarButton.Caption = MY_COMMAND_CAPTION
         myToolBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption ' It could be also msoButtonIcon

         ' Make visible the toolbar
         myTemporaryToolbar.Visible = True

         ' ------------------------------------------------------------------------------------
         ' New submenu under the "Tools" menu
         ' ------------------------------------------------------------------------------------

         ' Add a new commandbar popup 
         myTemporaryCommandBarPopup1 = DirectCast(toolsCommandBar.Controls.Add( _
            MsoControlType.msoControlPopup, System.Type.Missing, System.Type.Missing, _
            toolsCommandBar.Controls.Count + 1, True), CommandBarPopup)

         ' Change some commandbar popup properties
         myTemporaryCommandBarPopup1.CommandBar.Name = MY_TEMPORARY_COMMANDBAR_POPUP1_NAME
         myTemporaryCommandBarPopup1.Caption = MY_TEMPORARY_COMMANDBAR_POPUP1_CAPTION

         ' Add a new button on that commandbar popup
         myCommandBarPopup1Button = DirectCast(myCommand.AddControl(myTemporaryCommandBarPopup1.CommandBar), _
            CommandBarButton)

         ' Change some button properties
         myCommandBarPopup1Button.Caption = MY_COMMAND_CAPTION

         ' Make visible the commandbar popup
         myTemporaryCommandBarPopup1.Visible = True

         ' ------------------------------------------------------------------------------------
         ' New main menu
         ' ------------------------------------------------------------------------------------

         ' Calculate the position of a new commandbar popup to the right of the "Tools" menu
         toolsCommandBarControl = DirectCast(toolsCommandBar.Parent, CommandBarControl)
         position = toolsCommandBarControl.Index + 1

         ' Add a new commandbar popup 
         myTemporaryCommandBarPopup2 = DirectCast(menuCommandBar.Controls.Add( _
            MsoControlType.msoControlPopup, System.Type.Missing, System.Type.Missing, _
            position, True), CommandBarPopup)

         ' Change some commandbar popup properties
         myTemporaryCommandBarPopup2.CommandBar.Name = MY_TEMPORARY_COMMANDBAR_POPUP2_NAME
         myTemporaryCommandBarPopup2.Caption = MY_TEMPORARY_COMMANDBAR_POPUP2_CAPTION

         ' Add a new button on that commandbar popup
         myCommandBarPopup2Button = DirectCast(myCommand.AddControl(myTemporaryCommandBarPopup2.CommandBar, _
            myTemporaryCommandBarPopup2.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myCommandBarPopup2Button.Caption = MY_COMMAND_CAPTION

         ' Make visible the commandbar popup
         myTemporaryCommandBarPopup2.Visible = True

      Catch e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub

   Private Function GetCommandBarPopup(ByVal parentCommandBar As CommandBar, ByVal commandBarPopupName As String) As CommandBar

      Dim commandBar As CommandBar = Nothing
      Dim commandBarControl As CommandBarControl
      Dim commandBarPopup As CommandBarPopup

      For Each commandBarControl In parentCommandBar.Controls

         If commandBarControl.Type = MsoControlType.msoControlPopup Then

            commandBarPopup = DirectCast(commandBarControl, CommandBarPopup)

            If commandBarPopup.CommandBar.Name = commandBarPopupName Then

               commandBar = commandBarPopup.CommandBar

               Exit For

            End If

         End If

      Next

      Return commandBar

   End Function

   Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, _
      ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnDisconnection

      Try

         Select Case RemoveMode

            Case ext_DisconnectMode.ext_dm_HostShutdown, ext_DisconnectMode.ext_dm_UserClosed

               If Not (myStandardCommandBarButton Is Nothing) Then
                  myStandardCommandBarButton.Delete()
               End If

               If Not (myCodeWindowCommandBarButton Is Nothing) Then
                  myCodeWindowCommandBarButton.Delete()
               End If

               If Not (myToolsCommandBarButton Is Nothing) Then
                  myToolsCommandBarButton.Delete()
               End If

               If Not (myTemporaryToolbar Is Nothing) Then
                  myTemporaryToolbar.Delete()
               End If

               If Not (myTemporaryCommandBarPopup1 Is Nothing) Then
                  myTemporaryCommandBarPopup1.Delete()
               End If

               If Not (myTemporaryCommandBarPopup2 Is Nothing) Then
                  myTemporaryCommandBarPopup2.Delete()
               End If

         End Select

      Catch e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub

   Public Sub OnBeginShutdown(ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnBeginShutdown
   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As System.Array) _
       Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
   End Sub

   Public Sub Exec(ByVal cmdName As String, _
      ByVal executeOption As vsCommandExecOption, _
      ByRef varIn As Object, ByRef varOut As Object, ByRef handled As Boolean) _
      Implements IDTCommandTarget.Exec

      handled = False

      If (executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault) Then

         If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
            handled = True
            System.Windows.Forms.MessageBox.Show("Command executed.")
         End If

      End If

   End Sub

   Public Sub QueryStatus(ByVal cmdName As String, _
      ByVal neededText As vsCommandStatusTextWanted, _
      ByRef statusOption As vsCommandStatus, ByRef commandText As Object) _
      Implements IDTCommandTarget.QueryStatus

      If neededText = vsCommandStatusTextWanted.vsCommandStatusTextWantedNone Then

         If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
            statusOption = CType(vsCommandStatus.vsCommandStatusEnabled + _
               vsCommandStatus.vsCommandStatusSupported, vsCommandStatus)
         Else
            statusOption = vsCommandStatus.vsCommandStatusUnsupported
         End If

      End If

   End Sub

End Class
Language: C#   Copy Code Copy Code (IE only)
public class Connect : Extensibility.IDTExtensibility2, IDTCommandTarget
{
   // Constants for command properties
   private const string MY_COMMAND_NAME = "MyCommand";
   private const string MY_COMMAND_CAPTION = "My command";
   private const string MY_COMMAND_TOOLTIP = "My command tooltip";

   // Variables for IDE and add-in instances
   private EnvDTE.DTE applicationObject;
   private EnvDTE.AddIn addInInstance;

   // Buttons that will be created on built-in commandbars of Visual Studio
   // We must keep them at class level to remove them when the add-in is unloaded
   private CommandBarButton myStandardCommandBarButton;
   private CommandBarButton myToolsCommandBarButton;
   private CommandBarButton myCodeWindowCommandBarButton;

   // CommandBars that will be created by the add-in
   // We must keep them at class level to remove them when the add-in is unloaded
   private CommandBar myTemporaryToolbar;
   private CommandBarPopup myTemporaryCommandBarPopup1;
   private CommandBarPopup myTemporaryCommandBarPopup2;

   public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode,
      object addInInst, ref System.Array custom)
   {
      try
      {
         applicationObject = (EnvDTE.DTE)application;
         addInInstance = (EnvDTE.AddIn)addInInst;

         switch (connectMode)
         {
            case ext_ConnectMode.ext_cm_UISetup:

               // Do nothing for this add-in with temporary user interface
               break;

            case ext_ConnectMode.ext_cm_Startup:

               // The add-in was marked to load on startup
               // Do nothing at this point because the IDE may not be fully initialized
               // Visual Studio will call OnStartupComplete when fully initialized
               break;

            case ext_ConnectMode.ext_cm_AfterStartup:

               // The add-in was loaded by hand after startup using the Add-In Manager
               // Initialize it in the same way that when is loaded on startup
               AddTemporaryUI();
               break;
         }
      }
      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

   public void OnStartupComplete(ref System.Array custom)
   {
      AddTemporaryUI();
   }

   public void AddTemporaryUI()
   {
      // Constants for names of built-in commandbars of Visual Studio
      const string VS_STANDARD_COMMANDBAR_NAME = "Standard";
      const string VS_MENUBAR_COMMANDBAR_NAME = "MenuBar";
      const string VS_TOOLS_COMMANDBAR_NAME = "Tools";
      const string VS_CODE_WINDOW_COMMANDBAR_NAME = "Code Window";

      // Constants for names of commandbars created by the add-in
      const string MY_TEMPORARY_COMMANDBAR_POPUP1_NAME = "MyTemporaryCommandBarPopup1";
      const string MY_TEMPORARY_COMMANDBAR_POPUP2_NAME = "MyTemporaryCommandBarPopup2";

      // Constants for captions of commandbars created by the add-in
      const string MY_TEMPORARY_COMMANDBAR_POPUP1_CAPTION = "My sub menu";
      const string MY_TEMPORARY_COMMANDBAR_POPUP2_CAPTION = "My main menu";
      const string MY_TEMPORARY_TOOLBAR_CAPTION = "My toolbar";

      // The only command that will be created. We will create several buttons from it
      Command myCommand = null;

      // Built-in commandbars of Visual Studio
      CommandBar standardCommandBar = null;
      CommandBar menuCommandBar = null;
      CommandBar toolsCommandBar = null;
      CommandBar codeCommandBar = null;

      // Buttons that will be created on a toolbars/commandbar popups created by the add-in
      // We don't need to keep them at class level to remove them when the add-in is unloaded 
      // because we will remove the whole toolbars/commandbar popups
      CommandBarButton myToolBarButton = null;
      CommandBarButton myCommandBarPopup1Button = null;
      CommandBarButton myCommandBarPopup2Button = null;

      // The collection of Visual Studio commandbars
      CommandBars commandBars = null;

      // Other variables
      CommandBarControl toolsCommandBarControl = null;
      int position = 0;
      object[] contextUIGuids = new object[] { };

      try
      {
         // ------------------------------------------------------------------------------------

         // Try to retrieve the command, just in case it was already created, ignoring the 
         // exception that would happen if the command was not created yet.
         try
         {
            myCommand = applicationObject.Commands.Item(addInInstance.ProgID + "." + MY_COMMAND_NAME, -1);
         }
         catch
         {
         }

         // Add the command if it does not exist
         if (myCommand == null)
         {
            myCommand = applicationObject.Commands.AddNamedCommand(addInInstance,
               MY_COMMAND_NAME, MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, true, 59, ref contextUIGuids,
               (int)(vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled));
         }
         // ------------------------------------------------------------------------------------

         // Retrieve the collection of commandbars
         // Note:
         // - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         //   DTE.CommandBars returns directly a CommandBars type, so a cast 
         //   to CommandBars is redundant
         // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         //   DTE.CommandBars returns an Object type, so we do need a cast to CommandBars
         commandBars = (CommandBars)applicationObject.CommandBars;

         // Retrieve some built-in commandbars
         standardCommandBar = commandBars[VS_STANDARD_COMMANDBAR_NAME];
         menuCommandBar = commandBars[VS_MENUBAR_COMMANDBAR_NAME];
         toolsCommandBar = GetCommandBarPopup(menuCommandBar, VS_TOOLS_COMMANDBAR_NAME);
         codeCommandBar = commandBars[VS_CODE_WINDOW_COMMANDBAR_NAME];

         // ------------------------------------------------------------------------------------

         // Create the buttons from the commands
         // Note:
         // - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         //   Command.AddControl returns directly a CommandBarControl type, so a cast 
         //   to CommandBarControl is redundant
         // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         //   Command.AddControl returns an Object type, so we do need a cast to CommandBarControl

         // ------------------------------------------------------------------------------------
         // Button on the "Standard" toolbar
         // ------------------------------------------------------------------------------------
         myStandardCommandBarButton = (CommandBarButton)myCommand.AddControl(standardCommandBar,
            standardCommandBar.Controls.Count + 1);

         // Change some button properties
         myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon; // It could be also msoButtonIconAndCaption
         myStandardCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // Button on the "Tools" menu
         // ------------------------------------------------------------------------------------

         // Add a button to the built-in "Tools" menu
         myToolsCommandBarButton = (CommandBarButton)myCommand.AddControl(toolsCommandBar,
            toolsCommandBar.Controls.Count + 1);

         // Change some button properties
         myToolsCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myToolsCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // Button on the "Code Window" context menu
         // ------------------------------------------------------------------------------------

         // Add a button to the built-in "Code Window" context menu
         myCodeWindowCommandBarButton = (CommandBarButton)myCommand.AddControl(codeCommandBar,
            codeCommandBar.Controls.Count + 1);

         // Change some button properties
         myCodeWindowCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myCodeWindowCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // New toolbar
         // ------------------------------------------------------------------------------------

         // Add a new toolbar 
         myTemporaryToolbar = commandBars.Add(MY_TEMPORARY_TOOLBAR_CAPTION, 
            MsoBarPosition.msoBarTop, System.Type.Missing, true);

         // Add a new button on that toolbar
         myToolBarButton = (CommandBarButton)myCommand.AddControl(myTemporaryToolbar,
            myTemporaryToolbar.Controls.Count + 1);

         // Change some button properties
         myToolBarButton.Caption = MY_COMMAND_CAPTION;
         myToolBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption; // It could be also msoButtonIcon

         // Make visible the toolbar
         myTemporaryToolbar.Visible = true;

         // ------------------------------------------------------------------------------------
         // New submenu under the "Tools" menu
         // ------------------------------------------------------------------------------------

         // Add a new commandbar popup 
         myTemporaryCommandBarPopup1 = (CommandBarPopup)toolsCommandBar.Controls.Add(
            MsoControlType.msoControlPopup, System.Type.Missing, System.Type.Missing,
            toolsCommandBar.Controls.Count + 1, true);

         // Change some commandbar popup properties
         myTemporaryCommandBarPopup1.CommandBar.Name = MY_TEMPORARY_COMMANDBAR_POPUP1_NAME;
         myTemporaryCommandBarPopup1.Caption = MY_TEMPORARY_COMMANDBAR_POPUP1_CAPTION;

         // Add a new button on that commandbar popup
         myCommandBarPopup1Button = (CommandBarButton)myCommand.AddControl(
            myTemporaryCommandBarPopup1.CommandBar, myTemporaryCommandBarPopup1.Controls.Count + 1);

         // Change some button properties
         myCommandBarPopup1Button.Caption = MY_COMMAND_CAPTION;

         // Make visible the commandbar popup
         myTemporaryCommandBarPopup1.Visible = true;

         // ------------------------------------------------------------------------------------
         // New main menu
         // ------------------------------------------------------------------------------------

         // Calculate the position of a new commandbar popup to the right of the "Tools" menu
         toolsCommandBarControl = (CommandBarControl)toolsCommandBar.Parent;
         position = toolsCommandBarControl.Index + 1;

         // Add a new commandbar popup 
         myTemporaryCommandBarPopup2 = (CommandBarPopup)menuCommandBar.Controls.Add(
            MsoControlType.msoControlPopup, System.Type.Missing, System.Type.Missing, position, true);

         // Change some commandbar popup properties
         myTemporaryCommandBarPopup2.CommandBar.Name = MY_TEMPORARY_COMMANDBAR_POPUP2_NAME;
         myTemporaryCommandBarPopup2.Caption = MY_TEMPORARY_COMMANDBAR_POPUP2_CAPTION;

         // Add a new button on that commandbar popup
         myCommandBarPopup2Button = (CommandBarButton)myCommand.AddControl(
            myTemporaryCommandBarPopup2.CommandBar, myTemporaryCommandBarPopup2.Controls.Count + 1);

         // Change some button properties
         myCommandBarPopup2Button.Caption = MY_COMMAND_CAPTION;

         // Make visible the commandbar popup
         myTemporaryCommandBarPopup2.Visible = true;
      }
      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

   private CommandBar GetCommandBarPopup(CommandBar parentCommandBar, string commandBarPopupName)
   {
      CommandBar commandBar = null;
      CommandBarPopup commandBarPopup; 

      foreach (CommandBarControl commandBarControl in parentCommandBar.Controls)
      {
         if (commandBarControl.Type == MsoControlType.msoControlPopup)
         {
            commandBarPopup = (CommandBarPopup) commandBarControl;

            if (commandBarPopup.CommandBar.Name == commandBarPopupName)
            {
               commandBar = commandBarPopup.CommandBar;
               break;
            }
         }
      }
      return commandBar;
   }

   public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref System.Array custom)
   {
      try
      {
         switch (RemoveMode)
         {
            case ext_DisconnectMode.ext_dm_HostShutdown:
            case ext_DisconnectMode.ext_dm_UserClosed:

               if ((myStandardCommandBarButton != null))
               {
                  myStandardCommandBarButton.Delete(true);
               }

               if ((myCodeWindowCommandBarButton != null))
               {
                  myCodeWindowCommandBarButton.Delete(true);
               }

               if ((myToolsCommandBarButton != null))
               {
                  myToolsCommandBarButton.Delete(true);
               }

               if ((myTemporaryToolbar != null))
               {
                  myTemporaryToolbar.Delete();
               }

               if ((myTemporaryCommandBarPopup1 != null))
               {
                  myTemporaryCommandBarPopup1.Delete(true);
               }

               if ((myTemporaryCommandBarPopup2 != null))
               {
                  myTemporaryCommandBarPopup2.Delete(true);
               }

               break;
         }
      }
      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

   public void OnBeginShutdown(ref System.Array custom)
   {
   }

   public void OnAddInsUpdate(ref System.Array custom)
   {
   }

   public void Exec(string cmdName, vsCommandExecOption executeOption, ref object varIn,
      ref object varOut, ref bool handled)
   {

      handled = false;

      if ((executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault))
      {
         if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
         {
            handled = true;
            System.Windows.Forms.MessageBox.Show("Command executed.");
         }
      }
   }

   public void QueryStatus(string cmdName, vsCommandStatusTextWanted neededText,
      ref vsCommandStatus statusOption, ref object commandText)
   {
      if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
      {
         if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
         {
            statusOption = (vsCommandStatus) (vsCommandStatus.vsCommandStatusEnabled | 
               vsCommandStatus.vsCommandStatusSupported);
         }
         else
         {
            statusOption = vsCommandStatus.vsCommandStatusUnsupported;
         }
      }
   }
}

For permanent commandbars:

Language: VB.NET   Copy Code Copy Code (IE only)
Public Class Connect
   Implements Extensibility.IDTExtensibility2
   Implements IDTCommandTarget

   ' Constants for command properties
   Private Const MY_COMMAND_NAME As String = "MyCommand"
   Private Const MY_COMMAND_CAPTION As String = "My command"
   Private Const MY_COMMAND_TOOLTIP As String = "My command tooltip"

   ' Variables for IDE and add-in instances
   Private applicationObject As EnvDTE.DTE
   Private addInInstance As EnvDTE.AddIn

   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

      Try

         applicationObject = CType(application, EnvDTE.DTE)
         addInInstance = CType(addInInst, EnvDTE.AddIn)

         Select Case connectMode

            Case ext_ConnectMode.ext_cm_UISetup

               ' Initialize the UI of the add-in
               AddPermanentUI()

            Case ext_ConnectMode.ext_cm_Startup

               ' The add-in was marked to load on startup
               ' Do nothing at this point because the IDE may not be fully initialized
               ' Visual Studio will call OnStartupComplete when fully initialized

            Case ext_ConnectMode.ext_cm_AfterStartup

               ' The add-in was loaded by hand after startup using the Add-In Manager
               ' Initialize it in the same way that when is loaded on startup
               InitializeAddIn()

         End Select

      Catch e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub

   Public Sub OnStartupComplete(ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnStartupComplete

      InitializeAddIn()

   End Sub

   Private Sub InitializeAddIn()

      ' Initialize non-UI add-in

   End Sub

   Private Sub AddPermanentUI()

      ' Constants for names of built-in commandbars of Visual Studio
      Const VS_STANDARD_COMMANDBAR_NAME As String = "Standard"
      Const VS_MENUBAR_COMMANDBAR_NAME As String = "MenuBar"
      Const VS_TOOLS_COMMANDBAR_NAME As String = "Tools"
      Const VS_CODE_WINDOW_COMMANDBAR_NAME As String = "Code Window"

      ' Constants for names of commandbars created by the add-in
      Const MY_PERMANENT_COMMANDBAR_POPUP1_NAME As String = "MyPermanentCommandBarPopup1"
      Const MY_PERMANENT_COMMANDBAR_POPUP2_NAME As String = "MyPermanentCommandBarPopup2"

      ' Constants for captions of commandbars created by the add-in
      Const MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION As String = "My sub menu"
      Const MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION As String = "My main menu"
      Const MY_PERMANENT_TOOLBAR_CAPTION As String = "My toolbar"

      ' CommandBars that will be created by the add-in
      Dim myPermanentToolbar As CommandBar
      Dim myPermanentCommandBar1 As CommandBar
      Dim myPermanentCommandBar2 As CommandBar
      Dim myPermanentCommandBarPopup1 As CommandBarPopup
      Dim myPermanentCommandBarPopup2 As CommandBarPopup

      ' Buttons that will be created on built-in commandbars of Visual Studio
      Dim myStandardCommandBarButton As CommandBarButton
      Dim myToolsCommandBarButton As CommandBarButton
      Dim myCodeWindowCommandBarButton As CommandBarButton

      ' The only command that will be created. We will create several buttons from it
      Dim myCommand As Command = Nothing

      ' Built-in commandbars of Visual Studio
      Dim standardCommandBar As CommandBar
      Dim menuCommandBar As CommandBar
      Dim toolsCommandBar As CommandBar
      Dim codeCommandBar As CommandBar

      ' Buttons that will be created on a toolbars/commandbar popups created by the add-in
      ' We don't need to keep them at class level to remove them when the add-in is unloaded 
      ' because we will remove the whole toolbars/commandbar popups
      Dim myToolBarButton As CommandBarButton
      Dim myCommandBarPopup1Button As CommandBarButton
      Dim myCommandBarPopup2Button As CommandBarButton

      ' The collection of Visual Studio commandbars
      Dim commandBars As CommandBars

      ' Other variables
      Dim toolsCommandBarControl As CommandBarControl
      Dim position As Integer

      Try

         ' ------------------------------------------------------------------------------------

         ' Try to retrieve the command, just in case it was already created, ignoring the 
         ' exception that would happen if the command was not created yet.
         Try
            myCommand = applicationObject.Commands.Item(addInInstance.ProgID & _
               "." & MY_COMMAND_NAME)
         Catch
         End Try

         ' Add the command if it does not exist
         If myCommand Is Nothing Then

            myCommand = applicationObject.Commands.AddNamedCommand(addInInstance, _
               MY_COMMAND_NAME, MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, True, _
               59, Nothing, vsCommandStatus.vsCommandStatusSupported Or _
               vsCommandStatus.vsCommandStatusEnabled)

         End If

         ' ------------------------------------------------------------------------------------

         ' Retrieve the collection of commandbars
         ' Note:
         ' - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         '   DTE.CommandBars returns directly a CommandBars type, so a cast 
         '   to CommandBars is redundant
         ' - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         '   DTE.CommandBars returns an Object type, so we do need a cast to CommandBars
         commandBars = DirectCast(applicationObject.CommandBars, CommandBars)

         ' Retrieve some built-in commandbars
         standardCommandBar = commandBars.Item(VS_STANDARD_COMMANDBAR_NAME)
         menuCommandBar = commandBars.Item(VS_MENUBAR_COMMANDBAR_NAME)
         toolsCommandBar = GetCommandBarPopup(menuCommandBar, VS_TOOLS_COMMANDBAR_NAME)
         codeCommandBar = commandBars.Item(VS_CODE_WINDOW_COMMANDBAR_NAME)

         ' ------------------------------------------------------------------------------------

         ' Create the buttons from the commands
         ' Note:
         ' - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         '   Command.AddControl returns directly a CommandBarControl type, so a cast 
         '   to CommandBarControl is redundant
         ' - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         '   Command.AddControl returns an Object type, so we do need a cast to CommandBarControl

         ' ------------------------------------------------------------------------------------
         ' Button on the "Standard" toolbar
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Standard" toolbar
         myStandardCommandBarButton = DirectCast(myCommand.AddControl(standardCommandBar, _
            standardCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION
         myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon ' It could be also msoButtonIconAndCaption
         myStandardCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' Button on the "Tools" menu
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Tools" menu
         myToolsCommandBarButton = DirectCast(myCommand.AddControl(toolsCommandBar, _
            toolsCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myToolsCommandBarButton.Caption = MY_COMMAND_CAPTION
         myToolsCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' Button on the "Code Window" context menu
         ' ------------------------------------------------------------------------------------

         ' Add a button to the built-in "Code Window" context menu
         myCodeWindowCommandBarButton = DirectCast(myCommand.AddControl(codeCommandBar, _
            codeCommandBar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myCodeWindowCommandBarButton.Caption = MY_COMMAND_CAPTION
         myCodeWindowCommandBarButton.BeginGroup = True ' Separator line above button

         ' ------------------------------------------------------------------------------------
         ' New toolbar
         ' ------------------------------------------------------------------------------------

         ' Try to delete the commandbar if it exists from a previous execution, 
         ' because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         ' projects only resets commands and buttons, not commandbars
         Try
            commandBars.Item(MY_PERMANENT_TOOLBAR_CAPTION).Delete()
         Catch ex As Exception
         End Try

         ' Add the new toolbar
         myPermanentToolbar = DirectCast(applicationObject.Commands.AddCommandBar( _
            MY_PERMANENT_TOOLBAR_CAPTION, vsCommandBarType.vsCommandBarTypeToolbar, Nothing, 1), _
            CommandBar)
         myPermanentToolbar.Position = MsoBarPosition.msoBarTop
         myPermanentToolbar.RowIndex = 10 ' Hopefully the last one

         ' Make the toolbar visible
         myPermanentToolbar.Visible = True

         ' Add a new button on that toolbar
         myToolBarButton = DirectCast(myCommand.AddControl(myPermanentToolbar, _
            myPermanentToolbar.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myToolBarButton.Caption = MY_COMMAND_CAPTION
         myToolBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption ' It could be also msoButtonIcon

         ' ------------------------------------------------------------------------------------
         ' New submenu under the "Tools" menu
         ' ------------------------------------------------------------------------------------

         ' Try to delete the commandbar if it exists from a previous execution, 
         ' because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         ' projects only resets commands and buttons, not commandbars
         Try
            commandBars.Item(MY_PERMANENT_COMMANDBAR_POPUP1_NAME).Delete()
            toolsCommandBar.Controls.Item(MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION).Delete()
         Catch ex As Exception
         End Try

         ' Add a new commandbar popup 
         myPermanentCommandBar1 = DirectCast(applicationObject.Commands.AddCommandBar( _
            MY_PERMANENT_COMMANDBAR_POPUP1_NAME, vsCommandBarType.vsCommandBarTypeMenu, _
            toolsCommandBar, toolsCommandBar.Controls.Count + 1), CommandBar)

         ' Get the actual commandbar popup
         myPermanentCommandBarPopup1 = DirectCast(myPermanentCommandBar1.Parent, CommandBarPopup)

         ' Change some commandbar popup properties
         myPermanentCommandBarPopup1.Caption = MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION

         ' Add a new button on that commandbar popup
         myCommandBarPopup1Button = DirectCast(myCommand.AddControl(myPermanentCommandBar1, _
            myPermanentCommandBar1.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myCommandBarPopup1Button.Caption = MY_COMMAND_CAPTION

         ' ------------------------------------------------------------------------------------
         ' New main menu
         ' ------------------------------------------------------------------------------------

         ' Calculate the position of a new command bar popup to the right of the "Tools" menu
         toolsCommandBarControl = DirectCast(toolsCommandBar.Parent, CommandBarControl)
         position = toolsCommandBarControl.Index + 1

         ' Try to delete the commandbar if it exists from a previous execution, 
         ' because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         ' projects only resets commands and buttons, not commandbars
         Try
            commandBars.Item(MY_PERMANENT_COMMANDBAR_POPUP2_NAME).Delete()
            menuCommandBar.Controls.Item(MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION).Delete()
         Catch ex As Exception
         End Try

         ' Add a new commandbar popup 
         myPermanentCommandBar2 = DirectCast(applicationObject.Commands.AddCommandBar( _
            MY_PERMANENT_COMMANDBAR_POPUP2_NAME, vsCommandBarType.vsCommandBarTypeMenu, menuCommandBar, position), _
            CommandBar)

         ' Get the actual commandbar popup
         myPermanentCommandBarPopup2 = DirectCast(myPermanentCommandBar2.Parent, CommandBarPopup)

         ' Change some commandbar popup properties
         myPermanentCommandBarPopup2.Caption = MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION

         ' Add a new button on that commandbar popup
         myCommandBarPopup2Button = DirectCast(myCommand.AddControl(myPermanentCommandBar2, _
            myPermanentCommandBar2.Controls.Count + 1), CommandBarButton)

         ' Change some button properties
         myCommandBarPopup2Button.Caption = MY_COMMAND_CAPTION

      Catch e As System.Exception
         System.Windows.Forms.MessageBox.Show(e.ToString)
      End Try

   End Sub
      
   Private Function GetCommandBarPopup(ByVal parentCommandBar As CommandBar, ByVal commandBarPopupName As String) As CommandBar

      Dim commandBar As CommandBar = Nothing
      Dim commandBarControl As CommandBarControl
      Dim commandBarPopup As CommandBarPopup

      For Each commandBarControl In parentCommandBar.Controls

         If commandBarControl.Type = MsoControlType.msoControlPopup Then

            commandBarPopup = DirectCast(commandBarControl, CommandBarPopup)

            If commandBarPopup.CommandBar.Name = commandBarPopupName Then

               commandBar = commandBarPopup.CommandBar

               Exit For

            End If

         End If

      Next

      Return commandBar

   End Function

   Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, _
      ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnDisconnection

   End Sub

   Public Sub OnBeginShutdown(ByRef custom As System.Array) _
      Implements Extensibility.IDTExtensibility2.OnBeginShutdown
   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As System.Array) _
       Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
   End Sub

   Public Sub Exec(ByVal cmdName As String, _
      ByVal executeOption As vsCommandExecOption, _
      ByRef varIn As Object, ByRef varOut As Object, ByRef handled As Boolean) _
      Implements IDTCommandTarget.Exec

      handled = False

      If (executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault) Then

         If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
            handled = True
            System.Windows.Forms.MessageBox.Show("Command executed.")
         End If

      End If

   End Sub

   Public Sub QueryStatus(ByVal cmdName As String, _
      ByVal neededText As vsCommandStatusTextWanted, _
      ByRef statusOption As vsCommandStatus, ByRef commandText As Object) _
      Implements IDTCommandTarget.QueryStatus

      If neededText = vsCommandStatusTextWanted.vsCommandStatusTextWantedNone Then

         If cmdName = addInInstance.ProgID & "." & MY_COMMAND_NAME Then
            statusOption = CType(vsCommandStatus.vsCommandStatusEnabled + _
               vsCommandStatus.vsCommandStatusSupported, vsCommandStatus)
         Else
            statusOption = vsCommandStatus.vsCommandStatusUnsupported
         End If

      End If

   End Sub

End Class
Language: C#   Copy Code Copy Code (IE only)
public class Connect : Extensibility.IDTExtensibility2, IDTCommandTarget
{
   // Constants for command properties
   private const string MY_COMMAND_NAME = "MyCommand";
   private const string MY_COMMAND_CAPTION = "My command";
   private const string MY_COMMAND_TOOLTIP = "My command tooltip";

   // Variables for IDE and add-in instances
   private EnvDTE.DTE applicationObject;
   private EnvDTE.AddIn addInInstance;

   public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, 
      object addInInst, ref System.Array custom)
   {
      try
      {
         applicationObject = (EnvDTE.DTE)application;
         addInInstance = (EnvDTE.AddIn)addInInst;

         switch (connectMode)
         {
            case ext_ConnectMode.ext_cm_UISetup:

               // Initialize the UI of the add-in
               AddPermanentUI();
               break;

            case ext_ConnectMode.ext_cm_Startup:

               // The add-in was marked to load on startup
               // Do nothing at this point because the IDE may not be fully initialized
               // Visual Studio will call OnStartupComplete when fully initialized
               break;

            case ext_ConnectMode.ext_cm_AfterStartup:

               // The add-in was loaded by hand after startup using the Add-In Manager
               // Initialize it in the same way that when is loaded on startup
               InitializeAddIn();
               break;
         }
      }
      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }

   public void OnStartupComplete(ref System.Array custom)
   {
      InitializeAddIn();
   }

   private void InitializeAddIn()
   {
      // Initialize non-UI add-in
   }

   private void AddPermanentUI()
   {
      // Constants for names of built-in commandbars of Visual Studio
      const string VS_STANDARD_COMMANDBAR_NAME = "Standard";
      const string VS_MENUBAR_COMMANDBAR_NAME = "MenuBar";
      const string VS_TOOLS_COMMANDBAR_NAME = "Tools";
      const string VS_CODE_WINDOW_COMMANDBAR_NAME = "Code Window";

      // Constants for names of commandbars created by the add-in
      const string MY_PERMANENT_COMMANDBAR_POPUP1_NAME = "MyPermanentCommandBarPopup1";
      const string MY_PERMANENT_COMMANDBAR_POPUP2_NAME = "MyPermanentCommandBarPopup2";

      // Constants for captions of commandbars created by the add-in
      const string MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION = "My sub menu";
      const string MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION = "My main menu";
      const string MY_PERMANENT_TOOLBAR_CAPTION = "My toolbar";

      // CommandBars that will be created by the add-in
      CommandBar myPermanentToolbar = null;
      CommandBar myPermanentCommandBar1 = null;
      CommandBar myPermanentCommandBar2 = null;
      CommandBarPopup myPermanentCommandBarPopup1 = null;
      CommandBarPopup myPermanentCommandBarPopup2 = null;

      // Buttons that will be created on built-in commandbars of Visual Studio
      CommandBarButton myStandardCommandBarButton = null;
      CommandBarButton myToolsCommandBarButton = null;
      CommandBarButton myCodeWindowCommandBarButton = null;

      // The only command that will be created. We will create several buttons from it
      Command myCommand = null;

      // Built-in commandbars of Visual Studio
      CommandBar standardCommandBar = null;
      CommandBar menuCommandBar = null;
      CommandBar toolsCommandBar = null;
      CommandBar codeCommandBar = null;

      // Buttons that will be created on a toolbars/commandbar popups created by the add-in
      // We don't need to keep them at class level to remove them when the add-in is unloaded 
      // because we will remove the whole toolbars/commandbar popups
      CommandBarButton myToolBarButton = null;
      CommandBarButton myCommandBarPopup1Button = null;
      CommandBarButton myCommandBarPopup2Button = null;

      // The collection of Visual Studio commandbars
      CommandBars commandBars = null;

      // Other variables
      CommandBarControl toolsCommandBarControl = null;
      int position = 0;
      object[] contextUIGuids = new object[] { };

      try
      {
         // ------------------------------------------------------------------------------------

         // Try to retrieve the command, just in case it was already created, ignoring the 
         // exception that would happen if the command was not created yet.
         try
         {
            myCommand = applicationObject.Commands.Item(addInInstance.ProgID + "." + MY_COMMAND_NAME, -1);
         }
         catch
         {
         }

         // Add the command if it does not exist
         if (myCommand == null)
         {
            myCommand = applicationObject.Commands.AddNamedCommand(addInInstance, MY_COMMAND_NAME,
               MY_COMMAND_CAPTION, MY_COMMAND_TOOLTIP, true, 59, ref contextUIGuids, 
               (int) (vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled));
         }

         // ------------------------------------------------------------------------------------

         // Retrieve the collection of commandbars
         // Note:
         // - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         //   DTE.CommandBars returns directly a CommandBars type, so a cast 
         //   to CommandBars is redundant
         // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         //   DTE.CommandBars returns an Object type, so we do need a cast to CommandBars
         commandBars = (CommandBars)applicationObject.CommandBars;

         // Retrieve some built-in commandbars
         standardCommandBar = commandBars[VS_STANDARD_COMMANDBAR_NAME];
         menuCommandBar = commandBars[VS_MENUBAR_COMMANDBAR_NAME];
         toolsCommandBar = GetCommandBarPopup(menuCommandBar, VS_TOOLS_COMMANDBAR_NAME);
         codeCommandBar = commandBars[VS_CODE_WINDOW_COMMANDBAR_NAME];

         // ------------------------------------------------------------------------------------

         // Create the buttons from the commands
         // Note:
         // - In VS.NET 2002/2003 (which uses the Office.dll reference) 
         //   Command.AddControl returns directly a CommandBarControl type, so a cast 
         //   to CommandBarControl is redundant
         // - In VS 2005 or higher (which uses the new Microsoft.VisualStudio.CommandBars.dll reference) 
         //   Command.AddControl returns an Object type, so we do need a cast to CommandBarControl

         // ------------------------------------------------------------------------------------
         // Button on the "Standard" toolbar
         // ------------------------------------------------------------------------------------

         // Add a button to the built-in "Standard" toolbar
         myStandardCommandBarButton = (CommandBarButton)myCommand.AddControl(standardCommandBar, 
            standardCommandBar.Controls.Count + 1);

         // Change some button properties
         myStandardCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myStandardCommandBarButton.Style = MsoButtonStyle.msoButtonIcon; // It could be also msoButtonIconAndCaption
         myStandardCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // Button on the "Tools" menu
         // ------------------------------------------------------------------------------------

         // Add a button to the built-in "Tools" menu
         myToolsCommandBarButton = (CommandBarButton)myCommand.AddControl(toolsCommandBar, 
            toolsCommandBar.Controls.Count + 1);

         // Change some button properties
         myToolsCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myToolsCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // Button on the "Code Window" context menu
         // ------------------------------------------------------------------------------------

         // Add a button to the built-in "Code Window" context menu
         myCodeWindowCommandBarButton = (CommandBarButton)myCommand.AddControl(codeCommandBar, 
            codeCommandBar.Controls.Count + 1);

         // Change some button properties
         myCodeWindowCommandBarButton.Caption = MY_COMMAND_CAPTION;
         myCodeWindowCommandBarButton.BeginGroup = true; // Separator line above button

         // ------------------------------------------------------------------------------------
         // New toolbar
         // ------------------------------------------------------------------------------------

         // Try to delete the commandbar if it exists from a previous execution, 
         // because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         // projects only resets commands and buttons, not commandbars
         try
         {
            commandBars[MY_PERMANENT_TOOLBAR_CAPTION].Delete();
         }
         catch
         {
         }

         // Add the new toolbar
         myPermanentToolbar = (CommandBar)applicationObject.Commands.AddCommandBar(MY_PERMANENT_TOOLBAR_CAPTION, 
            vsCommandBarType.vsCommandBarTypeToolbar, null, 1);
         myPermanentToolbar.Position = MsoBarPosition.msoBarTop;
         myPermanentToolbar.RowIndex = 10; // Hopefully the last one

         // Make the toolbar visible
         myPermanentToolbar.Visible = true;

         // Add a new button on that toolbar
         myToolBarButton = (CommandBarButton)myCommand.AddControl(myPermanentToolbar, 
            myPermanentToolbar.Controls.Count + 1);

         // Change some button properties
         myToolBarButton.Caption = MY_COMMAND_CAPTION;
         myToolBarButton.Style = MsoButtonStyle.msoButtonIconAndCaption; // It could be also msoButtonIcon

         // ------------------------------------------------------------------------------------
         // New submenu under the "Tools" menu
         // ------------------------------------------------------------------------------------

         // Try to delete the commandbar if it exists from a previous execution, 
         // because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         // projects only resets commands and buttons, not commandbars
         try
         {
            commandBars[MY_PERMANENT_COMMANDBAR_POPUP1_NAME].Delete();
            toolsCommandBar.Controls[MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION].Delete(false);
         }
         catch
         {
         }

         // Add a new commandbar popup 
         myPermanentCommandBar1 = (CommandBar)applicationObject.Commands.AddCommandBar(
            MY_PERMANENT_COMMANDBAR_POPUP1_NAME, vsCommandBarType.vsCommandBarTypeMenu, 
            toolsCommandBar, toolsCommandBar.Controls.Count + 1);

         // Get the actual commandbar popup
         myPermanentCommandBarPopup1 = (CommandBarPopup)myPermanentCommandBar1.Parent;

         // Change some commandbar popup properties
         myPermanentCommandBarPopup1.Caption = MY_PERMANENT_COMMANDBAR_POPUP1_CAPTION;

         // Add a new button on that commandbar popup
         myCommandBarPopup1Button = (CommandBarButton)myCommand.AddControl(myPermanentCommandBar1, 
            myPermanentCommandBar1.Controls.Count + 1);

         // Change some button properties
         myCommandBarPopup1Button.Caption = MY_COMMAND_CAPTION;

         // ------------------------------------------------------------------------------------
         // New main menu
         // ------------------------------------------------------------------------------------

         // Calculate the position of a new command bar popup to the right of the "Tools" menu
         toolsCommandBarControl = (CommandBarControl)toolsCommandBar.Parent;
         position = toolsCommandBarControl.Index + 1;

         // Try to delete the commandbar if it exists from a previous execution, 
         // because the /resetaddin command-line switch of VS 2005 (or higher) add-in 
         // projects only resets commands and buttons, not commandbars
         try
         {
            commandBars[MY_PERMANENT_COMMANDBAR_POPUP2_NAME].Delete();
            menuCommandBar.Controls[MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION].Delete(false);
         }
         catch
         {
         }

         // Add a new commandbar popup 
         myPermanentCommandBar2 = (CommandBar)applicationObject.Commands.AddCommandBar(
            MY_PERMANENT_COMMANDBAR_POPUP2_NAME, vsCommandBarType.vsCommandBarTypeMenu, 
            menuCommandBar, position);

         // Get the actual commandbar popup
         myPermanentCommandBarPopup2 = (CommandBarPopup)myPermanentCommandBar2.Parent;

         // Change some commandbar popup properties
         myPermanentCommandBarPopup2.Caption = MY_PERMANENT_COMMANDBAR_POPUP2_CAPTION;

         // Add a new button on that commandbar popup
         myCommandBarPopup2Button = (CommandBarButton)myCommand.AddControl(myPermanentCommandBar2, 
            myPermanentCommandBar2.Controls.Count + 1);

         // Change some button properties
         myCommandBarPopup2Button.Caption = MY_COMMAND_CAPTION;
      }

      catch (System.Exception e)
      {
         System.Windows.Forms.MessageBox.Show(e.ToString());
      }
   }
   
   private CommandBar GetCommandBarPopup(CommandBar parentCommandBar, string commandBarPopupName)
   {
      CommandBar commandBar = null;
      CommandBarPopup commandBarPopup; 

      foreach (CommandBarControl commandBarControl in parentCommandBar.Controls)
      {
         if (commandBarControl.Type == MsoControlType.msoControlPopup)
         {
            commandBarPopup = (CommandBarPopup) commandBarControl;

            if (commandBarPopup.CommandBar.Name == commandBarPopupName)
            {
               commandBar = commandBarPopup.CommandBar;
               break;
            }
         }
      }
      return commandBar;
   }

   public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref System.Array custom)
   {
   }

   public void OnBeginShutdown(ref System.Array custom)
   {
   }

   public void OnAddInsUpdate(ref System.Array custom)
   {
   }

   public void Exec(string cmdName, vsCommandExecOption executeOption, ref object varIn,
      ref object varOut, ref bool handled)
   {
      handled = false;

      if ((executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault))
      {
         if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
         {
            handled = true;
            System.Windows.Forms.MessageBox.Show("Command executed.");
         }
      }
   }

   public void QueryStatus(string cmdName, vsCommandStatusTextWanted neededText, 
      ref vsCommandStatus statusOption, ref object commandText)
   {
      if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
      {
         if (cmdName == addInInstance.ProgID + "." + MY_COMMAND_NAME)
         {
            statusOption = (vsCommandStatus)(vsCommandStatus.vsCommandStatusEnabled | 
               vsCommandStatus.vsCommandStatusSupported);
         }
         else
         {
            statusOption = vsCommandStatus.vsCommandStatusUnsupported;
         }
      }
   }
}

You may have noticed that when calling Commands.AddCommandBar the code uses the value vsCommandBarType.vsCommandBarTypeToolbar for toolbars and the value vsCommandBarType.vsCommandBarTypeMenu for both menu entries in the main menu or in a commandbar such as the "Tools" menu. There is a third value vsCommandBarType.vsCommandBarTypePopup that it is not used in the code. This value is used to create a commandbar popup that appears only when you right-click somewhere (like a context menu). To do this, you would call the ShowPopup(x,y) method of the returned CommandBar.

Related articles



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


Top