Aaron Stebner's WebLog

Thoughts about setup and deployment issues, WiX, XNA, the .NET Framework and Visual Studio

How Windows Installer handles file replacement logic for versioned and unversioned files

How Windows Installer handles file replacement logic for versioned and unversioned files

  • Comments 49

I ran into an interesting problem yesterday where a team had built an MSI-based setup package, and they were seeing sporadic problems where some of the files failed to install.  They enabled Windows Installer verbose logging and this is an example of an entry for one of the files that was failing to install:

MSI (s) (B4:4C) [11:30:07:906]: Executing op: FileCopy(SourceName=eulatxt|eula.txt,SourceCabKey=FILE1,DestName=eula.txt,Attributes=512, FileSize=29239,PerTick=32768,,VerifyMedia=1,,,,, CheckCRC=0,,,InstallMode=58982400,HashOptions=0, HashPart1=-1713153497,HashPart2=58557210, HashPart3=1046945815,HashPart4=871163290,,)
MSI (s) (B4:4C) [11:30:07:906]: File: C:\WINDOWS\system32\eula.txt; Won't Overwrite; Won't patch; Existing file is unversioned but modified

After I saw this, I took a look at the MSI package and I found that this MSI was divided into one component per file, and each component used the one file that it contained as the key path.  This led me to understand the root cause of this issue.  Windows Installer has a specific set of rules for file versioning and how it decides when to replace files when they already exist in the destination location.  Here are the possible permutations for file versioning:

  • In the case when the source and destination files are both versioned files, these rules are straightforward - if the key path file does not exist in the destination location or if it exists in the destination location and it is of a lower version, Windows Installer will install the component (and all of the files in it, including the key path).  If the key path file exists in the destination location and it is of an equal or higher version, Windows Installer will not install the component but instead only reference counts the component.  It becomes trickier when only one of the files is versioned or neither of them are.
  • In the case when only one file is versioned, Windows Installer will install the component (and all of the files in it, including the key path file) if the source file is versioned and the destination file is not (meaning it will replace an unversioned file with a versioned one).  It will not install the component but instead only reference counts the component if the source file is unversioned and the destination file is versioned (meaning it will not replace a versioned file with an unversioned one).
  • In the case when both files are unversioned and have file hashes (as in the scenario I was debugging yesterday), Windows Installer will compare the created time and the last modified time of the destination file.  If the times are the same, Windows Installer will compare file hashes of the source and destination files.  If the file hashes are different, Windows Installer will install the component (and all of the files in it, including the key path).  If the file hashes are the same, Windows Installer will not install the component but instead only reference counts the component.  This means that if the key path file already exists in the destination location but has been changed sometime after it has been created, Windows Installer will not update this file, even if it is carrying a different copy of the file as part of the setup package.  The intent of this logic is to prevent Windows Installer from overwriting data files that customers may have modified on their machine before running setup
  • In the case when both files are unversioned and do not have file hashes, Windows Installer will compare the created time and the last modified time of the destination file.  If the times are the same, Windows Installer will install the component (and all of the files in it, including the key path).  If the times are different, Windows Installer will not install the component but instead only reference counts the component.

This particular MSI I was investigating was trying to update a text file named eula.txt in %windir%\system32.  In some test cases, the file did not exist, in some cases it existed and was identical and in some cases it existed and was different.  The 3rd and 4th versioning rules above explains why this problem would only occur on some test machines but not others.  This illustrates one of the problems with using an unversioned file as the keypath for a component, especially if the file could be shared by other products on the system.  The solution I recommended to the team hitting this problem was to move this eula.txt file to be installed as part of another component that installed to %windir%\system32 and had a binary file as a key path.  In general you have to be careful about installing multiple files in one component (because of the Windows Installer component rules), but in this case it is a simple text file, which mitigates some of the drawbacks of including multiple files in a component (complicated servicing and incorrect uninstall behavior being the main risks here).

<update date="9/6/2005"> I listed the logic incorrectly that Windows Installer uses when both the source and destination file are unversioned.  I have updated the 3rd bullet above based on the feedback in Stefan's comment. </update>

<update date="4/29/2008"> MSDN links in this post were broken, so I updated them to work again. </update>

 

  • Aaron - just to point out that the ref counts are only updated if the msidbComponentAttributesSharedDllRefCount bit flag is set (set the Attribute column of the Component table to 0x0008) or if the ref count already exists. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/component_table.asp
  • I'm getting error un install MS SQL Native CLient from Beta 1, any I deas on how to remove this sucker, I tried the vs_uninstall tool, msizap and add remove programs, not is this order, none of these approaches rids me of this cancer.

    HELP!
    V.
  • Hi Tom - your comment is true for shared DLL ref counts (which are stored in HKLM\Software\Microsoft\Windows\CurrentVersion\SharedDlls. Windows Installer also keeps an internal ref count for component IDs of all components that are installed on the system, regardless of whether or not it installs the files contained in those components, and regardless of what the component attribute settings are in the Component table of your MSI.
  • Hi Vince - I'm sorry for the hassles you're facing while trying to uninstall SQL 2005. Can you please gather the SQL log files located at %ProgramFiles%\Microsoft SQL Server\90\Setup BootStrap\LOG\Files\*.*, zip them up and send them to me at aaronste (at) microsoft (dot) com so I can take a more detailed look at what might be causing this uninstall issue?

  • Aaron,

    in your case no. 3 (both files are unversioned) in a first step Windows Installer DOES NOT compare source file with destination file. Instead it ONLY looks at the destination file and compares its "created" and "modified" dates. If the modified date is more recent - which means the file was edited by the user after it was created/installed - it will never be overwritten.

    Only if the modified date is less recent or equal than the created date of the destination file Windows Installer will compare the hashes of the two files. If it finds that the files are different, it will install the file (regardless of the date of the source file). This hash comparison was added to avoid unnecessary copy operations on files that are binary identical, thus minimizing requests for the original CD.

    This means (and that's often confusing people) that for unversioned files the date of the file in your setup package doesn't matter. Actually, Windows Installer doesn't even know about the date, as the File table only stored version and size, but not date.
  • Hi Stefan - thank you for the clarification. I will update the text of the main post to reflect this.

  • This might be a little off, but i was wondering how i can run two installers at the same time, cause i need one to call on a java installer which sadly is an exe file so i cant decompile it. thanks for the help
  • Hi Hochi - You cannot run 2 Windows Installer-based setups at the same time.  In this scenario, you will need to use a setup.exe bootstrapper/chainer to launch each of the MSIs.  You should include logic in the bootstrapper to detect if the MSI is already installed on the machine and then conditionally launch the MSI if it is detected as being needed.
  • Do you have any suggestions about how to deal with .NET application configuration files (e.g. SomeApp.exe.config)? We use these to store version redirects for both .NET applications and COM apps which use .NET assemblies via Interop.

    Since these are not versioned and not changed by the user, the Windows Installer will happily overwrite a newer config file with an older one.

    I cannot use the EXE as a companion file, since a version change in any of the 4 dependent DLLs listed in the config file could require a config file change without recompiling the EXE.
  • Hi Mike - Unfortunately, you have found a case that Windows Installer does not handle very well.  You may need to author this logic as a custom action to workaround possible cases where a newer file could be overwritten by an older file.  If you are using WiX for your setup (http://wix.sourceforge.net), it has a built-in custom action that you can use to modify XML data.  Check out http://www.tramontana.co.hu/wix/lesson5.html#5.11 for more information.
  • I am trying to get a MSI to update the bitmap we use as the background.  However, the MSI does not seem to want to replace the file the new bitmap has a later modified date then the one currently on the system.  It installs the bitmap if it does not exist.
  • Hi Kevin - It seems like the BMP should have been updated in that scenario.  Do you have a verbose log file from that installation scenario that you could send me?  If not, you can use the steps at http://blogs.msdn.com/astebner/archive/2005/03/29/403575.aspx to gather it and you can contact me at Aaron.Stebner@microsoft.com and send it to me so I can take a look.
  • One of the features included in the WiX v3.0 source files included in the C# project template in the

  • One of the features included in the WiX v3.0 source files included in the C# project template in the

  • PingBack from http://msdnrss.thecoderblogs.com/2007/09/06/subtle-problem-with-major-upgrades-in-wix-files-in-the-media-center-sdk/

Page 1 of 4 (49 items) 1234
Leave a Comment
  • Please add 3 and 6 and type the answer here:
  • Post