使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(二)——自定义安装

使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(二)——自定义安装自定义产品卸载方式        继续从上一次的基础上前进,现在我们已经知道了最简单的bootstrapper打包方法,现在我们对其中的每个节点深入自定义,争取可以达到我们需要的效果。先把最后全部的XML贴出来。

大家好,又见面了,我是你们的朋友全栈君。

自定义产品卸载方式

      

        继续从上一次的基础上前进,现在我们已经知道了最简单的bootstrapper打包方法,现在我们对其中的每个节点深入自定义,争取可以达到我们需要的效果。先把最后全部的XML贴出来。

<?xml version="1.0" encoding="UTF-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" > <Bundle Name="CamCard" Version="4.0.0.0" Manufacturer="IntSig Information Co., Ltd." AboutUrl="http://www.intsig.net" IconSourceFile="icon_256.ico" UpgradeCode="1EB9EC76-9E5F-4471-B522-314A62518A80" DisableRemove="no" DisableModify="yes" DisableRepair="yes"> <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"> <bal:WixStandardBootstrapperApplication LicenseFile="license.rtf" ThemeFile="MyTheme.xml" LocalizationFile="MyLocalize.wxl" LogoFile="logo.png" /> </BootstrapperApplicationRef> <Chain> <ExePackage Id="Netfx4Full" Cache="no" Compressed="no" PerMachine="yes" Permanent="yes" Vital="yes" InstallCommand=" /q /norestart" SourceFile="dotNetFx40_Full_x86_x64.exe" DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=164193" DetectCondition="DotNetFramework40FullInstallRegValue=1" /> <MsiPackage Compressed="no" SourceFile="SSCERuntime-CHS.msi" Vital="yes" DisplayInternalUI="no" Permanent="yes" ForcePerMachine="yes" DownloadUrl="http://go.microsoft.com/fwlink/?LinkID=166085" InstallCondition="VersionNT = v5.1" /> <MsiPackage Compressed="no" SourceFile="IntSig.CamCard.Installer.msi" Vital="yes" DisplayInternalUI="no" Permanent="no" ForcePerMachine="yes"> <MsiProperty Name="TARGETDIR" Value="[InstallFolder]"/> </MsiPackage> </Chain> <util:RegistrySearch Id="FindDotNet40FullInstallRegValue" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Install" Variable="DotNetFramework40FullInstallRegValue" /> </Bundle> </Wix>


        Bundle节点前面几个属性我们都已经知道了,IconSourceFile就是打包后exe的图标设置,DisableRemove、DisableModify这两个属性比较有讲究,他们分别设置了在“添加/删除程序”列表中,选中安装包后鼠标右击,是否会出现“卸载”和“修改”这两个选项。如果这两个选项都同时为yes,那这个产品安装后根本就不会出现在“添加/删除程序”列表中,只能通过再次双击bootstrapper安装exe进行卸载。


自定义产品安装界面

      

 <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"> <bal:WixStandardBootstrapperApplication LicenseFile="license.rtf" ThemeFile="MyTheme.xml" LocalizationFile="MyLocalize.wxl" LogoFile="logo.png" /> </BootstrapperApplicationRef>


        BootstrapperApplicationRef这个节点上一篇已经讲解过,但是我们使用的是最原始的默认界面,事实上可以通过在该节点中加入WixStandardBootstrapperApplication来自定义安装界面。LicenseFile就是要显示在用户安装协议中的RTF文件名称。ThemeFile是自定义主题xml文件,该文件详细定义了安装界面中的每个按钮和控件的位置。LocalizationFile是本地化配置文件,这个版本的Burn框架还不支持运行时自动根据安装语言环境自动切换。如果你需要采用本地化安装策略,比较靠谱的方法就是在bootstrapper之前再执行另一个exe,用来判断语言环境并自动执行不同的bootstrapper进行安装。LogoFile是安装界面左上角那个图标,注意XP环境下好像是不能使用ICON文件的。


        ThemeFile=”MyTheme.xml” 这个文件可以在WiX源代码中找到,我贴在这篇博客里面,方便大家直接复制粘贴,这文件和后面的本地化文件的确不好找。

