Windows

This section summarizes all of the Windows-specific features that InstallBuilder provides as well as describes solutions for commonly-found scenarios when creating Windows installers.

Windows Registry

The Windows Registry is a central hierarchical database in which Windows stores configuration information about the system and information about the installed applications and devices.

It can be manually edited using the command line through the reg.exe command of executing the graphical registry editor, regedit.exe. It is organized in keys, which can contain other keys (subkeys) and values, which can have different formats. The root keys on Windows, which contain all of the other subkeys and values are:

  • HKEY_LOCAL_MACHINE (HKLM): This key contains information about the configuration of the system that is common for all users. One of its subkeys, HKLM\SOFTWARE, contains information about the software in the machine organized by vendor (including Microsoft, for Windows itself). This subkey is especially useful to store per-application information such as the version installed and the installation directory. This makes the detection of existing installations of your product a trivial task using InstallBuilder registry actions.

  • HKEY_USERS (HKU): Contains all the user profiles configuration in the system.

  • HKEY_CURRENT_USER (HKCU): This key contains information about the current logged-in user. It is not a real key but a link to the appropriate subkey inside HKEY_USERS. The same information is stored in both keys and writing in one of them automatically updates the other.

  • HKEY_CLASSES_ROOT (HKCR): Contains information about registered applications such as file associations. From Windows 2000, this key is a mix of the values in HKCU\Software\Classes and HKLM\Software\Classes. If a value is defined in both, the one in HKCU\Software\Classes is used so per-user configuration always takes precedence.

  • HKEY_CURRENT_CONFIG: Contains information about the hardware profile used by the computer at boot time.

These main keys contain many other subkeys, which allow hierarchically organizing the registry. Inside those keys, the data is stored in values, which allow the following types:

  • REG_NONE: Data without type defined, treated as binary information.

  • REG_SZ: Used for string values, for example paths.

  • REG_EXPAND_SZ: This value is also intended to hold string values but in addition allows them to contain environment variables, which will be expanded when reading the data. For example if the data stored is %TEMP%\myFolder, it will be automatically expanded to C:\Users\user\AppData\Local\Temp\myFolder when accessed while a regular REG_SZ value would have been resolved to just %TEMP%\myFolder. The Path environment variable defined in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment is a good example of a REG_EXPAND_SZ value.

  • REG_BINARY: Binary data.

  • REG_DWORD: A 32bit unsigned integer (little-endian)

  • REG_DWORD_BIG_ENDIAN: A 32bit unsigned integer (big-endian)

  • REG_LINK: This is used to create symbolic links to other keys, specifying the root key and the path to the target key.

  • REG_MULTI_SZ: Stores a list of non-empty list of elements, separated by the null character. An example of this key is the value PendingFileRenameOperations under the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager, used to specify files to rename the next time the machine is restarted.

  • REG_RESOURCE_LIST: A resource list. Used to store nested arrays by hardware devices

Managing the Windows Registry From InstallBuilder

Although the registry can be managed using the reg.exe command line tool using a <runProgram> action, InstallBuilder includes a set of built-in actions that allow it to easily read, write and even find data in the registry:

  • <registryGet>: Store the value of a registry key in an installer variable. If the key or name does not exist, then the variable will be created empty.

<registryGet>
  <!-- By default, InstallBuilder stores the installation
  directory in this key -->
  <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}</key>
  <name>Location</name>
  <variable>previousInstallDir</variable>
 </registryGet>
  • <registrySet>: Create a new registry key or modify the value of an existing registry key.

<registrySet>
   <!-- Update the installed version -->
   <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}</key>
   <name>Version</name>
   <type>REG_SZ</type>
   <value>${project.version}</value>
</registrySet>
  • <registryDelete>: Delete a registry entry. If the entry to delete is only a registry key and it does not exist, the action will be ignored. Deleting a registry value (key + name combination) that does not exist will trigger a regular error.

<!-- Clean installed keys -->
<registryDelete>
   <abortOnError>0</abortOnError>
   <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}</key>
   <name></name>
</registryDelete>
  • <registryGetKey>: Store in variable the first registry key that matches the given pattern, or set the variable to empty otherwise. The search is case-sensitive for the whole key provided.

<!-- Gets the first key referencing one of the applications
under ${project.vendor} -->
<registryGetKey>
  <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\*</key>
  <variable>application</variable>
</registryGetKey>
  • <registryGetMatch>: Store the value of the first match of a registry key matching a certain expression in an installer variable. If the key or name does not exist, then the variable will be created empty. The name can contain a wildcard expression (using *)

<!-- Gets the data of the first value in our
application key -->
<registryGetMatch>
  <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}</key>
  <name>Loc*</name>
  <variable>location</variable>
</registryGetMatch>
  • <registryFind>: Retrieve the first registry hive and content matching a certain expression and store it as a list in an installer variable. If no match is found the variable will be created empty. This is an extension of the <registryGetMatch> and <registryGetKey> actions, and much more powerful. If the <findAll> tag is set to 1, it will return a space-separated list of all of the matches. The result of this action is intended to be interpreted using a foreach action:

<registryFind>
  <dataPattern>*Program Files*</dataPattern>
  <findAll>0</findAll>
  <keyPattern>*${project.fullName}*</keyPattern>
  <namePattern>*</namePattern>
  <rootKey>HKEY_LOCAL_MACHINE\SOFTWARE</rootKey>
  <searchDepth>2</searchDepth>
  <variable>result</variable>
