How to guarantee custom actions aren't executed on upgrades

Sep 13, 2016 at 2:15 PM
Edited Sep 13, 2016 at 2:18 PM

I have the following situation:
Setup installs a single .exe and a configuration file

Three custom actions:
  1. Installs the exe as a service (calls the console application with a given parameter)
  2. Uninstalls the exe as a service (calls the console application with a given parameter)
  3. Given user input, composes the configuration file
In order not to lose data when upgrading, the configuration file shouldn't be overwritten. For that, I defined it as a File and set NeverOverwrite to true.

Furthermore, the project is using a ManagedProject and ManagedUI. I have a custom dialog that obtains the user input that is necessary and places it into session.CustomActionData, so the custom action in 3 can compose the configuration file. This dialog should ideally be completely skipped if we are in the context of an upgrade.

Given all of this information, how can I make the setup behave correctly when it is in the context of an upgrade? Right now, I have been attempting to use e.UpgradingProductCode / session.Property("UPGRADINGPRODUCTCODE"), but it never seems to work correctly. My versions are all X.Y.ZZZ form, with only ZZZ being incremented in testing so far.

Thanks in advance,
José Maia.
Sep 14, 2016 at 10:30 AM
Hi José,

One obvious thing that can help is to fix the deployment to follow/respect "separation of concerns" principle.

Your config file does not belong to the deployment as is a part of the configuration. Remove the config file from your setup and update your application in such a way that it creates the config file with the defaults if it doesn't exist. This way you kill a few birds:
  • You can easy reset the config file to defaults by simply deleting it.
  • The config file can be auto-resurrected if it got deleted for whatever reason (e.g. by accident).
  • Your config file will never be overwritten by setup as setup is not aware about it at all.
  • The config file can be created in any location more appropriate than ProgramFiles (e.g. user profile).
  • Your product can automatically handle advertised setup scenarios.
  • Resetting/recreation of the config file doesn't longer require running setup in repair mode.
BTW, this principle "setup is only concerned about deploying files and the configuration is the responsibility of the application" is not something new. MS started enforcing this principle on the deployment solutions for the products to be officially "Windows certified" starting from introduction of Vista.

As for "UPGRADINGPRODUCTCODE" you are right MSI solution for that is messy. I can only suggest that you can play with upgrades and evaluate the properties as it is done in "Setup Events" sample. This way you may find some magic combination. Though if you follow my first suggestion you don't need to deal with detecting upgrades.
Sep 14, 2016 at 10:44 AM

Thank you for the quick reply. I will evaluate with the team if we have an alternative, but I believe the decision to make configuration and setup a single step is irreversible. I will look into the sample you mention and attempt to figure out a solution. Will report back.
Sep 14, 2016 at 10:56 AM
You may also find useful this info.
It's a fragment from the WixSharp.MsiRuntime code doco:
 * Expected to be like this:
 *        Property Name                 Install     Uninstall   Repair      Modify      Upgrade
 *        --------------------------------------------------------------------------------------
 *        Installed                     False       True        False       True        True    
 *        REINSTALL                     True        False       True        False       False     
 *        UPGRADINGPRODUCTCODE          True        False       True        True        True      
 * Though in the reality it is like this:
 *        Property Name                 Install     Uninstall   Repair      Modify      Upgrade
 *        ---------------------------------------------------------------------------------------------------
 *        Installed                     <null>      00:00:00    00:00:00    00:00:00    <not tested yet>    
 *        REINSTALL                     <null>      <null>      All         <null>      <not tested yet>       
 *        UPGRADINGPRODUCTCODE          <null>      <null>      <null>      <null>      <not tested yet>
 * */
It only confirms how flaky the UPGRADINGPRODUCTCODE handling is.