<?xml version="1.0" encoding="utf-8"?>
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
  <Window Width="485" Height="300" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
  <Font Id="0" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
  <Font Id="1" Height="-24" Weight="500" Foreground="000000">Segoe UI</Font>
  <Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
  <Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
  <Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>

  <Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
  <Text X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Text>

  <Page Name="Help">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Text>
    <Text X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Text>
    <Button Name="HelpCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.HelpCloseButton)</Button>
  </Page>
  <Page Name="Install">
    <Richedit Name="EulaRichedit" X="11" Y="80" Width="-11" Height="-70" TabStop="yes" FontId="0" HexStyle="0x800000" />
    <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
    <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.InstallOptionsButton)</Button>
    <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
    <Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
  </Page>
  <Page Name="Options">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Text>
    <Text X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Text>
    <Editbox Name="FolderEditbox" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
    <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">#(loc.OptionsBrowseButton)</Button>
    <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsOkButton)</Button>
    <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsCancelButton)</Button>
  </Page>
  <Page Name="Progress">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
    <Text X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
    <Text Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
    <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
    <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
  </Page>
  <Page Name="Modify">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
    <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
    <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
    <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyCloseButton)</Button>
  </Page>
  <Page Name="Success">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.SuccessHeader)</Text>
    <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
    <Text Name="SuccessRestartText" X="-11" Y="-51" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
    <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
    <Button Name="SuccessCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.SuccessCloseButton)</Button>
  </Page>
  <Page Name="Failure">
    <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FailureHeader)</Text>
    <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
    <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
    <Text Name="FailureRestartText" X="-11" Y="-51" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
    <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
    <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
  </Page>
</Theme>

        可以看到这个XML文件可以通过自定义的方法来进行界面修改,其中#(loc.Caption)之类的是WiX使用变量的语法,这些变量都是已经内嵌在框架中了,我们还可以通过在bundle.wxs文件中自行增加变量的方法来达到增加变量的目的。MyLocalize.wxl文件如下:

<?xml version="1.0" encoding="utf-8"?>
<WixLocalization xmlns="http://schemas.microsoft.com/wix/2006/localization">
  <String Id="Caption">Setup [WixBundleName]</String>
  <String Id="Title">[WixBundleName]</String>
  <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
  <String Id="HelpHeader">Setup Help</String>
  <String Id="HelpText">
    /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
    creates a complete local copy of the bundle in directory. Install is the default.

    /passive | /quiet -  displays minimal UI with no prompts or displays no UI and
    no prompts. By default UI and all prompts are displayed.

    /norestart   - suppress any attempts to restart. By default UI will prompt before restart.
    /log log.txt - logs to a specific file. By default a log file is created in %TEMP%.
  </String>
  <String Id="HelpCloseButton">&Close</String>
  <String Id="InstallAcceptCheckbox">I &agree to the license terms and conditions</String>
  <String Id="InstallOptionsButton">&Options</String>
  <String Id="InstallInstallButton">&Install</String>
  <String Id="InstallCloseButton">&Close</String>
  <String Id="OptionsHeader">Setup Options</String>
  <String Id="OptionsLocationLabel">Install location (disk root path is not recommanded):</String>
  <String Id="OptionsBrowseButton">&Browse</String>
  <String Id="OptionsOkButton">&OK</String>
  <String Id="OptionsCancelButton">&Cancel</String>
  <String Id="ProgressHeader">Setup Progress</String>
  <String Id="ProgressLabel">Processing:</String>
  <String Id="OverallProgressPackageText">Initializing...</String>
  <String Id="ProgressCancelButton">&Cancel</String>
  <String Id="ModifyHeader">Modify Setup</String>
  <String Id="ModifyRepairButton">&Repair</String>
  <String Id="ModifyUninstallButton">&Uninstall</String>
  <String Id="ModifyCloseButton">&Close</String>
  <String Id="SuccessHeader">Setup Successful</String>
  <String Id="SuccessLaunchButton">&Launch</String>
  <String Id="SuccessRestartText">You must restart your computer before you can use the software.</String>
  <String Id="SuccessRestartButton">&Restart</String>
  <String Id="SuccessCloseButton">&Close</String>
  <String Id="FailureHeader">Setup Failed</String>
  <String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.</String>
  <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
  <String Id="FailureRestartButton">&Restart</String>
  <String Id="FailureCloseButton">&Close</String>
