What causes an MSI update to not update a component in an installer?
(EDIT: Question changed.)
I have a product with an installer which was built by InstallShield 2010, and appears by all accounts to be installing just fine as a "new" install.
Periodically, I make changes to the contents of the installation, as I update this or that component with bug fixes and so forth. At those times I try to change the version numbers in the metadata of the files that got updated, but there are components for which that isn't possible. Of course they always end up with more recent modify dates. I change the version number for the product in the MSI data as well. However, I have not been changing the Package Code each time.
When some users run the installer on a system where my product is already present, they're prompted with update mode UI ("would you like to update?" etc.) and the installer appears to complete. However, the updated files don't always overwrite the older files until a "repair" installation is run afterwards, especially if the version number didn't change, and there is evidence now that flagging the component's contents with a "force overwrite" doesn't change this behavior.
What's going on here? Is there any way I can get a better result? Does the Package Code need to change whenever I rev the product or update a component? (Edit: The Package Code is changing each time开发者_StackOverflow I build the release, so this is not the cause of the problem.)
Edit: It's an update UI, but maintenance after update is what actually completes the desired installation.
You should certainly be changing the PackageCode every single build. In fact, by default, InstallShield has a build setting that does just this.
In fact, the MSDN help topic Package Codes says:
Nonidentical .msi files should not have the same package code. It is important to change the package code because it is the primary identifier used by the installer to search for and validate the correct package for a given installation. If a package is changed without changing the package code, the installer may not use the newer package if both are still accessible to the installer.
This is why you are getting a Maintenance UI experience instead of an Upgrade experience.
Now once you start doing this you are going to have to next consider do you want to support Minor Upgrades, Major Upgrades or Patches to service your application. It's very important that you understand this and test your strategy before putting your installer into production.
In @ChristopherPainter's answer above I too learned that InstallShield has a setting to auto-generate the package code, but he didn't say where it was. So for anyone else looking for it:
This setting is found under Media / Releases / (release name), product configuration, general tab. There you will find "Generate Package Code" and you can verify that it is set to Yes.
The installer is doing what it's supposed to, based on the unchanging file version information.
Ideally you update the file version each time you alter a file (for files that contain version information at all), but if for whatever reason you're not going to do that, there are still a couple ways to force components to be updated.
The easy way is to set the REINSTALLMODE property. You could set it to "amus", which would cause all files to be reinstalled. See MSDN - http://msdn.microsoft.com/en-us/library/aa371182%28v=vs.85%29.aspx
That works, but may introduce its own problems. For instance, if you are including some redistributables in your package, forcing those redistributable components to be reinstalled can cause them to be backleveled.
The somewhat harder way, which allows you to have control at the individual component level, is to use a custom action. Call MsiSetComponentState to explicitly set each of your components to whatever state you want. http://msdn.microsoft.com/en-us/library/aa370383%28v=VS.85%29.aspx
My recollection is that your custom action must come after CostFinalize, so the installer doesn't wipe out your updates.
When Windows Installer decides whether to install your component, it will first look whether the "keypath" resource is already present. If it is, none of the resources in the component are installed. (I assume Installshield puts each file in its own component, and the keypath is the file.)
When the keypath resource is a versioned file, Windows Installer will consider it to exist only if it finds a file with an equal or higher version. So if a file with the same version number is already present, it will not be installed again. Changing a file without changing the version number will therefore cause problems.
edit: as to why a repair fixes the problem: I believe it will reinstall all components from the cached MSI file in c:\windows\installer
regardless of the presence/version of the keypath resource. This seems logical as it would be the only way to make sure that corrupted files are restored. (I can't immediately find a clear reference on MSDN to back this up, sorry.)
The TortoiseSVN developer has blogged about a similar problem in TortoiseSVN when upgrading from a pre-1.6.10 version to a later one. In his case the problem was not the version of the file, but a change in the keypath of some components with the same result. A repair also fixed the application in that case.
精彩评论