Creating an auto-update framework with WiX
The WiX utility does it job at letting you create Microsoft Installer packages (known as_.msi_ files), but it involves it own set of weird peculiarities.
For my uISV, I have designed a minimal auto-update framework for WinForm applications. The spec was the following: the user can click on Check for update, and will optionally be notified if a new version is available. In such event, the user is proposed to upgrade toward the new version. Three clicks total, not bad (counting one click for the UAC notification under Vista).
First, let me introduce a word about minor revisions and major revisions as defined by the Microsoft Installer.
- A minor revision is a revision that simply upgrade in place the very piece of software.
- A major revision installs another software version, side-by-side with the old version.
For a simple upgrade framework, we will obviously stick with minor revisions
So far, all this well and this framework should be completely straightforward to do, yet some MSI absurd behavior is making the design much more difficult than it seems.
First, the MSI installer is taking into account the account the MSI file name. Any upgrade attempt with different MSI file name will be considered as a major upgrade. Apparently, this behavior based on some lame and deprecated considerations related to CD-ROM installations.
Thus, when your auto-update framework download the latest MSI package, it must be first be renamed to match the name of the MSI package at install-time. Yet, web browser just happens to frequently renamed downloaded files. For example, when people just download twice the very same file, your MSI package Setup.msi
is renamed Setup[1].msi
. Not even considering the situation where the users willingly rename the MSI file (why shouldn’t they be permitted to do that?).
So you need to get the MSI name out of the Windows registry to figure out what was the file name at installation time. Well, it happens that this information can be found at
HKEY_CURRENT_USER\Software\Microsoft\Installer\Products\PRODUCT-CODE\SourceList\PackageName
where PRODUCT-CODE
is a token associated to your product.
One could have thought that it would have been natural to use the ProductId
as defined in the MSI package (and your WiX project file) as PRODUCT-CODE
, but some developers rightly send from hell, decided that it wasn’t fun enough.
So, they settled for an arithmetic permutation of the ProductId
. That’s right, you can actually infer the PRODUCT-CODE
by applying a not-too-simple permutation scheme on your original ProductId
. For those would do not wish to loose as much time as I did on this matter, here is a PowerShell function to produce the conversion:
# Get-MsiGuid
# By Joannes Vermorel, 2008
# Convert PackageId GUID (as provided in WiX) into ProductCode GUID (as used by MSI).
# Usage: Get-MsiGuid 'FOO-GUID-1234'
function Get-MsiGuid
{
param(
[string] $guidToken = $(throw "Missing: provide the GUID token to be converted.")
)
begin
{
}
process
{
$origGuid = new-object System.Guid $guidToken
$raw = $origGuid.ToString('N')
$aRaw = $raw.ToCharArray()
# compressed format reverses 11 byte sequences of the original guid
$revs = 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2
$pos = 0
for( $i = 0; $i -lt $revs.Length; $i++)
{
[System.Array]::Reverse($aRaw, $pos, $revs[$i])
$pos += $revs[$i]
}
# Passing the char array as a single argument
$n = new-object System.String (,$aRaw)
$newGuid = new-object System.Guid $n
# GUID in registry are all caps, ouput formats are N, D, B, P
write-output( $newGuid.ToString('N').ToUpper())
}
end
{
}
}
As a final note, the small auto-update framework is available as open source as part of Lokad Safety Stock Calculator on Sourceforge. The update information is directly grabbed from a PAD file (Portable Application Description).
Reader Comments (2)
- Wow, WiX certainly looks like an acronym for “Wicked Xcopy”.
- “HKEY_CURRENT_USER\So…” breaks the line and goes beyond the column.
August 19, 2008 | Rinat Abdullin