</WixLocalization>

        我们只需要修改每个String节点中的内容,就可以达到本地化安装内容的目的。


自定义安装序列


        上面我们已经将安装界面全部自定义完毕,脸面上的事情总算是做完了,我们要解决的根本问题还在眼前,如何自定义调整安装顺序?答案就是通过Chain节点来完成。Chain节点定义了打包安装的顺序,默认是从上到下逐个完成,当然你也可以在子节点中通过After属性来调整安装顺序。


        首先是判断并安装.NET Framework 4.0环境。

      <ExePackage Id="Netfx4Full"
          Cache="no"
          Compressed="no"
          PerMachine="yes"
          Permanent="yes"
          Vital="yes" InstallCommand=" /q /norestart"
          SourceFile="dotNetFx40_Full_x86_x64.exe"
          DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=164193"
          DetectCondition="DotNetFramework40FullInstallRegValue=1" />

        我们知道,从网上下载得到的.NET 4.0是一个exe安装包,因此我们要用ExePackage进行声明。

        Compressed表示是否要将该安装包打包在bootstrapper.exe文件中,我们回忆一下上一讲,上一讲我们的Setup1.msi文件因为没有带上该属性,就自动将安装包打包在bootstrapper中了,因此我们只得到了一个安装文件。如果Compressed=”no”,那就会在bootstrapper.exe边上出现另外一个单独的安装文件,这样可以减小我们发布的尺寸。

        PerMachine是表示是否要采用UAC权限进行安装,因为有些安装文件需要以管理员身份运行才能安装成功,而我们现在采取的是静默安装策略,因此需要在定义安装的时候就表明是否需要UAC权限。

        Permanent表示卸载时是否需要同时卸载该安装包。yes表示卸载产品时该安装包不需要同时卸载,将会永远留在客户的计算机里面。

        Vital表示是否该安装时必须的,如果该安装是必须的,那如果该安装没有成功,后续的所有安装都不会进行。

        InstallCommand是在安装时需要跟上的参数,我们知道.NET的静默安装需要带上“ /q /norestart”参数,这样我们用bootstrapper托管下就可以让.NET静默安装完毕了。

        SourceFile表明安装文件的名称是什么,它和DownloadUrl是任选的,也就是说如果安装时发现该文件包不存在的话,需要从什么URL进行自动下载并安装。

        DetectCondition是bootstrapper的精髓,它用一个表达式来判断一台计算机上该包是否已经安装过,DotNetFramework40FullInstallRegValue和文档最后的util:RegistrySearch节点ID是一致的,util:RegistrySearch代表查看注册表中的某个表项的值的变量,然后匹配该注册表项值满足条件,则说明已经安装,如果不满足则说明需要安装。


<MsiPackage Compressed="no" SourceFile="SSCERuntime-CHS.msi" Vital="yes" DisplayInternalUI="no" Permanent="yes" ForcePerMachine="yes"
          DownloadUrl="http://go.microsoft.com/fwlink/?LinkID=166085"
          InstallCondition="VersionNT = v5.1" />


        MsiPackage节点上一讲已经使用过,如果要安装MSI文件必须用这个节点,它的属性和ExePackage大同小异,DisplayInternalUI表示是否要静默安装,ForcePerMachine代表需要UAC权限。InstallCondition代表需要安装的判定条件,请注意,这个和上面的DetectCondition是反的,上面是如果判定为false则安装,这个是判定为true则安装。(看到这儿实在觉得这是不是两个人写的框架啊,属性名称也不统一,连判定安装条件也要反一反,很是反人类啊!)InstallCondition=”VersionNT = v5.1″表示如果是XP则进行安装,VersionNT是框架自带的变量,可以在WiX的网站中查询并得到其他的变量使用方法。


      <MsiPackage Compressed="no" SourceFile="IntSig.CamCard.Installer.msi" Vital="yes" DisplayInternalUI="no" Permanent="no"  ForcePerMachine="yes">
        <MsiProperty Name="TARGETDIR" Value="[InstallFolder]"/>
      </MsiPackage>

        最后一个MSI就是我们自己定义的MSI了,前面是把环境安装包给安装掉,最后就是安装我们自己的产品包。重点需要解释的是<MsiProperty Name=”TARGETDIR” Value=”[InstallFolder]”/>节点,这个其实就是相当于我们使用msiexec.exe系统命令进行MSI安装,如果我们要把MSI静默安装,又必须指定要装到某个目录下,需要使用msiexec.exe ***.msi TARGETDIR=”C:\AA\” 这样的命令格式,其实上面的
MsiProperty属性就是把之前在bootstrapper启动界面选项中选中的安装目录路径通过变量传送了过来。


        完成上面的这些工作,再把所需要的安装包,配置文件都放到工程里面后,经过项目生成,我们就拿到很完美的bootstrapper了。现在的结果是,最极限情况下我们只需要发布一个bootstrapper,后续所有的软件依赖就能下载并安装,极大得减少了用户下载安装的负担。并且因为可以动态判断依赖包,所以用户的安装速度也得到极大的提升。最最重要的是,只需要在安装第一个包的时候进行一次UAC询问,后续就不再会有类似的恼人确认对话框了。至此,我们之前所有提出的VS打包项目的不足就全部解决了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162177.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【网络安全】ettercap详细使用

    【网络安全】ettercap详细使用ettercap 劫持一 什么是 ettercap 1 Ettercap 是一款用户用于远方控制的黑客工具 是非常主流的工具之一 简单的来说一下原理吧所有的物理机执行命令都是通过命令发送给 DNS 解析 DNS 解析命令后 发送给服务器 服务器再发给主机进行响应 图片来源 https image so com view q dns E8 A7 A3 E6 9E 90 E8 BF 87 E7 A8 8B amp src tab www amp correct dns E8 A7 A3 E6 9E 90

    2025年10月8日
    2
  • 最大公约数和最小公倍数的关系

    最大公约数和最小公倍数的关系联系:最大公约数:指两个或多个整数共有的约数中最大的那个最小公倍数:指两个或多个整数共有的倍数中最小的那个以两个整数为例:最大公约数表示为:(a,b)最小公倍数表示为:[a,b]定理:(a,b)X[a,b]=ab(a,b均为整数)例题:#include<stdio.h>intmain(){ intm,n,min=0,max=0; scanf(“%d%d”,&m,&n); //求最大公约数 for(inti

    2022年5月17日
    63
  • 【SSM – SpringMVC篇】02 – SpringMVC执行流程详解,SpringMVC三大核心组件和使用,SpringMVC头文件模板

    【SSM – SpringMVC篇】02 – SpringMVC执行流程详解,SpringMVC三大核心组件和使用,SpringMVC头文件模板1.SpringMVC执行流1.1SpringMVC三大核心组件HandlerMapping处理器映射器:建立地址与方法的映射。HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。HandlerAdapter处理器适配器:根据地址调用方法。Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet

    2022年6月28日
    31
  • chmod的用法_crontab用法

    chmod的用法_crontab用法整理一下chmod用法,给自己看~~~~语法chmod[-cfvR][–help][–version]modefile…参数说明:-c:若该文件权限确实已经更改,才显示其更改动作-f:若该文件权限无法被更改也不要显示错误讯息-v:显示权限变更的详细资料-R:对目前目录下的所有文件与子目录进行相同的权限变更(即以递回的方式逐个变更)–help:…

    2022年10月19日
    3
  • 三极管的应用之开关电路设计「建议收藏」

    三极管的应用之开关电路设计「建议收藏」—引言—开关电路在单片机电路设计中经常用到,一般有两个作用,一是电平的转换,二是增加单片机IO口的驱动能力。虽然这个电路很简单,也很常用,但是我发现还是有些人电路结构错误或者参数不会设置。—电路结构—如图1所示,三极管开关电路基本结构由基极电阻,集电极电阻(负载)组成。图1三极管开关电路基本结构有些人设计的开关电路就没有基极电阻,有可能不是他不知道这种电路结构,而是他不会调参数,不管怎么改变Rb,始终电路都没有进入饱和区,最后将Rb短接后发现电路正常了,导致他认为这样电路是可以..

    2022年9月20日
    2
  • native DRAMAtical Murder_project diablo 2

    native DRAMAtical Murder_project diablo 2投影投影是JMESPath的关键特性之一。它允许您将表达式应用于元素集合。有五种投影:列表投影切片投影对象投影展平投影过滤投影处理投影需要注意的点投影分为两个步骤。左侧(LHS)创建一

    2022年7月29日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号