Recently I was working on a Visual Studio Extension for VS2010, instead of a single item in the the tools menu, what I wanted was a single item with a set of child items.

Strangely enough, documentation on this is quite lacking. So if you need to know how to do it, here's the gist. First, create a standard Visual Studio 2010 extension with the wizard, we'll have some code like the below to start off with, in the OnConnection function:

[csharp]object []contextGUIDS = new object[] { }; Commands2 commands = (Commands2)_applicationObject.Commands; string toolsMenuName = "Tools"; //Place the command on the tools menu. //Find the MenuBar command bar, which is the top-level command bar holding all the main menu items: Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"]; //Find the Tools command bar on the MenuBar command bar: CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName]; CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl; //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in, // just make sure you also update the QueryStatus/Exec method to include the new command names. try { //Add a command to the Commands collection: Command command = commands.AddNamedCommand2(_addInInstance, "MyCommand", "MyCommand", "Executes the command for MyCommand", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); //Add a control for the command to the tools menu: if((command != null) && (toolsPopup != null)) { command.AddControl(toolsPopup.CommandBar, 1); } } catch(System.ArgumentException) { //If we are here, then the exception is probably because a command with that name // already exists. If so there is no need to recreate the command and we can // safely ignore the exception. }[/csharp]

Now what we're going to do first, is change the code so that we don't actually add a Command named MyCommand, but instead a popup:

[csharp]//This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in, // just make sure you also update the QueryStatus/Exec method to include the new command names. try { // Have we got the tools popup? if(toolsPopup != null) { // Create 'MyCommand' as a popup. var popup = (CommandBarPopup)toolsPopup.Controls.Add(MsoControlType.msoControlPopup); popup.Caption = "MyCommand"; } } catch(System.ArgumentException) { //If we are here, then the exception is probably because a command with that name<br /> // already exists. If so there is no need to recreate the command and we can<br /> // safely ignore the exception. }[/csharp]

Now that we have the popup object, we can create commands and add them to the popup instead:

[csharp]// Have we got the tools popup? if(toolsPopup != null) { // Create 'MyCommand' as a popup. var popup = (CommandBarPopup)toolsPopup.Controls.Add(MsoControlType.msoControlPopup); popup.Caption = "MyCommand"; // Create sub item 1. var subItem1Command = commands.AddNamedCommand2(_addInInstance, "MyCommand1", "My Command Subitem 1", "My Command Subitem 1", true, 59, ref contextGUIDS); // Add it. subItem1Command.AddControl(popup.CommandBar, 1); // Create sub item 2. var subItem2Command = commands.AddNamedCommand2(_addInInstance, "MyCommand2", "My Command Subitem 2", "My Command Subitem 2", true, 59, ref contextGUIDS); // Add it. subItem2Command.AddControl(popup.CommandBar, 2); }[/csharp]

Now that we have made these changes, if we run the addin, we get a menu structure like this: