To get familiar with the concept of a Visual Studio Package, in this post we create an empty Visual Studio 2008 package. Start a new project and select the Visual Studio Integration Package project type:

We create this project for .NET Framework 2.0. Set the name of the package to EmptyPackage and click OK. The Visual Studio Integration Package Wizard starts with the following screen:

By clicking Next button the real definition of our package starts.

As the screenshot indicates, we chose C# as the language of the package. Packages must have strong names so we need a key to sign the package assembly. Here we let the wizard to generate a key for us. On the next screen we are going to set the basic information about our package:

Please fill up the information to similar content as indicated on the picture above. VSPackage Name, VSPackage Version and Detailed information will be used to display information about our package. The Minimum Visual Studio value allows us to select a VS edition for our package to embed in.
This version can be important since the different editions of Visual Studio have different services. If our package plans to use a service held only by VS Professional edition, a Standard version will not allow the package to use that specific service. Also, you can use this version setting because of licensing considerations.
The next screen allows us to select package options:

The wizard can create us a menu command, a tool window or custom editor. This time we do not select any checkboxes since we decided to create an empty package. By clicking Next button we arrive to the last wizard page where we can select the type of test projects we want to use with our package project:

Just as in the previous screen we do not check any boxes (actually, we uncheck them since they are checked by default) to get the simplest package. By pressing the Finish button, Visual Studio creates us the package project in a few seconds. When looking for the package in the Solution Explorer, we see the followings:

The list of referenced assemblies contains a lot of interop assemblies that provide communication with the COM objects within the Visual Studio IDE providing the services required by ourpackage. You may discover the System.Core.dll on the list of referenced assemblies. This assembly is a part of the .NET Framework 3.5 and this is a small contradiction to the fact that we started to create our package project as a .NET 2.0 project. Right now let us skip this „feature”.
Package files
The essential part of our code is embedded into one resource and two .cs files:
| File |
Description |
| EmptyPackagePackage.cs |
This file defines the EmptyPackagePackage type representing the VS loadable module. |
| Guids.cs |
As the COM world uses GUIDs, our package also uses GUIDs to identify its entities. These are defined in this file. |
| VSPackage.resx |
Resource file holding strings and icons used by the package. |
The wizard has generated other source files that are “less” important from our aspect:
| File |
Description |
| AssemblyInfo.cs |
Global assembly attributes |
| Package.ico |
Icon representing the package |
| Resources.resx |
Placeholder file for package level resources (initially empty) |
| GlobalSupressions.cs |
Global static code analysis rule suppressions |
Checking the package
In case of a “Hello, world” program it is easy to test if it is working: when we run it displays its message. In case of an empty package it has only one visible interface with the VS IDE that proves the package is registered and “recognized” by the IDE. This is the Help|About dialog where all packages are displayed. When we run our empty package, it starts the experimental instance of Visual Studio 2008. Using Help|About we can recognize our small package:

