How to create Visual Studio add-ins with VSPackages

Along with macros and add-ins, VSPackages are a common tool for extending Visual Studio. The main reason why we are writing about them is that Microsoft announced that add-ins will be deprecated in future releases of Visual Studio. VSPackages are supported in all versions of VS coming from 2005. Some would say they are hard to use and understand but once you get to know them a little better they are not that difficult to implement

In this part of the series we’ll start with writing a simple Visual Studio add-in using VSPackages. In order for you to use them, Visual Studio SDK must be installed on your system. Depends on which version of VS you are working you can download the right one for you

Now, there are a couple of things you must know before starting to use VSPackages. They are actually COM component. Knowing that COM is not easy for everyone, Microsoft did a pretty good job on writing and providing a rich set of ready-to-go projects that can be used as a startup point. Also be aware that this topic is so big that in this part we are only going to scratch the surface

What is a VSPackage?

It’s a package or a module if you prefer, related to Visual Studio. It allows you to extended Visual Studio. Here are some general groups that VSPackage can extend:

  • User interface elements – Menus, toolbars, and windows can be used by developers to initiate some actions in the user interface, interact with, display messages, information and figures, and so on
  • Projects – When developing applications you generally work with a large number of files. A project is an organization of source files and resources. Project doesn’t just simply store these files , it also defines operations with them, allows building, debugging and deploying products created from source files
  • Services – These are software objects that offer functionality for other objects in the same package or even for other packages. For example, the C# Language Service (as its name also tells) is a service
  • Designers – Creating application is not just a text-typing activity. There are many visual tools known as designers that allow an alternative representation and design of modules, components, parts or even full applications. Well-known examples are Windows Forms designer, WPF Forms designer, ASP.NET page designer or Data Table designer
  • Editors – During development you write and modify a program text to create applications. This task is the responsibility of an editor. Visual Studio 2010 has its own core text editor and you can extend it or even create your own editors

The Anatomy of a VSPackage

Package base class implements several interfaces:

  • IVsPackage
  • IServiceProvider
  • IOleCommandTarget
  • IVsPersistSolutionOpts
  • IServiceContainer
  • System.IServiceProvider
  • IVsUserSettings
  • IVsUserSettingsMigration
  • IVsToolWindowFactory

Each of these interfaces enables you to access some APIs for developing your VSPackage. The most important one is IVsPackage which is required by VS in order to take an object into account as a package

Building VSPackage

Now we are going to start with a simple VSPackage, and I’ll do my best to explain all important parts of VSPackage so that you could fully understand its use. Using Visual Studio 2012 go to File –> New Project –> Visual C#, and choose Extensibility (option). Choose Visual Studio Package and click OK. Before I move on, let me point out this – you can write VSPackage in Visual Basic or Visual C++ if you like. I will not show you screen shots of each step through the wizard as I consider them self-explanatory, but we will go through each step. Just to make sure that we are on the right page with following this guide here, I will show you a screen shoot of the first step:

Building VSPackage - Selecting a Programming Language

In step one of the wizard, you’ll be able to choose the language in which you are going to write your code. Also you’ll choose a way in which your assembly will be signed, with an existing or a new key file. We will get to this part of key file later in this part so that you can see the importance of it

Step two is really simple. Enter the company information and the name of the package. Desired icon can be chosen for your package

In a step three we are going to choose which elements our package is going to have. You have check boxes for Menu Command, Tool Windows and Custom Editor. Let me stop here for a second and try to explain each one of them. Menu Command implies that you are adding a new menu or even a command in VS, we will go deeper with this later on where we will show you how to add a custom menu in VS. Tool Window is for adding your own custom window, similar to Tool Window. Custom Editor is a window that is very similar to C# file project for example, where you write your code or event Class Designer. They are editors in some way

In step four you’ll enter a command name and desired ID

In step five you can choose by default integration tests and unit tests, but for simplicity we will not select them in this project. Now click Finish and that’s it. Visual Studio did a great job for you. Created all necessary files that you need for working with package

