Patch creation fails (does not spot any differences) on build server - wix

I have a automated Setup creation on our build server, and try to create a patch between the released version and the current build version.
Sadly i can't get it working.
This is my Patch.wxs:
<Patch AllowRemoval="no" Manufacturer="Company" DisplayName="Product Patch" Description="Patch" Classification="Update">
<Media Id="5000" Cabinet="RTM.cab">
<PatchBaseline Id="RTM"/>
</Media>
<PatchFamily Id="SampleFamily" Version="1.0.0.0" Supersede="yes">
<FeatureRef Id="ProductFeature"/>
</PatchFamily>
</Patch>
i use a postBuild to compile&link the patchfile:
"C:\Program Files (x86)\WiX Toolset v3.8\bin\candle.exe" $(ProjectDir)Patch.wxs -dDebug -dOutDir=$(TargetDir) -o Patch.wixobj
"C:\Program Files (x86)\WiX Toolset v3.8\bin\light.exe" $(TargetDir)Patch.wixobj -o $(TargetDir)Patch.wixmsp
Until here everything works fine i guess.
I create a transform using torch after a sucessfull build:
torch -p -xi release.wixpdb latestBuild.wixpdb -out diff.wixmst
The diff is created successfully.
Then pyro gives me an warning that no files are different:
pyro Patch.wixmsp -t RTM diff.wixmst -out patch.msp"
warning PYRO1079 : The cabinet 'RTM.cab' does not contain any files. If this patch contains no files, this warning can likely be safely ignored. Otherwise, try passing -p to torch.exe when first building the transforms, or add a ComponentRef to your PatchFamily authoring to pull changed files into the cabinet.
The files are different if i install the msi files i get two different installations. but if i install the patch nothing changes. I played around with the PatchFamily but i can't get it working.
How can i get the Patch file including my changes?

The wix tools is seen to be failing to recognize file content change. To work properly do exactly as described in the WIX tutorial.
Here take special care to add version part in the source of the components, i.e 1.0 take component files from 1.0 source and say 2.0 takes source files from 2.0 root folder. This way file it is creating the patch as expected.

I found out what is causing this problem.
The Build server does not create a separate folder for each Build (just for the Drop, not for the Build itself) so at the time i create a patch both wixpdb files reference the same files of the build folder, thats why there are no differences found. I now changed the buildserver to create a administrative installation inside the drop folder and create a transform using the final msi files.
using the so created transform for pyro creates the msp as expected containing the changed files.

Related

How can I use bindpaths to create a WiX Patch?

