Be Seeing You: Detecting Installed Products

Each InstallShield project type has a mechanism for detecting and updating a project of the same type: InstallScript projects support updates packaged as differential or full releases, and Windows Installer projects support minor upgrades and major upgrades packaged as patches or full installation packages. For some background information please dowload our Building MSI Updates and Patches white paper.

A common requirement is to enable your new product’s installer to automatically detect and sometimes remove an older version or a related product. In today’s installment, we’ll look at detecting products installed using different project types.

The four main cases are:

  1. MSI installer detecting another product that was installed using MSI
  2. MSI installer detecting a product installed using something other than MSI
  3. InstallScript installer detecting product installed using MSI
  4. InstallScript detecting non-MSI

(In some of the examples below, we’re making the simplifying assumption that the products to detect have been installed per-machine.)

MSI detecting another MSI

Assuming the two products’ product codes—their ProductCode property values—are different, you can create a major upgrade item with the detect-only flag set for one product to detect the other. (If the product codes are the same, you can use the Installed property or the condition on SetupResume to detect maintenance mode or a minor upgrade.) This functionality takes as input the upgrade code and a range of versions from the product to be detected, and populates a property whose name you specify with the product code of any matching products it detects; you can then use the detection property in a condition to display a special message if the other product is detected.

To determine the upgrade code of the other product, open its project in InstallShield and look in General Information > Upgrade Code. If you don’t have the project, you can open its MSI database in Direct Edit mode to see the UpgradeCode value.

To create the major upgrade item in InstallShield, open the Media > Upgrades view; right click the Upgrade Windows Installer Setup icon and select Add Major Upgrade Item. With the item selected, select the Advanced tab. For the Upgrade Code field, enter the upgrade code of the product to detect, and in the version fields set a range of versions to detect.

To detect the other product, set Detect Only to “Yes”, and enter an all-caps (public) property name such as “FOUND_IT” in the Detect Property field.

SeeingYouBlog1

When you launch the installer, after the FindRelatedProducts action runs, you can use FOUND_IT as a condition to display additional information or take additional action if the other product is there, or use Not FOUND_IT to do something if the product isn’t found. See, for example, the tip Informing a User When a Major Upgrade Will Take Place.

MSI detecting non-MSI

To detect a product that was installed with something other than Windows Installer, you’ll need to look for some other telltale sign. A common piece of evidence to use is the other product’s uninstallation registry key, found in HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionUninstallSomething. The Something at the end is usually a product GUID, though really old InstallScript installations used the product name, and products installed with some other technology might use something else.

To detect if a value (say, the UninstallString value) inside that registry key is there, you can use the System Search Wizard. In the Behavior and Logic view, select System Search. In the view, right click in the view and select Add to create a new search.

In the System Search Wizard, in the What do you want to find? panel, select “Registry entry”.

SeeingYouBlog2

In the How do you want to look for it? panel, enter the product’s uninstall-key information. In the following figure, the product’s uninstallation key is the GUID “{CCCCCCCC-CCCC-…}”.

SeeingYouBlog3

In the What do you want to do with the value? panel, enter a property name such as “FOUND_NON_MSI”.

SeeingYouBlog4
At run time, after the AppSearch action runs, the “FOUND_NON_MSI” property will be filled in if the registry key and value you specified exist, and you can use it as a condition for an action or user interface element.

In addition, you can use system searches to populate a property based on other clues to a product’s existence, such as a file, directory, or XML entry.

InstallScript detecting MSI

For an InstallScript project to detect an MSI-installed product, you can prototype and call the MsiQueryProductState API function with the target product’s product code.

To use this API function, add the following prototype for the ANSI version of the function, which is exported from the system library msi.dll, somewhere in your InstallScript source file:

prototype int msi.MsiQueryProductStateA(byval string);

Your OnAppSearch event handler can then (say) display a message box based on the result of the function. If MsiQueryProductState returns 5, the product is installed for the current user; other values indicate cases where the product is advertised, installed for a different user, or not present at all.

function OnAppSearch( )
begin
if (MsiQueryProductStateA("{BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB}") = 5) then
MessageBox("That MSI product is installed for the current user.", INFORMATION);
else
    MessageBox("That MSI product is not installed for the current user.", INFORMATION);
endif
end;

You can get additional information about the installed product—such as its version or install location—using MsiGetProductInfo. And to query whether products with a particular upgrade code are present, you can use MsiEnumRelatedProducts instead. For more information about these APIs, see the Windows Installer help library.

InstallScript detecting non-MSI

For an InstallScript to detect a product installed with something other than Windows Installer, you can look for the same kinds of telltale signs described above, such as the other product’s uninstallation key. (If the products are both InstallScript and the products’ GUIDs are the same, you can use the MAINTENANCE or UPDATEMODE variable or the VerProduct- functions to detect maintenance or update mode or to read installed product properties.) For example, to detect a product’s uninstallation key, you can use InstallScript code similar to the following:

RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
if (RegDBKeyExist("SOFTWAREMicrosoftWindowsCurrentVersionUninstall" +
" {AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}") = 1) then
MessageBox("That non-MSI product is installed.", INFORMATION);
else
    MessageBox("That non-MSI product is not installed.", INFORMATION);
endif;

In addition, you can detect other traces of a product, such as detecting a file at a known location with Is with FILE_EXISTS or searching for a file using FindAllFiles.

So there you have the four main project examples for automatically detecting installed products. Please feel free to share your thoughts and experiences!

3 comments on “Be Seeing You: Detecting Installed Products

  1. Bob on

    On a 64-bit PC, once has to also search in this HKLM space,
    SOFTWAREWow6432NodeMicrosoftWindowsCurrentVersionUninstall

    Will all InstallShield installers write to the Wow3264Node area of the registry?

    Reply
  2. Debbie Urman on

    You’re right that you may need to check both 32-bit and 64-bit locations on 64-bit machines. When referring to registry paths, however, you should avoid direct use of the Wow6432Node key name to specify 32-bit registry locations, since in 32-bit scenarios it is redundant. Instead you should use other means to access either the 32-bit or 64-bit registry areas.

    In your example, it looks like you are probably using InstallScript; for InstallScript code, the proper means are specifying the REGDB_OPTION_WOW64_64KEY option with the REGDB_OPTIONS variable to refer to a 64-bit key, or leaving it out to refer to a 32-bit key (or, for use with the Registry view, there is a 64-bit setting on each component). Then you can use the REGDB_OPTION_USE_DEFAULT_OPTIONS option with REGDB_OPTIONS to refer to the 32-bit area of the registry. (Since some Windows functionality that could be used by the installation requires that redirection be enabled to work, Windows documentation recommends that you disable redirection only for as long as necessary.)

    For InstallShield prerequisites, there is a similar 32-bit or 64-bit option, and so forth.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *