Visual Studio Extension: Commands

A command connects the code of your application with the UI of Visual Studio. You can create a command with Add -> New File -> Extensibility -> CustomCommand. In the following context I will refer to it as Command1.
This will create you three files:

Command1Package.cs
The (…)Package.cs file will only be created once for all commands. It constructs them with the Visual Studio Package object. You probably will not have to change this file.

Command1Package.vsct
This file sets the foundation of how your command will appear inside Visual Studio. In short, every item which is displayed has a parent, and sometimes children. There are groups, menus & buttons. Buttons have a group as parent, groups have a menu as parent, menus have group as parent. Each items has a guid, which is kind of the “context” of the element. Below, most of the elements have the same guid (namely Command1PackageCmdSet). Also, each item has a unique id. All used ids & guids are defined in the section at the end of the xml, some will be used later (namely to link the Button to a specific callback).
I’ve cut out all automatically created comments and added some useful ones. Lets take a look at it:

<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <!--includes you need -->
  <Extern href="stdidcmd.h" />
  <Extern href="vsshlids.h" />

  <Commands package="Command1Package">
    <!-- groups together commands. Parent must be menu, children must be commands -->
    <Groups>
      <Group guid="Command1PackageCmdSet" id="MyTopMenuGroup" priority="0x4000">
        <!-- the parent of this group is a visual studio menu, the guid and id can be found in the vast space of the internet -->
        <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE" />
      </Group>

      <Group guid="Command1PackageCmdSet" id="MySubMenuGroup" priority="0x4000">
        <!-- the parent of this group is the menu defined below -->
        <Parent guid="Command1PackageCmdSet" id="MyMenuController" />
      </Group>
    </Groups>
        
    <!-- groups together groups. Parent must be group, children must be group -->
    <Menus>
      <Menu guid="Command1PackageCmdSet" id="MyMenuController" priority="0x0100" type="MenuController">
        <!-- the parent of this menu is the group defined above -->
        <Parent guid="Command1PackageCmdSet" id="MyTopMenuGroup" />
        <Strings>
          <ButtonText>Menu Text</ButtonText>
        </Strings>
      </Menu>
    </Menus>


    <!-- the actual things you can click on. Parent must be group, no children allowed -->
    <Buttons>
      <Button guid="Command1PackageCmdSet" id="CommandId0" priority="0x0100" type="Button">
        <Parent guid="Command1PackageCmdSet" id="MySubMenuGroup" />
        <Icon guid="guidImages" id="bmpPic1" />
        <Strings>
          <ButtonText>Invoke CommandId0</ButtonText>
        </Strings>
      </Button>

      <Button guid="Command1PackageCmdSet" id="CommandId1" priority="0x0100" type="Button">
        <Parent guid="Command1PackageCmdSet" id="MyTopMenuGroup" />
        <!-- the Icon is optional, 
        <Icon guid="guidImages" id="bmpPic1" />
        <Strings>
          <ButtonText>Invoke CommandId1</ButtonText>
        </Strings>
      </Button>
    </Buttons>

    <!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
    <Bitmaps>
      <Bitmap guid="guidImages" href="Resources\TileGeneratorCommand.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough" />
    </Bitmaps>
  </Commands>

  <!-- in this section, all used guids and ids are defined. -->
  <Symbols>
    <!-- the Command1Package context -->
    <GuidSymbol name="Command1Package" value="{aa71ec2a-1f27-46fb-ba00-8da6b0a43c73}" />

    <!-- the Command1PackageCmdSet context -->
    <GuidSymbol name="Command1PackageCmdSet" value="{145c5f09-ce3c-43f7-9948-18f1ba65f860}">
      <IDSymbol name="MyMenuController" value="0x1010" />
      <IDSymbol name="MyTopMenuGroup" value="0x1020" />
      <IDSymbol name="MySubMenuGroup" value="0x1030" />
      <IDSymbol name="CommandId0" value="0x0100" />
      <IDSymbol name="CommandId1" value="0x0200" />
    </GuidSymbol>

    <!-- the guidImages context -->
    <GuidSymbol name="guidImages" value="{99def054-e104-4328-821a-0dbb5d1c20cf}">
      <IDSymbol name="bmpPic1" value="1" />
      <IDSymbol name="bmpPic2" value="2" />
      <IDSymbol name="bmpPicSearch" value="3" />
      <IDSymbol name="bmpPicX" value="4" />
      <IDSymbol name="bmpPicArrows" value="5" />
      <IDSymbol name="bmpPicStrikethrough" value="6" />
    </GuidSymbol>
  </Symbols>
</CommandTable>

Command1.cs
This is the file you launch your logic from.
After you’ve defined the setup of your buttons, commands and groups you need to construct the buttons, and assign callbacks. For each button define a const int in your .cs file:

//use the same value as defined in the .vsct file
public const int CommandId0 = 0x0100;
public const int CommandId1 = 0x0200;

Now, create the Buttons in the constructor, and add them to the Visual Studio environment:

private Command1(Package package)
{
	if (package == null)
	{
		throw new ArgumentNullException("package");
	}

	this.package = package;

	OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
	if (commandService != null)
	{
		var command0 = new CommandID(CommandSet, CommandId0);
		var command0Item = new MenuCommand(Command0Callback, command0);
		commandService.AddCommand(command0Item);

		var command1 = new CommandID(CommandSet, CommandId1);
		var command1Item = new MenuCommand(Command1Callback, command1);
		commandService.AddCommand(command1Item);
	}
}

Debug the Application to be sure all worked out correctly.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *