Click here to Skip to main content
15,884,176 members
Articles / Programming Languages / XML

Visual Studio Add-in Library

Rate me:
Please Sign up or sign in to vote.
4.15/5 (10 votes)
15 Sep 2010CPOL5 min read 61.6K   924   43  
This library allows you to quickly and simply create add-ins for VS2008 and VS2010 (VS2005?).
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;

namespace VisualStudio.AddInLibrary.Menus
{
  /// <summary>
  /// Base class for implementing a menu item AKA Command
  /// </summary>
  public abstract class BaseMenu
  {

    #region Properties
    
    /// <summary>
    /// The kind of menu we want to create
    /// </summary>    
    protected MenuType MainMenuType { get; set; }

    /// <summary>
    /// Visual Studio instance
    /// </summary>
    public DTE2 VStudioApplication { get; set; }

    /// <summary>
    /// AddIn instance
    /// </summary>
    public AddIn AddInInstance { get; set; }

    /// <summary>
    /// Assembly containing our resources
    /// </summary>
    protected System.Reflection.Assembly ResourceAssembly { get; set; }

    #endregion

    #region Member variables
   
    /// <summary>
    /// STATIC List containing Menu items AND asscociated Commands
    /// </summary>
    private static Dictionary<string, VSCommandInfo> CommandDescriptionList = new Dictionary<string, VSCommandInfo>();
    
    /// <summary>
    /// the popup menu object we created if we choose MenuType.Popup
    /// </summary>
    private CommandBarPopup m_Popup =null;

    protected ResourceManager ResourceMANAGER = null;

    #endregion

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="BaseMenuParams">Paremeter class containing add-in instance, VS instance ...</param>
    public BaseMenu(BaseMenuParams _params)
    {
      VStudioApplication = _params.VisualStudioInstance;
      AddInInstance = _params.AddInInstance;
      ResourceAssembly = _params.ResourceAssembly;      
      ResourceMANAGER = new ResourceManager(ResourceAssembly.GetName().Name + ".Resources", ResourceAssembly);                   
    }

    /// <summary>
    /// Add a command object to our command list
    /// </summary>
    /// <param name="item">the menu we want to add</param>
    protected void AddCommand(VSCommandInfo item)
    {
      string cmdId = AddInInstance.ProgID + "." + item.Name;
      if (!CommandDescriptionList.ContainsKey(cmdId))
      {
        item.UniqueID = cmdId;
        CommandDescriptionList.Add(cmdId, item);
      }
      else
        MessageBox.Show(cmdId + " already exists in this plugin !", "Error : " + AddInInstance.ProgID, MessageBoxButtons.OK, MessageBoxIcon.Error); 
    }

    

    /// <summary>
    /// clear our command list
    /// </summary>
    protected void ClearCommands(object owner)
    {
      foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
      {
        VSCommandInfo desc = kvp.Value;
        if (desc.Owner == owner || desc.Owner==null)        
          CommandDescriptionList.Remove(kvp.Key);
      }      
    }

    

    /// <summary>
    /// Remove our menus from VStudio
    /// </summary>
    protected void RemoveMenu(object owner)
    {
      try
      {
        if (m_Popup != null)
          m_Popup.Delete(true);
        else
        {
          foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
          {
            VSCommandInfo desc = kvp.Value;
            if ((desc.Owner==owner || desc.Owner==null) && desc.Control != null)
            {
              desc.Control.Delete(true);
              desc.Control = null;
            }
          }
        }
        m_Popup = null;
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }


    }

