为了账号安全,请及时绑定邮箱和手机立即绑定

Wix Installer:在命令行执行MSIEXEC管理员安装时设置组件条件属性

/ 猿问

Wix Installer:在命令行执行MSIEXEC管理员安装时设置组件条件属性

我们的产品有三种类型/口味,但是只有一种用WiX编写的MSI。在构建安装程序时,我们通过定义的常量传递风味:


Call MSBUILD.bat ..\MSIs\CoreProduct\OurProduct.sln /p:DefineConstants="FLAVOUR=%_Flavour%"

并在Visual Studio中的“构建”->“将预处理器变量定义为FLAVOUR = 50”下设置该常数。构建过程会传递50、200或LITE值作为风味。


在WiX代码中,我们在组件上有很多条件,可以根据不同的情况告诉它要安装哪个文件。例如


      <Component Id="cmp7F45920B1AA100729BAE37FC846B3FC5" Guid="*">

    <File Id="fil238A776D9294E14671E012472F9F7196"

          KeyPath="yes"

          Source="$(var.MenusPath)\ClientListView 200.r5m"  

    <Condition>$(var.FLAVOUR)=200</Condition>

  </Component>


      <Component Id="cmp8BFF42B232724DC4BA5B8F87994DEF21" Guid="*">

    <File Id="fil808D6428D67248DDB8CA65DBC5978283" 

          KeyPath="yes" 

          Source="$(var.MenusPath)\ClientListView Lite.r5m"

    <Condition>$(var.FLAVOUR)=LITE</Condition>

  </Component>

因此,如果FLAVOR是LITE,则上面的示例将安装一个名为“ ClientListView Lite.r5m”的文件;如果FLAVOR是200,则将安装一个名为“ ClientListView 200.r5m”的文件。


这一切都按预期进行,并且已经完成了多年!


但是现在,我们有了产品的Web版本,我们需要一个zip文件来包含每种风味将安装的文件夹结构和文件。我发现您可以使用MSIEXEC和/ a参数在命令行上运行msi,然后它将重定向所有本应安装到文件夹中的内容,并认为这正是我想要的...但是a,它无法正常工作预期的。


似乎正在运行MSI,然后将文件提取到目标文件夹中,但是它忽略了这种风格,因此最终将“ ClientListView Lite.r5m”和“ ClientListView 200.r5m”文件提取到文件夹; 这显然不是我想要的。


阅读有关MSIEXEC的文档后,似乎可以传递Public属性的值,例如msiexec.exe / a“ C:\ Example.msi” MY_PROP =“ myValue”-因此,我认为这可能对我有所帮助;因此,在我的WiX代码中,添加了以下行:


    <Property Id='PRODTYPE' Value="$(var.FLAVOUR)"/>

然后将我的组件条件更改为:


  <Component Id="cmp7F45920B1AA100729BAE37FC846B3FC5" Guid="*">

    <File Id="fil238A776D9294E14671E012472F9F7196"

          KeyPath="yes"

          Source="$(var.MenusPath)\ClientListView 200.r5m"  

    <Condition><![CDATA[PRODTYPE=200]]></Condition>

  </Component>



但是尽管编译正常,但可以通过以下方式运行它:


msiexec /a OurProduct.msi /qb PRODTYPE=200 TARGETDIR="C:\InstalledFiles200"

仍然提取200和LITE口味的两个文件,而我只想提取200个。


因此,我是在尝试做一些不可能的事情...还是我在做错什么-感激不尽的帮助,因为可以在批处理文件中模仿该过程来创建我的zip;将是可怕的!


查看完整描述

3 回答

?
九州编程

通常,msiexec命令行中的/ a开关不是安装。实际上,这只是将文件解压缩到某个位置。如果要实际安装,则必须使用/ i或双击MSI文件。这将为您提供正确的完整安装,并在Programs&Features等条目中有一个条目。

通常,通过将安装分为功能来处理安装内容的选择,每个功能都包含一组包含所需功能的组件。在WiX UI中,您可以找到一个对话框来选择功能,而维护模式将使您返回并对其进行更改。在命令行安装中,您只需说/ i [msi文件] ADDLOCAL = Feature1,Feature2,依此类推。如果您真的想使用“风味”,则在内部将其转换为ADDLOCAL列表。


查看完整回答
反对 回复 2019-12-06
?
春华秋衣

您的预处理器使用

我是中途有一个建议回答使用预处理器结构(?if?等人),当我意识到你只是想一个MSI(至少在一段时间-看来),所以我跳过它。我通常使用这种构造来编译来自同一WiX源的MSI文件。我已经将我在下面写的内容转储了一些,没有进行过多的评论。我稍后会检查。


在您的情况下,我可能会缺少一些内容,但是我看不到?if?语句在安装时如何工作- 这是一个编译时结构。在编译和链接之前,它会对WiX源文件进行预处理。因此,听起来您实际上已经编译了MSI文件的三个不同版本,然后在每个版本上运行admin install?如果是这种情况,那么使用管理映像就无关紧要了,因为您的整个MSI除了包含的组件之外都不包含任何内容?if?-无需传递任何版本属性说明。


设置风味

当我需要创建不同的安装风格或产品版本时,我使用的常规技术方法如下:


预处理器构造:用于在编译时编译MSI的不同版本或版本(也包括不同的语言版本)。这样的构造就是?if?您要提及的语句。如上面直接提供的链接所示,还有其他几种。相关药粥,你将是条件语句(if,ifdef,ifndef,else,elseif,endif)和可能的include声明。


因此,总体信息是,预处理器构造使您可以从单个WiX XML源构建几种不同类型的MSI文件。


在您的情况下,这将产生一个WiX XML源和三个MSI文件 -每个文件用于应用程序的不同版本。都相似,但是只需要它们所需的组件。


通过/i或通过管理映像(文件解压缩)来运行安装/a只会产生添加到该安装程序样式中的组件,但您所说的没有一个MSI,而是三个不同的组件,具体取决于您的编译方式。


我更喜欢使用?include?语句包括WiX片段文件,而不是?if?像您提到的那样直接使用条件组件。在“ 预处理器构造 ”部分的底部有一个差异示例。


MSI功能(如PhilDW回答的那样):您还可以依靠MSI功能来提供不同口味的单个设置。功能用于将MSI分为各种用户可选择的安装项目(其中一些可以强制执行)。


功能允许单个MSI以不同的口味安装 -同时包含每种口味所需的所有组件。调理组件可以达到类似的效果。

条件组件类似于功能操纵,但在更原始和更基础的级别上工作。这些不是用户可选择的安装单元,而是要安装的产品的基本和基本的零组件,对于用户而言是隐藏的,而功能是用户可选择的,并且通常对用户可见。

哪些功能要安装可以由用户调整或编程方式操作通过自定义操作(重写用户规范和加强技术设计的自动神奇-例如)。


用户功能控制


用户可以通过大多数设置(并非全部)中找到的安装程序的FeatureTree对话框来控制功能以进行交互式安装。通常,这涉及选择进行“自定义”安装。


您还可以使用ADDLOCAL属性和REMOVE属性(以及可能的其他相似属性-通过链接了解详细信息),通过命令行指定要在安装程序中安装哪些功能。


有时,您可以在安装过程中设置一个自定义属性,该属性将根据指定的“版本”触发要安装的一组标准功能,这将使我们进入下一步。


程序特征控制


将链接添加到有关程序化功能控件的答案:如何根据在自定义操作中设置的属性安装功能?


如前所述,您可以在安装程序运行时通过其内部的ADDLOCAL属性和REMOVE属性来控制通过命令行安装哪些功能。为此,您可以使用自定义操作。


还有一个INSTALLLEVEL属性,与功能的安装状态有关。对于每个功能,都有一个安装级别,并且可能会受“ 条件”表中设置的条件影响。


因此,条件表可用于基于条件表达式来修改功能表中任何条目的选择状态。


换句话说,您可以使用此功能根据条件将功能设置为默认安装或不安装。


除了INSTALLLEVEL概念外,您还可以使用自定义操作来控制特征选择状态。


今天,这比功能状况更可靠,因为许多应用程序打包程序通常会最大化INSTALLLEVEL属性来强制安装所有功能。这是错误的,因为如果某些功能与您所运行的操作系统不兼容,则可能不需要安装这些功能。我已经尝试将其传达给许多充耳不闻的人。

使用这些程序结构,您的设置可以例如根据用户输入的序列号更改要安装的功能的功能选择状态。


您的设置还可以根据正在运行的操作系统确定不应安装某些功能(Tablet OS例如,不要安装功能)。


以编程方式更改功能选择可能有许多技术和实践原因。


重要的是要注意,总体结果是可以通过命令行或用户来设置功能选择,然后出于技术原因,您的设置将进行“幕后”修改。


需要指出的是:以编程方式进行安装操作的功能通常从视图中隐藏(但仍然可以通过命令行覆盖-这可能是一个问题)。


有关安装的功能,组件和自定义设置的更多信息,请点击此处:如何更好地利用MSI文件。


Setup.exe启动器:一种以不同方式进行复杂部署的“现代”方法可以是使用WiX的Burn功能来编译安装在不同“集合”中的较小MSI安装程序,以产生不同的安装状态。


我发现这对于一般用途来说太复杂了,但是肯定是可能的。我认为有些人发现它更容易,因为功能操纵较少。也许我只是缺乏经验。

好处是较小的MSI文件可以更快地安装,您可以更新单个MSI文件并创建新的setup.exe包装器,然后对整个解决方案进行总质量检查,而无需重建所有设置。

在我的世界中,无论如何,一个更新的MSI仍然需要完整的质量检查,因此我并不总是自己购买这些“简单性论证”。每个发布周期都有风险,因此会增加总风险。但是,能够重建一个很小的设置并保持大型的稳定状态可能很棒。

实际使用

我更喜欢尽量减少设置风格,但是大多数时候我都会使用预处理器构造为不同的语言版本(英语,德语,俄语)和不同的产品版本(企业版,专业版,标准版)创建不同的设置。。我通常将所有相关的共享设置为升级代码,并且不能并行安装。


我觉得单个MSI可以获得更多的质量检查资源,因此将得到更好的测试。但是,如果设置非常大,则这种单一的MSI方法通常会崩溃-在这种情况下,我希望将它们拆分。我还喜欢出于业务和现实中的实际原因,为每种语言进行单独的设置。实际和法律要求(许可)还可能必须编译同一MSI安装程序的特殊版本。我还被要求为OEM供应商构建新的MSI版本。


现在得出一个令人惊讶的结论(您从未要求过:-)):话虽如此,在理想的世界中,我喜欢安装所有功能,而无需在设置中进行任何技术麻烦,并使用序列号确定应用程序的功能和模块应在应用程序中激活。我还喜欢将串行密钥验证放入应用程序中,而不是放在安装程序中。原因是什么?我希望安装程序尽可能原始,以确保正确安装应用程序而不会导致较高的部署错误百分比。因此,我寻求在部署中消除复杂性,以确保减少部署支持问题。 可靠的部署对于产品的成功至关重要。安装后,您的应用程序可以在更加可调试和可预测的上下文中启动(无条件,模拟或排序问题),并以交互方式向用户有意义地报告任何错误-他们可以致电支持部门,他们更有希望成功解决任何问题如果安装程序只是用神秘的非交互式错误消息(在系统的事件日志中)轰炸了,情况将会是这样。


一旦有了一个好的,简单的部署解决方案,您作为发行经理和设置开发人员的工作应扩展到照顾应用程序的启动顺序,文件配置和整体配置,以及我认为您可能希望添加到该应用程序中的支持和调试功能。应用程序(应用程序的自检以及日志记录和自动收集信息以发送给支持人员)。尝试扩大您对应用程序本身的责任和影响,以使部署“尽可能原始”。从长远来看,任何可以在应用程序中而不是安装程序中进行编码的东西都将更加可靠(并且更容易调试)。


回到现实中:对于真正的部署,您将通过缓慢的网络共享获得一堆带有不规则版本控制方案的文件,以及来自离岸并按小时付费的开发人员的一堆不连贯的指令(您可以确定他会感到痛苦)也是:-))。他们将对您的设置有很多疯狂的要求,以制作魔术来掩盖其不理想的设计(这是他们付钱做的全部)。这不是夸大其词,它是现实-真难(好吧,这是在胡说八道)。我们必须努力改善应用程序的整体设计,以减少部署中易于出错的地方。魔术确实可以在设置中完成,但是由于不可避免且难以控制的部署复杂性,它会触发更高的部署错误百分比(最重要的是:1)错误是累积性的-每个版本都会增加风险和机会,破坏安装的可维护性(有时您必须撤回所有内容并重新开始-付出高昂的代价),2)目标系统处于极其多样且不可预测的状态(任何状态,任何语言,任何操作系统版本,任何硬件,任何恶意软件等),3)如果您无法以交互方式访问问题系统,调试将非常困难-有关更多详细信息,请参见链接答案的底部。我要补充4th issue的是第二点:您可以保证在充满恶意软件的计算机上进行部署吗?这样的系统无法支持和调试-只需选择您发现的无法解决的关键问题即可。如果您的软件包在此类恶意软件系统上失败,则不可避免的是自然错误百分比。


总的来说很明显:我们无法解决这些未知数-垃圾进,垃圾出(用道歉的方式道歉)-每次部署时都会出现错误百分比-即使是完美的软件包也是如此。确保抓住所有可用且始终有价值的质量检查专家并教给他们有关设置测试的信息(测试所有安装模式,测试卸载和与其他应用程序的交互,测试实际的升级方案,测试特定的高级设置功能,例如许可证检查等)。获得所有可获得的帮助,并重视他们的贡献。如果没有别的,作为同谋:-)。严重的是:在我作为发布经理和安装开发人员的最大的疏忽时,在我的榜单上,未能有效利用可用的QA资源并帮助他们进行部署测试培训是我的首要任务。可以肯定的是,您将立即欠您的质量检查人员一瓶Horílka-或绿茶或Rooibos茶-取决于您在世界上的位置:-)。


预处理器构造

我可能会使用预处理器构造, ?if?并?include?根据您定义的版本在?define?示例顶部的语句中选择性地包括WiX XML源代码/标记的不同部分:


<?define EditionType = “LITE” ?>


<!-- You can put your edition-specific components in an include file  -->

  <?if $(var.EditionType) = "200" ?> 

    <?include "200Features.wxi" ?>

  <?endif ?>

  <?if $(var.EditionType) = "LITE" ?>

    <?include "LiteFeatures.wxi" ?>

  <?endif ?>

除了使用包含文件,您还可以在主要源代码中内联执行此操作(这可能是您已经完成的操作):


 <?if $(var.EditionType) = "200" ?> 

    <Component>

       <File Source="$(var.MenusPath)\ClientListView 200.r5m" /> 

    </Component>

<?endif?>

<?if $(var.EditionType) = "LITE" ?>

    <Component>

       <File Source="$(var.MenusPath)\ClientListView Lite.r5m" />

    </Component>    

<?endif?>

在上述选项中,我希望将特定于版本的组件保留在单独的包含文件中(第一个选项)-这样,WiX源中的“行噪”就更少了(预处理器结构的重复次数减少了)。


包含文件基本上只是WiX XML文件,就像在编译时将C ++头文件包含到父WiX XML文件中一样。就像Phil所说的那样,我会在不同版本中使用不同的功能名称,因此您可以200Features在200Features.wxi包含文件中定义一个功能,但是虽然强烈建议您使用功能,但您无需使用这些功能。


还应注意片段元素的WiX概念。本质上是一种交叉引用WiX源文件中的内容的方法。这里有个例子。


我应该提到,MSI 中合并模块的原始概念提供了一种在不同设置之间共享组件的不同方法,但是我更喜欢include file方法。合并模块感觉就像是COM对象(二进制的blob作为一个版本控制的整体包含在内),而包含文件似乎更加动态,因为您无需为任何合并模块进行重建和版本控制就可以为每个构建链接到最新的文件。无疑,某些人会发现这是非常错误的。


查看完整回答
反对 回复 2019-12-06
?
炎炎设计

感谢您提供的信息,但是我想您错过了我试图实现的目标;我不想通过/ i运行安装程序,因为正如您所说的那样,这实际上将安装文件并更改注册表等。我想做的是两次运行安装程序-一次运行口味200,然后再次运行口味Lite;因此,如果使用/ i运行,我最终将得到两个包含“将要安装”文件的文件夹。显然,我无法使用/ i运行它两次,因为第二次运行它会卸载第一个。

无论如何,我发现在管理员“安装”过程中会忽略组件中的条件,而?语句不会被忽略-不确定为什么,但是我现在删除了所有条件语句,并用IF语句替换了-现在我可以做我想做的事情-用/ a运行两次,每个文件夹将包含独特风味的文件。


查看完整回答
反对 回复 2019-12-06
  • 3 回答
  • 0 关注
  • 46 浏览
我要回答

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信