At this point you can start your project and a new instance of VS will start. This is actually great because you can debug your package in a new instance, which is not related to the one that you are working from. This has to do with the registry and the experimental hive that is being created for you. Right now I will not go into specific details on how VS is allowing you to do this, because we’ll be concentrating on working with package. You can check the image at the end of creating our own custom menu, where in upper left corner of VS you have Experimental Instance written. After a new instance of VS is started you can go and check in Tools menu that your command is really being added. One more thing, if you chose Tool Windows and Custom Editor in step three, you can check in View – Other Windows menu to see your Tool Window that is being created for you. Regarding Custom Editor, go to File – New – File to create a new file. You can also find your custom editor that VS added for you. That’s it, for a start. In the next section we are going deeper

Developing a VSPackage

Developing a VSPackage - What files are created in Visual Studio

As you can see, Visual Studio created for you several files. We will not go into details with each one, since our goal is to show you the mechanism behind and how to create a new menu and other things, like submenus etc.

[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[Guid(GuidList.guidCompletePkgString)]
public sealed class CompletePackage : Package
{        
    
public CompletePackage()
    
{
        Debug.WriteLine
(string.Format(CultureInfo.CurrentCulture,
"Entering constructor for: {0}", this.ToString()));
    
}


Let me explain those attributes here:
PackageRegistration” – This marks this class as the Packageclass, which tells the registration tool that the current class should be registered as Packageclass. When Visual Studio is started, it collects information that is going to be entered in the registry and the registration process is done on the fly. Packages are loaded into the memory on-demand. Each object, window, menu, has its own identity. Visual Studio turns into the registry and addresses the corresponding key with, for example, tool window identity. Using this identity Visual Studio finds the registry key containing the package information and loads the package into the memory accordingly

InstalledProductRegistration” – Here you set the information that is shown to users in the Help About Microsoft Visual Studio menu.

ProvideMenuResource” – This tells the Visual Studio Shell that the package has some menu resources

You are probably going to see a lot of comments in your project, but for simplicity, again, they were omitted here

In the following method, you can see that is overridden from the base Package class for initialization of the package. This method is called after the package has been successfully sited. It has to do all the initialization steps that require access to services provided by the Shell or other packages. This method is first to be called when package is being initialized

… #region Package Members protected override void Initialize() { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));

base.Initialize();

OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) AS OleMenuCommandService;

IF (NULL != mcs) {
	// Create the command for the menu item.
	CommandID menuCommandID = new CommandID(GuidList.guidCompleteCmdSet, (INT) PkgCmdIDList.cmdidMyCommandComplete);
	MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);

mcs.AddCommand(menuItem);

} } #endregion

First base Initialize method is being called. Then, we are retrieving OleMenuCommandService. This mechanism checks if command is on the list, and if it is, required action is executed, otherwise command execute is refused

Command is being created with GUID and int value pair, CommandID is a wrapper for the compound key of a command

The Callback method is used to handle an event of that command that we created. Besides that, MenuCommand has Visible and Enabled property that you can use for setting menu command to those states

We need to make some things clear, the Visible state and the Enabled state are not the same. Availability of the command tells if the command is allowed to be invoked within specific context or not. Visibility properties tells if the menu items related to the command are visible

TheVisibility property can be set in a different way, from .vsct file. Flag, <CommandFlag> in that xml file needs to have “DynamicVisibility“. Packages are on-demand loaded, so menu command is going to have queried after package is loaded. Now you are wondering what the state of command by default is. Well a little advice you should always put it to visible, and when command is having “DynamicVisibility“ flag set, VS is querying the status of that command. When command is not flagged, its status is never queried

I’ll show you how to set this state in vsct file. Bear in mind this is only the part of vsct file


<Button guid="guidCompleteCmdSet"id="cmdidMyCommandComplete"priority="0x0100"TYPE="Button"
        
<Parent guid="guidCompleteCmdSet"id="MyMenuGroup"/>
        <