</registryFind>
<foreach>
  <variables>key name value</variables>
  <values>${result}</values>
  <actionList>
     <showInfo>
      <text>Key="${key}"
name="${name}"
value="${value}"</text>
     </showInfo>
  </actionList>
</foreach>

A much more complex application of the <registryFind> action is explained here.

InstallBuilder also provides a <registryTest> rule:

<!-- Set update mode if we detect that a well-known
key exists -->
<setInstallerVariable>
   <name>project.installationType</name>
   <value>upgrade</value>
   <ruleList>
     <registryTest>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}\</key>
        <logic>exists</logic>
        <name>Location</name>
     </registryTest>
   </ruleList>
</setInstallerVariable>

<!-- Throw an error if a required product is not installed -->
<initializationActionList>
   <throwError>
      <text>You need to install "Some Other Product" to install ${project.fullName}</text>
      <ruleList>
        <registryTest>
          <key>HKEY_LOCAL_MACHINE\SOFTWARE\Some Vendor\Some Other Product</key>
          <logic>exists</logic>
          <name></name>
        </registryTest>
      </ruleList>
   </throwError>
</initializationActionList>

It is even possible to check the type of key:

<throwError>
   <text>The registry key was corrupted. It exists but it is not a `REG_EXPAND_SZ` name</text>
   <ruleList>
     <registryTest>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}\</key>
        <logic>exists</logic>
        <name>myPath</name>
     </registryTest>
     <registryTest>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\${project.vendor}\${project.fullName}</key>
        <logic>is_not_type</logic>
        <name>myPath</name>
        <type>REG_EXPAND_SZ</type>
     </registryTest>
   </ruleList>
</throwError>
Note
Keys representing a "path" in the registry must be separated by backslashes

When referring to a key of the registry you have to provide a "path" with all of the parent keys as you would do with a real directory. Although InstallBuilder accepts using forward slashes instead of backslashes in Windows paths, backlashes are mandatory when working with the registry.

An example of a correct reference to the key InstallBuilder:

HKEY_LOCAL_MACHINE\SOFTWARE\Backstaff\InstallBuilder

But if you use:

HKEY_LOCAL_MACHINE\SOFTWARE\Backstaff/InstallBuilder

What the installer is going to look for is a key named Backstaff/InstallBuilder, which is a perfectly valid key name but not the one you expected.

Windows Registry in 64bit Systems

When accessing the registry, 32bit applications running on 64bit Windows are presented with a different view of some of the keys. This process allows the isolation of 32 and 64bit applications. If you take a look to how the registry looks in Windows 64bit with regedit you will see that some keys include a subkey named Wow6432Node. This key contains the registry keys corresponding to the 32bit view. For example, if a 32bit application tries to access HKEY_LOCAL_MACHINE\SOFTWARE\Backstaff/InstallBuilder it will be transparently redirected to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Backstaff/InstallBuilder. This process is known as "registry redirection". The special key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node is not visible from the 32bit view, but although it is discouraged by Microsoft guidelines, in some Windows versions it can be accessed from the 64bit view.

As InstallBuilder generates 32bit applications, it will by default follow the same registry redirection when using any of its registry actions. This may be convenient if you are bundling a 32bit application or if you are trying to read keys written by other 32bit applications but there are scenarios in which it is desirable to access the 64bit view of the registry (for example if you are bundling a 64bit application).

For these scenarios, InstallBuilder includes two ways of configuring which view of the registry should be used:

  • Project-level configuration: The easiest way to make your application access the 64bit view of the registry by default is by using the project property <windows64bitMode>. As explained in the next section, this setting enables much more than just making the 64bit view of the registry visible. Although the registry redirection is just enabled in 64bit OS, this setting can be just always enabled, as it will be ignored in 32bit Windows. This way there is no need to maintain two different projects for the 32 and 64bit versions of your installer or to configure this setting at build-time. This setting is applied at the very beginning of the installation process so it cannot be configured at runtime, it must be set at build-time or hardcoded in the XML project.

<project>
  ...
  <!-- This will be ignored in 32bit
  systems without consequences -->
  <windows64bitMode>1</windows64bitMode>
  ...
</project>
Note
Is safe to always enable <windows64bitMode>

Even if you are building a 32bit installer, you can keep <windows64bitMode> enabled in you project. On 32bit systems it will just be ignored.

  • Per-action configuration: All of the registry actions explained in the previous section accept an extra tag, <wowMode>, which allows configuring the registry view that will be accessed. Its default value is none, which allows the action use the default view. Setting none when using <windows64bitMode> will make the actions use the 64bit view on Windows x64. The tag also accepts 64 (which selects the 64bit view) and 32 as values (selecting the 32bit view) as values. The same way the <windows64bitMode> tag is ignored in 32bit systems, setting 64 will also be ignored on them.

The <wowMode> tag takes precedence over the <windows64bitMode> so it is easy to configure the installer to use the 64bit view by default and just use the 32bit view when needed.

