6.11 Launch Conditions

It is often useful to be able to impose installation prerequisites. Many applications will not run unless the target system meets certain requirements. For example, an application might run only on particular versions of Windows, or it might need the .NET Framework to be installed.

Only applications can specify launch conditions. You cannot specify launch conditions for a merge module.

The Launch Conditions view lets you add and edit such requirements and prevent installation if they are not met. As Figure 6-22 shows, the view is divided into two sections. The first section, Search Target Machine, does not impose any conditions. It merely collects information about the target machine. For example, you can add entries to search for a particular file or registry entry or the presence of a particular component. Each search item stores its result in an installer property. The installation constraints are defined in the Launch Conditions section.

Figure 6-22. Launch Conditions view

The items in the Launch Conditions section are nothing more than items with a normal Condition property and an error message. The Condition property uses the usual syntax described earlier. If the condition does not evaluate to be true, the installation will not be allowed to proceed, and the user will be shown the error text in the Message property.

You will often, but not always, add searches and conditions in pairs. For example, if you want to test whether a particular product has been installed by checking for a certain registry key, you would add a registry key search and a condition based on the result of that search. You can add a search and condition pair with the context menu for the Requirements on Target Machine nodethis will add a search and a condition that depends on the result of that search.

The .NET Framework Launch Conditions will just add a condition. (This is the MsiNetAssemblySupport condition, which is shown in Figure 6-22.) This condition does not need a corresponding search because Windows Installer provides an intrinsic property, MsiNetAssemblySupport, which indicates whether the .NET Framework is installed.

Visual Studio .NET will add this condition automatically if you add the project output from a .NET project. Note that the default behavior for installing .NET projects is therefore to fail the install if the .NET Framework is not presentit will not try to add the entire .NET Framework to your installer automatically. This usually is a good thing as the framework is large!

Although there is a series of merge modules for the .NET Framework, dotnetfxredist_x86_<xxx>.msm, where xxx is the language code, these merge modules do not install the .NET Framework. They are merely a complete list of all of the files in the framework. If an installer project has a reference to one of these merge modules, it will prevent Visual Studio .NET from listing dependencies for any framework assemblies that the project usesit is present only to keep the development environment happy. The only way to install the .NET Framework is to use the redistributable package Dotnetfx.exe.

The MSDN Library contains an article entitled 'Using Visual Studio .NET to Redistribute the .NET Framework.' This describes in detail the various options available for shipping the .NET Framework redistributable with your application. The MSDN Library can be found at http://msdn.microsoft.com/library/.

You can also add searches and conditions individually. If you are testing properties provided by Windows Installer, such as those indicating which OS version is installed or whether the .NET Framework is installed, you will not need a corresponding searchyou can just test the VersionNT or Version9X installer properties (see the following Detecting Windows Versions' sidebar). Also, you may wish to express combinational constraints (e.g., install on Windows 98 only if component Foo is installed), in which case there will not be a straightforward mapping of searches to conditions.

Detecting Windows Versions

Several intrinsic installer properties can be used to determine the exact version of Windows. The VersionNT and Version9X properties tell you the basic product version. Only one of these will be set on any given system. Windows 95, Windows 98, and Windows ME set the Version9X property to 400, 410, and 490, respectively. Windows NT 4.0, Windows 2000, and Windows XP set VersionNT to 400, 500, and 501, respectively. Windows Server 2003 also uses 501. (Windows Installer is not supported on older versions of Windows NT.)

If you need more specific information, the WindowsBuild property enables you to distinguish between certain flavors of Windows 9X. For example, early versions of Windows 95 were build 950, but Windows 95 OSR2.5 was build 1111. The original edition of Windows 98 was build 1998, but the second edition was 2222.

When installing on one of the Windows NT family (NT, 2000, XP, or Server 2003) the ServicePackLevel property is available, enabling you to find out which service packs (if any) are installed.

For example, the following condition:

(VersionNT=400 And ServicePackLevel>=6) Or VersionNT>=500

will allow installation on Windows NT 4.0 only if Service Pack 6 (or later) has been applied but will otherwise allow installation on Windows 2000, Windows XP, or subsequent members of the NT product family. It will not allow installation on any of the Windows 9x products.

You can perform three kinds of searches. You can search for the presence of a particular file, you can search for a registry entry, or you can test for the presence of a particular component. (A component search is added with the Add Windows Installer Search or Add Windows Installer Launch Condition context menu items.)

6.11.1 File Search

A file search simply looks for a particular file in a given location, optionally searching subdirectories. You should avoid using this to test for the presence of a particular piece of software. If you need a component that is normally installed by Windows Installer (i.e., it has an .msi or .msm file), then you should use the Windows Installer search. Failing that, a registry search is often more appropriate, since registry keys for a specific product are usually always in the same place, while files have a tendency not to be in the same location on all machines.

However, sometimes neither a component search nor a registry search will worksome software doesn't register its presence with Windows Installer or the registry. In this case, the only way to test for its presence is to look for one or more of its files.

You can add a file search through the context menu for the Search Target Machine node. (You can also add one with the Requirements on Target Machine's menu, which will also add a condition that tests the result of the search.) Visual Studio .NET will create a unique name for the installer property that will hold the result and store the name in the search's Property property. You will probably want to change this nameyou will use it in the corresponding condition, and it is easier for maintenance if these installer properties have meaningful names. Of course, you should also set the FileName property to indicate which file you are looking for.

The FileName property does not support wildcards. You are expected to know precisely which file you are looking for.

You should also set the Folder property to indicate where you expect to find the file. By default, this will be [SystemFolder], which is typically C:\Windows\System32. The Folder property supports several standard foldersit presents a drop-down list of these in the Properties window. Most are for normal system locations[ProgramFilesFolder], [WindowsFolder], and [FontsFolder] are all fairly self-explanatory, and [CommonFilesFolder] is usually c:\Program Files\Common Files. The list also has a [TARGETDIR] entry, which is the main application installation directory. As always, you can also use any other installer property here by enclosing it in square brackets.

If you want to search in subdirectories for the file, you can set the Depth propertythis is a number indicating how many levels of subdirectories should be searched before Windows Installer gives up.

If the mere presence of a file is not sufficient to be sure that your application will run, you can also test various other file attributes. You can specify a range of acceptable versions with the MinVersion and MaxVersion properties. MinDate and MaxDate let you specify a range of acceptable dates. (This will check the Modified date. For read-only files, this will be the same as the Created date.) Finally, if all other indicators are unreliable, you can specify the size of file you expect to find with MinSize and MaxSize.

File tests are an intrinsically fragile way of testing for a component's presence. The file may well be in different places on different systems. And just because you find a file of the right name, that doesn't necessarily mean that it is really the file you requireit could be an entirely different product that happens to have chosen the same filename. Although you can mitigate this by specifying versions, sizes, or dates, this makes your test fragile in the face of later versions of the same component. You should therefore always prefer one of the other searches whenever you have the choice.

6.11.2 Registry Search

A registry search lets you test for the presence of a registry value. You must specify the root and path with the Root and RegKey properties. Root provides a drop-down list supporting all the standard registry starting points. For example, the default is vsdrrHKLM, the HKEY_LOCAL_MACHINE root. The RegKey is relative to this root. If you want to retrieve a value other than the default, set the Value property.

The value retrieved will be stored in the installer property named in the Property property. If the key or value is not found, this value will be empty.

If you specify a RegKey but no Value, the key's default value will be retrieved. If the key has no default value, the property will be empty.

This means that there is no way to detect the presence of a key that has no default valuethe result will be the same whether the key is missing or it is present but has no default value. You should therefore always make sure that your registry searches either test for a named value or test a key that will have a default value.

If you really need to test for the presence of a key that has a default value, you will need to write your own code. Unfortunately, the only place Visual Studio .NET allows you to put your own code is in a custom action. Custom actions are run much later in the installation process. This is unsatisfactory, because it will allow the user to get all the way through the first phase of installation before discovering that there is a problem. The only way around this is to not use Visual Studio .NET to create the installer.

In a condition based on the results of a registry search, if you specify just the name of the installer property to which the result was assigned, the condition will succeed if a value was found and fail if it was not. However, if you need to, you can test for a particular value, because the property will be set to the value retrieved. For example, you might set the registry search to retrieve a CurrentVersion value of some application's key. You could then add a condition such as EXTAPPVERSION>=200 to make sure that your application can be installed only if a sufficiently recent version of the dependent application has been installed.

6.11.3 Windows Installer Search

If your application depends on another piece of software, it is best to get Windows Installer to find out whether the software is already installed. All .msi files and merge modules have unique identifiers. These are always in the form of a GUID (globally unique identifier), a 128-bit number generated with an algorithm that guarantees uniqueness.

You can add a Windows Installer search, specifying the identifier in the ComponentId property. This property expects the usual text formatting for a GUIDthe string of hexadecimal digits between braces.

If you do not know the component ID for a product that your application depends on, but you have either an .msi or .msm file for it, you can use the MSI Spy tool to discover the ID. Alternatively, you can discover component IDs programmatically with the MsiEnumComponents API.

MSI Spy used to ship with the Windows Installer SDK, which is a part of the Microsoft Platform SDK. For some reason, it has been removed from the Platform SDK but can still be downloaded from Microsoft's web site as a part of the Visual Studio 6 samples at the following URL: