Standalone applications will be installed into their own folders under Program Files
---we've already seen how to accomplish this. But plugins, add-ons or similar additional products, not meant for standalone use but to accompany other programs already installed on the system (either your own or some third party) has to learn when and where to install themselves first. Asking the user to provide this information would be both inelegant and possibly dangerous in many cases, thus we need means of querying the registry, to consult .ini files already on the system or to look for actual folders and files to determine what to do.
When we look for any of those items, the result will be stored in a property (a string variable). So, we start by specifying the property (note that the Id
we use is the same name we've already used in our first sample, denoting the target folder we install to). Inside the Property
tag, we launch a registry search. The attributes speak for themselves:
<Property Id="INSTALLDIR">
<RegistrySearch Id='AcmeFoobarRegistry' Type='raw' Root='HKLM' Key='Software\Acme\Foobar 1.0' Name='InstallDir' />
</Property>
If the registry search was successful (that is, the registry entry specified does exist), its value will be assigned to our INSTALLDIR
property, ready to be used for our purposes. To check this out, add this line after the Media
tag in our previous sample and save it to SampleRegistry.wxs (or, just download it again). Compile it but before you start the installation, go into the registry and create the HKEY_LOCAL_MACHINE\SOFTWARE\Acme\Foobar 1.0
key. Create a new string value named InstallDir
and set it to an empty folder you've just created anywhere on your system. Run the installer with logging enabled.
If you did everything right, our three sample files will appear in this new folder. Also note the shortcuts (in the Start Menu and on the Desktop) to point to this new location now.
Similar information can come from other sources as well. Let's assume a \Windows\SampleRegistry.ini
file (you can only read these files if they are located in the system folder):
[Sample]
InstallDir=C:\InstallHere
Replace the previous section with this new one:
<Property Id="INSTALLDIR">
<IniFileSearch Id='AcmeFoobarIniFile' Type='directory' Name='SampleRegistry.ini' Section='Sample' Key='InstallDir' />
</Property>
There might be cases when simply knowing the folder is not enough: you have to look into the folder and make sure a given file exists there. Depth=n
can be used to instruct the installer to look n levels deeper than the specified Path
. Zero or a missing Depth
attribute means only to look in the specified folder, not below it. We use square brackets in Path
to tell the installer to use the value of the INSTALLDIR
property---bracketed names will be looked up and if found, replaced with their actual value. If not found, the string will remain unchanged.
<Property Id="FILEEXISTS">
<DirectorySearch Id="CheckFileDir" Path="[INSTALLDIR]" Depth="0">
<FileSearch Id="CheckFile" Name="Lookfor.txt" />
</DirectorySearch>
</Property>
If the file has been found, its full path will be assigned to the FILEEXISTS
property, otherwise it will be left unassigned. You can check this if you build this sample (you need both the previous RegistrySearch
and this fragment) and then run it with logging enabled. Observe that if you first put the file Lookfor.txt
into the folder specified in the registry, the log will contain a reference to FILEEXISTS
, with the full path of the file as its value.
Although we don't yet have a user interface, it's already worth noting that properties meant to receive their value from any interaction with the user, passing that value to the installation logic (eg. destination folders or features selected by the user) need to be public properties. To ensure their public status, their name has to be in all uppercase letters.
It is also worth noting that Windows Installer has better ways of upgrading your product than to look for specific registry entries of the previous installation. You should use these features whenever you can---but you need some patience until we reach them during our discussion.