2

我正在使用 WiX 3.8 构建一个安装产品的项目。安装程序基本完成。软件包安装的其中一个程序依赖于第三方的 dll,这些 dll 经常更新。愚蠢的是,dll 的版本号会定期更改。在第一次编写安装程序项目时,我没有考虑包含对更改文件名的支持,而是手动编写了每个组件。

将来应该改变这种行为。如果我理解正确,可以在HeatDirectory Task的帮助下自动为文件生成组件。我现在使用正在运行的 HeatDirectory 任务创建了一个示例项目。但是 HeatDirectory 任务产生的输出和我过去一直使用的手动编写的组件之间存在一些差异。

我希望 HeatDirectory 任务产生与我的手动方法相同的输出,尽可能好。以下是两个组件的代码,第一个是手动创建的,第二个是由 HeatDirectory 任务创建的:

手动创建的组件:

<ComponentGroup Id="ThirdParty.v13.2" Directory="INSTALLFOLDER">
<Component 
  Id="CMP_ThirdParty.v13.2.dll" 
  Guid="AC5E00F0-B458-4272-B132-F13594ED4916">
  <File 
    Id="ThirdParty.v13.2.dll" 
    Name="ThirdParty.v13.2.dll" 
    Source="ComponentsDir\ThirdParty\ThirdParty.v13.2.dll" 
    KeyPath="yes" 
    Assembly=".net" 
    AssemblyApplication="ThirdParty.v13.2.dll" 
    AssemblyManifest="ThirdParty.v13.2.dll" 
    Compressed="no" 
    DiskId="$(var.ThirdPartyDiskId)"/>
</Component>
<Component 
  Id="CMP_ThirdParty.v13.2.xml" 
  Guid="64AC3F5F-38E9-41EC-B714-636F5D9C0CB4">
  <File 
    Id="ThirdParty.v13.2.xml" 
    Name="ThirdParty.v13.2.xml" 
    Source="Source="ComponentsDir\ThirdParty\ThirdParty.v13.2.xml" 
    KeyPath="yes" 
    Compressed="no" 
    DiskId="$(var.ThirdPartyDiskId)"/>
</Component>
</ComponentGroup>

HeatDirectory 任务生成代码:

<ComponentGroup Id="Files">
<Component 
  Id="cmp9D064A733360960E07277CFD9AB84AF1" 
  Directory="INSTALLFOLDER" 
  Guid="*">
  <File 
    Id="filD5DCB6E091D2D12303E2E80B0B767438" 
    KeyPath="yes" 
    Source="$(var.Path)\ThirdParty.v13.2.dll"/>
</Component>
<Component 
  Id="cmpA8681A63A8A4991D18824BA17E4CA4BF" 
  Directory="INSTALLFOLDER" 
  Guid="*">
  <File 
    Id="fil17554B3CD0E576337AEC758831009938" 
    KeyPath="yes" 
    Source="$(var.Path)\ThirdParty.v13.2.xml"/>
</Component>
</ComponentGroup>

产生上述输出的代码如下:

<Target Name="BeforeBuild">
<HeatDirectory 
  DirectoryRefId="INSTALLFOLDER" 
  OutputFile="Files.wxs" 
  Directory="S:\omePath" 
  SuppressRootDirectory="true" 
  ToolPath="$(WixToolPath)" 
  AutogenerateGuids="true" 
  ComponentGroupName="Files" 
  PreprocessorVariable="var.Path">
</HeatDirectory>
</Target>

现在,我将记下要更改的 HeatDirectory 任务生成代码的特征:

  1. 组件组中的每个组件都有一个Directory属性。我希望父级ComponentGroup拥有该Directory属性并在每个子组件中省略它。
  2. 我想要静态指南。
  3. 我希望组件的Id属性由前缀CMP后跟文件名组成。我知道项目中不能有两个具有相同文件名的文件,但我知道情况并非如此。我不想要任务生成的神秘标识符。
  4. 组件的File子项过于简陋。我希望 HeatDirectoy 任务Name为每个文件创建一个属性,该属性是文件的当前名称。然后Compressed属性应该加上值no,并且DiksId应该加上一个可以在任务中以某种方式指定的变量值。
  5. 如果收获的文件是 dll,则任务应在属性后面附加Asssemblyvalue .netAssemblyApplication将收获的文件的名称作为其值AssemblyManifest,并将收获的文件的名称作为其值。

是否可以通过 HeatDirectory 任务来实现这一点?

4

1 回答 1

2

处理 HeatDirectory 任务的输出的答案是使用 XSLT。在 HeatDirectory 任务中,Transforms可以指定一个名为的属性,该属性指向包含 XSLT 指令的文件。为了实现我要求的输出,可以使用以下 XSLT 代码:

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

  <xsl:output
    method="xml"
    indent="yes"/>
  <xsl:variable name="ComponentGroup-Id" select="//wix:ComponentGroup/@Id"/>
  <xsl:variable name="DestinationFolder" select="//wix:Component[1]/@Directory"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select ="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:Directory">
    <xsl:variable name="DirName" select="@Name" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:value-of select="$ComponentGroup-Id"/>
        <xsl:text>_</xsl:text>
        <xsl:value-of select="$DirName"/>
      </xsl:attribute>
      <xsl:attribute name="Name">
        <xsl:value-of select="$DirName"/>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:ComponentGroup">
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:value-of select="$ComponentGroup-Id"/>
      </xsl:attribute>
      <xsl:attribute name="Directory">
        <xsl:value-of select="$DestinationFolder"/>
      </xsl:attribute>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:Component">
    <xsl:variable name="FilePath" select="current()/wix:File/@Source" />
    <xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
    <xsl:variable name="Guid" select="@Guid" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:text>CMP_</xsl:text>
        <xsl:choose>
          <xsl:when test="contains($FileName,'\')">
            <xsl:value-of select="substring-after($FileName,'\')"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$FileName"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:attribute name="Guid">
        <xsl:value-of select="$Guid"/>
      </xsl:attribute>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:File">
    <xsl:variable name="FilePath" select="@Source" />
    <xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:choose>
          <xsl:when test="contains($FileName,'\')">
            <xsl:value-of select="substring-after($FileName,'\')"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$FileName"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:attribute name="KeyPath">
        <xsl:text>yes</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="Source">
        <xsl:value-of select="$FilePath"/>
      </xsl:attribute>
      <xsl:if test="contains($FileName,'.dll')">
        <xsl:attribute name="Assembly">.net</xsl:attribute>
        <xsl:attribute name="AssemblyApplication">
          <xsl:choose>
            <xsl:when test="contains($FileName,'\')">
              <xsl:value-of select="substring-after($FileName,'\')"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$FileName"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
        <xsl:attribute name="AssemblyManifest">
          <xsl:choose>
            <xsl:when test="contains($FileName,'\')">
              <xsl:value-of select="substring-after($FileName,'\')"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$FileName"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
      </xsl:if>
      <xsl:attribute name="Compressed">
        <xsl:text>no</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="DiskId">
        <xsl:text>$(var.SomeDiskID)</xsl:text>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
于 2014-03-12T12:53:24.890 回答