The example below tries to get the installed version of Microsoft SQL Server in the system, checking in both registry views if the platform is 64bit:

   <initializationActionList>
      <registryGet>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\CurrentVersion</key>
        <name>CurrentVersion</name>
        <variable>currentVersion</variable>
      </registryGet>
      <!-- The 64bit version takes precedence so we check it in second place -->
      <registryGet>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\CurrentVersion</key>
        <name>CurrentVersion</name>
        <variable>currentVersion</variable>
        <wowMode>64</wowMode>
        <ruleList>
           <platformTest type="windows-x64"/>
        </ruleList>
      </registryGet>
   </initializationActionList>

Or, if you are using <windows64bitMode>, force checking in the 32bit version:

<project>
   ...
   <windows64bitMode>1</windows64bitMode>
   ...
   <initializationActionList>
      <registryGet>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\CurrentVersion</key>
        <name>CurrentVersion</name>
        <variable>currentVersion</variable>
      </registryGet>
      <!-- If we are using <windows64bitMode> and we couldn't detect
      a 64bit version , check the 32bit key -->
      <registryGet>
        <key>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\CurrentVersion</key>
        <name>CurrentVersion</name>
        <variable>currentVersion</variable>
        <wowMode>32</wowMode>
        <ruleList>
           <platformTest type="windows-x64"/>
           <isTrue value="${project.windows64bitMode}"/>
           <compareText text="${currentVersion}" logic="equals" value=""/>
        </ruleList>
      </registryGet>
   </initializationActionList>
   ...
</project>

In some versions of Windows, a 32bit key on Windows x64 can be accessed in two ways:

  • Using the <wowMode>32</wowMode> setting (selecting the 32bit view):

<project>
  ...
  <windows64bitMode>1</windows64bitMode>
  ...
  <initializationActionList>
    <registryGet>
       <key>HKEY_LOCAL_MACHINE\SOFTWARE\Backstaff\InstallBuilder Enterprise</key>
       <name>Version</name>
       <variable>ibVersion</variable>
       <wowMode>32</wowMode>
       <ruleList>
          <platformTest type="windows-x64"/>
       </ruleList>
    </registryGet>
  </initializationActionList>
  ...
</project>
  • Accessing the redirected key in the 64bit registry:

<project>
  ...
  <windows64bitMode>1</windows64bitMode>
  ...
  <initializationActionList>
    <!-- This should be avoided -->
    <registryGet>
       <key>HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Backstaff\InstallBuilder Enterprise</key>
       <name>Version</name>
       <variable>ibVersion</variable>
       <ruleList>
          <platformTest type="windows-x64"/>
       </ruleList>
    </registryGet>
  </initializationActionList>
  ...
</project>

The latter way of accessing the 32bit key is discouraged by Microsoft guidelines and does not work in some Windows versions. The reason is that Wow6432Node is a special key and is not intended to be accessed directly.

Note
Never access 32bit keys using the 64bit registry view through the Wow6432Node key

Microsoft guidelines discourage accessing key under Wow6432Node directly from the 64bit view of the registry. It is known to fail in some Windows versions. The correct way of accessing a 32bit key from the 64bit view (enabled using <windows64bitMode>) is setting wowMode="32".

InstallBuilder built-in registry keys

By default, all InstallBuilder-generated installers write some values in the registry. These values can be organized in two keys:

Software Key

InstallBuilder writes some basic information about the installed version of the product under the key:

HKEY_LOCAL_MACHINE\SOFTWARE\${project.windowsSoftwareRegistryPrefix}

Where ${project.windowsSoftwareRegistryPrefix} resolves to the value of <windowsSoftwareRegistryPrefix> (${project.vendor}\${product_fullname} by default).

The values written are:

  • Version: Configured through the <version> project property.

  • Location: The installation directory (${installdir}).

  • Language: The installation language (${installation_language_code}).

To prevent this key from being created you just have to set <windowsSoftwareRegistryPrefix> to empty.

Another case in which the key won’t be created is when <installationType> is set to normal and <createUninstaller> is set to 0. This will also result in no uninstaller being created.

If <installationType> is set to upgrade, the installer will automatically update the Language and Version values if they exist (written in a previous installation being upgraded), regardless of the value of <windowsSoftwareRegistryPrefix> or <createUninstaller>. In addition, when working in upgrade mode, if the Language value exists, its value will be used as the default installation language.

Note
How to prevent the creation of the Software keys

To prevent the installer from writing the values under the HKEY_LOCAL_MACHINE\SOFTWARE key, just set the <windowsSoftwareRegistryPrefix> to empty.

Add/Remove Program Menu Key

The information stored in this key is used to populate the Add/Remove Program Menu. The information is organized in a set of values under the key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${project.windowsARPRegistryPrefix}

Where ${project.windowsARPRegistryPrefix} resolves to the value of <windowsARPRegistryPrefix> (${project.fullName} ${project.version} by default). The values written by InstallBuilder are:

  • DisplayName: Configured through the <productDisplayName> project property.

  • DisplayVersion: Configured through the <version> project property.

  • Publisher: Configured through the <vendor> project property.

  • DisplayIcon: Configured through the <productDisplayIcon> project property.

  • UrlInfoAbout: Configured through the <productUrlInfoAbout> project property.

  • Comments: Configured through the <productComments> project property.

  • Contact: Configured through the <productContact> project property.

  • HelpLink: Configured through the <productUrlHelpLink> project property.

  • UninstallString: Contains the path to the uninstaller.

  • InstallLocation: The installation directory (${installdir})

  • NoModify: If set to 1, disables the Modify button in the ARP Menu.

  • NoRepair: If set to 1, disables the Repair button in the ARP Menu.

  • EstimatedSize: The size of the installed application. This value is calculated at runtime based on the installed files.

  • InstallDate: The installation date.