I'm using cmake/cpack to build my project with WiX.
cmake runs heat.exe (or something similar) which produces files.wxs that contains the files of my project in the following format:
We'll assume a single file named a.txt inside a folder named "bin". The project is built in NewFolder on the Desktop.
<DirectoryRef Id="CM_DP_bin">
<Component Id="CM_CP_bin.a.txt" Guid="*">
<File Id="CM_FP_bin.a.txt" Source="C:/Users/mindlessbot/Desktop/NewFolder/_CPack_Packages/WIX/packageName/bin/a.txt" KeyPath="yes"/>
</Component>
</DirectoryRef>
After the MSI is created, the whole NewFolder is moved in a different directory (on our server). As a result, when I try to create a WiX Patch using the output .wixpdb, I get the following error:
error PYRO0103 : The system cannot find the file 'C:/Users/mindlessbot/Desktop/NewFolder/_CPack_Packages/WIX/packageName/bin/a.txt'
After some googling, I found out that the .wixpdb contains references to the files, which have changed location, so of course it can't find them. I found a thread where someone provided the commands to use bindpaths, however since I'm using cpack I can't directly call them.
So how should I got about doing this?
Some additional info:
My project contains multiple wxs files (not sure if it makes any difference)
The cpack command is:
path/to/cpack.exe -G WIX --config path/to/config.cmake
The patch command is run separately:
torch.exe -p -xi path/to/oldInstaller.wixpdb path/to/newInstaller.wixpdb -out path/to/patch.wixmst
candle.exe path/to/patch.wxs -out path/to/patch.wixobj
light.exe path/to/patch.wixobj -out path/to/patch/wixmsp
pyro.exe path/to/patch.wixmsp -out path/to/patch.msp -t PatchBaselineID path/to/patch/wixmst
In the event that you would like to build your MSIs on one machine, but build the patch on another, I recommend using the .wixout approach rather than relying on the .wixpdb approach. A .wixout file may be generated by the same WiX Toolset CLI tool that is used to build the MSIs, light.exe. The .wixout
Full documentation on the WiX Toolset linker, light.exe, may be found here. The following is an example use of light.exe to build a .wixout file:
"C:\Program Files (x86)\WiX Toolset v3.11\bin\light.exe" "/path/to/Some.wixobj" "/path/to/Another.wixobj" "/path/to/AndYetAnother.wixlib" -bf -xo -out "/path/to/MyInstaller_v1.wixout"
So now let's breakdown what these command line parameters are for:
"/path/to/Some.wixobj" "/path/to/Another.wixobj" "/path/to/AndYetAnother.wixlib" - These are the compiled outputs of WiX source files, they may be either .wixobj files (generated through candle.exe) or .wixlib files (generated through lit.exe, a way of consolidating .wixobj files into one, shareable library).
-bf - This switch causes all of the files to be bound int the resulting .wixout file. This is what removes the need to have the exact folder structure on the target machine when building patches, because the files are carried with the .wixout file.
-xo - This switch tells the linker to output an XML representation of the MSI, instead of the actual MSI. This is required to use the -bf switch.
-out "/path/to/MyInstaller_v1.wixout" - This tells the linker where to output the .wixout file.
Once you have the capability of generating .wixout files, the torch.exe command can be modified to run based on .wixout files instead of .wixpdb files and their associated folder structures. The following is how I would modify your torch.exe command to use .wixout files as opposed to .wixpdb files:
torch.exe -p -xi "path/to/oldInstaller.wixout" "path/to/newInstaller.wixout" -out "path/to/patch.wixmst"
So, all in all I really like this approach, and generally I make my build process produce both an .msi and a .wixout file. This allows us to cache various builds/versions of our installer as .wixout files, and then the process of creating a patch between various versions of the .wixout files becomes relatively easy.

Attempting to remove compression from an MSI causes its files to disappear

