Introduction
I found myself wondering how to create patches for my application. I looked at several third-party tools like Wise and InstallShield and some freeware installers and found that they were all overkill for what I needed. My distribution needs were simple, but my projects were large. I clearly needed a way to easily create patches.
The VS.NET deployment project is very easy to use, much easier than working with the Windows Installer SDK directly. This ease of use comes at a cost; VS.NET deployment projects eliminate many of the features and flexibility of the SDK in order to simplify the build process.
After reviewing the Windows Platform SDK documentation and several examples on MSDN I came up with this automatic build process for creating a MSP patch file.
Using the code
This procedure creates patch.msp files which contain the differences between the VS.NET deployment project current Release and Debug installers and the original installers you will place in a TargetImages folder. It requires that the VS.NET deployment project build properties be set to Package files=In setup file.
- Install the Microsoft Platform SDK.
- Install Orca.Msi located at C:\Program Files\Microsoft Platform SDK\Bin\.
- Copy TEMPLATE.PCP located at C:\Program Files\Microsoft Platform SDK\Samples\SysMgmt\Msi\Patching\ to your deployment project folder and rename it to patch.pcp.
- Double click the patch.pcp file to open it in ORCA.
- Add a record to the ImageFamilies table and set Family to fam1.
- Add a record to the PatchSequence table and set PatchFamily to fam1 and Sequence to 1.0.0.
- In the Properties table, select the value for PatchGUID and right click it. Select paste new GUID.
- In the Properties table, select the value for PatchOutputPath and set its value to Patch\patch.msp.
- Add a record to the Properties table and set its name to MinimumRequiredMsiVersion and its value to 200.
- Add a record to the TargetImages table and set these values: Target=target, MsiPath=TargetImage\setup.msi, Upgraded=upgrade, Order=1, IgnoreMissingSrcFiles=0.
- Add a record to the UpgradedImages table and set these values: Upgraded=upgrade, MsiPath=UpgradedImage\setup.msi, Family=fam1.
- Create a TargetImage\Release folder in your deployment project folder and copy the installer MSI of your first release install into it.
- Create a TargetImage\Debug folder in your deployment project folder and copy the installer MSI of your first debug install into it. If you do not create and distribute debug installs you can skip this step.
- Create a new patch.cmd file in your deployment project folder and add the following commands to it:
if "%1"=="" %0 Debug Release Done
@SETLOCAL
@set path=%path%;"C:\Program Files\Microsoft Platform
SDK\Samples\SysMgmt\Msi\Patching"
@set PatchTmp=C:\~VSTMP
:loop
if "%1"=="Done" goto end
if not exist %1\*.msi goto nopatch
if not exist TargetImage\%1\*.msi goto nopatch
:ok
rmdir /s /q %PatchTmp%
mkdir %PatchTmp%
mkdir %PatchTmp%\TargetImage
mkdir %PatchTmp%\UpgradedImage
mkdir %PatchTmp%\Patch
for %%a in (TargetImage\%1\*.msi) do copy %%a %PatchTmp%\setup.msi
msiexec /qb /a %PatchTmp%\setup.msi TARGETDIR=%PatchTmp%\TargetImage
/L*v %PatchTmp%\TargetImage\setup.log
del %PatchTmp%\setup.msi
for %%a in (%1\*.msi) do copy %%a %PatchTmp%\setup.msi
msiexec /qb /a %PatchTmp%\setup.msi TARGETDIR=%PatchTmp%\UpgradedImage
/L*v %PatchTmp%\UpgradedImage\setup.log
del %PatchTmp%\setup.msi
copy patch.pcp %PatchTmp%
set PatchDir=%CD%
chdir %PatchTmp%
msimsp -s patch.pcp -p Patch\patch.msp -l Patch\patch.log
-f %PatchTmp%\Tmp -d
rmdir /s /q %PatchTmp%\TargetImage
rmdir /s /q %PatchTmp%\UpgradedImage
rmdir /s /q %PatchTmp%\Tmp
chdir %PatchDir%
mkdir Patch
mkdir Patch\%1
copy %PatchTmp%\Patch\*.* Patch\%1\*.*
rmdir /s /q %PatchTmp%
:nopatch
shift
goto loop
:end
pause
- Edit your deployment project and change the version property. This is required so that the patch compiler (msimsp.exe ) sees a different version. Important: When it asks to update the
ProductCode
and PackageCode
, you must answer No. PackageCode
is a hidden property which VS.NET automatically updates each time you build the deployment project; but, ProductCode
must not be changed for the patch compiler to work. The patch compiler will refuse to create working patches of major upgrades and it determines this by the ProductCode
being changed, not by the Version
number. - Build your deployment project. If you use both Debug and Release configurations be sure to build both of them. The fact that the
UpgradeCode
and ProductCode
have not changed, and the hidden PackageCode
has changed will indicate to patch compiler that the updated version is a minor update instead of a major upgrade. - Run the patch.cmd batch program. This process can take several minutes to complete depending upon the size and complexity of your original deployment projects. The patch compiler will compare each file in both setup projects to determine which files have changed and either create a delta between the files, or include the whole file if there are too many changes. Be sure to check the patch.log files to see what files were included in your patch and to be sure everything compiled correctly with no errors.
Points of interest
If you use configurations with names other than Release and Debug, you will need to modify line 1 of the patch.cmd file to name the configurations you use, but make sure Done
is specified as the last word on that line so that the command will exit properly.
You can specify different locations for your msimsp.exe file and the temporary folder to use by editing the set
commands at the beginning of the batch program. Note that the PatchTmp
variable specifies a folder which will be totally created and totally deleted by this batch program, so don't specify a temp folder needed by Windows or any other program. I also recommend specifying a temporary location with as short a name as possible. I have had problems running msimsp in folders with very long full path names.
History
- August 20th, 2005 - Initial version.