This key is also just created when <installationType> is set to normal and <createUninstaller> is set to 1.

If <installationType> is set to upgrade, the installer will update the DisplayVersion and DisplayName values if they exist (written in a previous installation being upgraded).

Setting <installationType> to normal and <createUninstaller> to 0 will avoid creating or updating any key.

These keys are automatically deleted when uninstalling the product so you don’t have to add any additional logic to the uninstaller for that.

Windows 64bit

Creating native 64bit installers

Starting in version 19.5.0, InstallBuilder support the windows-x64 platform, which allows producing real Windows 64bit runtimes (in contrast to the legacy 64bit-capable installers, which used a 32bit runtime).

When using the new platform, you have to take into account that using windows in folders will result in no file being packed, as that instructs the builder to use it when building 32-bit installers. The snippet below explains how to define different set of platforms for Windows 32bit and Windows 64bit:

   <project>
      <shortName>myProject</shortName>
      <version>1.4</version>
      <componentList>
          <component>
             <name>windowsx86</name>
             ...
             <folderList>
                <folder>
                   <name>windowsx86</name>
                   <destination>${installdir}</destination>
                   <!-- windows means Windows 32bit, and it will be
                   packed when using 'windows' as build platform -->
                   <platforms>windows</platforms>
                   <distributionFileList>
                      <distributionDirectory>
                          <origin>path/to/32bit/windows-app</origin>
                      </distributionDirectory>
                   </distributionFileList>
                </folder>
             </folderList>
          </component>
          <component>
             <name>windowsx64</name>
             ...
             <folderList>
                <folder>
                   <name>windowsx64</name>
                   <destination>${installdir}</destination>
                   <!-- windows-x64 means Windows b4bit, and it will be
                   packed when using 'windows-x64' as build platform -->
                   <platforms>windows-x64</platforms>
                   <distributionFileList>
                      <distributionDirectory>
                          <origin>path/to/64bit/windows-app</origin>
                      </distributionDirectory>
                   </distributionFileList>
                </folder>
             </folderList>
          </component>
      </componentList>
   </project>

You can then build the different architectures by using windows or windows-x64 as build platform:

$> builder build project.xml windows
$> builder build project.xml windows-x64
Note

If you are curious, you can check how to simulate the windows-x64 build platform with older InstallBuilder versions that only supported windows 32bit platform checking the legacy Creating specific Windows 64bit installers section

Note

Legacy Windows 64bit capable installers used different InstallBuilder features such as the <windows64bitMode> project property or the <wow64FsRedirection> action. All these features are no longer required in pure Windows 64bit runtimes, but they won’t cause any problem if you keep them, they will be simply ignored when running with the 64bit runtime

Note

Don’t forget to use the windows-x64 platform when building Windows 64bit installers. Folders specifying windows as the only platform will be ignored unless you select windows as the build platform (which will generate a 32bit installer).

A similar restriction applies to the ${platform_name} variable when used at build time. When building a 64bit installer, it will equal to windows-x64, in contrast to its value when building 32bit Windows installer, windows. If you want to limit some build time actions to any Windows architecture (32 or 64bit), you can use a <compareText> rule with contains logic:

<project>
   <preBuildActionList>
      <showInfo text="Building Windows 32bit installer">
         <ruleList>
           <compareText text="${platform_name}" logic="equals" value="windows"/>
         </ruleList>
      </showInfo>
      <showInfo text="Building Windows 64bit installer">
         <ruleList>
           <compareText text="${platform_name}" logic="equals" value="windows-x64"/>
         </ruleList>
      </showInfo>
      <showInfo text="Building any Windows arch installer (32 or 64 bit)">
         <ruleList>
           <compareText text="${platform_name}" logic="contains" value="windows"/>
         </ruleList>
      </showInfo>
   </preBuildActionList>
</project>
Migrating From Windows 32bit Installers

As explained in the previous section, Windows x64 (windows-x64) is a new platform, which was not previously available and is completely independent from the previous windows target. Because of that, if you open a project with folders specifying windows in its <platforms> tag, and you build using windows-x64 target, they won’t be packed. The solution is to choose the proper installer target when building (Windows from the Builder GUI Build Platform in the Packaging section or windows as the build platform via command line) or to adapt your installer to support both windows and windows-x64:

   <project>
      <shortName>myProject</shortName>
      <version>1.4</version>
      <componentList>
          <component>
             <name>default</name>
             <folderList>
                <!-- This is packed when selecting "Windows" (windows) -->
                <folder>
                   <name>windowsx86</name>
                   <destination>${installdir}</destination>
                   <!-- windows means Windows 32bit, and it will be
                   packed when using 'windows' as build platform -->
                   <platforms>windows</platforms>
                   ...
                </folder>
                 <!-- This is packed when selecting "Windows x64" (windows-x64) -->
                <folder>
                   <name>windowsx64</name>
                   <destination>${installdir}</destination>
                   <!-- windows-x64 means Windows b4bit, and it will be
                   packed when using 'windows-x64' as build platform -->
                   <platforms>windows-x64</platforms>
                   ...
                </folder>
                <!-- This is packed when selecting any Windows target -->
                <folder>
                   <name>allwindows</name>
                   <destination>${installdir}</destination>
                   <!--  This will be packed for all windows targets -->
                   <platforms>windows-x64 windows</platforms>
                   ...
                </folder>
             </folderList>
          </component>
      </componentList>
   </project>

