0
votes

I am working on a new Basic MSI install in IS 2015 Professional, it is a major upgrade of a product that was previously installed with an installscript MSI (that I think was made in 2012).

The version, product, and package code are different and they share an upgrade code.

The old install gave the option to install for all users or just the current user, the new install is currently set to be 'all users' only.

When testing in virtualbox (having installed the old version for 'all users'), the old install uninstalls, and the new version installs successfully, but a broken entry remain in Add/Remove Programs for the old version. A new entry for the new version is of course also present.

The frustrating part is I am sure I had this working at one point (initially I had problems because I had not setup an upgrade path), but I do not know what I might have changed to to cause this error.

Any ideas how I can fix this or where to look next?

2

2 Answers

0
votes

This is a known (but undocuemnted) bug in InstallShield 2012.
If you do a major or minor upgrade of an MSI project written with IS 2012, it leaves the old InstallShield_{} key under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall.
This makes Windows display the old entry in Add/Remove Programs.

I don't know of a good way to solve it, what i did is to write an InstallScript function that I call at the end of each upgrade; see below. The parameter is the product name as appears in ARP. The function removes all keys with this display name, except the one which just installed, of course!

function FixMajorUpgradeBug(szDisplayName)
    STRING szFunctionName,szBaseKey,svString,svValue;
    LIST listResults;
    NUMBER nResult;
begin
    szBaseKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
    // go over the key, and remove all InstallShield_{} keys which have the given display name, except for the version installed by this very setup
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    listResults = ListCreate(STRINGLIST);
    nResult = RegDBQueryKey(szBaseKey,REGDB_KEYS,listResults);
    if nResult = 0 then
        nResult = ListGetFirstString (listResults, svString); 
        while (nResult != END_OF_LIST) 
            if (svString % "InstallShield_{") then
                if !(svString % PRODUCT_GUID) then
                    // delete only keys with the specified product name!
                    svValue = "";
                    GU_RegistryGetValue(szBaseKey + "\\" + svString,"DisplayName",svValue);
                    if (svValue = szDisplayName) then
                        RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
                        RegDBDeleteKey(szBaseKey + "\\" + svString);
                    endif;
                endif;
            endif;
            nResult = ListGetNextString (listResults, svString); 
        endwhile; 
    endif;
    ListDestroy(listResults);
end;

Note - if your product is one of those which changes the display name after each upgrade (e.g. includes the version number in the name), you will need to do a somewhat smarter comparison than svValue = szDisplayName.

0
votes

I ended up with 2 CA's one for 32 bit and one for 64 bit. The 64-bit: "[SystemFolder]cmd.exe" /C "echo y | reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\InstallShield_[ISACTIONPROP1]"

As a commit execution CA with execute condition: VersionNT64 AND IS_MAJOR_UPGRADE

Where "ISACTIONPROP1" is defined in an upgrade path (as the "Detect Property") to hold the previous product code.

The CA's execute in the Install Exec (after "WriteRegistryValues" and Admin Exec sequence (after "ScheduleReboot").

The 32-bit CA is almost identical except the condition has "NOT VersionNT64" and the registry path is different (basically w/o the Wow6432 in the path to the key).