    /// <summary>
    /// Return null OR a Visual Studio Command Bar (context menus too)
    /// </summary>
    /// <param name="commandBarName"></param>
    /// <returns></returns>
    private CommandBar GetVisualStudioCommandBar(bool IsOnMainMenu, string commandBarName)
    {
      string MyMenu=commandBarName;
      if (ResourceAssembly == null)
      {
        MessageBox.Show("The \"ResourceAssembly\" property is not defined\nin derived class \"" + this.GetType().Name + " \" !", "VisualStudio.AddInLibrary : ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return null;
      }
      try
      {
        string resourceName = ResourceAssembly.GetName().Name + ".CommandBar";
        ResourceManager resourceManager = new ResourceManager(resourceName,ResourceAssembly);
        CultureInfo cultureInfo = new CultureInfo(VStudioApplication.LocaleID);
        MyMenu = resourceManager.GetString(String.Concat(cultureInfo.TwoLetterISOLanguageName, MyMenu));
        if (String.IsNullOrEmpty(MyMenu))
          MyMenu = commandBarName;
      }
      catch
      {
        MyMenu = commandBarName;
      }      
      
      try
      {
        if (IsOnMainMenu)
        {
          CommandBar menuBar = ((CommandBars)VStudioApplication.CommandBars)["MenuBar"];
          if (menuBar != null)
          {

            CommandBarControl ctl = menuBar.Controls[MyMenu];
            if (ctl != null)
            {
              CommandBarPopup pop = (CommandBarPopup)ctl;
              if (pop != null)
                return pop.CommandBar;
            }
          }
        }
        else
          return ((CommandBars)VStudioApplication.DTE.CommandBars)[MyMenu];        
      }
      catch(Exception ex)
      {
          MessageBox.Show("Error while attaching to main menu \"" + MyMenu +"\" !"+ ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
          return null;
      }
      return null;
    }

    


    /// <summary>
    /// Main entry point for creating Menus with SubMenus
    /// </summary>
    /// <param name="MainMenuToAttach">Parent menu to attach to</param>
    /// <param name="SubMenu">Our Menu name</param>
    /// <param name="t">Menu type (popup, classic ...) </param>
    /// <param name="position">Our position</param>
    /// <param name="separator">need separator ?</param>
    /// <returns></returns>
    protected bool AddMenu(object owner,string MainMenuToAttach,bool IsOnMainMenu, string SubMenu, MenuType t, int position, bool separator)
    {
      bool ret = false;
      CommandBar _commandBar = GetVisualStudioCommandBar(IsOnMainMenu,MainMenuToAttach);
      MainMenuType = t;
      if (_commandBar != null)
      {
        CommandBarControl ctl = (CommandBarControl)(_commandBar.FindControl(Missing.Value, Missing.Value, SubMenu, Missing.Value, Missing.Value));
        if (ctl != null) ctl.Delete(true);
        switch (MainMenuType)
        {
          case MenuType.Popup:
            CommandBarPopup popup = CreatePopupMenu(_commandBar, SubMenu, position, separator);
            m_Popup = popup;
            BuildMenuItems(owner,true,popup,null);
            ret = true;
            break;

          case MenuType.Default:
            BuildMenuItems(owner,false,null,_commandBar);
            ret = true;
            break;

          case MenuType.Unknown:
            break;
        }

      }
      return ret;
    }

    /// <summary>
    /// Create Menu / Sub-menus / Events ... 
    /// </summary>    
    protected void BuildMenuItems(object owner,bool isPopup, CommandBarPopup popup,CommandBar cmd)
    {
      foreach (KeyValuePair<string, VSCommandInfo> kvp in CommandDescriptionList)
      {
        VSCommandInfo desc = kvp.Value;
        if (desc.Owner == owner || desc.Owner == null)          
          AddMenuItem(owner, isPopup,popup,cmd, desc);
      }

    }

    /// <summary>
    /// Create a popup menu linked to an existing menu
    /// </summary>
    /// <param name="cmd">Main command bar to attach to</param>
    /// <param name="subPopupMenuName">Menu name in command bar</param>
    /// <param name="position">position in command bar</param>
    /// <param name="separator">is there a separator for our item in the command bar ?</param>
    /// <returns></returns>
    public CommandBarPopup CreatePopupMenu(CommandBar cmd, string subPopupMenuName, int position, bool separator)
    {
      if (position < 0) position = 1;
      if (position > cmd.Controls.Count) position = cmd.Controls.Count - 1;
      if (cmd.Controls.Count <= 0) position = 1;
      CommandBarPopup menu = (CommandBarPopup)cmd.Controls.Add(MsoControlType.msoControlPopup, 1, "", position, true);
      menu.Caption = subPopupMenuName;
      menu.TooltipText = "";
      if (separator) menu.BeginGroup = true;
      return menu;
    }

    /// <summary>
    /// Add a sub-menu item in our popup menu / vs menu
    /// </summary>
    /// <param name="parent">menu where we add items</param>
    /// <param name="desc">the command object informations</param>
    /// <returns></returns>
    private void AddMenuItem(object owner, bool ispopup, CommandBarPopup popup, CommandBar cmd, VSCommandInfo desc)
    {
      if (popup == null && cmd==null) return  ;
      if (desc == null) return ;
      CommandBarControl ctl = null;
      try
      {
               
        object[] contextGUIDS = new object[] { };
        Commands2 commands = (Commands2)VStudioApplication.Commands;

        // checks existing command and delete it if necessary
        try
        {
          if (desc.Owner == owner || desc.Owner == null)
          {
            Command test = VStudioApplication.Commands.Item(desc.UniqueID, -1);
            if (test != null)
              test.Delete();
          }
        }
        catch
        {
        }

        int idRes= desc.BitmapResourceId;
        bool useOffice = desc.UseOfficeResources;
        if (idRes <= 0)
        {
          idRes = 59;
          useOffice = true;
        }      

        Command command = commands.AddNamedCommand2(AddInInstance, desc.Name, desc.Caption, desc.ToolTip, useOffice, idRes, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
        
        if (ispopup)
        {
          if (desc.Position == 0) desc.Position = popup.Controls.Count + 1;
            ctl= (CommandBarControl) command.AddControl(popup.CommandBar, desc.Position);
        }
        else
        {
          if (desc.Position == 0) desc.Position = cmd.Controls.Count + 1;
          ctl = (CommandBarControl)command.AddControl(cmd, desc.Position);
        }
        desc.Control = ctl;
      }
      catch (Exception exc)
      {
        MessageBox.Show(exc.Message, "Adding Sub-Item : " + desc.Caption);
      }      
    }

  
    /// <summary>
    /// check if command name is found in our internal list
    /// </summary>
    /// <param name="commandName"></param>
    /// <returns></returns>
    protected bool CommandExists(string commandName)
    {
      return CommandDescriptionList.ContainsKey(commandName);
    }

    /// <summary>
    /// Check if the command belongs to owner
    /// </summary>
    /// <param name="owner">object instance asking information</param>
    /// <param name="commandName">the command name</param>
    /// <returns>True if command belongs to owner</returns>
    protected bool IsItMyCommand(object owner, string commandName)
    {
      bool ret = false;
      if (CommandExists(commandName))
      {
         VSCommandInfo desc =  CommandDescriptionList[commandName];
         return (desc.Owner==owner) ;
      }
      return ret;
    }

    /// <summary>
    /// Find a command and returns infomations about it
    /// </summary>    
    /// <param name="commandName">the command name</param>
    /// <returns>CommandDescription</returns>
    protected VSCommandInfo GetCommand(string commandName)
    {
      VSCommandInfo ret = null;
      if (CommandExists(commandName))
       return CommandDescriptionList[commandName];        
      return ret;
    }

    /// <summary>
    /// Executes the code associated with a command
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    public virtual bool Exec(string command)
    {
      bool ret = false;
      VSCommandInfo cmd = GetCommand(command);
      if (cmd!=null)
      {
        PerformActionForVSCommandDelegate action = cmd.Action;
        if (action != null)
        {
          action();
          ret = true;
        }
      }
      return ret;
    }

    /// <summary>
    /// Translate VS commandStatus to "readable" state
    /// </summary>
    /// <param name="NeededText"></param>
    /// <returns></returns>
    protected QueryMenuVSCommandStatus TranslateCommandState(vsCommandStatusTextWanted NeededText)
    {
      QueryMenuVSCommandStatus status = QueryMenuVSCommandStatus.Unknown;
      switch (NeededText)
      {              
        case vsCommandStatusTextWanted.vsCommandStatusTextWantedStatus:
          status=QueryMenuVSCommandStatus.Step1_BeforeDisplay;
          break;
      
        case vsCommandStatusTextWanted.vsCommandStatusTextWantedName:
           status=QueryMenuVSCommandStatus.Step2_GetText;
          break;

        case vsCommandStatusTextWanted.vsCommandStatusTextWantedNone:
          status=QueryMenuVSCommandStatus.Step3_FinalState;
          break;
      }
      return status;
    }

  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Program Manager Digitas
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions