|
![]() |
| Automatically Uninstall Other Versions |
The method shown here completely uninstalls any version (older or newer) of the MSI being installed before the install continues (Applications to be uninstalled are identified by their "UpgradeCode"). This means that you will not have to worry about what is "allowed" in "minor upgrades" etc, each of your builds can work exactly the same way without requiring any knowledge of what was done for the last install...
| Optionally Generating a Random Upgrade code |
While I don't neccessarily recommend this the following code place into a common header file will modify the normal behavour so that you can still supply a fixed GUID (via version file or macro) but if not supplied a new unique GUID will be randomly generated for you:
;----------------------------------------------------------------------------
;--- If Upgrade GUID not supplied want a random one -------------------------
;----------------------------------------------------------------------------
#NextId
#( '<?NewLine>'
#define COMPANY_SET_PROPERTY_UPGRADECODE
;--- Simple validation ---------------------------------------------------
#if ['<$COMPANY_UPGRADE_CODE_QUALIFIER>' <> '']
#error ^Currently don't support use of a "COMPANY_UPGRADE_CODE_QUALIFIER"...^
#endif
;--- Generate a random GUID unless we already have one -------------------
#RexxVar @@UcMacName = '<$VER_PRODINFO_GUID_PREFIX>UpgradeCode'
dim UpgradeCode ;;VBS variable
#if Defined(@@UcMacName) = 'N'
;--- Generate Random GUID -------------------------------------------
#info "UpgradeCode GUID randomly generated..."
UpgradeCode = GuidMake("UpgradeCode") ;;VBS to generate random GUID
#else
;--- Use value supplied (probably in ".VER" file --------------------
#info "UpgradeCode: <$[@@UcMacName]>"
UpgradeCode = "<$[@@UcMacName]>" ;;GUID supplied as literal
VbsReturnGuid "UpgradeCode", UpgradeCode ;;Ensure HTML report can access this information
#endif
<$Property "UpgradeCode" *Value="UpgradeCode"> ;;Use GUID "calculated" above
#)
| Supporting Code in COMPANY.MMH |
The following code is an extract from "COMPANY.MMH" shows the supporting code for the above GUID manipulations:
;----------------------------------------------------------------------------
;--- Set MSI guids ----------------------------------------------------------
;----------------------------------------------------------------------------
#define? COMPANY_UPGRADE_CODE_QUALIFIER ;;Allow user scheme for having "sets" of upgrade codes
#if ['<$COMPANY_UPGRADE_CODE_QUALIFIER>' = '']
;--- Not part of a set (or at least using standard name) ----------------
#define @@UPGRADE_CODE_NAME UpgradeCode
#elseif
;--- Upgrade code name qualified by name of a "set" ---------------------
#option PUSH DefineMacroReplace=YES
#define @@UPGRADE_CODE_NAME UpgradeCode.<$COMPANY_UPGRADE_CODE_QUALIFIER>
#option POP
;--- Cludge so it can easily be referred to -----------------------------
#define VBSRET.GUID.UpgradeCode <$VBSRET.GUID.[@@UPGRADE_CODE_NAME]>
#endif
#define UpgradeCodeValue <$VBSRET.GUID.UpgradeCode> ;;Info returned from VBSCRIPT pass1
#define? COMPANY_UPGRADECODE_HOOK_AFTER_SETTING ;;Allow you to do something (perhaps validate value)
#( '<?NewLine>'
#define? COMPANY_SET_PROPERTY_UPGRADECODE
dim UpgradeCode ;;Need a VBSCRIPT variable
<$Guid '<$@@UPGRADE_CODE_NAME>' VB="UpgradeCode"> ;;Want same GUID every time!
<$Property "UpgradeCode" *Value="UpgradeCode"> ;;Use GUID "calculated" above
<$COMPANY_UPGRADECODE_HOOK_AFTER_SETTING> ;;Default is to do nothing (VBS variable "UpgradeCode" contains the value.
#)
#( '<?NewLine>'
#define? COMPANY_SET_PROPERTY_PRODUCTCODE
<$Property "ProductCode" *Value='GuidMake("ProductCode")'> ;;Random GUID
#)
#( '<?NewLine>'
#define? COMPANY_SET_PROPERTY_PACKAGECODE
<$Summary "PackageCode" *Value='GuidMake("PackageCode")'> ;;Random GUID
#)
<$COMPANY_SET_PROPERTY_UPGRADECODE> ;;User can override above macros to change behaviour...
<$COMPANY_SET_PROPERTY_PRODUCTCODE>
<$COMPANY_SET_PROPERTY_PACKAGECODE>
The following code is another "COMPANY.MMH" extract which performs these main functions:
#define? COMPANY_AUTO_UNINSTALL_VIA_UPGRADE_TABLE Y
#if ['<$COMPANY_AUTO_UNINSTALL_VIA_UPGRADE_TABLE>' = 'Y']
;--- Look for older/newer versions of the same package (group) -----------
#define UpgradeCode_PROPERTY UNINSTALLTHIS ;;Use this property in "Upgrade" table entry
<$UpgradeTable "=UpgradeCode"> ;;Use value in VB variable
;--- Any EXTRA upgrade codes to be handled? ------------------------------
#if ['<$ProdInfo.UpgradeCodes>' <> '']
<$UpgradeTable "<$ProdInfo.UpgradeCodes>">
#endif
;--- Install MSI AFTER complete uninstallation of older ------------------
#define? COMPANY_RemoveExistingProducts_HOOK_BEFORE_MOVING
#define? COMPANY_RemoveExistingProducts_HOOK_AFTER_MOVING
#define? COMPANY_RemoveExistingProducts_SEQ InstallValidate-InstallInitialize
#(
;--- Allow easy overiding/removal of this step ----------------------
#define? COMPANY_MOVE_RemoveExistingProducts
<$Table "InstallExecuteSequence">
;--- Move to desired location -----------------------------------
dim RepSeq : RepSeq = GetSeqNumber("InstallExecuteSequence", "<$COMPANY_RemoveExistingProducts_SEQ>", 1)
<$Row Action="RemoveExistingProducts" *Sequence="RepSeq">
<$/Table>
#)
<$COMPANY_RemoveExistingProducts_HOOK_BEFORE_MOVING>
<$COMPANY_MOVE_RemoveExistingProducts>
<$COMPANY_RemoveExistingProducts_HOOK_AFTER_MOVING>
#endif
| UpgradeTable Command |
The above code used The "UpgradeTable" command which I haven't documented separately. Note that this command generated debug output into the console file, this should help you understand where the values come from..
Its default configuration is:
#define? UPGRADETABLE_DEFAULT_VALIDATE NEW ;;Validation performed when row inserted (Don't allow overwrite of info).
#define? UPGRADETABLE_DEFAULT_REMOVE ALL
#define? UPGRADETABLE_DEFAULT_VERSION_MIN
#define? UPGRADETABLE_DEFAULT_VERSION_MAX
#define? UPGRADETABLE_DEFAULT_LANGUAGE
#define? UPGRADETABLE_DEFAULT_PREFIX UPGRADECODE.#. ;;# = unique number
#define? UPGRADETABLE_DEFAULT_PREFIX_MACRO <$UPGRADETABLE_DEFAULT_PREFIX>
#define? UPGRADETABLE_DEFAULT_PREFIX_VBVARIABLE <$UPGRADETABLE_DEFAULT_PREFIX>
#define? UPGRADETABLE_DEFAULT_PREFIX_GUID <$UPGRADETABLE_DEFAULT_PREFIX>
#(
#define? UPGRADETABLE_DEFAULT_ATTRIBUTES
(msidbUpgradeAttributesVersionMinInclusive
or
msidbUpgradeAttributesVersionMaxInclusive
or
msidbUpgradeAttributesLanguagesExclusive)
#)
It allows for "named" GUIDs which allow for GUID specific configuration as demonstrated by the following code:
#define ProductX.Version1 {11111111-1111-1111-1111-111111111111} ;;Define UpgradeCode for product "ProductX" (major version 1)
#define ProductX.Version1_VERSION_MIN 1.00.0000
#define ProductX.Version1_VERSION_MAX 1.99.9999
#define ProductX.Version1_PROPERTY MY_CONFIGURED_PROPERTY_NAME
#define ProductY {11111111-1111-1111-1111-333333333333} ;;Define UpgradeCode for product "ProductY" (any version)
#define FromVbVariable_PROPERTY MY_UPGRADE_CODE_FROM_VB_VARIABLE ;;Override property name for this GUID
#define {21AB9EAB-A161-45EA-9272-704EEC8175F9}_PROPERTY MY_UPGRADE_CODE_21AB9EAB
dim FromVbVariable : FromVbVariable ="{99999999-9999-9999-9999-999999999999}"
<$UpgradeTable "{21AB9EAB-A161-45EA-9272-704EEC8175F9} ProductX1.00.0002 ProductX1.00.0003 {22222222-2222-2222-2222-222222222222} =FromVbVariable">
The UpgradeCodes (version file keyword) can be passed GUIDS in the same way.
![]() | ![]() |