WIX - prevent executing uninstall action and copy some files on major upgrade - wix

This is my install execute sequence:
<InstallExecuteSequence>
<Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
<Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
<Custom Action="SetInstallParameters" Before="actionInstall"/>
<Custom Action="SetUninstallParameters" Before="RemoveFiles">Installed AND NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="actionInstall" Before="InstallFinalize">NOT Installed AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="actionUninstall" After="SetUninstallParameters">Installed AND NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="LaunchBrowser" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
So I need to implement major upgrade functionality. Custom action called "actionInstall" is responsible for registering MySQL exe as service and runnig application, that performs all neccesary database updates by connecting to it and executing some sql scripts included in my installer.
"actionUninstall" is responsible for unregistering mysql service. Currently I have no any support for upgrading.
I need to implement major upgrade. So while upgrading I need to perform following operations:
copy and replace all installer files, except MySQL binaries (MySQL is treated as to be never changed). All files should be copied to program directory, that was used previously (it can be non standard), without any user confirmation.
Don't execute SetInstallParameters, actionInstall, SetUninstallParameters and actionUninstall. Instead, I will create another custom action for upgrade only. It will ony execute app to perform database upgrade
Don't display any setup dialogs (for example, destination directory selection, license agreement dialog).
My problems:
It seems, that major upgrade causes also executing Install and Uninstall - how to avoid it?
How to exclude some files (MySQL binaries) from copying to destination dir, but only on upgrade (on install they should be copied)
How to set destination directory for new files to the same as it was used by previous installation (it can be any directory selected by user on first install), without asking user to choose directory?

There are a couple of things to point out first:
The uninstall of the old product is not really "in" the major upgrade - it's a consequence of the major upgrade calling the uninstall of the old product that is already on the system. You can't prevent that uninstall happening because it is embedded in the older installed product and it will happen in a major upgrade.
A major upgrade is not a patch, or update as you seem to be trying to make it. It is a complete new product that replaces the old product entirely. It's an entire product that is available to new clients that happens to replace older products as part of installing the entire brand new product. This comment is really related to your remarks about not replacing the SQL stuff.
So you may not need to implement major upgrade capability unless you change the requirement about the SQL things. For example, if you simply wanted to update some files without doing uninstalls, then you could build an entire MSI file of the same Product, changing only the files you wish to update and incrementing the ProductVersion, a minor upgrade to install with msiexec /i ... REINSTALL=ALL REINSTALLMODE=vomus and there will be no uninstall of the older product - you've done an in-place update. But I don't think you need that.
Note your conditions on the custom actions! They already won't be called on a major upgrade (because of UPGRADINGPRODUCTCODE) or a minor upgrade (because of REINSTALL), so it's not clear to me why you're worried that they will be called during major upgrade. The designer of these calls anticipated this issue.
In your position I'd do this as a major upgrade:
Include the same SQL files as previously. If the binaries are the same they won't be replaced, or the same ones will be there afterwards, so why is there a problem? The install also works as a fresh install for new customers.
The custom actions in the old product being uninstalled won't run because of UPGRADINGPRODUCTCODE in the condition.
The same custom actions in the new product will run during the install, and I assume you don't want that because they will clobber the existing DB. In a WiX major upgrade, use a not WIX_UPGRADE_DETECTED condition (as well as the others) to prevent CAs from running on its install.
If you want to change or suppress dialogs because it's a major upgrade, then use WIX_UPGRADE_DETECTED to alter the flow or suppress them. Don't delete them because, again, you're doing a major upgrade not a "patch".
If you want to install to the same location, it's sometimes useful to write that install location to the registry with the WiX remember property pattern in the older install so you can recover it later. I susperct you didn't test major upgrades before you shipped the product, so you'll need something else. Find a component Id that's in the directory you want to use, then use a WiX Component search to initialize a property that is the directory name.
For the future, make sure that your CA conditions allow a straight uninstall to work properly, and a major upgrade is essentially the same as a fresh install, and replacing or updating binaries doesn't really matter, so make sure new cuatomers can use it. Also, if you need to remember the install location of data files then your design may be incorrect and I suspect your data is in the user-browseable Application Folder. Data should be in a data folder (such as AppDataFolder) so you don't need to worry about its location on an upgrade AND to help enable limited users to run your app because they cannot update files in the Program Files directory.

