I am Joannes Vermorel, founder at Lokad. I am also an engineer from the Corps des Mines who initially graduated from the ENS.

I have been passionate about computer science, software matters and data mining for almost two decades. (RSS - ATOM)


Entries in wix (2)


Creating an auto-update framework with WiX

The WiX 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 (this code is based on this thread):

# 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

[string] $guidToken = $(throw "Missing: provide the GUID token to be converted.")


$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())



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).


Improved "Run external program" through environment variables

Dynacom is a Canadian accounting software that provides an add-on development framework named Synergy. We have started to work on an integration of the Lokad Desktop Sales Forecasting with Dynacom. This post might interest developers who want to integrate together several windows applications (we are considering Dynacom here, but the process would be quite similar for another application).

Basically, Dynacom provides build-in custom action Run external program; yet, this action has a huge drawback: it requires either your application to be part of the PATH on the client machine or it requires to provide an absolute file location (which is likely to vary from one machine to another). A lazy approach would consist in letting the user manually enter the application path; but this approach is likely to be a huge pain for the average user who may not be familiar with the location and the content of the Program Files directory.

Thus I have decided to create a Windows Environment Variable dedicated to Lokad Desktop Sales Forecasting. In the Windows Installer XML packaging script, I have added the following lines

<Environment Id="LokadDesktopPathVariable"

to get a new LOKAD_DESKTOP_PATH environment variable to be created at install-time (see Sourceforge for the full WiX script). Note that [INSTALLLOCATION] is a variable name; it might be different in your WiX script.

Then, in Dynacom, we retrieve the content of the LOKAD_DESKTOP_PATH environment variable though an Execute script action. The following VB-Script code illustrates how it is done.

Sub Main()
Set wshShell = CreateObject("WScript.Shell")
lokadPath = wshShell.ExpandEnvironmentStrings("%LOKAD_DESKTOP_PATH%")
lokadPath = lokadPath & "Lokad.Windows.SalesForecasting.exe"

' HACK: triple-quotes are actually needed to support path with spaces.
wshShell.Run """" & lokadPath & """"
End Sub

At the end, the Dynacom user will get an integration that is both straightforward and robust.