Tuesday, March 17, 2009

Automatically load a Visual Studio Extensibility package at IDE startup

I've been searching around for how one might cause a package to load upon IDE startup, even with no package tool window visible at IDE startup (having a tool window present in the IDE layout will cause the respective package to load). I’m posting this (a) for my own reference, (b) to keep this information in a single location, and (c) to assist any other VSX package developers who may run into this issue.

Setting a VSX Package to Auto-load using the Registry

This solution recently appeared here. Visual Studio 2008 will auto-load packages upon startup based on certain registry settings for the IDE. Therefore, in order to cause the package to load upon IDE startup, we need to add a reference for the package in the appropriate section of the Visual Studio’s registry tree:

HKLM\Software\Microsoft\VisualStudio\9.0\AutoLoadPackages

Now, under this key, you’ll notice several keys.

image

Each of these corresponds to an IDE context (see LearnVSXNow! #13), and the name of each key corresponds to the context’s GUID. Basically, we need to add the reference to our package under the key for the context in which we want the package to load. For example, if we want the package to load upon startup, with no solution, we need to use the key for the NoSolution context. {ADFC4E64-0397-11D1-9F4E-00A0C911004F} is the GUID for the NoSolution context, so this is the key under which we need to place the reference to our project:

HKLM\Software\Microsoft\VisualStudio\9.0\AutoLoadPackages\{adfc4e64-0397-11d1-9f4e-00a0c911004f}

We need to add a DWORD entry with a value of 0 under this key that has the package GUID as the value name. For example, the following is an excerpt from a .reg file containing an exported key/value for a package that will load on startup:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\AutoLoadPackages\{ADFC4E64-0397-11D1-9F4E-00A0C911004F}]
"{53514C4D-E3F8-4AA0-8195-8A8D16019623}"=dword:00000000

Basically, all that we need to be do is add another entry (under HKEY_LOCAL_MACHINE\ SOFTWARE\ Microsoft\ VisualStudio\ 9.0\ AutoLoadPackages\ {ADFC4E64-0397-11D1-9F4E-00A0C911004F}) that has the GUID of our package as the entry name.

In particular, we want this process to be automated. In other words, we want the installer for our package to make this change whenever the package is installed. Thankfully, this can be accomplished with ease using the setup project in your Visual Studio package solution.

1) Right-click on the setup project in the Solution Explorer. Select View->Registry.

2) Under the “Registry on the Target Machine” navigate to the desired location in the registry.

3) Right click on the {adfc4e64-0397-11d1-9f4e-00a0c911004f} key, and select New->DWORD Value.

4) Modify the name of the new entry to match the GUID for your package (it will be in the class GuidList, in the file Guids.cs).

5) Save-all and rebuild the setup project.

That should cause the registry entry to be automatically added to the hive when the package is installed using the MSI produced from Visual Studio.

How to add a setup project

I’m including this just in case the reader doesn’t know how to get a setup project up and running. This article contains a full write-up on how to deploy a project using a setup project:

http://msdn.microsoft.com/en-us/library/bb458038.aspx

The above can be cross-referenced with these tutorials for setting up deployment rules:

http://msdn.microsoft.com/en-us/library/bb187331(VS.80).aspx

http://msdn.microsoft.com/en-us/library/bb187327(VS.80).aspx

These are also good references for deploying packages.

http://msdn.microsoft.com/en-us/library/bb164659.aspx

http://msdn.microsoft.com/en-us/library/bb166419(VS.80).aspx

Those should be sufficient to get you going.

Alternative method for auto-loading a package

This way (found here) apparently works in the experimental hive, as I could not get the package to auto-load when deploying using the installer. I’m including it here for completeness:

There is an attribute in the Microsoft.VisualStudio.Shell namespace called ProvideAutoLoad. You can decorate your Package derived classes with this attribute. The constructor of ProvideAutoLoad requires a GUID that is the so-called context ID. Visual Studio will load your package automatically when it enters into the specified context. (To get more information about what these contexts are, read the “Visibility contexts” chapter in LearnVSXNow! #13.)

Basically, we need to place a ProvideAutoLoad attribute on the package class that specifies the "NoSolution" visibility context. Factoring in the visibility context information, the necessary code would look something like this:

[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.NoSolution)]
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.SolutionExists)]
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.FullScreenMode)]
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.DesignMode)]
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids.Debugging)]

public sealed class SomePackage : Package

Except that there is one caveat, from the MSDN documentation:

You must pass the GUID value of UICONTEXT_SolutionExists to ProvideAutoLoad instead of its symbolic name. See the enumerated fields of VSConstants for a list of the UI contexts and their GUID values.

So really, the above looks like this:

[ProvideAutoLoad("{ADFC4E64-0397-11D1-9F4E-00A0C911004F}")]
[ProvideAutoLoad("{F1536EF8-92EC-443C-9ED7-FDADF150DA82}")]
[ProvideAutoLoad("{ADFC4E62-0397-11D1-9F4E-00A0C911004F}")]
[ProvideAutoLoad("{ADFC4E63-0397-11D1-9F4E-00A0C911004F}")]
[ProvideAutoLoad("{ADFC4E61-0397-11D1-9F4E-00A0C911004F}")]
public sealed class SomePackage : Package

Finally:

A few hints when you try this feature: do not forget that changing the ProvideAutoLoad attribute requires your application to rebuild. If you find that you have your app rebuilt but it behaves like before (I mean it loads in the same context as it did before even if changing the ProvideAutoLoad context), reset the Visual Studio Experimental hive (with the tool provided in VS SDK).