Easy pure-WiX patching with Melt

“Pure WiX patching” is a godsend, if you’ve ever wrestled with the painfully useless errors common with MsiMsp.exe/PatchWiz.dll. However, pure WiX patching follows a different model than MsiMsp. One wrinkle a lot of people run into is that the loose files for the target and upgrade packages are expected to be available at the paths as written into the .wixpdb files you’re using to build the patches from. That works without additional effort only if the paths in the .wixpdbs differ between the builds and are available from the machine building the patch, such as if the build output is available in a versioned directory on a file server. Typically, the paths are instead local to a build machine and aren’t valid months later, even on the same build machine.

MsiMsp/PatchWiz requires the use of administrative installations, which are essentially an .msi package “unzipped” into a layout. On the plus side, it means you simply need the .msi package (and any external .cab files), which hopefully you kept a copy of, after shipping it to customers. One negative is that even though creating an admin installation just writes files to a directory, it requires elevated permissions, which is unpleasant in a build tool.

In WiX v3.6, I added functionality that lets you get the best of both worlds: Pure WiX patching without having to keep whole build trees around forever. All you need is the .msi package you shipped, the .wixpdb that goes with it, and Melt.exe.

Isn’t Melt for merge modules?

The Melt tool originally had one purpose: To decompile a merge module (.msm file) into the equivalent WiX authoring as a ComponentGroup. Melt lets you accept merge modules if they’re the only way you can get some bit of setup but build them as normal WiX fragments instead of forcing WiX to use the black box of mergemod.dll from Windows.

During the WiX v3.6 development cycle, I was working on patching and ran into the problem I talked about a couple paragraphs ago: Even though I had access to the full build tree, the .wixpdbs contained paths that were local to the original machine that built the product .msi packages, not the tree copied to the drop server.

It turns out that these two problems are very similar, at least in implementing a solution. In addition to Melt.exe supporting an input of a merge module and an output of a WiX source file, I added a new mode: inputs of the .msi and its matching .wixpdb files and as output, the directory where the .msi contents are extracted and a new .wixpdb that’s a copy of the input .wixpdb updated to point to the extracted .msi contents.

Here’s a typical command line:

Melt.exe ProductV1.msi -out %INTERMEDIATE_DIRECTORY%\ProductV1corrected.wixpdb -pdb ProductV1.wixpdb -x %INTERMEDIATE_DIRECTORY%\ProductV1bits

Repeat for ProductV2.msi and pass ProductV1corrected.wixpdb and ProductV2corrected.wixpdb to Torch.exe on its way to Pyro.exe.

Melt.exe doesn’t require elevated permissions. The only extra thing you need is the .wixpdb created by Light.exe when the original .msi package was built.