Icon guid="guidImages"id="bmpPic1"/>
<
CommandFlag>DynamicVisibility</CommandFlag>
        <
Strings>
          <
ButtonText>Test Complete</ButtonText>
        </
Strings>
      </
Button>

Don’t worry too much about this file, we will provide more details on it in the next section

How to add main menu

Everything is well and good, but what if we want to create a different custom menu for your own purposes? Well we are going to explain a little about vsct file, and actually this is how it looks like:

    <Commands package="..."
      
<Groups/>
      <
Menus/>
      <
Buttons/>
      <
Combos/>
      <
Bitmaps/>
      <
KeyBindings/>
    </
Commands>
<
Symbols>
  <
GuidSymbol name="guidCompletePkg"value="{3eaf3e40-3509-4d17-8fd1-1c2d470b81fe}"/>
  
    <
GuidSymbol name="guidCompleteCmdSet"value="{8f4ec6d6-6624-4bf6-9e86-7dfba808edd1}"
      
<IDSymbol name="MyMenuGroup"value="0x1020"/>
      <
IDSymbol name="cmdidMyCommandComplete"value="0x0100"/>
    </
GuidSymbol>

</Symbols>

As you can see it contains these elements. Group tags are used in order for you to group menu or other command in one group. But more important of them all is ‘Symbols’. Here you are defining GUID for a command or even a group. I’ve omitted GUID symbols that were added for icons

The ‘Menus’ node defines the structure of UI elements (such as menus and toolbars), also binding them to command groups in the ‘Groups’ node

<Menus>
<
Menu guid="guidCompleteCmdSet"id="MyMenuGroup"priority="0x700"TYPE="Menu"
  
<Parent guid="guidSHLMainMenu"id="IDG_VS_MM_TOOLSADDINS"/>
   <
Strings>
     <
ButtonText>TestMenu</ButtonText>
     <
CommandName>TestMenu</CommandName>
   </
Strings>
</
Menu>
</
Menus>

We created menu item, TestMenu near the Tools menu in Visual Studio. The ‘Menus’ element can have other tags. For more, you can check out references for detail explanations of all possible elements but for now let me explain, the difference between ‘ButtonText’ and ‘CommandName’ since on the first sight they are similar. ‘ButtonText’ holds value of the text that is going to be displayed in main menu of IDE and ‘CommandName’ holds the value that is going to appear in keyboard category in the Commands tab in the Customize dialog box. ‘CommandName’ can be omitted but for now let’s leave it like that

Every menu, submenu, button or other object that you create and set them in this file has to have the ‘Parent’ tag. Right now our menu has its parent main menu of IDE. Check out button creation. The Parent element is pointing to a group id that we previously created. If you remember as I said we can group menus, submenus and command in groups, so that we can easily work with them

<Button guid="guidCompleteCmdSet"id="cmdidMyCommandComplete"priority="0x0100"TYPE="Button"
  
<Parent guid="guidCompleteCmdSet"id="MyMenuGroup"/>
   <
Icon guid="guidImages"id="bmpPic1"/>
   <
Strings>
     <
ButtonText>ApexSQL TestButton</ButtonText>
   </
Strings>
</
Button>

This button is going to be shown in our menu that we created with the icon that we also provided. Start Visual Studio and check out the new menu we created in a main menu of IDE. When you click on it you will also see a button that we create there

As pointed on the beginning of this document, we only scratched the surface. There are a lot of options we can use here, but only for simplicity we didn’t spend much time on detail explanations. That is why in reference section you can find each link and read details more carefully just to be able to overcome these start steps

At the end when you start your project you should be seeing this like in the following image:

Starting the project - Created button is shown

If you click on this button that we created you are going to see something similar to the image bellow. This depends on the information you entered when you started creating your project:

Information shown when clicking the created button

References:
Manual on development of Visual Studio 2005-2012 and Atmel Studio plugins in C#
Menu Element

March 23, 2015