Как заставить Wix Heat.exe сохранять пользовательский идентификатор файла?

У меня есть основное приложение ASP.NET, для которого я создаю установщик WIX. Я использую Heat для создания всех файлов:

<!-- Remove read-only attribute -->
<Exec Command="attrib -R %(ProjectReference.Filename).wxs" Condition="'%(ProjectReference.WebProject)'=='True'" />

<ItemGroup>
  <LinkerBindInputPaths Include="%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\publish\" />
</ItemGroup>

<!-- Generate a WiX installer file using Heat Tool -->
<HeatDirectory OutputFile="%(ProjectReference.Filename).wxs"
               Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\publish\"
               DirectoryRefId="INSTALLFOLDER"
               ComponentGroupName="%(ProjectReference.Filename)"
               AutogenerateGuids="True"
               SuppressCom="True"
               SuppressFragments="True"
               SuppressRegistry="True"
               ToolPath="$(WixToolPath)"
               Condition="'%(ProjectReference.WebProject)'=='True'" />

Which puts entries like the following in my WebApp.sxs file:

<Component Id="cmp64BF6D207C595218157C321E631ED310" Guid="*">
    <File Id="myExe" KeyPath="yes" Source="SourceDir\MyExe.exe" />
</Component>

Проблема в том, что я изменил атрибут Id, чтобы можно было выполнить привязку к версии в Product.wxs:

  <Product Id="*"
           Name="..."
           Manufacturer="..."
           Version="!(bind.fileVersion.myExe)"
           Language="1033"
           UpgradeCode="143521a5-99df-4594-9d71-b028cddb9ed8">

Как я могу сделать так, чтобы тепло сохраняло тот же идентификатор для этого файла? Но заодно добавить какие-нибудь новые файлы?


person Colton Scottie    schedule 23.07.2019    source источник
comment
Пожалуйста, проверьте эту ссылку сейчас.   -  person Stein Åsmul    schedule 23.07.2019
comment
Вы можете удалить или изменить компонент MyExe.exe, применив XSLT (HeatDirectory Transforms="MyTransform.xslt", пример XSLT приведен в этом ответе).   -  person zett42    schedule 23.07.2019
comment
Я думаю, вы делаете это наоборот. Вместо замены идентификатора, сгенерированного нагревом, замените myExe в вашем файле .wxs идентификатором, сгенерированным нагревом. Тепло будет генерировать один и тот же идентификатор каждый раз.   -  person john ktejik    schedule 06.07.2021


Ответы (2)


Основная идея состоит в том, чтобы отфильтровать компонент MyExe.exe из вывода Heat, а затем вручную добавить его обратно в основную систему разработки WiX, где мы можем указать постоянный атрибут File/@Id.

Фильтрацию можно выполнить, передав XSLT-файл в Heat:

<HeatDirectory Transforms="$(ProjectDir)RemoveMyExeComponent.xslt" ... />

RemoveMyExeComponent.xslt может выглядеть следующим образом (идея из этого ответа, но упрощенная для текущего вопроса) . В этом файле замените MyExe.exe фактическим именем вашего EXE и замените - 8 длиной имени файла, уменьшенной на единицу.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    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"
    version="1.0" 
    exclude-result-prefixes="xsl wix">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:strip-space elements="*" />

    <!--
    Find the component of the main EXE and tag it with the "ExeToRemove" key.

    Because WiX's Heat.exe only supports XSLT 1.0 and not XSLT 2.0 we cannot use `ends-with( haystack, needle )` (e.g. `ends-with( wix:File/@Source, '.exe' )`...
    ...but we can use this longer `substring` expression instead (see https://github.com/wixtoolset/issues/issues/5609 )
    -->
    <xsl:key
        name="ExeToRemove"
        match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 8 ) = 'MyExe.exe' ]"
        use="@Id"
    /> <!-- In this expression "-8" is the length of "MyExe.exe" - 1 because XSLT uses 1-based indexes, not 0-based indexes. -->

    <!-- By default, copy all elements and nodes into the output... -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- ...but if the element has the "ExeToRemove" key then don't render anything (i.e. removing it from the output) -->
    <xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'ExeToRemove', @Id ) ]" />

</xsl:stylesheet>

Теперь, когда мы удалили сгенерированный компонент EXE, мы можем вручную добавить его обратно в разработку WiX, что дает нам полный контроль над всеми атрибутами:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" Name="WixHeatConstantExeFileId" Language="1033" Version="!(bind.fileVersion.myExe)" Manufacturer="zett42" UpgradeCode="PUT-GUID-HERE">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

    <Feature Id="ProductFeature" Title="WixHeatConstantExeFileId" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
      <ComponentGroupRef Id="HarvestedComponents" />
    </Feature>

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="WixHeatConstantExeFileId" />
      </Directory>
    </Directory>

    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <!-- Manually add back the EXE component that was filtered out from Heat output. -->
      <Component Id="myExe" Guid="*">
        <File Id="myExe" KeyPath="yes" Source="SourceDir\MyExe.exe" />
      </Component>
    </ComponentGroup>
  </Product>
</Wix>

Прекрасно работает в моем тестовом проекте!

person zett42    schedule 24.07.2019

Используйте SuppressRootDirectory="true" (параметр -srd) в Heat. Таким образом, Heat игнорирует полный путь и просто использует имя файла для генерации идентификаторов. Пока имя файла одно и то же, идентификатор всегда будет одинаковым.

Затем вместо замены идентификатора, сгенерированного нагревом, замените myExe в вашем файле .wxs идентификатором, сгенерированным нагревом.

См. Wix Harvest: тот же компонент / файл Идентификатор, когда файлы находятся в разных папках

person john ktejik    schedule 06.07.2021