【问题标题】:WIX HeatDirectory Task - Setting the preprocessorVariableWIX HeatDirectory 任务 - 设置预处理器变量
【发布时间】:2025-12-16 20:50:03
【问题描述】:

我正在尝试在 wix 中设置预处理器变量,但我无法在互联网上的任何地方找到此示例或有关如何执行此操作的说明,我希望这里有人可以解释或告诉我我在哪里出错了!

我已经尝试了此处显示的有关设置 var 值的示例 http://www.ageektrapped.com/blog/setting-properties-for-wix-in-msbuild/

在 wix 中使用 HeatDirectory taks 的文档可以在这里找到,而且一点用处都没有!

如何设置 preprocessorVariable 以将 SourceDir 替换为另一个变量名?

【问题讨论】:

标签: msbuild wix


【解决方案1】:

PreprocessorVariable for heat 确实需要更多文档和示例......我也花了很多时间让它工作。这就是它在我的 wixproj 文件中的工作方式:

<PropertyGroup>
  <DefineConstants Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">HarvestPath=..\distribution\Debug</DefineConstants>
  <DefineConstants Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">HarvestPath=..\distribution\Release</DefineConstants>
</PropertyGroup>

<Target Name="BeforeBuild">
  <HeatDirectory Directory="..\distribution\$(Configuration)"
               PreprocessorVariable="var.HarvestPath"
               OutputFile="HeatGeneratedFileList.wxs"
               ComponentGroupName="HeatGenerated"
               DirectoryRefId="INSTALLFOLDER"
               AutogenerateGuids="true"
               ToolPath="$(WixToolPath)"
               SuppressFragments="true"
               SuppressRegistry="true"
               SuppressRootDirectory="true"/>
</Target>

您只需要定义变量。没有神奇的“HeatDefinitions”:)

【讨论】:

  • 这就是我所需要的! FWIW MS 真的应该在 WiX 中投入一些资源,这是一种荒谬的事态(文档)。
  • 这对于专家(除了我之外)来说可能是显而易见的:必须将 var.HarvestPath 变量定义到 wixproj 文件中。它只会在稍后来自 wix 编译器的预处理步骤中被替换。我花了几个小时才完成这项工作。
  • 所以 HeatDirectory 的目录属性似乎不可能使用任何类型的变量作为路径?我讨厌这样的静态路径和多个定义。无论您做什么,那里的 $(HarvestPath) 都不起作用。
【解决方案2】:

我使用 Wix v3.10。

无需显式调用 HeatDirectory MSBuild 任务。可以准备具有特殊名称“HarvestDirectory”的ItemGroup,稍后“HarvestDirectory”目标将处理它。 *.wsx 文件在 IntermediateOutputPath 中创建,并包含在 Compile 列表中(由 Candle 处理)。

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
...
  <MyFinalFolder Condition=" '$(MyFinalFolder)' == '' ">$(MSBuildProjectDirectory)\Final\</MyFinalFolder>
  <DefineConstants>FinalFolder=$(MyFinalFolder)</DefineConstants>
</PropertyGroup>

...

<Import Project="$(WixTargetsPath)" />
<Target Name="BeforeBuild">
  <!--
  No need to explicitly call HeatDirectory MSBuild Task.
  Instead follow documentation http://wixtoolset.org/documentation/manual/v3/msbuild/target_reference/harvestdirectory.html, which has sample and 
  important comment:
   This target is processed before compilation. Generated authoring is automatically added to the Compile item group to be compiled by the Candle task.
  So, *.wsx file created in the IntermediateOutputPath and included in Compile list (processed by Candle).

  The following ItemGroup with special name "HarvestDirectory" can be prepared, and later the "HarvestDirectory" target will process it, see
  C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\wix2010.targets
  -->
  <ItemGroup>
    <HarvestDirectory Include="$(MyFinalFolder)">
      <DirectoryRefId>INSTALLFOLDER</DirectoryRefId>
      <SuppressRootDirectory>true</SuppressRootDirectory>
      <SuppressCom>true</SuppressCom>
      <SuppressRegistry>true</SuppressRegistry>
      <ComponentGroupName>FilesComponentGroup</ComponentGroupName>
      <PreprocessorVariable>var.FinalFolder</PreprocessorVariable>
    </HarvestDirectory>
  </ItemGroup>
</Target>

wxs 文件:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp9AA09F4A73FA53E2BDDE4B7BB5C91DFB" Guid="*">
                <File Id="fil9AA09F4A73FA53E2BDDE4B7BB5C91DFB" KeyPath="yes" Source="$(var.FinalFolder)\7z.dll" />
            </Component>

【讨论】:

  • 谢谢。花了半天时间尝试为 Asp.NET Core 站点的已发布输出创建设置。你会认为如此常见的事情会在互联网上得到很好的记录。你的答案是第一个真正有效的答案。
  • 很高兴它对你有用。似乎 MSBuild 和 WIX 没有太大变化,即使对于 ASP.NET Core 项目仍然有效。
  • 你能解释一下var.FinalFolder vs MyFinalFolder是错字还是更深层次的东西?
【解决方案3】:

我在 GitHub 上创建了一个示例项目,展示了如何成功使用 HarvestDirectory target,这是一个调用 HeatDirectory 任务的更高级别的东西。您不需要自己直接调用 HeatDirectory 任务。您可以在此处查看所有示例代码:

https://github.com/DavidEGrayson/wix-example-harvest-directory

以下是最重要的部分:

foo.wixproj

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProductVersion>1.0.0</ProductVersion>
    <DefineConstants>ProductVersion=$(ProductVersion);ItemDir=items</DefineConstants>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProjectGuid>27e80d9b-d8b6-423a-a6ff-1d9c5b23bb31</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputName>foo-$(ProductVersion)</OutputName>
    <OutputType>Package</OutputType>
    <DefineSolutionProperties>false</DefineSolutionProperties>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>Debug;ProductVersion=$(ProductVersion)</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="foo.wxs" />
    <HarvestDirectory Include="items">
      <DirectoryRefId>ItemDir</DirectoryRefId>
      <ComponentGroupName>Items</ComponentGroupName>
      <PreprocessorVariable>var.ItemDir</PreprocessorVariable>
    </HarvestDirectory>
    <WixExtension Include="WixUIExtension" />
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
</Project>

foo.wxs

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Name="Foo"
           Version="$(var.ProductVersion)"
           Manufacturer="Foo Inc."
           Language="1033"
           UpgradeCode="0c8504c9-4e62-4e2c-9e1c-4fbe1c478b37"
           Id="*">

    <Package Description="Foo"
             Manufacturer="Foo Inc."
             Compressed="yes"
             InstallerVersion="301" />

    <MajorUpgrade AllowDowngrades="no"
                  DowngradeErrorMessage="A newer version of this software is already installed."
                  AllowSameVersionUpgrades="no" />

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

    <Property Id="ARPCOMMENTS">
      Foo package.
    </Property>
    <Property Id="ARPCONTACT">Foo Inc.</Property>
    <Property Id="ARPURLINFOABOUT">https://www.example.com/</Property>

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder" Name="PFiles">
        <Directory Id="INSTALLDIR" Name="Foo">
          <Component Id="readme">
            <File Id="readme" Name="README.txt" Source="README.txt" />
          </Component>
          <Directory Id="ItemDir" />
        </Directory>
      </Directory>
    </Directory>

    <Feature Id="Software"
             Title="Foo"
             AllowAdvertise="no"
             ConfigurableDirectory="INSTALLDIR">
      <ComponentRef Id="readme" />
      <ComponentGroupRef Id="Items" />
    </Feature>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
    <UIRef Id="WixUI_InstallDir" />
  </Product>
</Wix>

【讨论】:

  • 感谢您提供 wxs 文件。
  • 谢谢。你不会相信我花了多长时间试图找出实际收获代码的去向。我想我可以把它放在我的 Product.wxs 的某个地方...
【解决方案4】:

您可以设置一个 $(HeatDefinitions) 属性来在父 .wixproj 文件中定义这些属性:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>  
        <HeatDefinitions>MySourcePath=..\src\Your.App\bin\Release</HeatDefinitions> 
    </PropertyGroup>

    <ItemGroup>
        <Compile Include="Phoenix.wxs" />
        <Compile Include="_HeatGeneratedFileList.wxs" />
    </ItemGroup>

    <Target Name="BeforeBuild">
        <HeatDirectory Directory="..\src\Your.App\bin\Release"
                       OutputFile="_HeatGeneratedFileList.wxs" 
                       PreprocessorVariable="var.MySourcePath" />
    </Target>
</Project>

我能找到(在整个互联网上)唯一提到的这个神奇属性是在 wix-users 邮件列表上的a single question about Team Build。在花了将近一天的时间试图修复未定义的预处理器变量错误后,我很幸运地偶然发现了它。

【讨论】:

  • 如果您查看该邮件列表帖子中的 wixproj sn-p,您会注意到一点&lt;DefineConstants&gt;$(HeatDefinitions)&lt;/DefineConstants&gt; ...这就是“魔术”所在,它将该变量喷溅到“真实”变量。它以这种方式拆分,因此他们不必在调试和发布时重复自己。
【解决方案5】:

我发现它是什么,经过 1 天的尝试,上面的链接是正确的,但是要在 heatdirectory 任务中使用 var,你必须这样做。

<HarvestDirectory Include="$(ProjectDirectory)\" >
      <DirectoryRefId>WEBDIR</DirectoryRefId>
      <KeepEmptyDirectories>true</KeepEmptyDirectories>
      <SuppressRegistry>true</SuppressRegistry>
      <ComponentGroupName>DynamicWebFiles</ComponentGroupName>
      <PreprocessorVariable>var.WixDynamicSourceDirectory</PreprocessorVariable>
   </HarvestDirectory>

【讨论】:

  • 以上?上面在哪里?请提供链接,并说明您的代码。
【解决方案6】:

我有一个非常大的安装工具包要在 Visual Studio 2013 中构建(包括一些与主项目相关的工具、一个 Windows 服务和一个具有非平凡目录结构的 Web 应用程序)。我仍在学习如何使用 WiX,并且仍在制作、测试和完善 WiX 项目。目前,我使用以下形式的命令将收获任务设置为构建事件

"C:\Program Files (x86)\WiX Toolset v3.9\bin\heat.exe" dir "$(SolutionDir)\MyProjectDir\bin\$(ConfigurationName)" -cg MyComponentRef -ag -dr MYINSTALLDIR - srd -wixvar -var var.MySourceFiles -sreg -out "$(SolutionDir)\Deployment\My Installer Project\ComponentList.wxs" -t "$(SolutionDir)\Deployment\My Installer Project\FileFilter.xslt"

此命令只获取项目的 bin\Debug(或 bin\Release)文件夹中的所有文件,然后使用 xml 样式表转换对其进行过滤。像这样收集很多收获,因此维护所有源文件变量(命令中的“var.MySourceFiles”参数)变得乏味且容易出错。最初,我已将声明添加到项目的预处理器变量中,但我想要一些更“独立”的东西。使用我在WiX tricks and tips 找到的有用提示,我声明了一个新的包含文件“PreprocessorVars.wxi”,其中包含内容

并让 xslt 使用 sn-p 将其包含在 heat.exe 生成的输出中

    <xsl:processing-instruction name="include">
        $(sys.CURRENTDIR)\PreprocessorVars.wxi
    </xsl:processing-instruction>

xslt 现在产生如下所示的输出:

<?xml version="1.0" encoding="utf-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
        <?include 
                $(sys.CURRENTDIR)\PreprocessorVars.wxi
            ?>
        <Fragment>
            <DirectoryRef Id="MYINSTALLDIR" />
        </Fragment>
        <Fragment>
            <ComponentGroup Id="MyComponentRef">
                <Component Id="xyz" Directory="MYINSTALLDIR" Guid="*">
                    <File Id="abc" KeyPath="yes" Source="$(var.MySourceFiles)\MyProjectExecutable.exe" />
                </Component>
            </ComponentGroup>
        </Fragment>
    </Wix>

哪些 Wix 处理没有任何错误。

【讨论】: