Always use Unique Package Codes


It’s well documented and understood that package codes should be unique for product and patch packages. The package code, also referred to as a patch code for .msp files, is a unique identifier for that package. For patches, the patch code may also be used for obsolescence, where patch codes for patches to be obsolesced are entered into the Revision Number Summary Property after the initial package code.

Our old patch build system only had to target products for x86 so patch codes were stored for each release, which corresponds to a Knowledge Base article. The new patch build system for .NET Framework 2.0 and Visual Studio 2005 inherits most of its code from the older system, so even when generating patches for different architectures a single patch code was used for each of the architectures. That really wasn’t a problem since,

  1. .NET Framework 2.0 only installs on a system for which it was designed, and 64-bit redistributables also install the 32-bit files.
  2. Visual Studio 2005 installs as an x86 product with smaller, platform-specific product packages designed for the host operating system architecture.

Then we ran into a problem recently where both the x86 and the IA64 versions of the Visual C runtime redistributable were installed, and found logs with abbreviated lines like the following. The first patch targeting the IA64 redistributable installed correctly, but then the patch targeting the x86 redistributable would fail with ERROR_PATCH_TARGET_NOT_FOUND (1642).

From the first patch:

MSI (c) (DC:FC) [09:35:38:182]: Patch we’re running from ==> D:DOCUME~1USERLOCALS~1Temp3baa330.msp

MSI (c) (DC:FC) [09:35:39:522]: SequencePatches starts. Product code: {03ED71EA-F531-4927-AABD-1C31BCE8E187}, Product version: 8.0.50727.42, Upgrade code: {08807905-177B-4964-B651-1E3E7A421ED0}, Product language 0

MSI (s) (84:50) [09:36:07:303]: Note: 1: 2318 2: D:windowsInstaller3b8bda7.msp

Windows Installer error code 2318 reads “File does not exist: [2].”, and denotes where Windows Installer is caching the .msp file. Then from the second patch:

MSI (c) (8C:38) [09:38:05:930]: Original patch ==> D:DOCUME~1USERLOCALS~1TempZNW7CVS80-KB919588-X86.msp
MSI (c) (8C:38) [09:38:05:930]: Patch we’re running from ==> D:DOCUME~1USERLOCALS~1Temp3bce44c.msp
MSI (c) (8C:38) [09:38:05:930]: Opening existing patch ‘D:windowsInstaller3b8bda7.msp’.
MSI (c) (8C:38) [09:38:05:940]: SequencePatches starts. Product code: {A49F249F-0C91-497F-86DF-B2585E8E76B7}, Product version: 8.0.50727.42, Upgrade code: {86C9D5AA-F00C-4921-B3F2-C60AF92E2844}, Product language 0

The reason the second patch would fail with ERROR_PATCH_TARGET_NOT_FOUND (1642) is because, since the patch code was the same as the IA64 patch already installed, the existing IA64 patch was opened and doesn’t target the same product code. Our database will instead need to generate and track package codes in the relationship between releases and target architectures, since we do need to track patch codes.

So, consider how your target products can be installed into different platform scenarios. If you don’t need to support obsolescence – i.e., you can use patch supersedence introduced in Windows Installer 3.0 – or need to track package codes for any other reason, you can just generate new package codes with every release. WIX, for example, supports this in the Package/@Id attribute using “????????-????-????-????-????????????” or “PUT-GUID-HERE” for the attribute value. Its simply safer to use unique package codes for every package you ship.

Heath Stewart

Senior Software Engineer

Follow Heath   

No Comment.