WIX 3.6安装程序 - Visual Studio 2010(HeatDirectory)

12
我正在为一个 Web 服务工作创建 WIX 3.6 安装程序。但是,在尝试使用 HeatDirectory 收集所有必要输出时,我遇到了一个问题,无论我尝试什么,都会对每个收集的文件产生以下错误:

系统找不到文件“SourceDir \ Some.dll ...”

错误发生在 WcfService.wxs 中;奇怪的是,WcfService.wxs 是由我的项目文件中的 heatdirectory 部分自动创建的(如下所示)。 如果它必须知道文件在哪里才能首先创建 WcfService.wxs,那么它怎么会出现找不到这些 .dll 的情况呢?即使我从我阅读的任何教程中下载和构建一个 WIX 示例项目(不做任何更改),这些错误仍然会发生。

目标:尽可能自动化 .dll 包含(即利用收集来处理依赖项目等)。

我正在运行 Win 7 64 位,项目是 .NET 4。

Product.wxs:

    <?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="*" Name="CompleteInstall" Language="1033" Version="1.0.0.0" Manufacturer="Technologies" UpgradeCode="b2ae6aa5-263f-4f9a-a250-8599a7f2cb03">
    <Package InstallerVersion="200" Compressed="yes" />

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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFiles64Folder">
        <Directory Id="CommonDir1" Name="Common Directory 1">
          <Directory Id="CommonDir2" Name="Common Directory 2">
            <Directory Id="INSTALLFOLDER" Name="Install Directory"/>
          </Directory>
        </Directory>
      </Directory>
    </Directory>

    <Feature Id="ProductFeature" Title="CompleteInstall" Level="1">
      <ComponentGroupRef Id="WcfService_Project" />
    </Feature>

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

项目文件:
<Target Name="BeforeBuild">
    <MSBuild Projects="%(ProjectReference.FullPath)" Targets="Build" Properties="Configuration=$(Configuration);Platform=x86" Condition="'%(ProjectReference.ContentProject)'=='True'" />
    <PropertyGroup>
      <LinkerBaseInputPaths>%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\$(Platform)\$(Configuration)\</LinkerBaseInputPaths>
    </PropertyGroup>
    <HeatDirectory OutputFile="%(ProjectReference.Filename)-temp.xml" 
                   Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)bin\$(Platform)\$(Configuration)\"
                   DirectoryRefId="INSTALLFOLDER" 
                   ComponentGroupName="%(ProjectReference.Filename)_Project"
                   SuppressCom="true" 
                   SuppressFragments="true" 
                   SuppressRegistry="true"
                   SuppressRootDirectory="true" 
                   AutoGenerateGuids="false" 
                   GenerateGuidsNow="true" 
                   ToolPath="$(WixToolPath)" 
                   Condition="'%(ProjectReference.ContentProject)'=='True'" />
    <XslTransformation XmlInputPaths="%(ProjectReference.Filename)-temp.xml"
                       XslInputPath="XslTransform.xslt" 
                       OutputPaths="%(ProjectReference.Filename).wxs" 
                       Condition="'%(ProjectReference.ContentProject)'=='True'" />
  </Target>

WcfService.wxs:

<?xml version="1.0" encoding="utf-8"?><Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmpE6EBA3D8D6D4DB0C93E73200C78DCC51" Guid="{C88B5CF9-8807-45DF-AA6F-732437B74BB6}">
                <File Id="fil0118BBA61671E80581CA9C9AA6DD3E8D" KeyPath="yes" Source="SourceDir\Some.dll" />
            </Component>
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="WcfService_Project">
            <ComponentRef Id="cmpE6EBA3D8D6D4DB0C93E73200C78DCC51" />
        </ComponentGroup>
    </Fragment>
</Wix>

你能发布完整的wxs文件吗?可能你没有输入正确的目录来引用Some.dll... - wimh
@Wimmel,我已经更新了原始帖子,包含完整的wxs。谢谢! - alan
@Wimmel,请记住,我已经说过我从多个源下载的示例项目也出现了同样的问题。 - alan
1
您引用了 WcfService_Project,它应该作为片段存在于另一个文件中。例如,请参见这里。在链接的问题中使用了 Source="PathToFile"PathToFile 应该指向一个已经存在的文件。 - wimh
@Wimmel,那实际上是对从收集的heat目录产生的wxs的引用。请看我上面的更新,我已经为您添加了那个wxs。顺便说一句:在我发布之前,我也看过你提供的那个例子。到目前为止,感谢你的帮助,我非常感激。 - alan
4个回答

14

问题是缺少 HeatDirectory PreprocessorVariable 属性。我通过以下方法在 wixproj 文件中添加解决方案:

