WIX Heat Wave Brings Changes

There has been some recent work to Heat.exe, within the Windows Installer XML Toolset (WiX), which I think will have a significant impact on how people use the application currently and how it will be used in the feature. The features are brought forth from a great deal of user feedback and a general need for some “tender, loving care.” People have been using Heat to harvest various data stores and including the auto-generated .wxs files as part of their projects. This has been a good “start” for many projects but the intent was not to use it for constant re-generation in a build environment for dynamic content.

Although this practice is still recommend against, this last update is a set in the direction of consistent regeneration. In Windows Installer this is a very difficult task to manage as there are many rules that a package must confirm to in order to be patch compliant. Not only must Component GUIDs remain stable, the File ID, Registry ID, Directory ID Media Number and other items must stay consistent. If this does not happen there can be serious implications to the “in-place” servicing of your product.

Several years ago I was working on a way to do what heat.exe is starting to do now, auto-generate dynamic content in a compliant way. My project, WIXML, failed to generate MSIs that were upgrade compliant. It was necessary to do a full uninstall with each new package because it broke all the rules that I mentioned above (additional information from Bob Arnson “Paying for Upgrades”). With the latest update, Heat is getting closer to the ability of being compliant with consistent re-generation.

There has been four significant command line switches added that will help users comply to the rules above.

-cg <GroupName>
-dr <DirectoryRefId>
-srd
-var

The –cg <GroupName> command instructs Heat to harvest a given directory and include all found components in a <ComponentGroup/> with the given name. This will ensure that, when authoring a full product, a developer can be guaranteed a static value to reference using a <CompnentGroupRef/>.

 heat.exe dir C:\MyDir -srd -cg TestMe


<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
  <Fragment>
    <ComponentGroup Id="TestMe">
      <Component Id="CO_BEA0A254206A075FE419AECC8F8323C3" Directory="DI_5E971BF1ECC0BC11795785D90F250FC0" ... >
        <File Id="FI_4273BB2732377498E74980308130C808" ... />
      </Component>

The -dr switch takes a value of a DirectoryRef/@Id. This will become the directory which all other directories are rooted under.

In addition, and important to note, this acts as the seed for all the identifier generation.

Changing this value will directly impact the values of ALL the identifiers. When this value is not specified, it will default to "TARGETDIR".

 heat.exe dir C:\MyDir -srd -dr MyDir


<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
  <DirectoryRef Id="MyDir">
    <Component Id="CO_BEA0A254206A075FE419AECC8F8323C3" Directory="DI_5E971BF1ECC0BC11795785D90F250FC0" ... >
      <File Id="FI_4273BB2732377498E74980308130C808" ... />
    </Component>

The -srd switch suppresses the including the root directory of the path given. Using this switch will also change the values of identifiers being generated because of how they will be rooted.

Change this switch with high caution and review on the impact to your product.

 heat.exe dir C:\MyDir -sfrag


<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
  <Fragment>
    <DirectoryRef Id="TARGETDIR">
      <Directory Id="dir86787CC870C17D6ABA6D1CDCBD925324" Name="MyDir">
        <Directory Id="dirAA5EBADF0D0CC654BAD8E2CEFBF96609" Name="one">
          <Component Id="cmp51B22E187A7403EF3A8EB589174E89DC" ...>
            <File Id="filEA449989D4339EB8C7329B93F83D35FE" ... />
          </Component>
        </Directory>

heat.exe dir C:\MyDir -srd -sfrag


<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
  <Fragment>
    <DirectoryRef Id="TARGETDIR">
      <Directory Id="dir090ACB8E8D9B8C1F26DE6E8300AA9049" Name="one">
        <Component Id="cmpE21824A6879A478E4A884BA6B00C33C9" ...>
          <File Id="filF1BA1271365EB2A130AA3F0BE83E9D6D" ... />
        </Component>
    </Directory>

The -var switch value of the preprocessor variable you want to use "$(<var|env>.MyVar)". Renaming this value will not impact dynamically created identifiers.

 heat.exe dir C:\MyDir -srd -sfrag -var var.MyVar


<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
<Fragment>
  <DirectoryRef Id="TARGETDIR">
    <Directory Id="dir090ACB8E8D9B8C1F26DE6E8300AA9049" Name="one">
      <Component Id="cmpE21824A6879A478E4A884BA6B00C33C9" ...>
        <File Id="filF1BA1271365EB2A130AA3F0BE83E9D6D" Source="$(var.MyVar)\one\test.txt" ... />
      </Component>
    </Directory>

As always, feedback is appreciated! I hope these changes help some people onboard!