Understanding GUIDS, updates, and patches with Windows-Installer - wix

I'm learning about Windows-Installer and Wix, and have a number of questions related to how it works:
If a component GUID changes, but the same files are in the component, what happens on a major upgrade? Do the files get replaced?
If a component is removed from a product, what happens to the associated files on a major upgrade? Do the original files get removed on an uninstall?
Am I correct in saying that a major upgrade will replace all files in all components, regardless of whether the assembly version of the file has changed, and that on small updates and minor upgrades, it only replaces a file if the GUID is the same, and the assembly version of the file has been incremented? What if the file doesn't have an assembly version, like an aspx page?
Suppose that a product was deployed on a machine without using an installer. If you then created an installer, with files of the same name in a component as what's in the installed directory, what happens to those files if you tried an installation? Are they replaced?
Am I correct in saying that if I used a tool like heat to create an xml file with all the files in a directory (like for a website), that you'd have to keep the GUIDs the same (manually or with a script), or you'd only be able to do major upgrades?

If a component GUID changes, but the
same files are in the component,
what happens on a major upgrade?
First, the question is whether the old component gets uninstalled. If you don't configure your upgrade to uninstall previous versions of your product, then the component will not be removed (although its files may be overwritten). See also answer to question 2.
Second, the question is whether the new component will be installed. A component is only installed if its keypath is missing. If the keypath is a versioned file, then a lower version also counts as "missing".
Finally, if the new component was marked for installation, and Windows Installer encounters a file with the same name as the one it is trying to install, the File Versioning Rules determine whether the file is replaced or not. For example, a file with a higher version will not be downgraded.
If a component is removed from a
product, what happens to the
associated files on a major upgrade?
Do the original files get removed on
an uninstall?
Unless you put the right entries in the Upgrade table and the InstallExecuteSequence that tells windows installer to remove the old product, the old components will be left alone. See this blog post by Alex Shevchuk for guidance on how to create an installer in wix that removes old versions.
Am I correct in saying that a major
upgrade will replace all files in all
components ...
No. It depends on whether the old component was removed first, whether the new component was installed depending on the keypath, and the file versioning rules.
Suppose that a product was deployed on
a machine without using an installer.
If you then created an installer, with
files of the same name in a component
as what's in the installed directory,
what happens to those files if you
tried an installation?
Again, it depends on whether the components get installed, depending on their keypath, and the file versioning rules.
Am I correct in saying that if I used
a tool like heat to create an xml file
with all the files in a directory
(like for a website), that you'd have
to keep the GUIDs the same (manually
or with a script), or you'd only be
able to do major upgrades?
Correct. The GUID is the identity of a component, so if you would change the GUID there would exist two components (in the old and new version of your product) that installed the same resources to the same target location. And that's a no-no according to MSDN: "Never create two components that install a resource under the same name and target location."

Learn the Component Rules. They're very easy to break and Windows Installer doesn't enforce them. However if you don't follow the rules, then weird strange voodoo happens.
Easy solution, stick with one file per component and use heat with compile time GUID generation (outputs with Guid="*" uses a stable algorithm, it's not random). Having heat generate GUIDs is random, but GUIDs generated by candle at compile time will be stable (based on filename + path hash or something from memory)
If windows installer finds a file already on disk during install, it will increment the reference count for that file assuming it's a "shared" file. Files are only removed from disk once the reference count returns to zero so if a file already existed, the count may never return to zero and you can get files left lying around even after uninstalling.

Related

WiX Setup: When do I need to change the GUID of a component?

I am creating a new version of an existing setup with WiX.
In the process, the version of an included third party product has been updated. It consists of several files (DLLs, Configs, exes), each of which is in its own component.
Do I need to change the GUIDs of all these components?
The new version of the third party product requires a newer VC redist package than the old version, so it is not backward compatible.
The names and destinations of the affected files are the same.
I have read
https://learn.microsoft.com/en-us/windows/win32/msi/changing-the-component-code?redirectedfrom=MSDN
Change my component GUID in wix?
but I am honestly even more confused now.
If it wasn't for the redist dependency change thing, I would have just put the new files in the places of the old ones and left the GUIDs the same.
But now?
The names and destinations of the affected files are the same.
Overall: This basically means that you should keep the same component GUIDs as before. The component GUID essentially identifies a target destination. If the target destination (the absolute path) changes you need a new component GUID.
File Name Change: Keep in mind that renaming a file changes the absolute path even if the path stays the same - hence you need a new component GUID for such file name changes.
Runtime: The incompatibility of the runtime should be irrelevant for the component GUID issue. What third party product is this? Perhaps it has its own installer? If it does it can potentially interfere with your installation in other ways (COM registration etc...).
Setup.exe Launcher: The standard procedure is to bundle runtimes in a setup.exe wrapping your MSI and all runtimes it requires. WiX offers the Burn framework to make such setup.exe launchers. Perhaps try my deployment info search grid for info on Burn. Also: Make yourself a single page PDF explaining your application's runtime requirements for corporate use and include it in your setup.exe so your setup is easy to deploy large scale.
The MSI File Itself: You can also add launch conditions to the MSI to identify that a required runtime is missing (so you can abort) - or you can use a custom action to inspect the system (I find this more flexible, but custom actions in general are complex. Use them read-only - for inspection only, and they are safer).
Links:
Will change in ComponentID for component in Windows Installer effect during upgrade scenerio.?

File of a new component isn't installed because there was an old component with the same file

We have a problem that a fie is not installed upon a major update
We have a major update with <MajorUpgrade Schedule="afterInstallInitialize"...
We an old component with 1 file (xyz.exe Version 12.34) from a external manufacturer
We have now a new file from a new manufacturer and with the same name (xyz.exe Version 2.34). The new file has a lower version number than the old one.
We created a new component in the install package and removed the old component (in fact we gave it a new guid)
Changing the name of the exe isn't possible, it would have to much influence upon documentation and internal functions.
On a normal installation everything is OK.
But what happens now on an update:
The installer starts.
And detects that the new component exists (xyz.exe) with a lower version, so it will not be installed.
the installer runs and removes the old component
But it doesn't install the new because it just detected that the component was already installed.
Doing a repair installation fixes the problem and the file is than again present.
Setting the KeyPath to the Component fixes the problem. But it seams wrong to me. The directory where this file is installed is the main installation directory.
How to force the installation of this component?
Similar Answer: How to Explicitly Remove dll During Majorupgrade Using Wix Toolset
Major Upgrade Downgrade: In order to overwrite binaries with higher version numbers on major upgrades there are a couple of preferred options:
The preferred approach would be to use a companion file (third party files).
Or if you can: compile a new binary with a higher version number (for your own files).
Companion Files: A snippet below on how to use companion files in WiX:
<..>
<Component Id="MyFile.exe" Feature="Main">
<File Id="MyFile.exe" Source="MyFile.exe"></File>
</Component>
<!-- Do not re-use any GUIDs in your own sources! (very important) -->
<Component Id="MyFile_2.exe" Guid="{00000000-0000-0000-0000-3D82EA2A99AF}" Feature="Main">
<File Source="MyFile_2.exe" CompanionFile="MyFile.exe"></File>
</Component>
<..>
One-Line Summary: In the second component we point to the first component's file so that MyFile_2.exe will install whenever MyFile.exe is installed - regardless of versioning issues.
Then there are a number of further options:
REINSTALLMODE: The MSI property REINSTALLMODE can be used - but it has a number of side-effects:
Setup 1: Version 1.0.0 for a setup:
msiexec.exe /i Setup1.msi /qn
Setup 2: Version 2.0.0 for the major upgrade setup:
msiexec.exe /i Setup2.msi REINSTALLMODE=amus /qn
Several Problems: There are several issues with REINSTALLMODE that makes it an unsafe feature to use (try emus instead? See documentation - a little less brute force maybe). It is a shame that this setting applies to all features in the setup - that makes it very dangerous:
can downgrade shared files system-wide - if there are merge modules included - for example (features in Windows are in place to prevent most of this problem: WFP and WRP in Vista an beyond - non-Microsoft merge modules can still cause problems for non-Microsoft shared files)
can cause inconsistent version estate since an old package can be installed after a newer one and downgrade only some of the shared files
can downgrade or wipe-out settings in non-versioned files and registry settings (note to self: test this again, there are complexities with component settings)
can cause a significant increase in the number of requested reboots due to attempts to needlessly replace in-use files of the same version (the real fix for this is to shut down services properly and to use the restart manager to allow applications to be shut down automatically during deployment - on file locks).
there are several further issues that are quite specific
Hack Binary Version: An ugly, but effective option is to change the version of the actual binary file using Visual Studio to set a higher version number (you open the binary as a resource and set a new version - this is obviously very different from compiling a new version of the binary using visual studio source code compilation). There are several side effects:
you break digital signatures
you can create "version confusion"
there are risks involved writing a new binary from Visual Studio
it is a "hack manual step" - you might need to keep doing this for new versions?
etc...
Move, Rename: If you can de-couple the new file from the old by renaming it or moving it you can work around the problem. If you get a new version again for the future, you might have to do this again. Clunky.
"Load From": Putting the file somewhere shared and load it from that specific location and removing the old copy from your installation folder. Could that work? This means the file could also be delivered by another setup at that location.
Version Lying: In Installshield there is a concept of being able to set a specific version number to a file. I am not sure how to implement that in WiX. There is also an "always overwrite option" that apparently sets a maximum value for the version so the existing file is always overwritten.
Some Links:
Why Windows Installer removes files during a major upgrade if they go backwards in version numbers
"Downgraded" MS dll disappears on upgrade - Windows Installer
Install a file regardless of version number with WiX
How to make better use of MSI files
The opposite side of it: file preservation and file overwrite rules.

WiX repair from managed bootstrapper fails to fix some corrupted DLLs

I have a WiX Managed Bootstrapper Application that installs some MSIs. I also have a series of tests that exercise the various functions of the installer. The problem I'm having is with the repair test. The test purposely corrupts all the DLLs we install then calls the EXE installer with "/repair /passive" flags. Once completed around 80% of the DLLs are repaired but the remaining ones are untouched and therefore still corrupted after the repair.
If I manually run msiexec on an individual MSI with the command line args "/fa" which instructs the MSI to forcibly replace all the files it installed, it fixes 100% of the DLLs.
My question is how can I force the MBA to instruct each MSI to repair in this way? I've tried setting the REINSTALLMODE property to 'amus' on the individual MSIs in their .wxs files but the MBA overwrites them at run time as is evident in the log via this line:
PROPERTY CHANGE: Modifying REINSTALLMODE property. Its current value is 'amus'. Its new value: 'cmuse'.
I've also tried to set the properties in the MBA to pass through to each MSI but it doesn't appear to pass them and instead uses it's default values.
I see many similar questions here but none actually address this specific issue. Any help would be greatly appreciated. Rob save me!
Here's your problem right here:
[12:25:25:874]: File: C:****\estimator.dll; Won't Overwrite; Won't patch; Existing file is unversioned but modified
The installer doesn't want to overwrite a file that has changed since it was installed if it cannot verify the version or language (and maybe some other properties?). Without these properties, it decides to look at the modified date. If it is newer than when it was first installed then it won't touch it assuming instead that something changed for a reason and reverting it will cause something to fail. (You can read more here)
One thing you can do in this case is use a Companion File
Set this attribute to make this file a companion child of another file. The installation state of a companion file depends not on its own file versioning information, but on the versioning of its companion parent. A file that is the key path for its component can not be a companion file (that means this attribute cannot be set if KeyPath="yes" for this file). The Version attribute cannot be set along with this attribute since companion files are not installed based on their own version.
Basically you will set the logic for installing/uninstalling this component to be the same as the "FileID" of another component in the install. In the estimator.dll component, in the File tag, remove KeyPath="yes" and instead replace that with CompanionFile="<NameOfAnotherFileID>".
The issue with this approach is that you may have a corrupted DLL but the companionFile it was linked to was fine so it is not reinstalled.
If this is a dll you do own, I would highly suggest versioning the file! Give it any version you want and this issue should go away.
Another thing you can try, although I don't know how it works really, is giving the file a DefaultVersion
This is the default version of this file. The linker will replace this value from the value in the file if the suppress files option is not used.
This would be the quickest solution to verify. Just build a new installer with DefaultVersion="1.0" in the estimator.dll's <File> and see if it gets replaced. I think this will have the installer think the file is versioned 1.0 but the installed file is not versioned so it will replace it (see here)

How does Wix decide to install a particular file?

As I put in title, the question is how does Wix decide to install a particular file?
So I have exe file and when I change something in exe file and rebuild it, it will not get reinstalled if I don't change version. But if I change something in resource file, resource file will be replaced even if I don't change version of my application. So how wix is deciding if he need to replace file during upgrade or not.
I am using wix3.9. MajorUpgrade is schedule afterInstallFinalize.
Versioned files get replaced based on file version, yes, but data files get replaced based on whether you have specified file hash or not. I think WiX generates file hases by default, so this is the overwrite rule:
https://msdn.microsoft.com/en-us/library/aa370532(v=vs.85).aspx
and it's a Windows Installer rule that applies to all MSI settup, not a WiX decision.
P.S. afterInstallFinalize isn't an ideal place. afterInstallExecute is safer, and it will have the same overall result. The issue is that after InstallFinalize means that the new product is installed. If the uninstall of the older product then fails and rolls back you will end up with both old and new products installed, otherwise known as a mess. afterInstallExecute makes everything part of the transaction so you get the original product installed if there is a failure to uninstall it.

Harvesting files leads to LGHT0231 error

I'm using latest votive (Wix v3.5) and created a simple Wix VS 2010 setup project. I added my website reference and set the Harvest option as true.
Now since my INSTALLDIR points to a folder under IISROOT, I get this light.exe error:
[filepath]: error LGHT0231: The component
'cmp93982C4086FF8C75F07339DD7CEA8152' has a key file with path
'TARGETDIR\webdir...[filename].xml'. Since this path is not rooted
in one of the standard directories (like ProgramFilesFolder), this
component does not fit the criteria for having an automatically
generated guid. (This error may also occur if a path contains a
likely standard directory such as nesting a directory with name
"Common Files" under ProgramFilesFolder.)
While I understand the reason behind this error, I don't necessarily agree to its rational (maybe I don't understand the innate workings of Wix MSI generation).
How can I resolve this error?
To provide some context:
I'm trying to set this up in conjunction with Team Build. I can use the legacy format and run Heat/Harvest task against a folder to bypass this issue but do not want to go the legacy route.
I have not played enough with the new workflow based build definition, so not sure how I can incorporate this custom task.
I need to run harvest every time the Setup project is built because I do not want to keep track of hundreds of files manually.
The problem is because the component is rooted in TARGETDIR, which WiX cannot use for automatically generating a guid. You can add Directory/#ComponentGuidGenerationSeed to a directory above this component to avoid the problem. By adding this attribute, you must now take responsibility for ensuring the component doesn't get installed to two different directories across upgrades.
In Windows Installer, components need to have a guid that doesn't change between patches, minor upgrades, and major upgrades. As a convenience, WiX can generate a version 5 UUID for you using the component's directory hierarchy as the seed. But, TARGETDIR is ineligible for this.
I believe the reason is that TARGETDIR changes across installations (it's set to the drive that has the most free space). One of the component rules is "each component must be stored in a single folder". If TARGETDIR changed between major upgrades, then you could end up trying to install the same component to a second folder.