启动.msi安装文件时,我在命令行上传递TRANSFORMS =“:X”(以及安装所需的其他几个变量),其中X是要使用的程序的版本.
在Product.wxs文件中,我然后使用InstanceTransforms标记分配一个新的ProductCode,例如:
<Property Id="INSTANCEID" Value="Default"/> <InstanceTransforms Property="INSTANCEID"> <Instance Id="I1" ProductCode="$(guid.NewGuid())"/> <Instance Id="I2" ProductCode="$(guid.NewGuid())"/> <Instance Id="I4" ProductCode="$(guid.NewGuid())"/> <Instance Id="I3" ProductCode="$(guid.NewGuid())"/> <Instance Id="I5" ProductCode="$(guid.NewGuid())"/> <Instance Id="I6" ProductCode="$(guid.NewGuid())"/> <Instance Id="I7" ProductCode="$(guid.NewGuid())"/> <Instance Id="I8" ProductCode="$(guid.NewGuid())"/> <Instance Id="I9" ProductCode="$(guid.NewGuid())"/> </InstanceTransforms>
此外,UpgradeCode在自定义操作中添加到UpgradeTable,相关代码为:
Database db = session.Database; session.Log("Get DB: {0}",db.FilePath ?? string.Empty); string sqlInsertSring = db.Tables["Upgrade"].SqlInsertString + " TEMPORARY"; session.Log("DB Tables,querying with SQL: {0}",sqlInsertSring); View view = db.OpenView(sqlInsertSring); session.Log("OpenView,adding two new records to the UpgradeView."); session.Log("Inserting line: {0},null,{1},512,\"UPDATE\"",session["UpgradeCode"],session["ProductVersion"]); view.Execute(new Record(new object[] { session["UpgradeCode"],session["ProductVersion"],"UPDATE"})); session.Log("Inserting line: {0},\"NEWERVERSIONINSTALLED\"","NEWERVERSIONINSTALLED" })); view.Close();
好的,到目前为止一切顺利,这适用于安装,允许我成功安装同一程序的两个实例.但是,更新似乎不起作用.我可以升级其中一个实例,但在升级第二个实例时,转换无法正常工作,另一个实例再次升级.
示例:两个实例(I1和I2).升级I2工作正常.但是,当我随后尝试更新I1时,它只是再次更新I2(尽管传递了正确的转换).
MSI的日志显示转换首先恢复为I1(应该如此),然后再次设置为I2(由于我无法理解的原因):
- MSI (s) (B0:F8) [09:06:48:745]: Running product '{C33371A0-C32A-4120-BD8F-ACDC79E13458}' with elevated privileges: Product is assigned. - MSI (s) (B0:F8) [09:06:48:776]: PROPERTY CHANGE: Modifying TRANSFORMS property. Its current value is ':I2'. Its new value: ':I1'. - MSI (s) (B0:F8) [09:06:48:823]: PROPERTY CHANGE: Adding DATADIR property. Its value is MSI (s) (B0:F8) [09:06:49:463]: PROPERTY CHANGE: Adding CURRENTDIRECTORY property. Its value is 'C:\Users\Administrator\Desktop'. - [Further arguments passed] - MSI (s) (B0:F8) [09:06:49:494]: PROPERTY CHANGE: Adding CLIENTUILEVEL property. Its value is '2'. - MSI (s) (B0:F8) [09:06:49:572]: PROPERTY CHANGE: Adding CLIENTPROCESSID property. Its value is '6424'. - MSI (s) (B0:F8) [09:06:49:587]: Machine policy value 'DisableAutomaticApplicationShutdown' is 0 - MSI (s) (B0:F8) [09:06:49:634]: RESTART MANAGER: Disabled by MSIRESTARTMANAGERCONTROL property; Windows Installer will use the built-in FilesInUse functionality. - MSI (s) (B0:F8) [09:06:49:681]: PROPERTY CHANGE: Adding MsiSystemRebootPending property. Its value is '1'. - MSI (s) (B0:F8) [09:06:49:728]: PROPERTY CHANGE: Modifying TRANSFORMS property. Its current value is ':I1'. Its new value: ':I2'. - MSI (s) (B0:F8) [09:06:49:821]: TRANSFORMS property is now: :I2
最后一行很重要:TRANSFORMS属性再次设置为I2,这意味着安装将更新实例I2而不是实例I1.
为什么会发生这种情况? TRANSFORMS正确传递,我无法理解为什么该属性会再次被撤回.
(如果需要更多代码或表达,我很乐意提供).
编辑:BTW我正在使用WiX工具集3.7.
编辑2:对于安装,我用以下参数调用.msi:
MSINEWINSTANCE=1 TRANSFORMS=":I[N]" [Further parameters] (where N is the Instance)
对于更新,我在没有MSINEWINSTANCE的情况下调用.msi,直接从TRANSFORMS部分开始
作为一个脏修复,我现在正在卸载/安装更新,这不是我的计划.
解决方法
我也在我的博客上解释了这个过程:(哇,真的是8年前吗?)
Multiple Instance MSI’s and InstallShield 12
更新:
我能够使用WiX和IsWiX正确实现这一点.
步骤1:使用IsWiX多项目解决方案加速器模板创建MSI / MSM项目.
步骤2:将文件添加到合并模块,以便安装程序具有一个文件作为要安装的密钥路径的组件. (这是必需的,因为a)您需要注册至少一个组件才能考虑安装功能/产品; b)具有非文件的密钥路径的组件必须使用不同的guid进行变更,并根据实例ID进行条件安装.要解决这个问题并将其设为简单,只需创建一个以文件作为键路径的组件即可
步骤3:将以下XML添加到主wxs文件Product.wxs:
<SetProperty Id="INSTALLLOCATION" Value="[ProgramFilesFolder][Manufacturer]\[ProductName]" Before="AppSearch" Sequence="first">Not INSTALLLOCATION and Not Installed</SetProperty> <Property Id="InstanceId" Value="0"/> <InstanceTransforms Property="InstanceId"> <Instance Id="I1" ProductCode="*" UpgradeCode="{10E90C30-F117-4EE8-A084-25E4D0076CE4}" ProductName="ProductName-1" /> <Instance Id="I2" ProductCode="*" UpgradeCode="{919F5399-4E7A-4D8A-9484-A85D0F5E2C77}" ProductName="ProductName-2" /> <Instance Id="I3" ProductCode="*" UpgradeCode="{0BEAEF92-1821-4909-A83A-9B2AE2194AAC}" ProductName="ProductName-3" /> </InstanceTransforms>
如果没有在命令行传递一个值并且以前没有安装产品(这种情况下目录是不可变的),那么这段代码会在第一次安装时改变安装目录.我还使用*来获取一个随机的ProductCode并传入一个UpgradeCode值,因为项目模板使用MajorUpgrades开箱即用,每个实例都是一个独特的产品系列,用于升级目的.最后,我将ProductName转换为添加/删除程序中的唯一,并驱动安装位置转换.
安装主实例:
msiexec /I ProductName.msi
安装辅助实例:
msiexec /I ProductName.msi MSINEWINSTANCE=1 TRANSFORMS=":I1" msiexec /I ProductName.msi MSINEWINSTANCE=1 TRANSFORMS=":I2" msiexec /I ProductName.msi MSINEWINSTANCE=1 TRANSFORMS=":I3"
请注意在TRANSFORMS属性中使用“:”.这指定了Storages表中的嵌入式转换.
这两个安装在“程序文件和程序和功能”中并排显示.