How does it work?
Now it is the time to dive into the source and discover how our package works. In this section I will show the source files omitting comments or trivial parts in order to make the code readable. Let us start with the Guids.cs file:
using System;
namespace MyCompany.EmptyPackage
{
static class GuidList
{
public const string guidEmptyPackagePkgString =
"223643a0-af7c-4741-99df-e9641691af50";
public const string guidEmptyPackageCmdSetString =
"cecdc1f1-2fb2-40e4-88e8-ae8c85287a7c";
public static readonly Guid guidEmptyPackageCmdSet =
new Guid(guidEmptyPackageCmdSetString);
};
}
This file holds the static GuidList class responsible for enumerating GUID constants used within the package. The two GUID strings are used to initialize two GUID values. The first string, guidEmptyPackagePkgString is the GUID of our package, while the second string is used to identify a so-called command set of our package. Because we have an empty package that does not have any commands, right now we can ignore the second GUID.
The definition of the package can be found in the EmptyPackagePackage.cs file:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
namespace MyCompany.EmptyPackage
{
[PackageRegistration(UseManagedResourcesOnly = true)]
[DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0")]
[InstalledProductRegistration(false, "#110", "#112", "1.0",
IconResourceID = 400)]
[ProvideLoadKey("Standard", "1.0", "EmptyPackage", "MyCompany", 1)]
[Guid(GuidList.guidEmptyPackagePkgString)]
public sealed class EmptyPackagePackage : Package
{
public EmptyPackagePackage()
{
Trace.WriteLine(string.Format(CultureInfo.CurrentCulture,
"Entering constructor for: {0}", this.ToString()));
}
protected override void Initialize()
{
Trace.WriteLine (string.Format(CultureInfo.CurrentCulture,
"Entering Initialize() of: {0}", this.ToString()));
base.Initialize();
}
}
}
The overall behavior of our package is declared by the attributes of our EmptyPackagePackage class that inherits from the abstract Package class. The later declares the basic behavior of a VS Package by implementing the IVsPackage interface. A type becomes a package if it implements the IVsPackage interface and registers itself with the Visual Studio shell. That is exactly what our class does. The attributes of the class describe how to register the package:
| Attribute |
Description |
| PackageRegistration |
The regpkg.exe utility scans types for this attribute to recognize that the type should be registered as a package. Adding this attribute to our class, regpkg.exe will handle it as a package and looks for other attributes to register the class according to our intention. In our example this attribute sets the UseManagedResourcesOnly flag to tell that all resources used by our package are described in the managed package and not in a satellite .dll.
|
| DefaultRegistryRoot |
To provide an easy way to develop and debug Visual Studio components, VS provides a quite simple method: it allows naming a registry root in the startup parameters of the devenv.exe (that is the VS IDE). When we run a VS component in debug mode, our component actually runs in an IDE using the so-called experimental hive. This hive uses different settings for our debug environment.
When we use the “Start Debugging” function of VS, it uses regpkg.exe with a command line parameter to register out package for the experimental hive.
The DefaultRegistryRoot attribute names the registry root to be used for the package registration if the corresponding regpkg.exe command line parameter is not used. In our example this is the registry root of the “normal” VS 2008 IDE.
|
| InstalledProductRegistration |
This attribute is responsible to provide information to be displayed by the Help|About function in the VS IDE. The constructor of this attribute requires four parameters with the following meanings:
The first false indicate that out package does not provide its own UI to display information about the package.
The second and third strings provide the name and the description of the package. The “#” characters indicate that these values should be looked up in the package resources with the IDs following the # character.
The fourth “1.0” parameter is the product ID (version number).
The fifth parameter (IconResourceID) tells which icon to use for the package.
The resources (name, description and icon) should be defined in the VSPackage.resx file.
|
| ProvideLoadKey |
Each VS component should be signed with a so-called package load key (PLK) that is used by Visual Studio to check if the package is the one it says about itself it is. When you install Visual Studio SDK, it installs a VSIP license that allows loading a package without a PLK.
However, in the production environment users do not have a VSIP license and so they need a PLK. The ProvideLoadKey attribute defines the PLK and the base information used to generate the PLK. By comparing the base information and the corresponding PLK, VS can check package identity and allow or refuse to load a particular package.
The first four parameter of the attribute defines the following elements:
Minimum VS edition expected
Version of the product (package)
Name of the product (package)
Company name (owner/developer).
The fifth parameter is the ID of the resource holding the PLK.
|
| Guid |
This attribute defines the GUID of our package. This GUID is the unique identifier of our package. This is used for the COM class registration, referencing to our package within the IDE, and so on.
|
These attributes are enough to define a “functioning” empty package. To make any package work, they may need to be initialized. We have two locations where initialization code can be put:
The package class constructor can be used to initialize anything that does not need the package to be sited in the VS IDE. In the package constructor the package class instance exists but it is not sited in the VS IDE (the instance is not connected in any way to the VS IDE). In the constructor we cannot access VS IDE services and so VS IDE objects.
The virtual Initialize method of the Package class is called when our package instance is sited in the VS IDE. Override this method and put any initialization code here that requires accessing VS IDE services and objects.
Where we are?
We created the smallest “functional” VS package that integrates with the VS IDE (and proves this fact by displaying information about itself in the About dialog). This package is represented by a simple class deriving from the Package class that implements the IVsPackage interface. To register this package and allow to VS IDE to site it, we decorate the class with attributes used by the regpkg.exe utility.
To move on, it is time to add some real functions to our package.
Posted
Jan 03 2008, 06:17 PM
by
inovak