How to correctly add new files in WiX installation to create an uninstallable patch? - wix

Good time,
I'm trying to create the uninstallable patch (msp file) which should contain the newly added files. The file is added in following maner:
<Directory Id="Some Dir">
<Directory Id="MYDIR" Name="Some Name">
<Component Id="Some Component" Guid="{GUID}" KeyPath="yes">
<File Id="README.txt" Name="README.txt" Source="to_install\README.txt" KeyPath="no"/>
<File Id="default.cfg" Name="default.cfg" Source="to_install\default.cfg" KeyPath="no"/>
... // some more files
</Component>
...
...
I've also tried using the DirectoryRef but got the same results.
The "MYDIR" directory is used in other places also and several other files are already installed there, but the patch is adding new files, and the installation log shows that the CreateDirectory table becomes modified and the uninstallation for patch becomes disabled.
What is a correct way to do it using WiX?

KeyPath :
This value points to a file or folder belonging to the component that the installer uses to detect the component.
It is creating entry in CreateFolder of MSI because of KeyPath is provide at component level that is taking installation folder as its key so your patch become not uninstallable.
Provide KeyPath at one of the file of component that is the most important for that component. So it does not make entry into CreatFolder table of MSI and your patch become uninstallable.

Whether a patch is uninstallable isn't really related to a piece of WiX source like that. One thing you definitely need for an uninstallable patch is a PatchMetadata table that says that the patch is uninstallable, as here:
http://wixtoolset.org/documentation/manual/v3/patching/patch_building.html
or here, see PatchMetadata table if you use a PCP file, AllowRemoval:
https://msdn.microsoft.com/en-us/library/aa370344(v=vs.85).aspx
So there are some things you need to do during patch creation to make the patch uninstallable that are nothing to do with your WiX source. It's not clear from your question how you are creating the patch correctly.
Even if you get the patch generation working, there are some rules that must be followed, described here:
https://msdn.microsoft.com/en-us/library/aa367850(v=vs.85).aspx
where it says (for example) that you can't change the component ids of any existing installed items. Create a verbose log when installing the patch and look for messages like SELMGR and entries saying removl of components is not supported, and if that has happened it means the patch will not apply correctly.

Related

Are install-time changes authored with XmlFile reversed during uninstallation?

Question
On the XmlFile element, does Permanent="yes" means it will not attempt to remove the changes applied by XmlFile during install? If this is not right, how can I copy an XML file to install folder during installation, apply changes to it, and then successfully remove that file during uninstall?
Background
I am creating an MSI file with WiX. I am using the XmlFile element to change an XML file after I install it. I am confused about whether changes made with XmlFile get backed out during uninstall, and how that relates to the XmlFile element's Permanent attribute.
I've seen conflicting answers to the question of whether changes made during install with XmlFile get backed out on uninstall. First, there is this SO answer by Stein Åsmul, which purports to quote WiX developer Bob Arnson (emphasis mine):
"You can do everything (and more) that XmlFile supports with XmlConfig but it requires extra authoring that's not necessary with XmlFile. XmlFile is best at modifying XML files that you're installing (e.g., to add an attribute reflecting the installed path of a file); it can't remove the modifications at uninstall time but if your setup installed the file, it will be uninstalled anyway. XmlConfig is best at modifying shared XML files because it supports uninstalling the modifications."
Unfortunately the source for that quote is a dead link, so I can't check to see if there are caveats, or what version of WiX Toolset it applies to.
This XML tutorial on FireGiant appears to contradict that quote (again, emphasis mine):
So, to carry out the modifications we planned, we need the following entries (note that we have to provide our own sequencing, this is important to ensure that the changes will be removed in the proper reverse order upon uninstallation):
The FireGiant tutorial goes on to show XML elements modified like this:
<Component Id='Settings' Guid='YOURGUID-574D-4A9A-A266-5B5EC2C022A4'>
<File Id='XmlSettings' Name='settings.xml' DiskId='1' Source='settings.xml' Vital='yes' />
<util:XmlFile Id='XmlSettings1' File='[INSTALLDIR]settings.xml'
Action='createElement' Name='add' ElementPath='//settings' Sequence='1' />
<util:XmlFile Id='XmlSettings2' File='[INSTALLDIR]settings.xml'
Action='setValue' Name='key' Value='a_key' ElementPath='//settings/add' Sequence='2' />
<util:XmlFile Id='XmlSettings3' File='[INSTALLDIR]settings.xml'
Action='setValue' Name='value' Value='a_value' ElementPath='//settings/add' Sequence='3' />
<util:XmlFile Id='XmlSettings4' File='[INSTALLDIR]settings.xml'
Action='setValue' Value='key_item' ElementPath='//settings/add' Sequence='4' />
<util:XmlFile Id='XmlSettings5' File='[INSTALLDIR]settings.xml'
Action='createElement' Name='inside' ElementPath='//settings/add' Sequence='5' />
<util:XmlFile Id='XmlSettings6' File='[INSTALLDIR]settings.xml'
Action='setValue' Value='inside_item' ElementPath='//settings/add/inside' Sequence='6' />
</Component>
I am using WiX Toolset version 3.11.2. I suspect the FireGiant tutorial is newer and thus more likely to be correct. The documentation for the XmlFile element doesn't discuss this one way or another. It does, however, seem to hint that an attribute named Permanent might come into play. Valid values for Permanent are yes or no, but the description of the attribute is not specific as to what the effect will be for each value. This is the complete description of the attribute Permanent:
Specifies whether or not the modification should be removed on uninstall. This has no effect on uninstall if the action was deleteValue.
I'm left guessing whether I am interpreting the meaning of the Permanent attribute correctly.
So here's my question: Does Permanent="yes" means it will not attempt to remove the changes applied during install? If this is not right, how can I copy an XML file to install folder during installation, apply changes to it, and then successfully remove that file during uninstall?
Notes
I am using WiX Toolset version 3.11.2.
The only change that XmlFile can "undo" is Action="createElement" -- because that just turns into deleting the specified element. The tutorial uses XmlFile elements that can be undone -- creating elements and setting values in them -- so it's accurate.
XmlConfig was created to allow arbitrary XML modifications to be made and unmade at uninstall.

INI disappear & NeverOverwrite="yes"

I have following problem : a new version disappears after upgrade, although I set NeverOverwrite='yes'. Could anyone help me about this issue?
<Feature Id="CompRef03" Title="CompRef" Level="1">
<Component Id="INIWindowsFolder" Directory="WindowsFolder" Guid="d09921c0-1192-458f-8a3e-88889f56a013" KeyPath="yes" NeverOverwrite="yes" Permanent="yes">
<File Id="test.INI" Source="test\intest.INI"/>
</Component>
</Feature>
Problem: Not sure exactly what has happened here. You don't set REINSTALLMODE=amus, do you? Maybe you have changed the component GUID from version 1 of your package? (component GUIDs must remain stable between versions for reference counting to work correctly). Or else the file could be uninstalled and reinstalled (should not happend when you set a file permanent, but maybe you forgot that in your first package).
IniFile Element: Ini files are actually not supposed to be installed as files, but as "change items" of INI value pairs. In other words you define what entries inside the file should be added, changed, removed, etc... In Wix you use the IniFile Element to achieve this. All merge capabilities, rollback support and advanced ini file handling come along for free. All you need to do is to define what needs to be added or modified in the ini file during your installation. It will also be created if it is not there in the first place. Please find more details in this answer. And here is one more link to IniFile Element usage.

WiX 3.8 keeping config file state during Major Upgrade

I'm using WiX 3.8 (the latest stable release, I think), and I can't seem to get a config file to not get uninstalled-and-reinstalled during a major upgrade.
There are lots of questions about this on SO -- a lot of answers point to this site as a good answer. However, the suggestion given doesn't work (for me).
What the site says is to place each config file in its own component and mark the file as the key path of the component. Something like this:
<Component Id="config.xml"
Guid="*"
Directory="folder_where_config_file_lives">
<File Id="config_file"
Source="$(var.Project.ProjectDir)bin\Release\configFile.xml"
KeyPath="yes"/>
</Component>
Great. Next it says to schedule RemoveExistingProduct after the InstallFiles action, like so:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallFiles"/>
</InstallExecuteSequence>
Problem is, when I compile, I get this error:
The InstallExecuteSequence table contains an action
'RemoveExistingProducts' that is declared in two different locations.
Please remove one of the actions or set the Overridable='yes'
attribute on one of their elements.
This person also had that problem, but he seems to have solved it. What fixed it for him was adding a scheduling attribute to the , which effectively got rid of the "two different locations" declaration problem (I guess):
<MajorUpgrade Schedule="afterInstallInitialize"
DowngradeErrorMessage="A newer version of [ProductName] is already installed."/>
So when I substitute the schedule change attribute (which contains a attribute itself, I guess), not only does it not work -- the config file gets removed and replaced during the upgrade -- it causes even more weirdness. My project has a bootstrapper with a lot of MSIs, and although I get log files for the installation of all of the MSIs that are after the MSI that contains the config file, they aren't installed.
Let me repeat that: the logs say that the MSIs are installed, but they aren't. There's probably a rollback somewhere that I can't find in the log files, but reading the MSI log files it looks like the installation went swimminly.
Does anyone know a way for a config file to not be removed-and-reinstalled during a Major Upgrade in Wix 3.8? What I've mentioned above is the best info from the interwebs that I could find, but I've tried pretty much everything on SO to no avail.
The MajorUpgrade element has everything you need, including where the RemoveExistingProducts action is scheduled. Don't add a RemoveExistingProducts into a sequence as well.
RemoveExistingProducts shouldn't be after InstallFiles. It's not clear where that comes from, but the documentation doesn't say that's a choice:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa371197(v=vs.85).aspx
When RemoveExistingProducts is sequenced early (such as after InstallInitialize or InstallValidate) it means that you are effectively uninstalling the old product followed by an install of the new product upgrade, and that means uninstalling the config file and installing the one in the upgrade. The way to retain the config file is to schedule REP afterInstallExecute. This results in an upgrade that is basically a version-rules install of the new product over the older installed one. The version rules mean that if you want updated binaries you must update their file versions. The good news about data files (your config file) is that updated data files won't be replaced:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370531(v=vs.85).aspx
The older product then gets uninstalled, retaining the resulting set of files.
So sequencing of REP afterInstallExecute in the MajorUpgrade seems to be what you want. A caveat is that you need to follow component rules, which should happen automatically if you have auto-generated * guids in WiX.
IMO, Windows Installer was invented before XML caught on and the component rules don't handle it well. What I prefer to do is to not fight this behavior. Write your application so that one config file is owned by the installer and can always be safely overwritten and another config file that holds your user configuration data and that MSI doesn't know about. This second file should take override the first file.

WIX, how to not replace config file

We have a MSI built with wix that installs our ruby based product. When we released the first version there was a bug. Upgrades would overwrite changes to a ruby config file (gemrc), effectively breaking the product in some cases.
I've been trying to get MSI to not remove or replace the config file on upgrades, without success.
What i have now is:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallExecuteAgain" />
</InstallExecuteSequence>
<Directory Id="embeddedDir" Name="embedded">
<Directory Id="embeddedEtcDir" Name="etc">
<Component Id="gemrcComponent" Guid="uuid..." NeverOverwrite='yes' Permanent='yes'>
<File Id='gemrc' Name='gemrc'
Source='$(var.ProjectSourceDir)\embedded\etc\gemrc.default' Vital='yes' KeyPath='yes' />
</Component>
</Directory>
</Directory>
However, going from the current version (1.0) to the new version (1.1) will leave the installation with no gemrc at all. Going forward it works, so going from 1.1 to 1.2 it leaves the existing (modified) file.
I'm assuming, that the reason it doesn't work is because it uses the old 1.0 MSI to remove the existing installation, and that version has the gemrc file marked as part of the product that needs to be removed.
This means the only way i could get around this is using custom actions (copy the file to a temp path before installation, and then move it back afterwards.
Or something similar). Is there a better/easier way?
Some of the reasons you may be seeing this are as follows, but there's not enough information to say which might apply in your cases:
If you originally had a major upgrade scheduled "early" (InstallInitialize or sooner) then the upgrade would completely uninstall the older product and then install the new one. This would look like an overwrite of the config file, but strictly speaking it's not. You do not say if you ever identified the actual root cause of this issue or if the major upgrade was scheduled differently.
In a major upgrade scheduled after InstallExecuteAgain, the upgrade installs on top of the old product and follows file replacement rules. So if the config file had really been updated after install it would not be replaced.
If the component id of the config file changed between any of the setups then you'd see it removed (even in an InstallExecuteAgain upgrade). File sharing is ref counted by component id, so if the upgrade has a component id for the config file that is not the same as the previous installs then you'd see strange behavior because the ref count of the previous file means it would be removed, but you're attempting to install another of the same name with different id.
You should do your upgrades with verbose MSI logging enabled to see what happens to the config file. If it's not clear from that, then post it somewhere accessible for others to look at.

Patch (minor upgrade) creation issues with MSM (merge modules)

I am facing issues with patches (minor upgrade) installation (updates) with MSM (merge modules).
I am creating MSI (test.msi) with texst.wxs. And inside text.wxs referring to app.msm file (there is a folder app, which contains so many folders and files. And harvesting this folder and making app.msm file)
Below are steps for making app.msm file.
heat dir "app" -gg -sfrag -template:module -srd -ke -var var.source -out app.wxs
candle -dsource=app app.wxs
light app.wixobj
Below is snippet of test.wxs file
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
....
....
<Directory Id='Config' Name='Config'>
<Component Id='APP_CLIENT' Guid='*'>
<Component Id='Manual' Guid='*'>
<File Id='Manual' Name='Manual.pdf' DiskId='1' Source='Resources/Manual.pdf'
KeyPath='yes'>
<Shortcut Id="startmenuManual" Directory="ProgramMenuDir"
Name="Instruction Manual" Advertise="yes" />
</File>
</Component>
</Directory>
<Directory Id='exmp_REPO' Name='!(loc.Merge_FolderTitle)'>
<Merge Id="LocalRepository" Language="1033" SourceFile="app.msm" DiskId="1"/>
<Component Id='exmp_REPOSITORY' Guid='*'>
<CreateFolder/>
<RemoveFolder Id='exmp_REPO' On='uninstall' />
</Component>
</Directory>
....
<Feature Id='Complete' Display='expand' Level='1' ConfigurableDirectory='MYAPPPATH'>
<ComponentRef Id='Manual'/>
<ComponentRef Id='App_CLIENT'/>
<ComponentRef Id='exmp_REPOSITORY'/>
...
...
I am able to make major upgrade with my test.wxs by using app.msm (merge module). But not able to make patch with successful installation. Patch install (update) is reflecting in version change in the "Programs and Features" and showing in "View Installed updates". The manual changes also are reflecting with patch update. But whatever the changes in "app" (which are created app.msm and referred in test.wxs) folder are not reflecting.
I have used 2 approaches for making patch, which are mentioend in below urls
1) http://wixtoolset.org/documentation/manual/v3/patching/patch_building.html
2) http://wixtoolset.org/documentation/manual/v3/patching/wix_patching.html
Please help in this regards.
First, I would advise to find out, whether the built patch contains the correct files or not. If not, you have a build problem, that the msm is not updated. If yes, you have most likely a problem with the content of the msm which may be not consistent with it's predecessor (especially GUIDs, table primary keys, etc.).
You can find out and see the content of the patch without installing with tools like Orca and Insted which you can search and download.
Second, using merge modules is highly complicating things, especially for patches, and of limited usefulness, if they are your own and you use them only once. Msms are primarily made for situations, where you need the .msm at least for 2 different MSI packages. I have seen a handfull of problems using merge modules in patches with other tools, BTW. I have no special experience here with WiX+patches+MSMs, but, it's as I said.
Last, but not least, you will have to choose, if you really want to keep this complexity in the future. As I remember, there are other possibilities in WiX to modularize / encapsulate parts of your software.
You can check the versions of files in merge modules and MSI files by opening them with Orca and looking in the File table. Or open the MSI file with Orca and then Transform=>View patch to see changes.
It may be obvious, but a binary versioned file will be replaced by a file with a higher file version. I mention because there is a belief out there that somehow "new" files replace "old" files, and that's wrong. Versions matter.
Generally you need to install a patch with an msiexec command that specifies REINSTALL=ALL REINSTALLMODE=omus. Double-clicking an MSP file will not necessarily just work unless you've arranged for it to do this internally with a custom action that sets them when PATCH is set.
The patch will not work if you break component rules. A common mistake is to remove a component during a patch, and that will result in an "advertised" update that doesn't actually update anything. In a verbose log look for SELMGR entries and text about removal of components is not supported. Setting the MSIENFORCEUPGRADECOMPONENTRULES property to 1 will fail the patch if you've done this.
If a file has no version whether it's overwritten depends on the replacement rules here, and there's some difference if the file is hashed or not:
https://msdn.microsoft.com/en-us/library/aa370531(v=vs.85).aspx
Also: how do you know the patch isn't working? If you have no file versions then you can't know if a file has been replaced unless you look very carefully. You cannot trust the dates because Windows changes timestamps when a file is installed. You really need to build binary files with file versions because everything like patches, hotfixes, service packs etc will use them to replace binary files. Otherwise for data files use file hashing.
I see several potential problems here, maybe even in addition to the other answers:
when you heat up files for your merge modules -gg autogenerates new component guids. This will not work with patches, since it'll basically add a bunch of new components (new guids each time!!). Also, you'll remove components this way, which is something you shouldn't do and which cannot be done easily, unless you still include the original merge module. And then you'll end up with path problems.
The tutorial for wix patching uses wixpdb files for diffing the original and the updated installer. With wixpdb files, merge modules will not be patched, irrespective of whether files changed in them or not. You will need to do administrative installations and then diff on the msi itself. You'll still have problem #1.
your wxs snippet is bad. At least the xml element is never correctly closed. Your Feature also has a MergeRef somewhere?
Some tips:
you can view what your patches do with a program called Orca. Open the original msi, then just drag your msp patch file on top of it.
rather don't use merge modules, they complicate things. You can also use heat to generate a fragment which you then simply include into your wix project.
use the wix patching approach (Patch element, not the PatchCreation element). It's easier, but you have the same control
don't autogenerate guids if you plan to update those autogenerated components with a patch. It won't be a problem with major upgrades :)
Just one important issue of a number of potential reasons while files are not updated correctly: You write, in your .msm is a high number of unversioned files, like .xml, etc.
Important rule:
EVERY unversioned file which is changed on the PC AFTER the first MSI install not by the MSI engine itself (e.g. you edited a config.xml file or so), will be normally NEVER updated by MSI again, not by patch and not by Major Upgrade. (With normally I mean, you have to take special actions, like uninstalling or especially specifying those files as socalled companion files).