Dotneteers.net
All for .net, .net for all!

LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive

When I created the Package Reference Sample Deep Dive I was constrained in the range. Originally I created a longer version with more details. However, I forgot about it... Now, while organizing my publications I have discovered it again and so here I publish the original version. I suggest reading it for developers starting with the basics of VSX development.

Originally it was created for VS 2008 SDK 1.0, but it also works with VS 2008 SDK 1.1.

Overview

The Package Reference Sample shipped with VS 2008 SDK is the first “must-have-a-look-at” sample for those who want to start extending Visual Studio with VSPackages. This sample contains four very simple non-functional packages that integrate into VS. By understanding how they work helps you catching the concept of packages in Visual Studio. If you read this whitepaper you will get familiar with the following things:

—  What is a Visual Studio package?

—  How a package is integrated into Visual Studio?

—  How Visual Studio loads packages into the memory?

—  What is the Package Load Key?

—  How to create a simple package using the Managed Package Framework?

—  How to add branding information to the Help About dialog?

What are Visual Studio Packages?

Although we think, Visual Studio is a monolithic product composed from devenv.exe and a few dynamic link libraries, in reality VS is frame application “stuffed” with functional units like the C# and VB project system, debugger, database tools, and so on. In this context, the frame is the so-called Visual Studio Shell that provides services like windows, text editor, menu and command system. The functional units are called packages (or VSPackages if we want to emphasize their integration with VS).

What we perceive when using VS is the result of cooperation between the shell and hosted packages. Actually, almost all functional units what we use during development are packages, and also majority of third-party extensions loaded into Visual Studio are also implemented as VSPackages. Generally, after installing VS, your machine has about a hundred of registered packages.

How packages integrate with Visual Studio?

Packages are binaries that implement a few COM interfaces used by Visual Studio to interact with the package. One binary can contain one or more packages. Each of them is a unit of deployment and can be written in any languages (VB, C#, C++, F# or whatsoever). Physically a package is a type that:

—  Implements the IVsPackage interface

—  Provides registration information about itself

Visual Studio recognizes packages through information in the system registry: each package should register itself in order to be recognized by VS. Registration must be the part of the installation or the build process. Registration entries provide enough information for Visual Studio to display the interaction points (menus, toolbars, context menu items, etc.) without loading the package into the memory. When the user interacts with a UI element or Visual Studio requests a service that refers to a functional unit within the package, VS loads the package into the memory and keeps there while it runs.

To be integrated successfully into the VS environment a package should have a valid Package Load Key (PLK). This key is a kind of certificate (hash) on the package and can be requested from Microsoft. When VS loads the package checks it for a valid PLK. Should this validation fail, VS refuses loading the package.

When a package is loaded into the memory, it can access all services of the Visual Studio Shell as well as services of third party packages proffered to the shell.

Building packages with Visual Studio

Since Visual Studio packages integrate with VS through COM interfaces we can create them both in managed and unmanaged code.  In the paper I focus only on building packages with C#. From deployment point of view a package is a type that is encapsulated in an assembly (Class Library). To create a usable solution that can be checked (tested) during development type, the build process should contain a task to register VSPackages built. Visual Studio SDK ships with a few extensibility project templates that make the creation of VSPackage easy.

Figure 1: Visual Studio Integration Package project type

The Visual Studio Integration Package project template starts the VSPackage wizard that creates a buildable and testable package in a few steps.

By the nature of VSPackages they can be best tested when hosted in Visual Studio. To make a good separation of development and test environments, packages are tested in the so-called Visual Studio Experimental Hive.

VS Experimental Hive is a separate Visual Studio instance with its own settings (registry entries). When VS SDK is installed it sets up the Experimental Hive so that it accepts packages without a valid PLK. When a VSPackage solution is about to start debugging, VS launches the Experimental Hive that loads the registered package. The development environment (the VS IDE we initiate debugging from) attaches to the Experimental Hive, so we can set breakpoints in the package source code and watch variables just like when debugging a console application.

VS SDK provides a set of assemblies with encapsulated types called Managed Package Framework. Types in MPF are the basic building blocks that help you create the bulk of VSPackages in an easy way. VS SDK also provides a utility called RegPkg.exe that helps you with package registration and unregistration tasks.

Package Reference Sample

Now, having the basic information about VS SDK and VSPackages let’s have a look at the Package Reference Sample. Open the Microsoft Visual Studio 2008 SDK Browser and select the Samples tab. In the top middle list you can search for the “C# Reference.Package” sample. Please, use the “Open this sample in Visual Studio” link at the top right panel of the browser app to prepare the sample. The application opens in Visual Studio 2008.

Running the sample

The reference sample solution contains the Package C# Class Library project. Rebuild the solution and run it. By rebuilding it Visual Studio not just simply compiles the binaries but also registers packages with the VS Experimental Hive. When you run the solution the VS Experimental Hive launches. Our packages are non-functional: they simply integrate with VS, and that is all they do. Open the Help About dialog and in the Installed products list you shall find the “traces” of the successful integration as it is shown in Figure 2:

Figure 2: Packages are integrated into VS Experimental Hive

In the Product Details box you can see the icon and descriptive text of packages selected from the list above.

Click OK, and close the Experimental Hive.

The structure of the sample

The core of the solution is the Package project. It is a simple C# class library with references to VS Shell interop assemblies. When you have a look at the referenced assemblies, you will find a few of them starting with name “Microsoft.VisualStudio”. Here is a table summarizing them (without the Microsoft.VisualStudio prefix):

Assembly

Description

~.Shell.Interop

This assembly defines several hundreds of core interoperability types (interfaces, structures, enumerations, classes, etc.).

~.Shell.Interop.8.0 and ~.Shell.Interop.9.0

There are COM types new in VS 2005 IDE and VS 2008 IDE. The interoperability wrappers of them are defined in these assemblies where the 8.0 suffix is for VS 2005 while 9.0 suffix for VS 2008.

~.OLE.Interop

There are a few hundred of standard OLE types and interfaces. This assembly provides wrapper types for them.

The project has only a few source file:

Source file

Description

ClassDiagram.cd

A class diagram summarizing solution elements.

GenericPackage.bmp

GenericPackage.ico

Images used in package resources

GlobalSuppressions.cs

Static code analysis global suppression

VSPackage.Designer.cs

VSPackage.resx

Package resource files

BasicPackage.cs

The most basic package that can be integrated with VS.

Package.LoadKey.cs

The basic package that has a Package Load Key and so can be loaded not only into the Experimental Hive but also into a Visual Studio on a machine without VS SDK.

Package.Splash.HelpAbout

A basic package that can advertise itself through the splash screen and the Help About dialog

Package.Splash.HelpAbout.LoadKey.cs

Package combining the PLK and advertising feature.

In the subsequent parts of this paper the focus is upon the types representing packages. In the original source code you find useful comments describing how the packages work. Please, read them. In the code extracts within this paper I will omit or change comments to support better readability.

The Basic Package

The BasicPackage.cs file contains the smallest package that actually has no functionality. The only thing this package can do is to give a “live sign” about itself when it is loaded into the memory. Let’s see the source!

using System;

using System.Diagnostics;

using System.Runtime.InteropServices;

using System.Globalization;

using MsVsShell = Microsoft.VisualStudio.Shell;

 

namespace Microsoft.Samples.VisualStudio.IDE.Package

{

  [MsVsShell.DefaultRegistryRoot(

    @"Software\Microsoft\VisualStudio\9.0Exp")]

  [MsVsShell.PackageRegistration(UseManagedResourcesOnly = true)]

  [Guid("01069CDD-95CE-4620-AC21-DDFF6C57F012")]

  public class BasicPackage : MsVsShell.Package

  {

    public BasicPackage()

    {

      Trace.WriteLine(String.Format(CultureInfo.CurrentCulture,

        "Entering constructor for class {0}.", this.GetType().Name));

    }

  }

}

The overall behavior of this package is declared by the attributes of our BasicPackage class that inherits from the abstract Package class of the Microsoft.VisualStudio.Shell namespace. Package declares the basic behavior of a VSPackage by implementing the IVsPackage interface. A type becomes a real VSPackage if it directly or indirectly implements the IVsPackage interface and registers itself with the Visual Studio shell. That is exactly what this 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.

Guid

Our class is accessible through other COM types and so requires a GUID. This GUID is referenced by VS and by objects (commands, menus, tool windows, etc.)

The class constructor simply signs to the Trace output that the package instance has been created by VS.

We need two more pieces to put the puzzle together.

How the package is built?

When we rebuild the solution not only the binaries get compiled but also a few other tasks run through the MSBuild mechanism used by VS. How VS knows that those extra build tasks should be run? When the solution was created it was based on the Visual Studio Integration Package project type that automatically adds tasks to the Package.csproj file. You can find them in the .csproj file: right-click on the Package project in the Solution Explorer and unload the project. On the next right-click edit the Package.csproj file. Go down to the end of the file and locate the Import sections:

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\

  v9.0\VSSDK\Microsoft.VsSDK.targets" />

(Please note, the last two lines are not broken in the original file).

The second line imports the build targets used by VS SDK. These targets make all the post-compile tasks that are related to VSPackages. Going into details about what those tasks are and how they work is beyond the scope of this paper.

Close the Package.csproj file (do not save any changes) and reload the project.

How the Experimental Hive starts?

When we debug the package Visual Studio launches the experimental hive. It works this way due to the Debug settings of the Package project. To have a closer look at them go into the properties of the project and select the Debug tab. In Figure 3 you can recognize that the devenv.exe is set as the startup program for the project and a few command line arguments are also specified.

Figure 3: Debug properties of the Package project

The /ranu switch tells VS to run as normal user. The /rootsuffix Exp option tells VS which registry key to use as the root for reading out configuration information. By using the command line switches above the Experimental Hive will start reading the information from the current user’s registry hive using the \Software\Microsoft\VisualStudio\9.0Exp root key.

When debugging, VS attaches itself to the newly started Experimental Hive and this is how we can set and catch breakpoints.

Using a Package Load Key

We can load packages into Visual Studio only if they have a valid Package Load Key (PLK). The Experimental Hive is set up so that it installs a DLK (Developer Load Key) that causes the PLK not needed. We can turn off this behavior by adding the /novsip switch to the command line arguments in the Package project’s debug settings. Let’s try it! Set the /novsip switch, rebuild and run the project.

Note, that the Experimental Hive starts just like before. However, when you try to open the Help About dialog, you’ll get a message:

Figure 4: Package with an invalid PLK

Where does this message come from? In the Package project we have four VSPackages. Two of them advertise themselves in the Help About dialog. When opening the dialog at the first time after VS started, it initiates the loading of packages advertising themselves. However, one of those two packages does not have a PLK (it’s like having an invalid PLK) and that is the message we get.

Setting the PLK

We can set the PLK by using the ProvideLoadKey attribute and putting the load key string into the package resources, as the following code (Package.LoadKey.cs) indicates:

[MsVsShell.ProvideLoadKey(

  "standard",

  "9.0",

  "Package Splash screen and Help About Official Name (C#)",

  "Litware, Inc.",

  150)]

[MsVsShell.DefaultRegistryRoot(

  @"Software\Microsoft\VisualStudio\9.0Exp")]

[MsVsShell.PackageRegistration(UseManagedResourcesOnly = true)]

[Guid("991245DA-68B0-421d-A611-B5D1B58E5B0F")]

public class PackageLoadKey : MsVsShell.Package

{

  public PackageLoadKey()

  {

    Trace.WriteLine(String.Format(CultureInfo.CurrentCulture,

      "Entering constructor for class {0}.", this.GetType().Name));

  }

}

(Please, note I extracted only the class definition from the source file.)

The first four parameter of ProvideLoadKey attribute defines the following parameters:

—  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. The PLK can be requested from Microsoft through the web and is calculated from the first four parameters and the package GUID.

In our case the PLK is the resource string with ID 150. If you open the VSPackage.resx file you can access that string:

M3AKZ3JTJTR2MQHRCJD3EKMQI1DPQAH0H9E1K3APDCK1MKE0KMZKECDQP8MCJ9ZRE2M8AHH1JIPMPZHPIZEECMPKMTE2J0EERCERCEK2D1DTAEE9RAKKE2K0EEAIRQRA

Should any of these five parameters change, the PLK gets invalid. You can try it: open the Package.Splash.HelpAbout.LoadKey.cs file and change the “Litware, Inc.” company name to “MyCompany”. After rebuilding and running VS, the Help About dialog pops up two Package Load Failure messages, since we touched the attributes and so invalidated the PLK.

Please, do not forget to remove the /novsip switch and change back “MyCompany” to “Litware, Inc.”!

Advertising package information

We have seen two packages advertising information about themselves in the Help About dialog. How to push this information to the dialog? There are two alternatives to do that: the package has to implement the IVsInstalledProduct interface or use the InstalledProductRegistration attribute with false value in the first parameter.

The Package.Splash.HelpAbout.LoadKey.cs file demonstrates this:

[MsVsShell.ProvideLoadKey("standard", "9.0",

  "Package Load key, Splash screen and Help About Official Name (C#)",

  "Litware, Inc.",

  151)]

[MsVsShell.InstalledProductRegistration(true, null, null, null)]

[MsVsShell.DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0Exp")]

[MsVsShell.PackageRegistration(UseManagedResourcesOnly = true)]

[Guid("EEE474A0-083B-4e9c-B453-F6FCCEDA2577")]

public class PackageSplashHelpAboutLoadKey : MsVsShell.Package,

  IVsInstalledProduct

{

  // --- Constructor omitted

  // ...

  // --- IVsInstalledProduct information

  public int IdBmpSplash(out uint pIdBmp)

  {

    pIdBmp = 300;

    return VSConstants.S_OK;

  }

 

  public int IdIcoLogoForAboutbox(out uint pIdIco)

  {

    pIdIco = 400;

    return VSConstants.S_OK;

  }

 

  public int OfficialName(out string pbstrName)

  {

    pbstrName = GetResourceString("@100");

    return VSConstants.S_OK;

  }

 

  public int ProductDetails(out string pbstrProductDetails)

  {

    pbstrProductDetails = GetResourceString("@102");

    return VSConstants.S_OK;

  }

 

  public int ProductID(out string pbstrPID)

  {

    pbstrPID = GetResourceString("@104");

    return VSConstants.S_OK;

  }

 

  public string GetResourceString(string resourceName)

  {

    // --- Omitted for clarity

  }

}

In this code we used the InstalledProductRegistration attribute with true value in the first parameter. This means that Visual Studio expects our package to implement the IVsInstalledProduct interface. This interface has five methods to implement. Each method has an HRESULT return parameter and an output parameter varying by methods. The output parameter is used to return the package information specific to the particular method. The following table summarizes IVsInstalledProduct methods:

Method Name

Description

IdBmpSplash

Gets the resource ID of the bitmap used on the splash screen of VS.

IdIcoLogoForAboutBox

Gets the resource ID of the icon used in the Help About dialog.

OfficialName

Retrieves the string describing the official name displayed in the splash screen and in the Help About dialog.

ProductDetails

Retrieves the string describing the detailed product description displayed in the Help About dialog.

ProductID

Gets the string describing the version id of the product displayed in the Help About dialog following the official product name.

The first two methods retrieve the integer values 300 and 400 as the corresponding bitmap and icon resource IDs. The latter three methods retrieve strings by their resource IDs using the GetResourceString helper method.

To check what is passed back by these methods, rebuild the solution and start the package but this time without debugging. Open the Help About dialog and stop at the packages registered (just like in Figure 2). Now, go back to the IDE where the Package project is open and check the content of the VSPackage.resx file. You can match the strings and images in the resource file with the ones displayed in the Help About dialog.

Summary

The Package Reference Sample contains a project that demonstrates four very simple packages each implemented by a type derived from the Package class of the Microsoft.VisualStudio.Shell namespace. Packages are decorated with attributes providing metadata for package registration. These packages demonstrate the role of Package Load Key and show how packages can advertise branding information about themselves to the splash screen and into the Help About dialog.

Package projects contain special MSBuild tasks responsible to build and register VSPackages. Package debugging takes place in the VS Experimental Hive. 


Posted Aug 30 2008, 04:59 PM by inovak
Filed under: ,

Comments

Visual Studio Hacks wrote Visual Studio Links #69
on Sun, Aug 31 2008 19:11

My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Busy week this week so this is a quick all at once version. Greg Duncan posted a link to release announcement for XamlPadX 4.0 . Sasha

shoe in money wrote re: LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive
on Mon, Feb 11 2013 15:08

Thanks again for the blog post.Much thanks again. Really Cool.

forex black book scam wrote re: LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive
on Mon, Feb 11 2013 16:38

Major thankies for the article post.Thanks Again. Awesome.

buy stendra generic wrote re: LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive
on Thu, Feb 14 2013 21:46

zTuyCq Thank you ever so for you blog post.Really looking forward to read more. Really Cool.

buy stendra wrote re: LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive
on Sun, Feb 24 2013 21:36

pZyJlK I really enjoy the blog.Really thank you! Awesome.

buy clomid wrote re: LVN Sidebar #6: Longer version of Package Reference Sample Deep Dive
on Fri, Mar 1 2013 5:08

1JFSMu Enjoyed every bit of your blog article.Much thanks again. Cool.