3
votes

I'm trying to create a Bootstrapper installer that will install My app plus one third party applications needed to run my application.

The third party application is an .exe package with a lot of complementary files.

My question is, How do I include the third party application into my Bundle? Do I have too add all the complentary files (100+ files) as payloads?

the below code is how I have set up my Bundle so far, it is compiling but not installing, the log says that the bootstrapper .exe can't find my .msi (my app) nor the .exe (third party app)

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Bundle Name="My_app"
            Version="1.0.0.0"
            Manufacturer="untitled"
            UpgradeCode="4d2de235-2286-4b06-8cfa-3f6ff3174244">

        <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />

        <Chain>
            <MsiPackage
                Id="MyApp_msi"
                SourceFile ="MyApp\MyApp.msi"
                Vital ="yes"/>
            <PackageGroupRef Id="thirdParty_package" />
        </Chain>
    </Bundle>

    <Fragment>
        <PackageGroup Id="thirdParty_package">
            <ExePackage
                SourceFile="thirdParty\Setup.exe"
                InstallCommand="/q /ACTION=Install"
                RepairCommand="/q ACTION=Repair /hideconsole"
                UninstallCommand="/q ACTION=Uninstall /hideconsole"/>
        </PackageGroup>
    </Fragment>
</Wix>
2
Silly question... are the directories you're referencing (MyApp and thirdParty) in the same directory, which is the same working directory as your installer project? Looks like your working directory is different from where you think it is (or those files really aren't there)Ryan J

2 Answers

2
votes

Yes, you have to list every Payload. It is convenient to put them in a PayloadGroup.

There are quite a few ways to generate a PayloadGroup. One way is to use/abuse heat to harvest a directory. This would be the same way as harvesting a directory for a Setup project.

As an example, let's package WiX's bin directory.

  <ExePackage Id="MyPackageId" SourceFile="$(env.WiX)bin/dark.exe" Compressed="yes">
    <PayloadGroupRef Id="MyPayloadGroupId"/>
  </ExePackage>

If you are using MSBuild (including via Visual Studio), you can configure the harvest by adding something like this to the project file:

  <ItemGroup>
    <HarvestDirectory Include="$(WIX)/bin">
      <ComponentGroupName>MyPayloadGroupId</ComponentGroupName>
      <PreprocessorVariable>var.MyPayloadSourceDirectory</PreprocessorVariable>
      <Transforms>FilesToPayloads.xsl</Transforms>
      <SuppressRegistry>true</SuppressRegistry>
      <!-- Hide from VS Solution Explorer -->
      <InProject>false</InProject>
    </HarvestDirectory>
  </ItemGroup>

When the build runs it adds the output .wsx (in the obj) folder to the build. (You don't need to see it.)

Notice that it uses a pre-processor variable to give the actual location of the source files. To pass the value, define it in the project properties. Or, as XML in the .wixproj:

<DefineConstants>Debug;MyPayloadSourceDirectory=C:/Program Files (x86)/WiX Toolset v3.8/bin</DefineConstants>

Finally, the XSL transform (FilesToPayloads.xsl) that heat will apply to its normal harvest output:

<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
  xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <xsl:template match="/">
    <Wix>
      <Fragment>
        <xsl:apply-templates select="*" />
      </Fragment>
    </Wix>
  </xsl:template>

  <xsl:template match="//wix:DirectoryRef">
    <PayloadGroup>
      <xsl:attribute name="Id">
        <xsl:value-of select="/wix:Wix/wix:Fragment/wix:ComponentGroup/@Id"/>
      </xsl:attribute>
      <xsl:apply-templates select="*" />
    </PayloadGroup>
  </xsl:template>

  <xsl:template match="//wix:File">
    <Payload>
      <xsl:attribute name="SourceFile">
        <xsl:value-of select="@Source"/>
      </xsl:attribute>
    </Payload>
  </xsl:template>

</xsl:stylesheet>

It's a rather trivial transliteration of File to Payload and the surrounding DirectoryRef to a PayloadGroup.

0
votes

Agreed it is a pain to generate the payload manually for installers with many files! Here is a small powershell script to generate the payload xml given a path. It will generate guids to use as id, recurse the folder and reproduce the folder structure.

if($args.Length -eq 0) {
    Write-Host "Error: No argument. Supply path to payload folder as script argument."
    Exit 1
}
$path = $args[0]
foreach($file in Get-ChildItem -Name $path -File -Recurse)
{
    Write-Host ("<Payload Id=`"" + ([guid]::NewGuid()) + "`" SourceFile=`"" + (Join-Path -Path $path -ChildPath $file) + "`" Name=`"" + $file + "`" />")
}