I'm trying to build an MSP patch for a program that's currently deployed using an MSI package. I've been able to successfully generate a PCP file using the following (slightly-redacted) WiX code, based on an example from the WiX documentation.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<PatchCreation
Id="D25F1136-2BEE-4A82-9236-7261067D4BDC"
CleanWorkingFolder="yes"
OutputPath="XYZ.pcp"
WholeFilesOnly="yes"
>
<PatchInformation />
<PatchMetadata
AllowRemoval="no"
Classification="Major Upgrade"
Description="XYZ Update"
DisplayName="XYZ Update"
ManufacturerName="XYZ"
MoreInfoURL="http://www.contoso.com/qr/XYZ.html"
TargetProductName="$(var.ProductName)"
/>
<Family Name="PrsnPtch">
<UpgradeImage Id="LatestImage" SourceFile="new_msi_dir\XYZ.msi">
<TargetImage Id="OldImage" Order="1" SourceFile="old_msi_dir\XYZ.msi" />
</UpgradeImage>
</Family>
<PatchSequence PatchFamily="XyzPatch" Supersede="yes" />
</PatchCreation>
</Wix>
and a build script set up to call msimsp.exe.
msimsp -s "%PCPDIR%\XYZ.pcp" -p "%PCPDIR%\XYZ.msp" -l "%PCPDIR%\patch.log"
Unfortunately, the above command fails with the following error message:
ERROR: UpgradedImages.MsiPath '[...]\XYZ.msi' is marked as having
compressed files (PID_WORDCOUNT property of Summary Information
stream). PatchWiz is unable to patch files compressed in a cabinet.
So I tried building an uncompressed version of the MSI by adding a CompressionLevel attribute to the MediaTemplate element in its WXS file.
<MediaTemplate EmbedCab="yes" CompressionLevel="none" />
For building the MSI itself, this is a success. The resulting file is 3.7 times the size of the uncompressed original, and 7-Zip shows the files therein as having a compression method of “None”. And I am able to successfully install the program on a VM.
The problem is that then I still get the “PatchWiz is unable to patch files compressed in a cabinet” error when running msimsp.
The culprit seems to be the Compressed attribute on the WXS Package element:
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Description="XYZ Installer"/>
So naturally, I tried changing Compressed="yes" to Compressed="no" (with no other changes to this WXS file). And this “works” as far as allowing msimsp to not give any errors.
But it introduces the serious problem that the MSI file is “empty”, its size having been reduced from about 3.6 MB to a mere 280 KB. Viewing the archive in 7-Zip shows that it does not contain any of the files that it's supposed to install. Viewing it in Orca shows a Media table with one row containing the values DiskId=1 and LastSequence=19, but nothing in the Cabinet column (the original MSI had an auto-generated “#cab1.cab” here).
Why would changing the Compression attribute make the CAB file go missing? How do I fix it?
This patch creation process does not work by using MSI files with embedded cabs or external cabs. It uses administrative images that you create using msiexec /a ..... This creates an MSI file together with all the external loose files in their appropriate directories. The patch creation process uses two of these admin images to generate the patch, the msp file, and it compares each corresponding file in each image to create the delta between the two products.
An administrative install is not an "install" - it's mainly just file extraction from the MSI into loose files in directories. This also marks the resultant MSI file as having "no files" in it - it's just the tables - so the patch creation process will complain if it finds this or anything indicating the files are in a cab. It needs separate loose files.
Once you have two administrative images the patch creation process (using a PCP file) runs against the two images comparing each file for changes and generating an actual patch, an msp file.
(Note that there is an IgnoreMissingSrcFiles setting in the PCP TargetImages table that allows missing files to be ignored while the patch is being created - it would make no sense to have this setting if the patch creation process used CAB files because all the files would always be there. )

Heat harvest Payload for ExePackage