If you are just upgrading InstallBuilder and are not interested in the Windows x64 support, you can keep using the Windows build target as you were previously doing. In addition, if you want to make sure you do not build Windows x64 by mistake, you can add the below snippet to your project, that will refuse to build it:

<project>
   ...
   <preBuildActionList>
        <throwError text="Windows x64 build target is not supported">
              <ruleList>
                    <compareText text="${platform_name}" logic="equals" value="windows-x64"/>
              </ruleList>
        </throwError>
   </preBuildActionList>
   ...
</project>
Note

The 32bit version of InstallBuilder is still available for download (and is capable of building Windows x64 if selected) still defaults to build 32bit installers. However, if you download the 64bit version of InstallBuilder, the new default platform is "Windows x64". This could result in building the windows-x64 target instead of windows by mistake. To help to troubleshoot those cases, we are including a warning message in the builder (only when building the new Windows x64 target):

 Building Sample Project windows-x64
 0% ______________ 50% ______________ 100%
 #########################################


Warning: You are building a 'windows-x64' installer but you are not including any folder containing 'windows-x64' in its <platforms>. However, some of them include 'windows', which won't be packed. You may be building the wrong Windows installer target for your project. If you know what you are doing, please disregard this warning.

Check the below article for more information:

http://installbuilder.com/docs/installbuilder-userguide.html#migrating_from_windows_32bit_installers

This is just a heuristic warning based on the current folders added to your project. If checks if you are building windows-x64 and not including any folder specifically listing in its platforms. In that case, the builder looks for folders including specific windows platforms, and if that is the case, the warning is triggered.

It doesn’t mean you are doing something incorrect if you know what you are doing. It is perfectly valid only including spefic folders for windows and not for windows-x64. For example:

   <project>
      ...
      <componentList>
          <component>
             <name>default</name>
             <folderList>
                <!-- Most of the files will be packed here, including windows and windows-x64
                    as it includes "all" as the build platform -->
                <folder>
                   <name>allfiles</name>
                   <destination>${installdir}</destination>
                   <!-- windows means Windows 32bit, and it will be
                   packed when using 'windows' as build platform -->
                   <platforms>all</platforms>
                   ...
                </folder>
                 <!-- Only pack the "move to windows x64" documentation in Windows 32 bit -->
                <folder>
                   <name>migrateto64docs</name>
                   <destination>${installdir}</destination>
                   <platforms>windows</platforms>
                   ...
                </folder>
             </folderList>
          </component>
      </componentList>
   </project>

In the above example, windows-x64 is not specifically mentioned but windows is (to pack documentation to inform your users they can migrate to the 64bit version of your application, for example). Even if the code is correct, it will trigger the warning, just to make sure you did not build the wrong target by mistake.

Note

This warning will be removed from future versions of InstallBuilder but if you are incorrectly receiving it and want to silence it, you can add a dummy windows-x64 folder to make the validation pass:

   <project>
      ...
      <componentList>
          <component>
             <name>default</name>
             <folderList>
                <!-- Just to make the builder happy -->
                <folder name="dummyWin64folder" platforms="windows-x64"/>
                ....
                <folder>
                   <name>allfiles</name>
                   <destination>${installdir}</destination>
                   <!-- windows means Windows 32bit, and it will be
                   packed when using 'windows' as build platform -->
                   <platforms>all</platforms>
                   ...
                </folder>
                <folder>
                   <name>migrateto64docs</name>
                   <destination>${installdir}</destination>
                   <platforms>windows</platforms>
                   ...
                </folder>
             </folderList>
          </component>
      </componentList>
   </project>

Legacy Windows 64bit capable installers

If you are using a version of InstallBuilder older than 19.5.0 you won’t be able to generate pure Windows 64bit installers, but InstallBuilder 32bit installers can be used to properly deploy applications and drivers to 64bit operating systems.

Although 32bit installers are fully compatible with 64bit systems, they are treated differently than native 64bit applications. They most important differences are:

  • When accessing the registry, they are automatically redirected to keys in the 32bit view of the registry. This can be configured using the <wowMode> tag in the registry actions or through the <windows64bitMode> project property. The registry redirection process is explained in detail in the Windows 64bit registry section.

  • When executing Windows commands (such as cmd.exe) the filesystem redirection provides a 32bit binary version of them. Specifically the below directories are redirected (%windir% usually resolves to c:\Windows):

    • Access to %windir%\System32 is redirected to %windir%\SysWOW64

    • Access to %windir%\lastgood\system32 is redirected to %windir%\lastgood\SysWOW64

    • Access to %windir%\regedit.exe is redirected to %windir%\SysWOW64\regedit.exe.

      With some exceptions, which are not redirected:

    • %windir%\system32\catroot

    • %windir%\system32\catroot2

    • %windir%\system32\drivers\etc

    • %windir%\system32\logfiles

    • %windir%\system32\spool

This can be solved by manually disabling the redirection using the <wow64FsRedirection> action. This action can be used at any point during the installation and allows disabling and enabling the filesystem redirection. For example, you could use it to disable the redirection, copy a binary to %windir%\system32 and enable it again:

