
Good day to all! I would like to share with all my experience of creating a system for generating patches (may the reader forgive me for using this word). There was a lot written about wix
here and I assume that the reader is a little familiar with it, but somehow they have bypassed the problem of creating patches. In our company, they are widely used, mainly because of its size, and also because of the possibility of rollback.
To begin, I will describe the task that I encountered, then I will describe the basic information for creating patches. I will also do the 2nd part with a specific example, utilities to simplify this process and source codes.
Task:
1. There is a highly specialized
desktop product that is installed in many subjects of the Russian Federation to many branches of the authority related to forestry. Let's name this conditional product for convenience, let's say Ash.
2. For each subject, their own installation version is assembled, which do not differ in binary, but content differs in files that do not change (maps, report templates, basic database, etc.).
3. In the “hot” season, updates are released every 1-2 weeks (everyone suddenly needs something and often something new). The product version changes (either
major ,
minor or
build )
4. At any time, any client can ask for both the update and the full version. It is necessary to get out of the situation with minimal costs.
5.
ClickOnce is not suitable, as some government agencies, oddly enough, do not have direct access to the Internet, or it is very bad.
6. Do everything on
Wix , since it is free.
Under these conditions (point 4!), In order to save traffic and not send 100 MB of full version each time it’s better to make patches.
')
There are a couple of whims of developers:
1. And you also want freedom in passing patches, that is, you can, for example, be updated after 1 or 2 updates.
2. On the scheme of possible updates, this whim looks like this:

That is, all variants of the sequence are allowed:
• Consistently get all the patches, then get the full msi (solid line).
• Skip 2 patches, put the 3rd, and then I understand msi (dotted).
• Put 1 patch, 1 skip, next put and get the full version of msi.
• etc.
Let's start from the beginning.
Understand the versions and patches
As is known, the version in
Wix consists (= takes into account) of 3 numbers: xyz, x -
Major version , y -
Minor version , z -
Build number . The principle of changing these values, in my opinion, is determined by the company, and there is no explicit rule, only
recommendations .
At the same time, there are 3 types of updates:
- Major update (more correctly - Major upgrade, but for unity, let's leave the major update):
Major update is a comprehensive product update that affects the structure of the installed features, changes the composition and name of the components, etc. Major update removes the previous version of the application and installs a new one. - Minor update (more correct - Minor upgrade, but for unity, let's leave the minor update):
Minor update affects many installation resources, but none of them require a change to the ProductCode (more on that below). Minor update can add new features or components, but cannot reorganize the feature tree and components, that is, cannot remove features and components and move components from one feature to another. - Small update :
Small update is a small update that usually affects several files, changing their contents.
"Base" for updates in Wix
The implementation of the listed update options in Wix is ​​based on 2 variables:
1. The
UpgradeCode attribute of the
Product element.
2. The
ProductCode attribute of the Product element.
About Package.Id we do not speak, as it changes
almost always. Details on when to change
UpgradeCode and
ProductCode are written
here and
here .
In short it is like this:
- UpgradeCode product of one generation usually does not change. Once the system has been completely rewritten, for example, the applied technologies are changed, for example, then UpgradeCode is changed, cutting off all previously made service packs.
- ProductCode changes if the name of the msi package is changed, Components are removed or changed. If the new version just changed already existing files or added a new Component, then the ProductCode is not changed.
Example
Suppose there is an already installed application version 1.0, we are creating the next version of the installation. We can change the
UpgradeCode and
ProductCode in it to a new value relative to the previous version.
Let's see what happens if we change \ leave the old values ​​of these attributes. Our success in trying to (1) create a package and (2) install it is reflected in the table below:

We get: * -
minor update , ** -
major update , *** -
small updateThe general approach of creating a patch
The procedure of creating a patch in general looks very simple: there is one or several “basic” assemblies and one “final” one. The patch generation utility creates a package that can update the product from versions that are contained in the “base” builds to the version that is contained in the “final” one.
As is known, Wix supports 2 technologies for creating patches: using
PatchWiz.dll and
Wix itself. I will not go deep into the analysis of all the advantages and disadvantages of these options. This is not the purpose of the article. Let me just say that as a result of our experiments, we stopped at the first option (because only on it could we get a result that satisfies us).
Creating a patch on Wix using PatchWiz.dll
To create a patch using
PatchWiz (we will use the utility
msimsp.exe ) you need at least 2 installation packages (or more precisely 2 msi files) and a patch handle (usually the file is called
Patch.wxs ). I will not describe in detail all the possibilities that they have provided, otherwise the article will turn out too big, but I will touch on the main points. (Details can be found
here )
1. First, create
Patch.wxs , and in it the element
PatchCreation .
<PatchCreation Id="{42D7EE3B-A712-4AD4-9B23-A8710FC486FA}" Codepage="1251" CleanWorkingFolder="yes" OutputPath="patch.pcp" WholeFilesOnly="yes">
Here:
Id - a unique patch Id, always new.
Codepage is the code page for the intermediate (for us) file with the PCP extension.
CleanWorkingFolder - clear the temporary folder after creating the patch.
OutputPath - the path and name of the intermediate file.
WholeFilesOnly - in the patch we will include the changed files as a whole, and not just the changed blocks in them.
Inside the PatchCreation elements are recorded with information about the patch, here, I think, everything is clear (PatchMetadata is not a mandatory element).
<PatchInformation Description=" " Comments=" 1.1" Manufacturer=" "/> <PatchMetadata AllowRemoval="yes" Description=" " ManufacturerName=" " TargetProductName="" MoreInfoURL="http://./" Classification="Update" DisplayName=" 1.1"/>
And, perhaps, the main thing: we indicate the paths where the base assemblies and the final ones lie.
<Family DiskId="2" Name="Yasen" SequenceStart="5000"> <UpgradeImage SourceFile="C:\Work\Yasen\v1.1\Setup.msi" Id="NewPackage"> <TargetImage SourceFile="C:\Work\Yasen\v1.0.8\Setup.msi" Order="2" Id="BasePackage1"/> <TargetImage SourceFile="C:\Work\Yasen\v1.0\Setup.msi" Order="3" Id="BasePackage2"/> </UpgradeImage> </Family>
Here:
DiskId is the number of the new entry in the Media table, it should not be the same as the
Media Id of the basic installer.
Name - the name of the update line. I did not try to update one product with updates with different Family Names.
SequenceStart - the number to be written in the
InstallExecuteSequence table, must not be the same as existing records. In most of the examples I’ve seen, it costs 5000. This value does not conflict with the standard Wix values; in our package this value is also not used. (Details about this are in the articles about wix listed above)
Element
UpgradeImage - describes the final assembly.
SoureFile - the path to the final assembly (in fact, not entirely on it, but on its "unpacked" version, this is written below)
Id - build identifier.
The
TargetImage element describes those assemblies that can be updated by the current update.
SourceFile - the path to the base assembly.
Order - the order of the basic assemblies (I still do not understand why this is necessary).
Id - ID of the base assemblies.
And at the end of the PatchCreation, the PatchSequence element is
inserted. <PatchSequence PatchFamily= "Yasen" Sequence="1.1.0.0" Supersede="yes" ProductCode="{7381ABA7-774B-4D44-BD7B-0A90BBCF2B0A}" />
Here:
PatchFamily - indicates to which line this patch belongs (somewhere we have already seen this?)
Sequence - indicates the version of the patch to distinguish in which order the patches were released. Specified in xxxx format
Supersede - indicates whether this patch can cancel all previous patches (cumulative patch?)
ProductCode - product code (apparently, not to be mistaken).
Assembly and installation
After the installation and the patch descriptor are ready, do the following:
1. Perform an administrative installation of all installations in separate folders, for example, like this:
msiexec.exe /a 1.0\product.msi /qb TARGETDIR=C:\sample\1.0\admin msiexec.exe /a 1.1\product.msi /qb TARGETDIR=C:\sample\1.1\admin
Please note that the path to installations in PatchCreation should point to these "unpacked" versions, for example,
C: \ sample \ 1.0 \ admin \ product.msi2. Compile the Wix files:
candle.exe patch.wxs light.exe patch.wixobj -out patch.pcp
3. Use the utility from
PatchWiz :
msimsp.exe -s patch.pcp -p patch.msp -l patch.log
And we finally got what we wanted!
Total
We got the desired patch, but to solve the problem we need something more:
- I don't want to create a patch file every time.
- This system does not work very effectively when you need to allow patch skipping. The reason is that we indicate which versions can patch this package, if we want it to be able to patch 5 versions, then the volume can increase 5 times! If we specify only the previous version as installations for the patch, we save volume, but lose the opportunity to skip patches.
- It is necessary to automate this process in order not to spend a lot of time collecting patches.
Accordingly, to address these inconveniences, I will write the second part and describe everything I promised at the beginning of the post.
References:
Wix tutorial (very good manual)Wix - Creating patchesMSDN - Patching and Upgrades