WiX Cookbook
上QQ阅读APP看书,第一时间看更新

Adding a file to a directory

Markup to copy files to the end user's computer is probably going to make up the bulk of your installer. That's because for each file you want to install, which may number in the hundreds, there will be a corresponding XML element in your .wxs file to represent it. In this recipe, we'll cover the basics—installing a single text file to a directory that we'll create under Program Files. All file-types, whether plain text or binary, will follow this same pattern.

Getting ready

To prepare for this recipe, perform the following steps:

  1. Create a setup project and call it FileInstaller.
  2. Add a text file to the project and name it Sample.txt. Although we're adding the file directly to the setup project, in most cases the source files we use will be from other projects or folders.
  3. Update the default directory structure to the following wherein a folder called My Software is added to the Program Files directory:
    <Fragment>
      <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="ProgramFilesFolder">
          <Directory Id="INSTALLFOLDER" Name="My Software" />
        </Directory>
      </Directory>
    </Fragment>

How to do it…

Use ComponentGroup to install a collection of files to a directory as shown in the following steps:

  1. By default, Product.wxs already contains a ComponentGroup that has a Directory attribute set to INSTALLFOLDER. This is exactly the syntax we want and will install any child Component elements to the My Software folder:
    <Fragment>
      <ComponentGroup Id="ProductComponents" 
                      Directory="INSTALLFOLDER"> 
      </ComponentGroup>
    </Fragment>
  2. Add a Component element to the ComponentGroup with an Id of your choosing and generate a new GUID for the Guid attribute:
    <ComponentGroup Id="ProductComponents" 
                    Directory="INSTALLFOLDER">
      <Component Id="cmpSampleTXT" 
                 Guid="{759CE9A8-F4DF-4DE7-B995-E5F0D926BE43}">
      </Component>
    </ComponentGroup>
  3. Within that component, add a File element that points to our Sample.txt file:
    <Component Id="cmpSampleTXT" 
               Guid="{759CE9A8-F4DF-4DE7-B995-E5F0D926BE43}">
      <File Source="Sample.txt" />
    </Component>
  4. Although the setup project template already sets it up for you, make sure that the Id of the ComponentGroup is referenced by a ComponentGroupRef element inside of a Feature element:
    <Feature Id="ProductFeature" Title="The Software" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>

How it works…

ComponentGroup is a container for a group of Component elements. It's really handy when declaring where the components should be installed to since it comes with a Directory attribute for specifying this. Any child Component elements will go into that directory on the target computer. It points to the Id of a Directory element.

Each component is in turn a container for a single File element and, through the use of its GUID, allows the file to be tracked from version to version. For example, if we need to patch the file in the future, we'll be able to match it by this identifier. The GUID uniquely identifies it among all other components that have been installed to the end user's system. The ID is used to differentiate the component within the MSI package. You can use any identifier you like, but as a convention, I prefix mine with cmp.

The File element points to our source file on disk with its Source attribute. In this example, we used the relative path Sample.txt, but we could have used an absolute path or a preprocessor variable. Note that we added the text file directly to our setup project, but in practice the files you reference do not need to be in the project. As long as the path to the file is correct, the WiX linker will find it.

There's more…

If all the files in the ComponentGroup can be found in the same directory on your development computer then you can save yourself some typing by setting the ComponentGroup element's Source attribute. In the following example, we use the Source attribute to specify that all child components can be found in the SourceFiles directory. For this to work, you must switch all File elements in the group to use the Name attribute, rather than the Source attribute, to specify the name of the file. The code is as follows:

<ComponentGroup Id="ProductComponents" 
                Directory="INSTALLFOLDER" 
 Source="..\SourceFiles">
  <Component Id="cmpSampleTXT" 
             Guid="{759CE9A8-F4DF-4DE7-B995-E5F0D926BE43}">
 <File Name="Sample.txt" />
  </Component>
</ComponentGroup>