如何将WiX安装程序版本设置为当前构建版本?

147

我编写了一个应用程序和它的WiX安装程序,并使用Subversion将其置于版本控制下。当WiX安装程序构建时,我希望它的版本号是应用程序的当前构建版本。我该如何实现这一点?我使用c#编写了应用程序。

注:我正在使用ccnet来构建此项目

7个回答

196
你可以使用 Product/@Version="!(bind.FileVersion.FileId)"(将FileId替换为您想要获取版本号的文件的Id),然后light.exe将使用所引用的FileId文件的版本填充该值。请参阅WiX v3文档以获取所有可用变量。

22
请注意,“Fileid”应是来自于一个 <File Id="Fileid" ...> 元素的值,并且显然可以包含点(.)字符。 - James Hugard
6
对于一个软件捆绑包或引导程序来说,这种做法是否可行? - noelicus
1
@Ali,请将FileId替换为实际的文件ID。 - Icerman
8
相关文档链接,章节:绑定变量 - mcdon
3
Binder Variables在WiX文档中应有更高的可见度。我花了几个小时来使用预处理器变量,但现在可以用两个简单的Binder Variables替换它们。 - PhilS
显示剩余7条评论

42

如果有人正在寻找一个真实的XML示例,这个示例适用于.NET程序集(你不必使用Assembly或KeyPath属性)。我用 [...] 占位符删除了无关的代码:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product [...] Version="!(bind.fileVersion.MyDLL)">
        [...]
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder" Name="PFiles">
                <Directory Id="INSTALLDIR" Name="MyDLLInstallLocation">
                    <Component Id="MainLib" Guid="[...]">
                        <File Id="MyDLL" Name="MyDll.dll" Source="MyDll.dll" />
                        [...]
                    </Component>
                    [...]
                </Directory>
            </Directory>
        </Directory>
    </Product>
</Wix>

它从哪里获取实际版本号? - foobar
1
@foobar 我已经有一段时间没来了,但是如果你看一下字符串!(bind.fileVersion.MyDLL),它使用第三部分来引用<File Id="MyDLL"...部分。 - K0D4
这对我很有效。适用于编译的可执行文件以及dll,非常适合将安装程序版本和UI内容固定到exe程序集信息中,而无需在多个地方更改内容。 - rcbevans

39

我在我的一个项目中通过编写预处理器扩展来读取可执行文件的文件版本来实现了这一点。因此,WiX文件看起来像:

<?define ProductName="$(fileVersion.ProductName($(var.MyApp.TargetPath)))" ?>
<?define CompanyName="$(fileVersion.CompanyName($(var.MyApp.TargetPath)))" ?>
<?define ProductVersion="$(fileVersion.ProductVersion($(var.MyApp.TargetPath)))" ?>
<Product 
    Id="<product ID>" 
    Name="$(var.ProductName)" 
    Version="$(var.ProductVersion)" 
    Manufacturer="$(var.CompanyName)" 
    Language="1033" 
    UpgradeCode="<upgrade code>">

我已在CodePlex上发布了该代码:http://wixfileversionext.codeplex.com/


你的扩展还能用吗?我试着将它添加为引用,但是出现了错误。 - Stefan Vasiljevic
这个扩展在Wix 3.5上运行得非常好,但更新到Wix 3.9后会抛出NullPointerException异常。显然,在这些版本之间发生了一些问题。 - Gigo
2
@Gigo 我已经通过 <?define ProductName="!(bind.property.ProductName)" ?><?define CompanyName="!(bind.property.Manufacturer)" ?><?define ProductVersion=!(bind.FileVersion.FileId) ?> 让它工作了。其中 FileIdComponent 内的一个 File 元素的 Id 属性的值。 - Jesus is Lord
CodePlex的链接对我来说无法打开。除了编写自己的预处理器扩展之外,还有其他方法吗? - RDV

26

使用 BeforeBuild TargetDefineConstants,可以非常简单地使您的 Bootstrapper Bundle 版本与 MyApp AssemblyVersion 匹配。

Bundle.wxs:

<Bundle Name="$(var.ProductName) Bootstrapper v$(var.BuildVersion)"
     Version="$(var.BuildVersion)"

引导程序.wixproj:

<Target Name="BeforeBuild">
  <GetAssemblyIdentity AssemblyFiles="..\MyApp\bin\$(Configuration)\MyApp.exe">
    <Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
  </GetAssemblyIdentity>
  <PropertyGroup>
    <DefineConstants>BuildVersion=%(AssemblyVersion.Version)</DefineConstants>
  </PropertyGroup>
</Target>

@AliKazmi 你是否在<Bundle>上方定义了你的 var.ProductNamevar.BuildVersion 变量? - Brock Hensley
3
我尝试过这个方法并且强烈推荐 - 结合TeamCity的汇编程序修补工具,你会得到一个成功的方案。我没有使用Bundle元素,而是使用了Product元素,但对我仍然有效。 - IbrarMumtaz
如果你在 IDE 中构建,VS 就喜欢忽略 BeforeBuild 目标,因此有必要明确指定 AfterTargets="AfterResolveReferences" - Dmitry
我在我的*.wixproj中添加了Bootstrapper.wixproj代码,并在Product.wxs文件中将buildversion变量定义为: - RDV
不幸的是,这对于 .NET Core 不起作用。 - Stepagrus
我正在使用Wix v.4,并根据这个问题#7048对这段代码进行了修改: <Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild"> 从一个EXE文件中获取版本对我来说不起作用,只有DLL文件可以。 - undefined

9
你可以像为应用程序的构建脚本传递版本一样,将版本传递给设置项目的MSBuild脚本。
例如,如果您的CI系统定义了变量“AppVersion”和“BuildNumber”,并将它们传递给您的MSBuild脚本,那么您的wixproj可以创建一个相应的“Version”属性,并将其转发到Wix,如下所示:
<PropertyGroup>
    <Version Condition=" '$(BuildNumber)' == '' ">0.0.1</Version>
    <Version Condition=" '$(BuildNumber)' != '' ">$(AppVersion).$(BuildNumber)</Version>
    <DefineConstants>Version=$(Version)</DefineConstants>
</PropertyGroup>

版本的第一个定义为在本地构建时提供默认值。无论最终结果是什么,都会成为Wix中的版本变量。可以在wsx文件中像这样使用它:

<Product Version="$(var.Version)" ...>
    <Package Description="$(var.ProductName) $(var.Version): $(var.ProductDescription)" ... />

我喜欢在描述中包含版本号,这样可以方便地从Windows资源管理器中查找(在详细视图中作为列或在属性页面上),与文件名无关。
将版本号作为变量传递比从文件中读取更具控制性。当您从文件中读取时,您会获得程序化版本的所有4个部分。但是,ProductVersion仅设计用于使用前3个部分。

谢谢,这个救了我的一天。顺便说一下:上面的代码片段要放入您的项目(*.wxiproj)中。在管理Devops/VSTS CI-Build时,这是最好的答案。由于我已经准备好了我的最终版本变量,所以在我的情况下它变成了:<Version Condition=" '$(BuildVersionOfAsm)' != '' ">$(BuildVersionOfAsm)</Version>,其中BuildVersionOfAsm是devops管道中的一个变量。 - Robetto
我想动态选择版本,使用这种方法将要求我不断更新*.wixproj中的版本。在此字段中是否有任何dll版本的方式? - RDV
@RDV 这种方法的意图是不更改源代码控制中的任何文件,包括 .wixproj 文件。动态版本号由您的 CI 系统提供(例如 AppVersion 和 BuildNumber)。通常,您将主要和次要版本号设置为 CI 变量,并让 CI 系统动态生成构建号。 - Edward Brey
非常好 - 这正是我需要的解决方案,包括本地构建的默认设置。 - ColH

4

0
在我参与的项目中,我采用了以下方法:
我在`Directory.Build.props`文件中定义版本。
<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PropertyGroup>
    <LangVersion>latest</LangVersion>
    <Version>0.1.0</Version>
  </PropertyGroup>
</Project>

.wixproj 中获取版本并定义一个常量
<Project Sdk="WixToolset.Sdk/4.0.0">
    <PropertyGroup>
        <OutputName>Example_MSI_name_v$(Version)_$(RuntimeIdentifier)</OutputName>
        <DefineConstants>
            ProductVersion=$(Version);
        </DefineConstants>
    </PropertyGroup>
</Project>

.wxs 文件中,定义了软件包设置。
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">

    <Package ProductCode="*"
             UpgradeCode="$(var.UpgradeCode)"
             Name="!(loc.ProductName)"
             Language="!(loc.Language)"
             Version="$(var.ProductVersion)"
             Manufacturer="!(loc.Company)">

        [...]

    </Package>
</Wix>

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