<PropertyGroup>
  <DefineConstants>BasePath=%(ProjectReference.RootDir)%(ProjectReference.Directory);</DefineConstants>
</PropertyGroup>
<HeatDirectory OutputFile="%(ProjectReference.Filename).wxs" 
               DirectoryRefId="INSTALLFOLDER" 
               Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)"
               ComponentGroupName="%(ProjectReference.Filename)_Project"
               SuppressCom="true"
               SuppressFragments="true"
               SuppressRegistry="true"
               SuppressRootDirectory="true"
               AutoGenerateGuids="false"
               GenerateGuidsNow="true"
               ToolPath="$(WixToolPath)"
               Condition="'%(ProjectReference.ContentProject)'=='True'" 
               PreprocessorVariable="var.BasePath"/>

如您所见,我需要先定义一个常量变量供本地使用。我将该变量设置为我的WCF项目的根路径。其次,我将该变量用作我的预处理器变量。最后,我能够动态/递归地收集MsBuild生成的文件。下一步是排除不必要的文件。我将参考此链接

请查看下面完整的wixproj:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProductVersion>3.5</ProductVersion>
    <ProjectGuid>{4005592f-cc0e-41a3-8e64-33b2824e7fd9}</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputName>MyWCF.WCF.Webservice</OutputName>
    <OutputType>Package</OutputType>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <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>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="MyWCF.WcfService.wxs" />
    <Compile Include="IISConfig.wxs" />
    <Compile Include="InstallUi.wxs" />
    <Compile Include="Product.wxs" />
    <Compile Include="UIDialogs.wxs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\MyWCF.WcfService\MyWCF.WcfService.csproj">
      <Name>MyWCF.WcfService</Name>
      <Project>{8e528b38-2826-4793-a66d-f6ff181e1139}</Project>
      <Private>True</Private>
      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
      <RefTargetDir>INSTALLFOLDER</RefTargetDir>
      <ContentProject>True</ContentProject>
      <DoNotHarvest>True</DoNotHarvest>
      <PackageThisProject>True</PackageThisProject>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <WixExtension Include="WixIIsExtension">
      <HintPath>$(WixExtDir)\WixIIsExtension.dll</HintPath>
      <Name>WixIIsExtension</Name>
    </WixExtension>
    <WixExtension Include="WixUtilExtension">
      <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
      <Name>WixUtilExtension</Name>
    </WixExtension>
    <WixExtension Include="WixUIExtension">
      <HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
      <Name>WixUIExtension</Name>
    </WixExtension>
    <WixExtension Include="WixNetFxExtension">
      <HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath>
      <Name>WixNetFxExtension</Name>
    </WixExtension>
  </ItemGroup>
  <ItemGroup>
    <Content Include="ConfigurationInitialize.wxi" />
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
  <PropertyGroup>
    <PreBuildEvent />
  </PropertyGroup>
  <Target Name="BeforeBuild">
    <MSBuild Projects="%(ProjectReference.FullPath)" Targets="Package" Properties="Configuration=$(Configuration);Platform=$(Platform)" Condition="'%(ProjectReference.PackageThisProject)'=='True'" />
    <PropertyGroup>
      <DefineConstants>BasePath=%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Platform)\$(Configuration)\Package\PackageTmp\</DefineConstants>
    </PropertyGroup>
    <HeatDirectory OutputFile="%(ProjectReference.Filename).wxs" 
                   Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Platform)\$(Configuration)\Package\PackageTmp"
                   DirectoryRefId="INSTALLFOLDER"
                   ComponentGroupName="%(ProjectReference.Filename)_Project"
                   SuppressCom="true"
                   SuppressFragments="true"
                   SuppressRegistry="true"
                   SuppressRootDirectory="true"
                   AutoGenerateGuids="false"
                   GenerateGuidsNow="true"
                   ToolPath="$(WixToolPath)" Condition="'%(ProjectReference.PackageThisProject)'=='True'"
                   PreprocessorVariable="var.BasePath" />
  </Target>
</Project>

我遇到了同样的问题,但目前我还没有看到这如何解决问题。DefineConstants是否应该替换原始的LinkerBaseInputPaths元素? - jpierson
1
@jpierson 我已经更新了答案,请告诉我如果这个答案没有回答你的问题。 - alan
好的,感谢您,我相信现在一切都正常了。由于格式问题,我错过了您的HeatDirectory元素上的PreprocessorVariable="var.BasePath"属性。接下来,我不得不将其他WIX项目文件中的所有SourceDir引用替换为对var.BasePath的引用,包括我的XSLT转换中。 - jpierson
我想补充说明一下,我仍然不确定为什么在WIX 3.6中SourceDir不再起作用,而在WIX 3.5的教程中似乎可以正常工作。 - jpierson
太棒了,谢谢Alan!我已经在我的博客上发布了这些信息,很快也会修改原始帖子。感谢你的帮助! - Chris Surfleet

2
我遇到了与你类似的问题,当我从使用Wix设置基本网站转移到我们的生产网站之一时。
假设您正在按照Paul Reynolds的示例Paraesthesia的示例进行操作。
如果您查看以下页面的评论 - http://blogs.planetsoftware.com.au/paul/archive/2011/02/20/creating-a-web-application-installer-with-wix-3.5-and-visual.aspx 第一条评论提到更改在Paraesthesia的示例中找到的beforebuild方法。
        <Target Name="BeforeBuild"> 
    
    <MSBuild Projects="%(ProjectReference.FullPath)" Targets="Package" Properties="Configuration=$(Configuration);Platform=AnyCPU" Condition="'%(ProjectReference.WebProject)'=='True'" /> 
    <PropertyGroup> <DefineConstants Condition="'%(ProjectReference.WebProject)'=='True'"> %(ProjectReference.Name).PackageDir=%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\ </DefineConstants> </PropertyGroup> <HeatDirectory OutputFile="%(ProjectReference.Filename).wxs" Directory="%(ProjectReference.RootDir)%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\" DirectoryRefId="INSTALLDIR" ComponentGroupName="%(ProjectReference.Filename)_Project" AutogenerateGuids="true" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" ToolPath="$(WixToolPath)" Condition="'%(ProjectReference.WebProject)'=='True'" Transforms="%(ProjectReference.Filename).xsl" PreprocessorVariable="var.%(ProjectReference.Name).PackageDir" /> 
</Target>

我不得不删除transform属性并更改DirectoryRefId,但目前为止效果很好。希望这可以指引您找到正确的方向。

谢谢您的建议。我有机会的话会尝试并更新这个帖子。 - alan
虽然这不是解决我的问题的方法,但它确实让我朝着一个新的方向开始了。请查看标记的答案。 - alan

0
更新:如果您放置了

<PropertyGroup>
<DefineConstants Condition="'%(ProjectReference.WebProject)'=='True'">
%(ProjectReference.Name).PackageDir=%(ProjectReference.RootDir)
%(ProjectReference.Directory)obj\$(Configuration)\Package\PackageTmp\
</DefineConstants>

并添加:

PreprocessorVariable="var.%(ProjectReference.Name).PackageDir"

请看底部的评论。我没有进行转换,所以将其省略了。 对于HeatDirectory,它应该可以正常工作,而不必在底部拥有proj文件。

这可能会降低我的声誉,但我发现http://www.paraesthesia.com网站很有趣,我曾经为一个项目工作过,但尝试另一个项目时却无法工作。
在查看输出后,似乎采用了适当的Heat和Candle项目,但Light似乎随机选择了一个。比较了两个项目后,我注意到工作项目将要收集的项目列在最后。当我将项目在.wixproj文件中移动到最后引用时,它就起作用了。
我目前使用的是3.5.2519版本。我知道这是一个旧版本,但我们有一些需要在Visual Studio中将Harvest设置为True并实际进行收集的项目。


不是相关的回答。 - αƞjiβ
WIX很难理解。我认为我的答案回答了这个问题。 - Pete Hecht

-1

所以你的 WcfService.wxs 包括:

<File Id="fil0118BBA61671E80581CA9C9AA6DD3E8D" KeyPath="yes" Source="SourceDir\Some.dll" />

这是关于 SourceDir\Some.dll 的。这个文件必须存在于您编译项目的计算机上。您可能需要更改路径。

据我所知,SourceDir是指源.dll文件所在的路径关键字。WcfService.wxs实际上是收集的heatdirectory的产物(WcfService.wxs会自动创建)。问题是如何修复它。我已经更新了原帖以进行澄清。 - alan
1
@alan 如果你每次构建时都运行heat,我认为在更新过程中会遇到问题,因为每次都会生成一个新的guid。你可以向heat添加一个[参数-var](https://dev59.com/oWoy5IYBdhLWcg3wg-cm#8590298),以指定使用什么代替SourceDir。或者使用light的[-b选项](https://dev59.com/M2w05IYBdhLWcg3w9mnd#6920979)指定文件存储位置。 - wimh
如果我是通过Visual Studio 2010 WIX设置项目构建这个,我应该把这个变量放在哪里?你知道有没有什么例子吗? - alan
1
@Wimmel 你可以创建一个 config.wxi 文件来存储你的变量,然后在安装项目中引用该文件。你可以在这里看到一些使用配置文件的示例:https://dev59.com/UHRB5IYBdhLWcg3w6LV2 - BryanJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接