I have a Compressed file (Self-extracting) that was included as a ExePackage for the current BootStrapper project I'm working on.
I was asked to Unzip the package before including it in the BootStrapper, so that the end user doesn't have to unzip the file before starting the install process of that package.
Excluding the install application, there is two folders (win32 && win64) that contain 288 files each, I need to create a PayloadGroup out of these files. I started doing this by hand, but after looking at Heat element, I saw that Heat can generate Payloadgroup.
How can I harvest from the directories the Payloadgroup that is required for this package.
Doing this manually is a very long process ...
If using Visual Studio you're supposed to be able to go in your setup project's references and click on the reference in question and set Harvest to true.
If I recall this had some issues, and some online sources said it wasn't working for them, I'm not sure at the moment. Which is why I called heat from the command line in a post-build event. Something like this:
call "$(WIX)bin\heat.exe" dir "$(TargetDir)." -var var.$(ProjectName).TargetDir -dr INSTALLFOLDER -cg Binaries -gg -g1 -ag -scom -sreg -sfrag -srd -o "$(SolutionDir)Setup$(ProjectName)\$(ProjectName).Binaries.wxs"
You can even specify an XSLT transform that filters your generated wxs file. For more info check this helpful blog post
I implemented heat.exe dir -generate payloadgroup in v4.0 (https://github.com/wixtoolset/issues/issues/3470). In v3.x, the -generate option was only supported by project harvesting (heat.exe project ...).

Windows Installer XML relative Path for Patch

I'm using the Microsoft Team Foundation Server to manage and Deploy Setups for my Applications.
My Setups are WiX-Setups with relative Paths.
p.e.
Components
<Component Id="Anwendung.exe" Directory="INSTALLLOCATION" Guid="*">
<File Id="Anwendung.exe" KeyPath="yes" Source="$(var.SourceFiles)\Anwendung.exe" />
</Component>
Variables.wxi:
<Include>
<?define SourceFiles = "..\OutputFiles"?>
</Include>
Setups are building correctly.
The Problem: I'm using Torch and Pyro to generate Patches for my applications.
I'm using a pure Wix Patch Project with manipulated build events and additional linker information
(Pre Build - Torch)
(Post Build - Pyro)
(Linker additional Parameters - output as wixmsp)
When I build my Patch, I'm getting 579Failures.
(1x)
Error 776 The command ""C:\Program Files (x86)\WiX Toolset v3.8\bin\pyro.exe" Patch.wixmsp -out Patch.msp -t AnwendungBaseline diff.wixmst" exited with code 103.
C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\wix2010.targets
and (578x)
Error 322 The system cannot find the file '..\SourceFiles\Anwendung.exe'. C:\Patch\Client\Upgrade\Setup\ComponentMain.wxs
I'm sure it's not resolving the paths from the sourcesetups correctly.
Could anybody help me? Rob Arnson , Rob Mensching, Heath Steward? Please :)
To get around issues like this, you can write a custom build activity for TFS to update variables in your WiX config file with fully qualified paths. For instance, you can create a build activity that takes in the path to a config file, the name of a variable, and value for that variable, and then write the new value to the config file. You can keep the config file with relative paths checked into source control, but then the build will update the config file to use the fully qualified path just for the build.
If you are unfamiliar with creating custom build activities, there is a great blog series on it here. The link is for TFS 2010 but the process is similar for TFS 2012.

Wix 3.6 Burn: unmanaged custom UI

I want to package multiple MSIs into a single install package, hence I am using Burn from Wix3.6.
I want to have a simple user interface allowing to select which package(s) should be installed.
I understand the standard BA (wixstdba.dll) does not provide this functionnality and that I need to write my own BA.
I have been looking at project 'wixstdba' from the 'wix36-sources' package as an example of a C++ BA. To get started I have tried simply rebuilding the project and adding the resulting DLL to my Bundle as follows:
<Bundle
Name="$(var.ProductName)"
Version="$(var.ProductVersion)"
Manufacturer="$(var.VendorName)"
UpgradeCode="$(var.UpgradeCode)" >
<BootstrapperApplication SourceFile="wixstdba.dll" />
<Chain>
...
I succesfully built the Bundle:
light -ext WixBalExtension.dll -ext WixUIExtension -ext WixUtilExtension installer-v$(VERSION).wixobj -o installer-v$(VERSION).exe
candle -o installer-v$(VERSION).wixobj bundle.wxs -d"Platform=x64"
However, when I run the resulting .exe, nothing happens. No UI appears, no software is installed and no error message.
Any idea what I might be doing wrong?
When you run the .exe, it should create a log file in your system's %TEMP% folder. This should tell you if any errors are being encountered. The file name will be the product name (with spaces replaced with underscores). The easiest way to find it is to open a Windows Explorer window, type "%TEMP%" for the folder name, and sort by Date Modified desc. The top file is likely the right one.
It is likely that the bootstrapper is running, but when it attempts to load your code it is unable to load some dependency, or otherwise has some error. Hopefully, the log will provide enough hints for you to find the issue.
If you end up needing to add additional libraries/files to be used by your BA, add them to the bundle payload files, like this:
<BootstrapperApplicationRef SourceFile="wixstdba.dll" >
<Payload SourceFile="$(var.ReferencedProject.TargetDir)\file.needed.at.runtime" />
</BootstrapperApplicationRef>
This will place the file in the same folder as your unpacked BA at runtime.