<project>
  ...
  <postInstallationActionList>
      <wow64FsRedirection>
         <action>disable</action>
      </wow64FsRedirection>
      <copyFile>
         <origin>${installdir}/myApp.exe</origin>
         <!-- ${windows_folder_system} is a
         Built-in variable resolved to %windir% -->
         <destination>${windows_folder_system}</destination>
      </copyFile>
      <wow64FsRedirection>
         <action>enable</action>
      </wow64FsRedirection>
  </postInstallationActionList>
  ...
</project>

Using <windows64bitMode> will also disable the filesystem redirection on 64bit Windows.

  • The environment variables presented to the 32bit application are modified. These modifications affect, for example, to the default installation directory, which is configured to be under C:\Program Files (x86) instead of C:\Program Files. The only way to safely reverse this is to use <windows64bitMode>.

If you are installing a 32bit application, Microsoft guidelines recommend that you respect the above behavior, as it is used to provide the 32bit application with the appropriate environment. However, if the application bundled is a native 64bit binary, the best way of properly configuring the installer is by enabling the <windows64bitMode> project property. As explained in the Windows 64bit registry section, the setting is ignored in 32bit systems so it can be safely enabled in a project shared by 32 and 64bit applications.

Note
Enable <windows64bitMode> when packing native 64bit applications for Windows

The <windows64bitMode> project property makes an installer behave as a 64bit application by modifying its access to the environment:

  • Disables the filesystem redirection

  • Disables the registry redirection

  • Gives access to the 64bit environment variables

In addition, it can always be enabled as it will be ignored on 32bit Windows (or non-Windows systems such as Linux and OS X).

Creating specific Windows 64bit installers

If you want to distribute both 32 and 64bit versions of your installer, the project can still be configured for this purpose. The example below explains how to construct an XML project that will allow building a 32 or 64bit Windows installer on demand. It also includes some validations at runtime to prevent the user from trying to install the wrong binary on each platform.

The first step is to include your files with some "should pack rules" attached. You can find a detailed explanation of the process in the "Custom Build Targets" section:

   <project>
      <shortName>myProject</shortName>
      <version>1.4</version>
      ...
      <windows64bitMode>1</windows64bitMode>
      ...
      <parameterList>
         ...
         <stringParameter name="windowsArchitecture" value="x86" ask="0"/>
         ...
      </parameterList>
      <componentList>
          <component>
             <name>windowsx86</name>
             ...
             <folderList>
                <folder>
                   <name>windowsx86</name>
                   <destination>${installdir}</destination>
                   <distributionFileList>
                      <distributionDirectory>
                          <origin>path/to/32bit/windows-app</origin>
                      </distributionDirectory>
                   </distributionFileList>
                </folder>
             </folderList>
             ...
             <shouldPackRuleList>
                 <compareText text="${windowsArchitecture}" logic="equals" value="x86"/>
             </shouldPackRuleList>
          </component>
          <component>
             <name>windowsx64</name>
             ...
             <folderList>
                <folder>
                   <name>windowsx64</name>
                   <destination>${installdir}</destination>
                   <distributionFileList>
                      <distributionDirectory>
                          <origin>path/to/64bit/windows-app</origin>
                      </distributionDirectory>
                   </distributionFileList>
                </folder>
             </folderList>
             ...
             <shouldPackRuleList>
                 <compareText text="${windowsArchitecture}" logic="equals" value="x64"/>
             </shouldPackRuleList>
          </component>
      </componentList>
   </project>

Please note that the above also enables the <windows64bitMode> to make your installer behave as a native 64bit application on Windows x64.

At this point, you can select whether to build a 32 or a 64bit application by passing the appropriate value when using the command line:

$> builder build project.xml --setvars windowsArchitecture=x64

The next step is to include the validation. You can include it in the components so the code will only be executed when the platform in which the installer is running does not match its bundled files:

   <project>
      <shortName>myProject</shortName>
      <version>1.4</version>
      ...
      <windows64bitMode>1</windows64bitMode>
      ...
      <parameterList>
         ...
         <stringParameter name="windowsArchitecture" value="x86" ask="0"/>
         ...
      </parameterList>
      <componentList>
          <component>
             <name>windowsx86</name>
             ...
             <initializationActionList>
                 <throwError>
                    <text>You are trying to install a 32bit application in a
64bit system. Please download the correct binary from our website</text>
                    <ruleList>
                       <platformTest type="windows-x64"/>
                    </ruleList>
                 </throwError>
             </initializationActionList>
             <shouldPackRuleList>
                 <compareText text="${windowsArchitecture}" logic="equals" value="x86"/>
             </shouldPackRuleList>
          </component>
          <component>
             <name>windowsx64</name>
             ...
             <initializationActionList>
                 <throwError>
                    <text>You are trying to install a 64bit application in a
32bit system. Please download the correct binary from our website</text>
                    <ruleList>
                       <platformTest type="windows-x86"/>
                    </ruleList>
                 </throwError>
             </initializationActionList>
             ...
             <shouldPackRuleList>
                 <compareText text="${windowsArchitecture}" logic="equals" value="x64"/>
             </shouldPackRuleList>
          </component>
      </componentList>
   </project>

This code will prevent the wrong binary from being installed even if the platform supports running the installer.

If you want to relax the validation in the 32bit component running on Windows 64bits because the OS will accept it and just give the the end user the opportunity to continue or abort, you could use the below code instead:

