Troubleshooting pkgdef Files
For those using the Visual Studio 2010 SDK to create extensions for Visual Studio, you should find the creation and use of .pkgdef files to be mostly automatic (see What’s a PkgDef and Why?). However, like anything involving computers and software, there are occasions that require manual intervention because they aren’t covered by the automatic settings or things can go wrong. This article illustrates some possible issues with .pkgdef files and provides techniques for discovering what’s wrong and correcting them.
Please note that these techniques apply not only to the Visual Studio 2010 IDE, but also to applications built using the Visual Studio 2010 Shell (Isolated) (or Integrated). All of the examples assume the case of VS 2010 running on 32-bit Windows 7. For other cases, substitute the appropriate file locations and names and registry root key.
What Could Go Wrong?
First of all, how do you know if something goes wrong? A problem with a .pkgdef file usually manifests itself in one of two ways:
- All or part of a Visual Studio extension, such as a VS Package, simply fails to load or an error message is displayed about needing to reinstall Visual Studio.
- Your Visual Studio extension tries to retrieve a registry value it expected to be included in the install and does not find it. The result can be anything from using an appropriate default to displaying a message about an exception.
Either of these symptoms can be caused by one or more of the issues listed below. The list is by no means intended to be exhaustive.
- Per-user Extension Is Not Enabled
- pkgdef File Is Not Found
- Invalid Syntax
- Unrecognized Substitution String
- Invalid Registry Key
- Registry Value Collisions
Pkgdef files that are installed as part of a user extension deployed using the new VSIX format are copied to a sub-folder of %LocalAppData%MicrosoftVisualStudio10.0Extensions. The pkgdef loader does not automatically search for pkgdef files here. Rather, it loads pkgdef files for user extensions that have been enabled, which the Extension Manager and the stand-alone VSIX installer both do automatically. If you choose to unpack a VSIX file yourself, or otherwise do a manual xcopy-style deployment, it’s easy to forget the step that enables the extension. This is easily fixed.
Remedy: Use the Extension Manager to enable per-user extensions
It’s entirely possible that if you manually deployed the contents of a VSIX file, you simply need to enable it in the Extension Manager dialog and restart Visual Studio before the pkgdef loader will pick it up.
Remedy: Enable per-user extensions when running as administrator
On a related note, there is an option to disable loading of all per-user extensions when running ‘as administrator’ (elevated), regardless of being enabled or not. This is controlled under Tools-Options-Extension Manager as Load per user extensions when running as administrator. Make sure this checkbox is checked (when appropriate).
For all other extensions (those that are not per user), the pkgdef loader searches the locations listed in the PkgDefSearchPath of the master pkgdef file. The value of PkgDefSearchPath has three elements:
$RootFolder$ is the location where Visual Studio is installed (C:Program FilesMicrosoft Visual Studio 10.0). The first two search elements are folders, which are recursively scanned looking for pkgdef files. The third element is a specific pkgdef file (which does not typically exist, but is kept in the list as a placeholder for system administrators).
An easy mistake to make is to drop a pkgdef file into either $RootFolder$ or $RootFolder$Common7IDE or some other sub-folder and expect the pkgdef loader to just find it. However, these locations are not in the search path.
Remedy: Use /log to discover which pkgdef files are loaded
You can find out exactly which pkgdef files the loader is finding, using the /log command line option for Visual Studio. Among the items the pkgdef loader logs are the full expanded value for the PkgDefSearchPath, a list of all of the pkgdef files found on the search path, and a list of the pkgdef files found for enabled extensions.
|Trick Since the pkgdef loader will not rebuild the cache if it does not think it is out of date, there is a bit of a trick to using /log to debug pkgdef load issues when you are not sure which files it is finding (and thus which ones to touch). Use Notepad to create a file called “log.pkgdef” that contains a single comment line (“// comment”) and copy it to C:Program FilesMicrosoft Visual Studio 10.0Common7IDEExtensions. This ensures that the pkgdef loader has a new file to process. If you need to run /log more than once with this file in place, be sure that it gets saved with a new timestamp before each run.|
Run: devenv.exe /log
When Visual Studio is finished loading (status bar reads “Ready”), File – Exit, start Windows Explorer, browse to C:UsersUserAppDataRoamingMicrosoftVisualStudio10.0, and open the file ActivityLog.xml. It should open in Internet Explorer using the associated XSL to format it in an table.
Near the top of the file, Visual Studio will list the PkgDefSearchPath:
This is followed by the number of files found and then the list of those files, for example:
Armed with the knowledge of which folders are being scanned and which pkgdef files were discovered, you should now be able to make sure your pkgdef file is deployed to an appropriate location.
Remedy: Install System-wide extensions under the PkgDefSearchPath
Any extension that is not installed per-user should be installed in a sub-folder of $RootFolder$Common7IDEExtensions or $RootFolder$Common7IDECommonExtensions.
This issue is most likely to crop up if you run into a situation where you must create or edit a pkgdef file manually. Like any language, it’s easy to forget a closing quote or insert an extra one.
The syntax of a pkgdef file is actually quite simple. Each line can be one of:
- comment – starts with a semi-colon (‘;’’) or double-slash (‘//’)
- registry key – starts with a square bracket (‘[‘) and ends with a square bracket (‘]’) that defines a section of values
- registry value – starts with a name in double quotes or the at sign (‘@’ not in quotes) for a ‘default’ value of a key, followed by an equals sign, and then a string or numeric value
Common syntax mistakes include:
- Not enclosing a registry value name in double quotes: incorrect: name=”value” correct: “name”=”value”
- Enclosing the symbol for the default value of a registry key in double quotes: incorrect: “@”=”value” correct: @=”value”
- Omitting an opening or closing double quote for a name or string value
- Adding comments at the end of a line defining a key or value. Comments must be on their own line.
The pkgdef loader is not very tolerant of syntax errors and will simply refuse to load a pkgdef file that contains even a single error, rather than risk corruption of the pkgdef cache. When it does reject a pkgdef, this information is written to the activity log.
Remedy: Use /log to discover pkgdef file syntax errors
Use /log to generate ActivityLog.xml. Any syntax errors will be highlighted in red, along with a warning showing the name of the offending file (which is not loaded).
In this example, the value of “foo” is missing the closing quote expected for strings and the value of bar is given as word, rather than dword or qword. The name for “bax” is not put in quotes. Once you edit the file to make these corrections (and save it and deploy it to the correct location), the pkgdef loader will see that the file has been updated and rebuild the cache automatically (you do not have to force this rebuild by deleting the registry value from the cache again).
Remedy: Use the PkgDef Editor extension for Visual Studio
Another way to find and fix syntax errors is to download and install the new editor extension we’ve created to give syntax coloring and error output for pkgdef files. It can be found in the Visual Studio gallery, either through the Extension Manager or directly in the gallery. Just search for “pkgdef” under the Tools category and download the PkgDef Editor extension.
In this example, the same errors as above are flagged, along with the pop-up message describing the problem with the value of “foo”.
pkgdef files are made portable by tokenizing system-specific and user-specific information. These are known as substitution strings. Examples are $RootKey$, which defines the root of the Visual Studio configuration registry, the starting point for all key values, and $PackageFolder$, which is the full path in the file system to the location from where the current pkgdef file is being loaded.
Substitution strings are case-sensitive and must be enclosed between two dollar-signs (‘$’). Common mistakes related to tokens are:
- Omitting the closing dollar-sign” on a substitution string name: incorrect: [$RootKeysubkey] correct: [$RootKey$subkey]
- Using incorrect case or spelling: incorrect: “pathtomyfile”=”$packagefolder$myfile.dll” or “$pkgfolder$myfile.dll” correct: “pathtomyfile”=”$PackageFolder$myfile.dll”
When the pkgdef loader cannot recognize a substitution string, it simply does nothing and uses it ‘as is’. When this happens in a registry key or value name, it means the key or value will not be put in the correct location or get the correct name.
Remedy: Search the registry
This can be very difficult to debug, except by knowing what to look for. When this happens for a string value, it is a little easier to detect, simply by looking in the registry using regedit.exe:
In this example, the value for “bax” was specified with “$PkgFolder$”, rather than “$PackageFolder$”.
Remedy: Use PkgDef Language Integration for Visual Studio
As seen above, the PkgDef Editor extension can make it much easier to see problems with pkgdef files. In particular, it knows the valid tokens for string substitution and can flag the ones it does not recognized:
In this example, all of the string substitution tokens (anything starting and ending with the dollar-sign) are highlighted (in blue) and the unrecognized tokens are flagged as errors. One string contains a value that was intended to be a string substitution, but is missing the closing dollar-sign, so it is not highlighted. Also in this example, it is easy to see that $RegRoot$ is not a recognized string substitution, but using regedit it was simply missing-in-action.
The pkgdef loader will not write to arbitrary registry locations. It only writes registry entries within the configuration hive of Visual Studio (or an Visual Studio Shell (Isolated) application). This rule is easily followed by starting all key/section names with $RootKey$.
Remedy: Use /log to discover invalid registry keys
The pkgdef loader will log attempts to write to locations outside of the application’s configuration hive:
In this example, using the file from the previous example, $RegRoot$ was not recognized as a substitution string, so it did not get replaced with the appropriate root key for the application. And the result is not a valid location for a registry key for the application.
Sometimes the same registry value is being set by more than one pkgdef file. In other cases, a registry value is being set, but it’s not clear which pkgdef file is doing it. You can either scan all of the pkgdef files and discover where the value is being set. Or use /log again.
Remedy: Use /log to discover which pkgdef(s) set a value
To discover all pkgdef files that are setting a value, use a simple trick: explicitly set that same value by temporarily changing the master pkgdef (C:Program FilesMicrosoft Visual Studio 10.0Common7IDEdevenv.pkgdef) to explicitly set the value before all of the other pkgdef files are processed. This will require Administrator rights to edit the file, but is otherwise straightforward. Make a backup copy of devenv.pkgdef, then bring it up in an editor. Below the [$Initialization$] section, add a new section for the parent key of the value. Then add the key value below it, save it, and run devenv.exe with /log. The pkgdef loader will log all of the additional writes to that value, along with the path to the offending pkgdef.
In this example, we caught the blog.pkgdef file writing to the value “foo” under “$RootKey$MyExtension”. The next step is to determine why and whether this needs to change (be sure to put devenv.pkgdef back the way you found when you’re done).
This post has described several tactics for troubleshooting pkgdef issues. The most basic of these is to use /log, along with a trick for forcing PkgDef Management to rebuild the pkgdef cache. You may also find that the PkgDef Editor extension is helpful when editing pkgdef files.
| Bill Weinberger: Developer, Visual Studio Platform
Bill has been with the VS Platform team for about two years, and has more than a few previous years of software industry experience working on IDEs and vertical applications. For Visual Studio 2010, he was a key contributor to PkgDef Management.