Related

Query regarding WIX custom Action REMOVE

had few doubt regarding customAction
<Custom Action='CustomActionId.StopService2' After='CustomActionId.StopService1>REMOVE</Custom>
so will this REMOVE flag enables this action to run my custom action only on uninstall or both Upgrade/Uninstall/Repair/Reconfigure
Windows Services: Windows services should not be controlled or installed via custom actions, but by means of built-in MSI mechanisms: ServiceInstall, ServiceControl. These WiX elements map to the corresponding MSI tables and they support everything a normal service needs to install correctly. It is very reliable when done right. The various ways used (and abused) to install Windows Services (few are recommended).
WiX Service Example: Here is a good example of how to install a Windows service properly with MSI / WIX:
https://github.com/rstropek/Samples/tree/master/WiXSamples/WindowsService
REMOVE: As to the property REMOVE. It will be set during several MSI operations: modify, remove, upgrade. During full uninstall it will be set to REMOVE=ALL, in other scenarios it is set to a feature list which will be affected during the maintenance operation. Conditions are hard. Here is an older answer on conditions.
Major Upgrade: Keep in mind that during a major upgrade operation there is both an uninstall of the old version and an install of the new version happening. REMOVE will be set in the version being uninstalled, but generally not in the version being installed.
If you want to skip the action during a major upgrade you could try: (REMOVE~="ALL") AND (NOT UPGRADINGPRODUCTCODE) as explained in this answer. Here is a longer answer on conditions and their permutations.
Condition Debugging: You can debug conditions by using VBScripts to show message boxes during installation as explained here (towards bottom). This can help a lot to take out the guesswork. Just run the setup and show message boxes for when your custom actions run - I guarantee you there will be surprises. Conditions can reach a state when such debugging is necessary. See this example.

Existing Uninstaller Broken During Upgrade - Patch MSI?

I wrote a custom action to help during upgrade of my product (from 1.0 to 1.1). Now I need to upgrade from 1.1 to 1.2 but the existing uninstaller is failing during upgrade. I got the execution conditions of my custom action wrong. (Lesson learned, always test upgrading to the next version before deploying).
Right now it seems my best option is to modify the InstallExecuteSequence table in the existing .msi to disable the failing custom actions. I'll have to create another custom action to browse the registry, locate the existing .msi in C:\
Windows\Installer, patch it, and then continue with the upgrade. This sounds like a terrible, error prone solution, but I'm really at a loss. This was supposed to be an automatic, silent upgrade pushed down from a remote cloud.
Another option would be to write a batch script to uninstall the existing product, then execute the new installer.
Any advice?
EDIT This question is already answered here: I screwed up, how can I uninstall my program?
The supported way to do this is a patch (by which I mean an MSP file, not coding to alter the cached MSI file). That's by far the most straightforward way to get out of the situation. After that, do the upgrade. Using WiX you could probably put the MSP and the upgrade in a bundle.
In any case, you wouldn't do your proposed change with another MSI. A small executable can do what you propose, and:
MsiGetProductInfo (ProductCode, …, INSTALLPROPERTY_LOCALPACKAGE)
is how you find the cached MSI.
Conditioning: What condition did you set on the failing custom action? And more importantly, what is the new condition you are intending to use? It sounds like regular uninstall works but major upgrade fails? The typical problem is that uninstall fails altogether, and then the usual solution is a minor upgrade which I will quickly describe.
Minor Upgrade: Normally what I use is a minor upgrade to fix whatever is wrong in the current install's (un)installation sequence(s). A minor upgrade does not uninstall the existing installation, it upgrades it "in-place", and the uninstall sequence is hence never called and thusly you avoid all its errors from manifesting themselves. There is no need to browse to the cached MSI file and hack it manually if you do things correctly in your minor upgrade. The updating of the cached MSI will happen auto-magically by the Windows Installer Engine provided you install with the correct minor upgrade command line.
Future Upgrades: A minor upgrade will generally always work if you make it simple enough, but the problem is usually applying it since it often targets only a single, previous version. When you get to the next release and if you then use a major upgrade, you will see the error in your original MSI manifest itself on uninstall if you are upgrading an installation that never had the minor upgrade applied - in other words it is still the oldest version of your installation. This is generally solved by a setup.exe launcher which will install the minor upgrade if need be. The bad news is that you need to keep that update in every future release - if you want to avoid any upgrade errors. Or in a corporate environment you would use the distribution system to check what is already on the box and install accordingly. If your manual uninstall works correctly (but major upgrade uninstall fails), all you should need to do is to push an uninstall command line to msiexec.exe as the first command to run via your setup.exe I think. Then there is no need to include any minor upgrade binaries in your setup.exe launcher.
Detect & Abort?: Michael Urman's answer here explains how it might be difficult to make sure that the minor upgrade is present on the box before applying the next version of your software:
InstallShield fails because of a bad uninstall. He suggests making your package better at detecting whether a new upgrade can be safely applied.
Some Links:
how to omit a component when we try to build .msi using wix (on how patching is just a distribution mechanism for MSI upgrades that must already be working)
Is there any possible way to perform upgrade when Product codes for old and new versions are same? (on minor upgrades and their technical limitations)
Here is a hack that I got working, but based on the answers above it looks like it's not the preferred way.
[CustomAction]
public static ActionResult Patch11Installer(Session session)
{
string localPackage = NativeMethods.GetMsiInstallSource("{MY-PRODUCT-CODE}");
if (String.IsNullOrEmpty(localPackage))
{
session.Log("Failed to locate the local package");
return ActionResult.Failure;
}
session.Log($"Found local package at {localPackage}");
using (Database database = new Database(localPackage, DatabaseOpenMode.Direct))
{
foreach (string action in new string[] { LIST OF CUSTOM ACTION NAMES })
{
session.Log($"Modifying condition for action {action}");
database.Execute($"UPDATE InstallExecuteSequence SET Condition='WIX_UPGRADE_DETECTED' WHERE Action='{action}'");
}
database.Commit();
}
return ActionResult.Success;
}
The custom action calls MsiGetProductInfo to query for the v1.1 MSI using the v1.1 product code which I obtained from installer log files. It then opens the MSI database and modifies the Condition property of the InstallExecuteSequence table for the list of custom actions that are failing. It changes the Condition from "UPGRADINGPRODUCTCODE OR WIX_UPGRADE_DETECTED" to "WIX_UPGRADE_DETECTED". UPGRADINGPRODUCTCODE is the property that's causing the uninstall to fail during a major upgrade as this property is passed to the uninstaller and contains the new product code; the product code for v1.2 in my case. Here is the custom action definition in my installer file.
<CustomAction Id="Patch11Installer" Return="check" Impersonate="yes" Execute="immediate" BinaryKey="MyUpgradeCustomActions" DllEntry="Patch11Installer" />
I'll look into implementing a minor upgrade as suggested in other answers. I just thought I would leave this solution here.

Run Wix Custom action only during uninstall and not during Major upgrade

I am trying to delete a file using a custom action scheduled between InstallInitialise and InstallFinalize standard action.
MajorUpgrade element is used to design upgrades.
However, I want the custom action to run only during uninstall and not during the Major upgrade(this includes uninstall and install).
I have used the following conditions to execute the CUstom action:
(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
REMOVE AND NOT WIX_UPGRADE_DETECTED
Is there a way to uniquely detect the Major Upgrade using properties in Wix?
Phil has already answered. I'll just post what I wrote a few hours ago
before heading out. The conditions you specify look pretty good to me.
Maybe I'll do a quick review of things that are likely to cause
confusion - such as what custom actions run when?
Major Upgrades: A major upgrade is really an install of a new application version combined with the uninstall of the old version - with different uninstall scheduling possible (uninstall old and install new, or install new and uninstall old). Hence, during a major upgrade operation, 1) the uninstall sequence runs only for the old setup, and 2) the new setup runs only its install sequence. This is of crucial importance to understand what custom actions runs when and why.
Custom Actions and Major Upgrades: To put it in other words: this sequencing can cause quite a bit of confusion for custom action sequencing, since it could appear that an action runs from the new setup, when it in fact runs in the old setup's uninstall sequence. If you are sloppy with sequencing, the typical error is seeing the same action run many times during the upgrade process - potentially twice from each setup (four times in total - or perhaps even more - I haven't tested that in detail) - if you run the custom action in immediate mode.
No Retrofitting for Major Upgrades: As Phil explains, you can not add a custom action that will run during the old setup's uninstall sequence inside the new setup. That custom action would have had to be part of the original setup, or added via a minor upgrade (which upgrades the existing installation in-place, rather than uninstall and reinstall it).
Important:
UPGRADINGPRODUCTCODE is set only in a setup that is being uninstalled as part of a major upgrade. It is not set in the new
version being installed.
The condition UPGRADINGPRODUCTCODE is hence not true in the installing setup, only in the uninstalling setup.
WIX_UPGRADE_DETECTED is set only in setups that are using WiX's MajorUpgrade element that have detected that another version is
being uninstalled as part of its install.
The condition WIX_UPGRADE_DETECTED is hence true in the installing setup, but not in the uninstalling setup.
WIX_UPGRADE_DETECTED: To go into even more detail, WIX_UPGRADE_DETECTED is strictly speaking not a custom WiX feature - it is a WiX standard or convention for setting the built-in MSI property ActionProperty for the upgrade process. All MSI files supporting major upgrades have such a property, WiX just names it in a standard way. The property is set in a column in the Upgrade table, and it is a property that is set when a setup finds related products - that are lower versions (and hence to be uninstalled) - on the same box during installation.
WIX_DOWNGRADE_DETECTED: Note that in a standard WiX-compiled MSI using the MajorUpgrade element there is also WIX_DOWNGRADE_DETECTED - the property used to list products found that are of higher version than the running setup. These would block the setup in question from installing - in most cases (unless the settings are customized by the setup designer).
The action property specified in the upgrade table can be "anything", but the MajorUpgrade Element "convenience feature" does this for you in an "auto-magical" way that makes sense for most purposes - using the mentioned property names WIX_UPGRADE_DETECTED and WIX_DOWNGRADE_DETECTED. Check the Upgrade Table of your compiled MSI to see how this works in detail. Here is a screen shot:
I wrote this other answer showing how to use another property name (YOURUPGRADEPROPERTY) as "ActionProperty": wix installer update process and confirmation dialog (the linked answer is not a recommendation, demonstration only). Just a link, probably not very useful for you now that I think about it.
Some Links:
http://forum.installsite.net/index.php?showtopic=13809
NOT UPGRADINGPRODUCTCODE evaluates to true on a major upgrade for custom action
It's not obvious whether you want to do this in the older installed product (which is presumably already shipped and therefore can't be changed without an update such as a patch) or in the newer upgrade install.
I'll also assume you've looked at the RemoveFile element and it doesn't meet your requirements.
The UPGRADINGPRODUCTCODE property applies to the older product being upgraded and uninstalled. If the file belongs to that installed product and you want to remove it only at uninstall with a custom action in that older install the condition on the custom action would be:
REMOVE="ALL" and not UPGRADINGPRODUCTCODE
but as I said, that custom action would need to be already in the older installed product and there's nothing you can do in your upgrade MSI to fix that.
If you are removing the file from the upgrade then the condition during an upgrade is only:
WIX_UPGRADE_DETECTED
It might also help to say where your major upgrade is sequenced. If it's early (such as around InstallInitialize) then the upgrade is basically an uninstall of the older product followed by an install of the newer product, and that might be related to the removal of the file, if that's what you're seeing.

Reboot on install, Don't reboot on uninstall

We have an installer which requires a reboot on install, but it is also rebooting on uninstall. Is there a way we can prevent the reboot when uninstalling?
This is what we have at the moment:
<InstallExecuteSequence>
<ScheduleReboot After="InstallFinalize"/>
</InstallExecuteSequence>
Many thanks in advance!
Restart Manager: The Restart Manager Feature of Windows (Installer) (middle page) is designed to help restart applications automatically during installation rather than requiring a reboot.
This feature should always be used to try to eliminate reboot requirements.
Only in very special circumstances should a reboot be really required.
Technical Crash Course: This is a technical tidbit and recommendation for implementing Restart Manager in your application - from Advanced Installer, makers of leading deployment tools:
https://www.advancedinstaller.com/user-guide/qa-vista-restart-manager.html
UPDATE: MSI Expert Phil Wilson on Restart Manager (for some Restart Manager reality check - please read).
Add Condition to ScheduleReboot
You need to insert a condition for your ScheduleReboot entry along the lines of what is described here: https://www.firegiant.com/wix/tutorial/events-and-actions/extra-actions/ (the linked article may show a condition that is a little too inclusive or unrestricted).
UPDATE: There are some issues to consider:
Undesired action: ScheduleReboot should never be used unless it is really necessary. For example, if you are trying to replace files that are in use MSI will handle that without a call to ScheduleReboot.
Many installation modes: Without a proper condition, the ScheduleReboot will cause a reboot prompt to show up in many installation modes: install, uninstall, upgrade, repair, self-repair, patching, etc... This is not desirable.
Silent, instant reboot: If an MSI is run in silent mode and REBOOT=ReallySuppress is not specified, a ScheduleReboot action will automatically trigger an instant reboot of the computer in question - which might be very surprising and very undesirable.
For your purpose, you can perhaps use a condition along these lines:
<InstallExecuteSequence>
<ScheduleReboot After='InstallFinalize'>NOT Installed AND NOT WIX_UPGRADE_DETECTED</ScheduleReboot>
</InstallExecuteSequence>
It all depends on whether you want to schedule a reboot during a major upgrade, or just during the original, fresh installation? There is no way to tell without more information. A more run-of-the-mill condition like NOT Installed AND NOT REMOVE~="ALL" would appear to schedule a reboot during a major upgrade, but not for a manual uninstall not triggered by a major upgrade (I will test when I get a chance - UPDATE: verified, basic testing only).
Note that the special WIX_UPGRADE_DETECTED property is a WiX-specific construct that may only be set if you use WiX's MajorUpgrade element. You can also set up major upgrades the old fashioned way in WiX and avoid the MajorUpgrade element "convenience feature" which allows easier configuration of the major upgrade with fewer options - "auto-magic". I didn't verify if WIX_UPGRADE_DETECTED is still set using this "old school" major upgrade configuration.
You can also use the ActionProperty from the Upgrade table to detect that a major upgrade is "about to happen" (see this answer for a sample). This should work even for non-WiX MSI setups - and as such should be an alternative to WIX_UPGRADE_DETECTED (I believe this property is set after FindRelatedProducts has run).
WIX_UPGRADE_DETECTED vs UPGRADINGPRODUCTCODE
The MSI package being uninstalled during a major upgrade will have the special property UPGRADINGPRODUCTCODE set (which will not be set in the MSI being installed during the upgrade). This is a built-in MSI property, and not a WiX-specific construct. In other words, during a major upgrade - which is an uninstall of an old version and an install of a new version - the MSI being uninstalled will have the property UPGRADINGPRODUCTCODE set whilst the MSI being installed will have the property WIX_UPGRADE_DETECTED set (I will verify this shortly). It will also have the ActionProperty from the Upgrade table set after the standard action FindRelatedProducts has run.
If this sounds complicated, then I am afraid it is. This is a key problem with Windows Installer (despite the technology's major corporate benefits) -
that basic, key operations - such as upgrades - are sometimes very complicated to get right. There may be some violations of the principle of least astonishment. There is good and bad in all technologies - obviously.
Special Considerations
Note that a reboot may be initiated regardless of whether the ScheduleReboot action is suppressed or not (for example if there are files that could not be replaced - or worse: a custom action forces a reboot via code - which is always wrong, a reboot should be scheduled not forced via code).
You can suppresses certain prompts for a restart of the system by using the REBOOT property (something you will have read already). More on System Reboots.
MSI Conditions
MSI conditions can be very tricky to get right. Get it wrong and your action runs unexpectedly during the wrong installation mode - or it doesn't run at all when it should. This is much easier to get wrong than what you might think - even with experience. The proof is in the pudding here, real-life testing. Here are some sample, complex conditions as an example: Wix Tools update uses old custom actions (just in case it is interesting).
There are many installation modes you should test in when you try to use complex conditions (or any condition for that matter): 1. fresh install, 2. repair, 3. modify, 4. self-repair, 5. patching, 6. uninstall, 7. major upgrade invoked uninstall, etc... There are also a few weird modes like resumed suspended installs featuring the RESUME property, and the AFTERREBOOT property relating to the ForceReboot action etc... Things one should keep in mind that are rarely tested.
Here are two "cheat-sheets" for conditioning:
Installshield condition cheat sheet.
How to add a WiX custom action that happens only on uninstall (via MSI)?
I have not had the time to go through all these conditions and test them, but the latter table looks reasonable at face value. However: I believe REMOVE can sometimes be set during installation (and during change). It is very complicated to deal with all permutations of possibilities since MSI's command line interface and property configuration is so flexible. Installed is also not set for the new MSI version being installed as part of a major upgrade, but it will be set for the MSI version being uninstalled - very confusing.
The Installshield cheat sheet I have never actively used or checked, but I find their suggestions for repair interesting to say the least - there are different entries depending on how the repair is invoked.
Please remember to also check self-repair - just delete the main application EXE and trigger self-repair by then invoking the application's advertised shortcut (if any). It has been years since I checked, but self-repair may only run actions between InstallInitialize and InstallFinalize. You don't want to schedule a reboot during a self-repair.

How to prevent database drop during Wix Major upgrade

I am building an installer with Wix 3.10 that will install files, create a service as well as create and populate a database.
I am using the Wix sql:SqlDatabase element to create the database and run some sql scripts to populate it during installation (based heavily on WIX database deployment, installation)
As recommended in the Wix documentation, I am testing a mock upgrade before releasing the initial installer. From what I can tell sticking to major upgrades is strongly recommended and so I am using the MajorUpgrade element as per the examples.
Unfortunately however during the major upgrade I can't seem to prevent Wix from uninstalling the database, nor can I find any guidance on how to handle this. I understand that a major upgrade is effectively an uninstall of the current version followed by a fresh install of the new version, but surely there is a way of retaining parts of the original?
I have a similar problem with the service that I install too, but based on this SO question Wix Major Upgrade: how do I prevent Windows service reinstallation? the solution appears to be to add a condition to the delete service entry of the install sequence:
<InstallExecuteSequence>
<DeleteServices>NOT UPGRADINGPRODUCTCODE</DeleteServices>
</InstallExecuteSequence>
This implies to me that it is possible to retain entries across a major upgrade, but I may be misunderstanding.
Unfortunately there does not appear to be any equivalent installexecute sequence element for a SqlDatabase entity. Is there any guidance on how one should approach this?
UPDATE
Based on PhilDW's answer, changing the sequence or schedule of the major upgrade is done by changing the Schedule attribue:
<MajorUpgrade
DowngradeErrorMessage="A newer version of [ProductName] is already installed."
Schedule="afterInstallExecute"/>
Note however that this will only take you so far - if you plan to add support for trusted authentication as well as SQL authentication in your installer (as per the SO article above) it will not work, my assumption is that Wix determines that one component was never installed (whichever authentication option was not chosen) and therefore will always drop the database.
There are a few ways to address this, depending on the internals of your MSI:
A major upgrade that is sequenced at the "end", after InstallExecute and just before InstallFinalize, means that the upgrade is basically an install of the new product on top of the currently installed product. File overwrite rules apply, one of which is that data files won't be replaced if they have been updated after installation. So data files are saved. Other considerations are that binary file versions must be updated for those you need updating, and component rules must be followed.
If the issue is based on custom actions that run when the older product is being uninstalled, then you can use a custom action condition such as REMOVE="ALL" and not UPGRADINGPRODUCTCODE. UPGRADINGPRODUCTCODE is set in the older product as it is being uninstalled, not in the incoming upgrade.
I believe some WiX util types custom actions are based on the uninstall of the related component, so you wouldn't need that condition in 2. A major upgrade after InstallExecute increments the ref counts of each component (which is why you need to follow component rules) while following file overwrite rules. So your data file would have its ref count counted up to 2, would not be overwritten, then the older product uninstall would count it down to 1, so that the component remains, and an uninstall custom action based on component removal would not run.
If there is something you need to do in the upgrading install that's custom action based, then WIX_UPGRADE_DETECTED will tell you that you are upgrading an installed product.
On the upgrade link you refer to, Chris Painter's answer is the correct one. It's basically the same point that I'm making here, so of course he's correct :)