<project>
  <version>1.4</version>
  ...
  <windows64bitMode>1</windows64bitMode>
  ...
  <componentList>
    <component>
      <name>windowsx86</name>
      ...
      <initializationActionList>
        <actionGroup>
          <actionList>
            <showQuestion>
              <default>yes</default>
              <text>You are trying to install a 32bit application in a
64bit system. A 64bit installer can be downloaded from our website. Do you
want to continue anyway?</text>
              <variable>shouldinstall</variable>
            </showQuestion>
            <exit>
              <exitCode>1</exitCode>
              <ruleList>
                <isFalse>
                  <value>${shouldinstall}</value>
                </isFalse>
              </ruleList>
            </exit>
          </actionList>
          <ruleList>
            <platformTest>
               <type>windows-x64</type>
            </platformTest>
          </ruleList>
        </actionGroup>
      </initializationActionList>
      ...
      <shouldPackRuleList>
        <compareText text="${windowsArchitecture}" logic="equals" value="x64"/>
      </shouldPackRuleList>
    </component>
  </componentList>
  ...
</project>
Installing applications in 32bit and 64bit folders

It is also possible to install 32bit and 64bit components into different directories. This example sets up a 32bit application installer that will install additional components - such as 64bit libraries - when executed on Windows 64bit.

To do so, you could create a <parameterGroup> with two instances of <directoryParameter> - one for 32bit parts and one for 64bit parts. Next, initialize a default value for them in <initializationActionList> and pass this value to <default> tag.

<project>
  <windows64bitMode>0</windows64bitMode>
  ...
  <initializationActionList>
     <setInstallerVariable>
       <name>installationroot32</name>
       <value>${platform_install_prefix}</value>
     </setInstallerVariable>
     <setInstallerVariable>
       <name>installationroot64</name>
       <value>${platform_install_prefix}</value>
     </setInstallerVariable>
     <setInstallerVariable>
       <name>installationroot64</name>
       <value>${env(ProgramW6432)}</value>
       <ruleList>
         <platformTest>
           <type>windows-x64</type>
         </platformTest>
       </ruleList>
     </setInstallerVariable>
  </initializationActionList>
  ...
  <componentList>
    <component>
      ...
      <folderList>
        <folder>
           <description>Program Files (32bit)</description>
           <destination>${installdir}</destination>
           <name>programfileswindows</name>
           <platforms>windows</platforms>
           <ruleList>
             <platformTest type="windows" />
           </ruleList>
           (...)
        </folder>
        ...
        <folder>
           <description>Program Files (64bit)</description>
           <destination>${installdirx64}</destination>
           <name>programfileswindowsx64</name>
           <platforms>windows</platforms>
           <ruleList>
             <platformTest type="windows-x64" />
           </ruleList>
           ...
        </folder>
      </folderList>
    </component>
  </componentList>
  ...
  <parameterList>
    <parameterGroup>
       <name>installdirs</name>
       <explanation></explanation>
       <value></value>
       <default></default>
       <parameterList>
         <directoryParameter>
           <name>installdir</name>
           <description>Installer.Parameter.installdir.description</description>
           <explanation>Installer.Parameter.installdir.explanation</explanation>
           <value></value>
           <default>${installationroot32}/${project.shortName}-${project.version}</default>
           <allowEmptyValue>0</allowEmptyValue>
           <cliOptionName>prefix</cliOptionName>
           <mustBeWritable>1</mustBeWritable>
           <mustExist>0</mustExist>
           <width>40</width>
         </directoryParameter>

         <!-- folder for 64-bit specific files -->
         <directoryParameter>
           <name>installdirx64</name>
           <description>Installer.Parameter.installdirx64.description</description>
           <explanation>Installer.Parameter.installdirx64.explanation</explanation>
           <value></value>
           <default>${installationroot64}/${project.shortName}-${project.version}</default>
           <allowEmptyValue>0</allowEmptyValue>
           <cliOptionName>prefix</cliOptionName>
           <mustBeWritable>1</mustBeWritable>
           <mustExist>0</mustExist>
           <width>40</width>
           <ruleList>
             <platformTest>
               <type>windows-x64</type>
             </platformTest>
           </ruleList>
         </directoryParameter>
       </parameterList>
    </parameterGroup>
  </parameterList>
</project>

On 32bit Microsoft Windows operating systems, the user will only be asked about one installation directory. The installer will deploy the 32bit files to that directory while 64bit files will be skipped.

On 64bit systems, the user will have the option of choosing directories for both 32bit and 64bit files. The installer will deploy the 32bit and 64bit files to the appropriate directories. As the installer is running as a 32bit application, certain target directories will point to their 32bit counterparts - such as the system directory for installing drivers. You must use <wow64FsRedirection> action to enable/disable this redirection when deploying drivers and/or other files to the WINDOWS directory.

Note
The installer must be running in 32bit mode

The <windows64bitMode> project setting must be set to 0 (the default value) to make the installer run in 32bit mode. If installer were running in 64bit mode, the default installdir would be C:\Program Files, not C:\Program Files (x86).

Managing Access Control Lists

Access Control Lists (ACLs) allow defining which users or groups can perform certain operations on one or more files. This allows preventing or granting access to reading or writing to files to certain users.

The <setWindowsACL> action allows configuring the ACLs of the desired files for the specified set of users. For example, to grant all permissions to all users you could use the following code:

