This article contains the overview of several different methods for extending Visual Studio IDE. The creation, debugging, registration and end-user deployment of Visual Studio extension packages will be explained in detail.
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Creating, debugging and deploying Visual Studio extensions
1. Creating, debugging and deploying
extension packages for Microsoft Visual
Studio 2005/2008/2010/2012
Author: Paul Eremeev
Date: 12.10.2012
Abstract
This article contains the overview of several different methods for extending Visual Studio IDE. The
creation, debugging, registration and end-user deployment of Visual Studio extension packages will be
explained in detail.
Introduction
The following series of articles is dedicated to the development of the extension package for Visual
Studio 2005/2008/2010/2012 IDEs utilizing .NET framework and C# programming language. The
following topics will be covered:
• basic information on creating and debugging of MSVS plug-ins and maintaining these
extensibility projects for several versions of Visual Studio inside a common source code base;
• overview of Automation Object Model and various Managed Package Framework (MPF) classes
• extending interface of the IDE though the automation object model's API (EnvDTE) and MPF
(Managed Package Framework) classes with custom menus, toolbars, windows and options
pages;
• utilizing Visual C++ project automation model for gathering data needed to operate an external
preprocessor/compiler, such as compilation arguments and settings for different platforms and
configurations;
The content of these articles is based on our experience in developing an MSVS extension package plug-
in for PVS-Studio static analyzer. A more detailed in-depth references for the topics covered here are
available at the end of each article through the links to MSDN library and several other external
resources.
The articles will cover the extension development only for Visual Studio 2005 and later versions. This
limitation reflects that PVS-Studio also supports integration to Visual Studio starting only from version 8
(Visual Studio 2005). The main reason behind this is that a new extensibility API model was introduced
for Visual Studio 2005, and this new version is not backward-compatible with previous IDE APIs.
Creating and debugging Visual Studio VSPackage extension modules
There exists a number of ways to extend Microsoft Visual Studio features. On the most basic level it's
possible to automate simple routine user actions using macros. An add-In plug-in module can be used
for obtaining an access to environment's UI objects, such as menu commands, windows etc. Extension
of IDE's internal editors is possible through MEF (Managed Extensibility Framework) components
2. (starting with MSVS 2010). Finally, a plug-in of the Extension Package type (known as VSPackage) is best
suited for integrating large independent components into Visual Studio. VSPackage allows combining
the environment automation through Automation Object Model with usage of Managed Package
Framework classes (such as Package). It also provides the means of extending the automation model
itself by registering user-defined custom automation objects within it. Such user automation objects, in
turn, will become available through the same automation model from other user-created extensibility
packages, providing these packages with access to your custom components.
In its' earlier versions, PVS-Studio plug-in (versions 1.xx and 2.xx to be precise, when it was still known as
Viva64) existed as an Add-In package. Starting with PVS-Studio 3.0 it was redesigned as VSPackage
because the functionality Add-in was able to provide became insufficient for the tasks at hand and also
the debugging process was quite inconvenient. After all, we wanted to have our own logo on Visual
Studio splash screen!
Projects for VSPackage plug-in modules. Creating the extension package.
Contrary to Add-In plug-ins, developing VS extension packages requires the installation of Microsoft
Visual Studio SDK for a targeted version of IDE, i.e. a separate SDK should be installed with every version
of Visual Studio for which an extension is being developed. We will be examining the 2005, 2008, 2009
and 2012 versions of Visual Studio. Installation of Visual Studio SDK adds a standard project template for
Visual Studio Package (on the 'Other Project Types -> Extensibility' page) to VS template manager. If
selected, this template will generate a basic MSBuild project for an extension package, allowing several
parameters to be specified beforehand, such as a programming language to be used and the automatic
generation of several stub components for generic UI elements, such as menu item, an editor, user
toolwindow etc.
We will be using a C# VSPackage project (csproj), which is a project for managed dynamic-link library
(dll). The corresponding csproj MSBuild project for this managed assembly will also contain several XML
nodes specific to a Visual Studio package, such as VSCT compiler and IncludeinVSIX (in later IDE
versions).
The main class of an extension package should be inherited from the
Microsoft.VisualStudio.Shell.Package. This base class provides managed wrappers for IDE interaction
APIs, implementation of which is required from a fully-functional Visual Studio extension package.
public sealed class MyPackage: Package
{
public MyPackage ()
{}
...
}
The Package class allows overriding of its base Initialize method. This method receives execution control
at the moment of package initialization in the current session of IDE.
protected override void Initialize()
{
base.Initialize();
...
3. }
The initialization of the module will occur when it is invoked for the first time, but it also could be
triggered automatically, for example after IDE is started or when user enters a predefined environment
UI context state.
Being aware of the package's initialization and shutdown timings is crucial. It's quite possible that the
developer would be requesting some of Visual Studio functionality at the moment when it is still
unavailable to the package. During PVS-Studio development we've encountered several such situations
when the environment "punished us" for not understanding this, for instance, we are not allowed to
"straightforwardly" display message boxes after Visual Studio enters a shutdown process.
Debugging extension packages. Experimental Instance.
The task of debugging a plug-in module or extension intended for an integrated development
environment is not quite a typical one. Quite often such environment itself is utilized for plug-in's
development and debugging. Hooking up an unstable module to this IDE can lead to instability of the
environment itself. The necessity to uninstall a module under development from the IDE before every
debugging session, which in turn often requires restarting it, is also a major inconvenience (IDE could
block the dll that needs to be replaced by a newer version for debugging).
It should be noted that a VSPackage debugging process in this aspect is substantially easier than that of
an Add-In package. This was one of the main reasons for changing the project type of PVS-Studio plug-
in.
VSPackage solves the aforementioned development and debugging issues by utilizing Visual Studio
Experimental Instance mechanism. Such an experimental instance could be easily started by passing a
special command line argument:
"C:Program Files (x86)Microsoft Visual Studio 10.0
Common7IDEdevenv.exe" /RootSuffix Exp
An experimental instance of the environment utilizes a separate independent Windows registry hive
(called experimental hive) for storing all of its settings and component registration data. As such, any
modifications in the IDE's settings or changes in its component registration data, which were made
inside the experimental hive, will not affect the instance which is employed for the development of the
module (that is your main regular instance which is used by default).
Visual Studio SDK provides a special tool for creating or resetting such experimental instances —
CreateExpInstance. To create a new experimental hive, it should be executed with these arguments:
CreateExpInstance.exe /Reset /VSInstance=10.0 /RootSuffix=PVSExp
Executing this command will create a new experimental registry hive with a PVSExp suffix in its name for
the 10th version of IDE (Visual Studio 2010), also resetting all of its settings to their default values in
advance. The registry path for this new instance will look as follows:
HKEY_CURRENT_USERSoftwareMicrosoftVisualStudio10.0PVSExp
While the Exp suffix is utilized by default for package debugging inside VSPackage template project,
other experimental hives with unique names could also be created by the developer at will. To start an
4. instance of the environment for the hive we've created earlier (containing PVSExp in its name), these
arguments should be used:
"C:Program Files (x86)Microsoft Visual Studio 10.0
Common7IDEdevenv.exe" /RootSuffix PVSExp
A capacity for creating several different experimental hives on a single local workstation could be quite
useful, as, for example, to provide a simultaneous and isolated development of several extension
packages.
After installing the SDK package, a link is created in the Visual Studio program's menu group for
resetting the default Experimental Instance for this version of the IDE (for instance, "Reset the Microsoft
Visual Studio 2010 Experimental Instance").
In the end, the faster you'll figure out how the debugging environment works, the fewer issues you'll
encounter in understanding how plug-in initialization works during development.
Registering and deploying Visual Studio extension packages
Registering a VS extension package requires registering a package itself, as well as registering all of the
components it integrates into the IDE (for example, menu items, option pages, user windows etc.). The
registration is accomplished by creating records corresponding to these components inside the main
system registry hive of Visual Studio.
All the information required for registration is placed, after building your VSPackage, inside a special
pkgdef file, according to several special attributes of the main class of your package (which itself should
be a subclass of the MPF 'Package' class). The pkgdef can also be created manually using the
CreatePkgDef utility. This tool collects all of the required module registration information from these
special attributes by the means of .NET reflection. Let's study these registration attributes in detail.
The PackageRegistration attribute tells the registration tool that this class is indeed a Visual Studio
extension package. Only if this attribute is discovered will the tool perform its search for additional ones.
[PackageRegistration(UseManagedResourcesOnly = true)]
The Guid attribute specifies a unique package module identifier, which will be used for creating a
registry sub-key for this module in Visual Studio hive.
[Guid("a0fcf0f3-577e-4c47-9847-5f152c16c02c")]
The InstalledProductRegistration attribute adds information to 'Visual Studio Help -> About' dialog and
the loading splash screen.
[InstalledProductRegistration("#110", "#112", "1.0",
IconResourceID = 400)]
The ProvideAutoLoad attribute links automatic module initialization with the activation of a specified
environment UI context. When a user enters this context, the package will be automatically loaded and
initialized. This is an example of setting module initialization to the opening of a solution file:
[ProvideAutoLoad("D2567162-F94F-4091-8798-A096E61B8B50")]
5. The GUID values for different IDE UI contexts can be found in the
Microsoft.VisualStudio.VSConstants.UICONTEXT class.
The ProvideMenuResource attribute specifies an ID of resource that contains user created menus and
commands for their registration inside IDE.
[ProvideMenuResource("Menus.ctmenu", 1)]
The DefaultRegistryRoot attribute specifies a path to be used for writing registration data to the system
registry. Starting with Visual Studio 2010 this attribute can be dropped as the corresponding data will be
present in manifest file of a VSIX container. An example of registering a package for Visual Studio 2008:
[DefaultRegistryRoot("SoftwareMicrosoftVisualStudio9.0")]
Registration of user-created components, such as toolwidows, editors, option pages etc. also requires
the inclusion of their corresponding attributes for the user's Package subclass. We will examine these
attributes separately when we will be examining corresponding components individually.
It's also possible to write any user-defined registry keys (and values to already existing keys) during
package registration through custom user registration attributes. Such attributes can be created by
inheriting the RegistrationAttribute abstract class.
[AttributeUsage(AttributeTargets.Class, Inherited = true,
AllowMultiple = false)]
public class CustomRegistrationAttribute : RegistrationAttribute
{
}
The RegistrationAttribute-derived attribute must override its Register and Unregister methods, which
are used to modify registration information in the system registry.
The RegPkg tool can be used for writing registration data to Windows registry. It will add all of the keys
from pkgdef file passed to it into the registry hive specified by the /root argument. For instance, the
RegPkg is utilized by default in Visual Studio VSPackage project template for registering the module in
the Visual Studio experimental hive, providing convenient seamless debugging of the package being
developed. After all of the registration information have been added to the registry, Visual Studio
(devenv.exe) should be started with '/setup' switch to complete registration for new components inside
the IDE.
Deploying plug-ins for developers and end-users. Package Load Key.
Before proceeding to describe the deployment process itself, one particular rule should be stressed:
Each time after a new version of the distribution containing your plug-in is created, this new
distribution should be tested on a system without Visual Studio SDK installed, as to make sure that it
will be registered correctly on the end-user system.
Today, as the releases of early versions of PVS-Studio are past us, we do not experience these kinds of
issues, but several of these early first versions were prone to them.
Deploying a package for Visual Studio 2005/2008 will require launching of regpkg tool for a pkgdef file
and passing the path to Visual Studio main registry hive into it. Alternately, all keys from a pkgdef can be
written to Windows registry manually. Here is the example of automatically writing all the registration
data from a pkgdef file by regpkg tool (in a single line):
6. RegPkg.exe /root:SoftwareMicrosoftVisualStudio9.0Exp
"/pkgdeffile:objDebugPVS-Studio-vs2008.pkgdef"
"C:MyPackageMyPackage.dll"
After adding the registration information to the system registry, it is necessary to start Visual Studio
with a /setup switch to complete the component registration. It is usually the last step in the installation
procedure of a new plug-in.
Devenv.exe /setup
Starting the environment with this switch instructs Visual Studio to absorb resource metadata for user-
created components from all available extension packages, so that these components will be correctly
displayed by IDE's interface. Starting devenv with this key will not open its' main GUI window.
We do not employ RepPkg utility as part of PVS-Studio deployment, instead manually writing required
data to the registry by using our stand-alone installer. We chose this method because we have no desire
of being dependent on some external third-party tools and we want full control over the installation
process. Still, we do use RegPkg during plug-in development for convenient debugging.
VSIX packages
Beginning from Visual Studio 2010, VSPackage deployment process can be significantly simplified
through the usage of VSIX packages. VSIX package itself is a common (Open Packaging Conventions)
archive containing plug-in's binary files and all of the other auxiliary files which are necessary for plug-
in's deployment. By passing such archive to the standard VSIXInstaller.exe utility, its contents will be
automatically registered in the IDE:
VSIXInstaller.exe MyPackage.vsix
VSIX installer could also be used with /uninstall switch to remove the previously installed package from
a system. A unique GUID of the extension package should be used to identify such package:
VSIXInstaller.exe /uninstall: 009084B1-6271-4621-A893-6D72F2B67A4D
Contents of a VSIX container are defined through the special vsixmanifest file, which should be added to
plug-in's project. Vsixmanifest file permits the following properties to be defined for an extension:
• targeted Visual Studio versions and editions, which will be supported by the plug-in;
• a unique GUID identifier;
• a list of components to be registered (VSPackage, MEF components, toolbox control etc.);
• general information about the plug-in to be installed (description, license, version, etc.);
To include additional files into a VSIX container, the IncludeInVSIX node should be added to their
declarations inside your MSBuild project (alternately, they could also be marked as included into VSIX
from their respective property windows, by opening it from Visual Studio Solution Explorer).
<Content Include="MyPackage.pdb">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
In fact, the VSIX file could be viewed as an almost full-fledged installer for extension packages on the
latest versions of Visual Studio (2010 and 2012), allowing the extensions to be deployed by a "one-click"
7. method. Publishing your VSIX container in the official Visual Studio Gallery for extensions allows end-
users to install such package through the Tools -> Extension Manager IDE dialog.
This new VSIX installation procedure in Visual Studio 2010 does substantially alleviate package
deployment for end-users (as well as for developers themselves). Some developers even had decided to
support only VS2010 IDE and versions above it, if only not to get involved with the development of a
package and installer for earlier IDE versions.
Unfortunately, several issues can be encountered when using VSIX installer together with Visual Studio
2010 extension manager interface. For instance, sometimes the extension's binary files are not removed
correctly after uninstall, which in turn blocks the VSIX installer from installing/reinstalling the same
extension. As such, we advise you not to depend upon the VSIX installer entirely and to provide some
backup, for example by directly removing your files from a previous plug-in installation before
proceeding with a new one.
Package Load Key
Each VSPackage module loaded into Visual Studio must possess a unique Package Load Key (PLK). PLK
key is specified through the ProvideLoadKey attribute for the Package subclass in 2005/2008 versions of
the IDE.
[ProvideLoadKey("Standard", "9.99", "MyPackage", "My Company", 100)]
Starting with Visual Studio 2010, the presence of a PLK, as well as of the ProvideLoadKey attribute
respectively, in a package is not required, but it can still be specified in case the module under
development is targeting several versions of MSVS. The PLK can be obtained by registering at the Visual
Studio Industry Partner portal, meaning it guarantees that the development environment can load only
packages certified by Microsoft.
However, systems containing Visual Studio SDK installed are exceptions to this, as Developer License Key
is installed together with the SDK. It allows the corresponding IDE to load any extension package,
regardless of validity of its PLK.
Considering the aforementioned, one more time it is necessary to stress the importance of testing the
distribution on a system without Visual Studio SDK present, because the extension package will operate
properly on developer's workstation regardless of its PLK correctness.
Extension registration specifics in the context of supporting several different versions of
Visual Studio IDE
By default, VSPackage project template will generate an extensibility project for the version of Visual
Studio that is used for the development. This is not a mandatory requirement though, so it is possible to
develop an extension for a particular version of IDE using a different one. It also should be noted that
after automatically upgrading a project file to a newer version through devenv /Upgrade switch, the
targeted version of the IDE and its' corresponding managed API libraries will remain unchanged, i.e.
from a previous version of Visual Studio.
To change the target of the extension to another version of Visual Studio (or to register an extension
into this version to be more precise), you should alter values passed to the DefaultRegistryRoot attribute
(only for 2005/2008 IDE versions, as starting from Visual Studio 2010 this attribute is no longer required)
or change the target version in the VSIX manifest file (for versions above 2008).
8. VSIX support appears only starting from Visual Studio 2010, so building and debugging the plug-in
targeted for the earlier IDE version from within Visual Studio 2010 (and later) requires setting up all the
aforementioned registration steps manually, without VSIX manifest. While changing target IDE version
one should also not forget to switch referenced managed assemblies, which contain COM interface
wrappers utilized by the plug-in, to the corresponding versions as well.
Altering the IDE target version of the plug-in affects the following Package subclass attributes:
• the InstalledProductRegistration attribute does not support overloading of its constructor with a
(Boolean, String, String, String) signature, starting from Visual Studio 2010;
• the presence of DefaultRegistryRoot and ProvideLoadKey attributes is not mandatory starting
from Visual Studio 2010, as similar values are now specified inside VSIX manifest;
References
1. MSDN. Experimental Build.
2. MSDN. How to: Register a VSPackage.
3. MSDN. VSIX Deployment.
4. MSDN. How to: Obtain a PLK for a VSPackage.
5. MZ-Tools. Resources about Visual Studio .NET extensibility.
6. MSDN. Creating Add-ins and Wizards.
7. MSDN. Using a Custom Registration Attribute to Register an Extension.
Other articles in this series
1. Introduction.
2. Creating, debugging and deploying extension packages for Microsoft Visual Studio
2005/2008/2010/2012.
3. Visual Studio Automation Object Model. EnvDTE interfaces.
4. Visual Studio commands.
5. Visual Studio tool windows.
6. Integrating into Visual Studio settings.
7. Visual C++ project model.