Updating the last modified time to prevent Windows Installer from updating an unversioned file
Someone recently asked me a question about the unversioned file replacement scenarios that I wrote about a while ago in this blog post. The scenario that they described to me is similar to one that we faced when building the installer for the XNA Game Studio components that ship in the Windows Phone SDK 8.0, so I wanted to provide an overview of our problem and the solution we implemented in case it is useful to anyone else.
The problem we faced was that version B of our product (the XNA components in the Windows Phone SDK 8.0) upgrades several components that are shared by version A (the XNA Game Studio 4.0 Refresh). One of the components is an MSBuild .targets file, which is an unversioned file. Version B ships a version of the .targets file that is backwards compatible with Version A, so we wanted the installer for version B to overwrite the .targets file if a user installs version A and then version B. However, we did not want the installer for version A to overwrite (and downgrade) the .targets file if a user installs version B and then version A.
In order to prevent Windows Installer from overwriting this unversioned file, the last modified time had to be different than the creation time (as documented here). This feels a bit dirty, but we ended up solving this problem by implementing a custom action in version B of our product to call the SetFileTime function to update the last modified time of the .targets file after installing it. This causes version A of our product to not overwrite the file if a user installs version B and then version A. The .targets file is in its own Windows Installer component, which is reference counted by Windows Installer so that the .targets file is left behind after uninstalling either version of the product. Since we designed version B of the .targets file to be backwards compatible, it would continue to work even if a user installs version B, installs version A, and then uninstalls version B (which leaves them with version A of the product installed but version B of the .targets file installed).