<setWindowsACL>
  <action>allow</action>
  <files>${installdir}/admin;${installdir}/admin/*</files>
  <permissions>generic_all</permissions>
  <users>S-1-1-0</users>
</setWindowsACL>

The <setWindowsACL> action supports the following tags:

  • <users>: Comma separated list of users to set permissions for.

  • <action>: Whether to allow (allow action) or deny (deny action).

  • <permissions>: Space-separated list of permissions to set

  • <files>: List of files or file patterns to match; separated by semi-colon or newlines.

  • <excludeFiles>: List of files or file patterns to exclude from the defined <files>.

  • <self>: Determines if the objects specified in the <files> tag will be modified or just their children, if the recursion tags are enabled.

  • <recurseOneLevelOnly>: If enabled, the action will only affect the first level of hierarchy if one of the below is enabled.

  • <recurseObjects>: The action will affect to child objects (files)

  • <recurseContainers>: The action will affect to child to containers (folders)

The <clearWindowsACL> action allows removing all of the ACLs for the specified files or directories.

For example, in order to make sure just the Administrators group can access some files, you should first remove all of the current ACLs (that may be inherited from a parent directory) and then the permissions appropriately:

<clearWindowsACL>
  <files>${installdir}/admin;${installdir}/admin/*</files>
</clearWindowsACL>
<setWindowsACL>
  <action>allow</action>
  <files>${installdir}/admin;${installdir}/admin/*</files>
  <permissions>file_all_access</permissions>
  <users>S-1-5-32-544</users>
</setWindowsACL>

The <clearWindowsACL> action supports the following tags:

  • <files>: List of files or file patterns to match; separated by semi-colon or newlines

  • <excludeFiles>: List of files or file patterns to exclude from the defined <files>.

It is also possible to retrieve the ACL for a given user over a certain file using the <getWindowsACL> action. For example, the following will set granted and denied variables to the space-separated list of permissions for specified user:

<getWindowsACL>
  <deniedPermissions>denied</deniedPermissions>
  <file>${installdir}/admin</file>
  <grantedPermissions>granted</grantedPermissions>
  <username>S-1-1-0</username>
</getWindowsACL>

The <getWindowsACL> action supports the below tags:

  • <file>: File to retrieve the list of permissions for.

  • <username>: User or group to retrieve the list of permissions for.

  • <grantedPermissions>: Variable used to store the list of granted permissions.

  • <deniedPermissions>: Variable used to store the list of denied permissions.

When specifying a user for ACL actions, it can either be a user name, group name or a Security Identifier (SID). User names and group names are names of local or domain users and groups. SIDs are internal identifiers that specify unique user identification as well as several global values that are the same for all Windows based computers - such as Everyone, which maps to S-1-1-0 and Administrators which maps to S-1-5-32-544. Using SIDs is the recommended approach when referring to well known groups as the name of the groups is localized depending on the OS language.

More details on universal well-known SID values can be found on MSDN:

The <permissions> tag can include any number of permissions, separated by space. The following permissions are allowed in the ACL related actions:

Table 5. ACL permissions
ACL permissions

permission

file permission

directory permission

file_read_data

allow reading from file

allow listing contents of directory

file_write_data

allow writing to file

allow creating files

file_append_data

allow appending data to file

allow creating subdirectory

file_read_ea

allow reading extended attributes

allow reading extended attributes

file_write_ea

allow writing extended attributes

allow writing extended attributes

file_execute

allow running a binary

allow traversing directory

file_delete_child

N/A

allow deleting directory and its children, even if files are read-only

file_read_attributes

allow reading attributes

allow reading attributes

file_write_attributes

allow writing attributes

allow writing attributes

For setting access, the following generic permissions can also be used:

Table 6. Generic ACL permissions
Generic ACL permissions

permission

description

file_all_access

allow all available permissions

file_generic_read

allow common read permissions for file, directory and its attributes

file_generic_write

allow common write permissions for file, directory and its attributes

file_generic_execute

allow common execution permissions for file, directory and its attributes

More details on permissions related to files can be found on MSDN:

Note
ACLs are only supported on NTFS file systems.

If the action is used in a non-supported file system, it will silently fail.

Changing file attributes

File and folder attributes are set using the <changeWindowsAttributes> action.

For example, the following action can be used to set read-only and system attributes for admin subdirectory and all its child files:

<changeWindowsAttributes>
  <files>${installdir}/admin;${installdir}/admin/*</files>
  <readOnly>1</readOnly>
  <system>1</system>
</changeWindowsAttributes>

It accepts the following tags:

  • <files>: List of files or file patterns to match; separated by semi-colon or newlines

  • <excludeFiles>: List of files or file patterns to exclude from the defined <files>.

  • <hidden>: Whether or not the specified files should not be visible in applications such as Windows Explorer.

  • <readOnly>: Whether or not the specified files should allow write access.

  • <system>: Whether or not the specified files must be marked as system files.

  • <archive>: Whether or not the specified files must be marked to be archived. Some applications use this attribute to know which files should be backed up.

Please note that only setting these attributes does not prevent users from modifying the files, as the user can still unset each of these attributes manually. In order to prevent users (such as non-administrators) from modifying or accessing certain files, Access Control Lists should be used instead.

Read-only and system attributes can only be set for files. They are ignored by the operating system if applied to a folder. It is documented in more detail by Microsoft: