Question

I'm trying to use the WIX Toolset 3.7 in VS2012 to create an installer for my WFC services. All services got the same structure:

Rest Service structure

The service.svc is simply linking to the specific class

<%@ ServiceHost Language="C#" Debug="true"
    Service="LandwehrServices.Service.Vorlage.ServiceOption" 
    Factory="ServiceCreator.DigestAuthenticationHostFactory" %>

The dlls are getting installed right, but all folders contain the same service.svc (of the first installed service) file...

This is my Product.wxs

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="020f2a79-d085-4c05-b49d-a09300e8a144"
       Name="!(loc.ProductName)"
       Language="1031" 
       Version="1.0.0.0"
       Manufacturer="!(loc.CompanyName)" 
       UpgradeCode="a0bbe6c8-1658-43e4-9cf8-51d6bbdf84d2">

  <Package InstallerVersion="200" Compressed="yes"
         Languages="!(loc.LANG)"
         Manufacturer="!(loc.CompanyName)" Comments="!(loc.Comments)"
         Description="!(loc.Description)" Keywords="!(loc.Keywords)"/>

    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION" Name="!(loc.ProductName)">
          <Directory Id="INSTALLLOCATION.Option" Name="Service.Option" />
          <Directory Id="INSTALLLOCATION.Personal" Name="Service.Personal" />
          <Directory Id="INSTALLLOCATION.Postbox" Name="Service.Postbox" />
        </Directory>
      </Directory>
    </Directory>

    <Feature Id="ProductFeature" Title="!(loc.ProductName)" Level="1">
      <ComponentGroupRef Id="Option_Project" />
      <ComponentGroupRef Id="Personal_Project" />
      <ComponentGroupRef Id="Postbox_Project" />
    </Feature>
</Product>
</Wix>

And my BeforeBuild entry in the .wixdproj

<Target Name="BeforeBuild">
<MSBuild Projects="%(ProjectReference.FullPath)"
         Targets="Package"
         Properties="Configuration=$(Configuration);Platform=AnyCPU"
         Condition="'%(ProjectReference.WebProject)'=='True'" />
<ItemGroup>
  <LinkerBindInputPaths Include="%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\" />
</ItemGroup>
<HeatDirectory OutputFile="%(ProjectReference.Filename).wxs"
               Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\"
               DirectoryRefId="INSTALLLOCATION.%(ProjectReference.Filename)"
               ComponentGroupName="%(ProjectReference.Filename)_Project"
               AutogenerateGuids="true" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true"
               SuppressRootDirectory="true" ToolPath="$(WixToolPath)" Condition="'%(ProjectReference.WebProject)'=='True'" />
</Target>

Any ideas? This is my first time using WIX...

Was it helpful?

Solution

Ok. This has solved the problem for me.

Force linker to be called with named bind paths

I added the following item group with items pointing to the two packages.

<ItemGroup>
    <BindInputPaths Include="..\MyProject1\obj\Debug\Package\PackageTmp">
      <BindName>MyProject1</BindName>
      <InProject>false</InProject>
    </BindInputPaths>
    <BindInputPaths Include="..\MyProject2\obj\Debug\Package\PackageTmp">
      <BindName>MyProject2</BindName>
      <InProject>false</InProject>
    </BindInputPaths>
</ItemGroup>

Remove the item group in the pre-build step containing the LinkerBindInputPaths element.

Verify this in the Visual Studio output window. The Light.exe command line should now have named bind paths.

-b "MyProject1=D:\Projects\...\MyProject1\obj\Debug\Package\PackageTmp" 
-b "MyProject2=D:\Projects\...\MyProject2\obj\Debug\Package\PackageTmp"

Use named bind paths in harvest output

I tried to get the HeatDirectory task to generate this output but in the end just used a XSLT transformation to update the SourceDir part to use the bindpath variable.

Update Wix project to direct Heat output to tmp file prior to piping through XSLT transform.

<HeatDirectory OutputFile="%(ProjectReference.Filename)-temp.wxs" 
               Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\" 
               DirectoryRefId="%(ProjectReference.Name)InstallFolder" 
               ComponentGroupName="%(ProjectReference.Name)_Project" 
               AutogenerateGuids="true" 
               SuppressCom="true" 
               SuppressFragments="true" 
               SuppressRegistry="true" 
               SuppressRootDirectory="true" 
               ToolPath="$(WixToolPath)" 
               Condition="'%(ProjectReference.WebProject)'=='True'" />

<XslTransformation XmlInputPaths="%(ProjectReference.Filename)-temp.wxs" 
                   XslInputPath="XslTransform.xslt" 
                   OutputPaths="%(ProjectReference.Filename).wxs" 
                   Condition="'%(ProjectReference.WebProject)'=='True'" />

Include the XSLT Transformation into the Wix project (XslTransform.xslt)

<?xml version="1.0" encoding="utf-8"?>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
                exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template name="string-replace-all">
    <xsl:param name="text" />
    <xsl:param name="replace" />
    <xsl:param name="by" />
    <xsl:choose>
      <xsl:when test="contains($text, $replace)">
        <xsl:value-of select="substring-before($text,$replace)" />
        <xsl:value-of select="$by" />
        <xsl:call-template name="string-replace-all">
          <xsl:with-param name="text" select="substring-after($text,$replace)" />
          <xsl:with-param name="replace" select="$replace" />
          <xsl:with-param name="by" select="$by" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@Source['SourceDir']" >

    <xsl:attribute name="Source">

      <xsl:variable name="projectName">
        <xsl:value-of select="/wix:Wix/wix:Fragment/wix:ComponentGroup/@Id"/>
      </xsl:variable>

      <xsl:call-template name="string-replace-all">
        <xsl:with-param name="text" select="." />
        <xsl:with-param name="replace" select="'SourceDir'" />
        <xsl:with-param name="by" select="concat('!(bindpath.',$projectName,')')" />
      </xsl:call-template>

    </xsl:attribute>

  </xsl:template>

</xsl:stylesheet>

The Heat output should then use the ComponentGroup name as the bind path variable.

<Component Id="..." Guid="*">
    <File Id="..." KeyPath="yes" Source="!(bindpath.MyProject1)\Default.aspx" />
</Component>

Once built I verified the MSI in Orca. Before the fix Orca listed two versions of my files both with the same byte size. Now it lists both versions with their proper sizes.

OTHER TIPS

I currently have the exact same problem. I believe it is being caused by the linker (Light) bind paths. They take the two packaged output folders and combine them. Looking at the linker command line in VS output it uses the –b flag to specify the bind paths. When there are multiple paths I believe it should use named paths.

http://wixtoolset.org/documentation/manual/v3/howtos/general/specifying_source_files.html

C:\Program Files (x86)\WiX Toolset v3.7\bin\Light.exe 
-out "D:\Projects\...\Setup.msi" 
-pdbout "D:\Projects\...\Setup.wixpdb" 
-b "D:\Projects\...\MyProject1\obj\Debug\Package\PackageTmp\\" 
-b "D:\Projects\...\MyProject2\obj\Debug\Package\PackageTmp\\" 
-cultures:en-us -ext "C:\Program Files (x86)\WiX Toolset v3.7\bin\\WixUtilExtension.dll" 
-ext "C:\Program Files (x86)\WiX Toolset v3.7\bin\\WixIIsExtension.dll" 
-ext "C:\Program Files (x86)\WiX Toolset v3.7\bin\\WixUIExtension.dll" 
-loc WebAppInstallDlg_en-us.wxl -contentsfile obj\Debug\Setup.wixproj.BindContentsFileListen-us.txt 
-outputsfile obj\Debug\Setup.wixproj.BindOutputsFileListen-us.txt 
-builtoutputsfile obj\Debug\Setup.wixproj.BindBuiltOutputsFileListen-us.txt 
-wixprojectfile "D:\Projects\...\Setup.wixproj" obj\Debug\MyProject1.wixobj obj\Debug\MyProject2.wixobj obj\Debug\SetupUI.wixobj obj\Debug\Setup.wixobj

I think the solution is to use named bind paths. However I haven’t managed to find a way of specifying named bind paths within my pre-build step. My pre-build step is identical to yours so I’m trying to figure out how to modify the LinkerBindInputPaths part to used names as below.

<File Source="!(bindpath.foo)bar\baz.txt" />
<File Source="!(bindpath.bar)baz\foo.txt" />

light -b foo=C:\foo\ -b bar=C:\bar\ -b foo=D:\

Andy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top