Minor and Major Upgrades Using IPWI

Version 1.0.0 of SampleApp may be on a user’s machine, and you want to update it to version 1.1.0 if it’s there, or just install 1.1.0 if it’s not. Here’s an outline of some options that don’t involve patching. (These notes may be useful even if you are creating a patch, since you’ll want to make sure the upgrade works as a standalone project before turning it into a patch.)

1: Upgrading by reinstalling

Build a 1.1.0 release that includes Setup.exe; after the build, open Setup.ini in the Disk1 folder and enter “REINSTALLMODE=voums REINSTALL=ALL” (no quotes) into the CmdLine key of the [Startup] section. This won’t work, however, with the Network-Image/Compress-all-files combination (unless you—at your own risk—modify the “master” Setup.ini in the Support folder of your IPWI distribution).

If we set REINSTALL=ALL at the command line or in Setup.ini, only those features that were already installed will be reinstalled, and therefore this technique won’t work for a first-time installation (i.e., if version 1.0.0 isn’t already on the target system). One way around this is to create a custom action that undefines REINSTALL if the user is running a first-time install. Create a Type-51 (set-a-property) custom action called “fix_reinstall” in the Action/Scripts view by right-clicking the Custom Actions icon and selecting New (don’t use the wizard):

Type:51
Source:REINSTALL
Target:{} (no space between braces)

Next, go to the Sequences view and insert “fix_reinstall” in both the User Interface and Execute sequences before CostFinalize; making certain to attach the condition “Not Installed” to “fix_reinstall”. (Property names are case-sensitive; for example, the condition “Not INSTALLED” won’t work.)

After that, first-time installations and reinstallations both behave correctly.

Summary:

  • Change the package code and product version;
  • Do not change the product code or upgrade code;
  • If the upgrade contains any new features, set the ADDLOCAL, COMPADDLOCAL, etc., properties at the command line or in Setup.ini, or use the AddLocal control event (see the MSI help pages “Using Transforms to Add Resources” and “Changing the Component Code” for guidelines);
  • If you need to remove any files or registry data during the upgrade, add records to the RemoveFile or RemoveRegistry tables of the newer database.

2: Upgrading by launching MsiExec

Uninstall any previous versions of the product by launching MsiExec in a custom action, as described in InstallShield KB article Q104221. Change the Product Code in the 1.1 project, write a custom action to detect the earlier version (perhaps using the MsiGetProductInfo API, setting a property FOUNDV100 to 1 if the product is installed), create a custom action “uninstall100”—

Type: 34 (launch an executable + stored in the Directory table)
Source: SystemFolder
Target: msiexec.exe /x {version-1.0.0-product-code} /qb

—insert “uninstall100” into the UI sequence after CostFinalize, with a condition that evaluates to True if the earlier version is found (e.g., “FOUNDV100=1”; the condition should probably also include “And Not Installed”). Better yet, if FOUNDV100=1, display a custom dialog box that reads “May I remove the earlier version…?”, and then run “uninstall100” if the user clicks Yes, and cancel the whole thing if the user clicks No.

A drawback is that this doesn’t work if the user runs the 1.1 setup silently; it also goes against the “philosophy” of Windows Installer, since the User Interface sequence should only ask the user questions and query the target system, and not alter the target system.

Summary:

  • At the very least, change the package code and product code.

3: Major upgrades

For major upgrades (e.g., updating SampleApp 1.1 to 2.0.0), there’s a third option. Using IPWI 1.10 or later (and assuming the target system will have version 1.1 or later of the Windows Installer service), write information to the Upgrade table using Power Editor (you’ll have to change the Product Code for this to work). Here’s a sample row:

UpgradeCode: {upgrade-code} (should be the same for both versions)
VersionMin: 0.0.0
VersionMax: 2.0.0 (by default, “endpoints” aren’t included)
Language:  
Attributes: 1025 (1 + 1024, migrate 1.x feature states + detect all langs.)
Remove:  
ActionProperty: OLDPRODUCTS

(Note that Windows Installer uses only the first three fields of the ProductVersion property; the Upgrade table can’t tell the difference between, say, versions 1.1.1.1 and 1.1.1.2 of a product. Also note that the Attributes field can accept flags that specify whether to include the VersionMin and VersionMax “endpoints” when performing version comparisons.)

In the Property Manager (in the Advanced Views section of the IDE), add a property called SecureCustomProperties with the value “OLDPRODUCTS” (no quotes). What happens is, the FindRelatedProducts action looks for installed products with the upgrade code we specified in the Upgrade table, and sets OLDPRODUCTS to the product codes of any installed products; later, the RemoveExistingProducts invokes a nested-(un)install action to remove any products whose codes are stored in OLDPRODUCTS. If no old versions of the product are installed, nothing special happens.

One thing to look out for is that the ALLUSERS property has to be the same for the installed product and the upgraded product; one can write a custom action that sets the appropriate value to ALLUSERS. (IPWI versions 1.5 and later automatically include such a custom action, a DLL custom action called ISSetAllUsers, which is described in the online help.)

A similar technique (adding a similar row to the Upgrade table, using the detect-only bit in the Attributes column; see the MSI help page “How do I prevent an old package from installing over a newer version?”) in the old product lets you prevent users from installing an older version of a product over a newer one.

Summary:

  • Change the package code, product version, and product code;
  • As a rule, don’t change the upgrade code;
  • As a rule, you don’t need to set REINSTALLMODE or REINSTALL when deploying a major upgrade;
  • Do not add OLDPRODUCTS, etc., to the Property Manager, except as the value of the SecureCustomProperties property.

What codes do I need to change?

Package CodeProduct VersionProduct CodeUpgrade Code
Small updatex   
Minor upgradexx  
Major upgradexxx 

Note that the Upgrade code never changes; having a constant upgrade code ensures a setup program will recognize both earlier and later versions of itself.

The Package Code appears under the Summary Information Stream icon; and the Product Version, Product Code, and Upgrade Code appear under the Product Properties icon, all under (1) Organize Your Setup > General Information in the IPWI IDE. Moreover, the Releases view of IPWI 2.x allows you to specify a per–build configuration package code, product version, product code, and upgrade code.

To change these codes from an automated process, you can use the IPWI Automation interface. (See the IPWI help topics under “Automation Interface”.) Note that IPWI 2.x has a Generate Package Code setting for each product configuration in the Releases view, which performs this automatically.

For example, here is code for a Visual Basic executable that changes the package code for a project file (.ism file) passed as an argument on the command line.

Option Explicit

Public Type GUID_t
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type

Public Const S_OK = 0

Private Declare Function CoCreateGuid Lib "OLE32.dll" (pGuid As GUID_t) As Long

Private Declare Function StringFromGUID2 Lib "OLE32.dll" _
    (ByRef rguid As GUID_t, ByVal lpsz As String, ByVal cchMax As Long) As Integer

Sub Main( )

Dim oProject ' As ISWiAutomation.ISWiProject
Dim newGuid As GUID_t
Dim strIsmPath As String, strPackageCode As String
Dim iChars As Integer, lReturn As Long

On Error GoTo ErrorHandler

If Command$ = "" Then
    MsgBox "Usage: ChangePkgCode <path-to-ISM>", vbInformation + vbOKOnly
    Exit Sub
End If

strIsmPath = Command$

' in case user put ISM path in quotation marks...
If Left$(strIsmPath, 1) = """" Then
    strIsmPath = Right$(strIsmPath, Len(strIsmPath) - 1)
    strIsmPath = Left$(strIsmPath, Len(strIsmPath) - 1)
End If

lReturn = CoCreateGuid(newGuid)

If (lReturn <> S_OK) Then
    MsgBox "CoCreateGuid failed!" & vbCrLf & "(It's not your fault.)", vbExclamation + vbOKOnly
    Exit Sub
End If

strPackageCode = Space(100)

iChars = StringFromGUID2(newGuid, strPackageCode, Len(strPackageCode))
strPackageCode = StrConv(strPackageCode, vbFromUnicode)
strPackageCode = Left(strPackageCode, iChars - 1)
strPackageCode = UCase(strPackageCode)

Set oProject = CreateObject("ISWiAutomation.ISWiProject")

oProject.OpenProject strIsmPath

oProject.PackageCode = strPackageCode

oProject.SaveProject
oProject.CloseProject

Set oProject = Nothing

Exit Sub

ErrorHandler:

MsgBox "Something happened!" & vbCrLf & vbCrLf & _
    "Error number: " & Err.Number & vbCrLf & _
    "Error description:" & vbCrLf & Err.Description

End Sub

(Note that we can’t do this specific example from a VBScript file, since VBScript doesn’t support calling Windows APIs.) Changing the Product Version or Product Code from a script or application follows similarly.


Last modified 19 February 2001.
Robert Dickau, InstallShield Software Corp.

 

English News Discussions Windows Installer Related Tools More Help InstallScript About InstallSite Shop Site Search
deutsch Neuigkeiten Diskussionsgruppen Windows Installer MSI FAQ Artikel     Shop Suche

Copyright © by InstallSite Stefan Krueger. All rights reserved. Legal information.
GERMAN Impressum,Datenschutzerklärung, Haftungsausschluss
By using this site you agree to the license agreement. Webmaster contact.