WiX Installer:维护对话框修复时环境变量丢失问题
我正在使用WiX 3.11.1为Petrel插件创建安装程序,Product.wxs基于GitHub上的示例文件修改而来。我在向导中添加了一个页面,允许用户在编辑框中指定许可服务器,以此创建或更新系统环境变量LIC_HOST,相关代码如下:
<!-- 获取已存在的环境变量 --> <SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="first"></SetProperty> <snip> <!-- 验证许可服务器名称非空 --> <Control Type="PushButton" Id="Next" X="239" Y="243" Width="56" Height="17" Default="yes" Text="Next"> <Publish Event="SpawnDialog" Value="ServerNameErrorDlg"><![CDATA[LICENSE_SERVER_ENV_VAR = ""]]></Publish> <Publish Event="NewDialog" Value="ngenDialog"><![CDATA[LICENSE_SERVER_ENV_VAR <> ""]]></Publish> </Control> <snip> <!-- 安装插件并设置环境变量 --> <Fragment> <ComponentGroup Id="PluginComponents" Directory="INSTALLLOCATION"> <Component Id="PetrelPluginPip" Guid="120AF5B9-E751-43F4-AF4C-7DED33C8BEB4"> <Environment Id="LicenseServerEnVar" Action="set" Name="LIC_HOST" System="yes" Permanent="yes" Value="[LICENSE_SERVER_ENV_VAR]"/> <File Id="PetrelPluginPippip" Source="../OceanPluginPip/bin/$(var.OceanPluginPip.Platform)/$(var.OceanPluginPip.Configuration)/PetrelPluginPip.pip" KeyPath="yes" /> </Component> </ComponentGroup> </Fragment>
初始安装和通过「添加/删除程序」执行修复时均正常,环境变量可保留。但右键点击安装包(.msi文件)选择「安装」,再在维护对话框中选「修复」时,向导虽能正确读取许可服务器信息,但修复完成后系统环境变量LIC_HOST被删除。
我已尝试以下方案:
- 将SetProperty的Sequence设为"both"
- 将Environment标签放入独立的Component中
- 创建自定义操作设置许可服务器并加入InstallExecuteSequence
但均未解决问题。
添加详细日志后,修复过程中出现如下关键信息:
MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding RestrictedUserControl property. Its value is '1'. MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding PETRELINSTALLLOCATION property. Its value is 'C:\Program Files\Schlumberger\Petrel 2022\'. MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property INSTALLLOCATION MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property LICENSE_SERVER_ENV_VAR MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property TARGETDIR Action start 11:42:25: LaunchConditions. Action ended 11:42:25: LaunchConditions. Return value 1. MSI (s) (60:78) [11:42:25:468]: Doing action: SetLICENSE_SERVER_ENV_VAR MSI (s) (60:78) [11:42:25:468]: Note: 1: 2205 2: 3: ActionText Action start 11:42:25: SetLICENSE_SERVER_ENV_VAR. MSI (s) (60:78) [11:42:25:469]: Skipping action due to msidbCustomActionTypeFirstSequence option. Action ended 11:42:25: SetLICENSE_SERVER_ENV_VAR. Return value 0.
请问为何修复时该属性被禁用?且环境变量被删除的原因是什么?
一、属性被禁用的原因
日志中的Ignoring disallowed property LICENSE_SERVER_ENV_VAR是因为维护模式下的属性限制:当通过MSI文件直接启动维护修复时,Windows Installer会启用RestrictedUserControl模式(日志中显示该属性值为1)。在这个模式下,只有标记为Secure的公共属性才能在UI序列和执行序列之间传递,未标记的属性会被忽略。
另外,SetLICENSE_SERVER_ENV_VAR操作被跳过,是因为Sequence="first"意味着该操作只在首次安装的执行序列中运行,维护修复属于后续序列,因此被跳过。即使改成Sequence="both",如果属性未标记为Secure,依然会被RestrictedUserControl拦截。
二、环境变量被删除的原因
WiX的Environment元素在修复时会重新评估其值:
- 由于
LICENSE_SERVER_ENV_VAR属性被忽略,其值为空字符串 Environment元素的Action="set"会将环境变量设置为当前属性值,也就是空字符串- 虽然设置了
Permanent="yes",但这个属性仅表示卸载时不删除环境变量,修复时依然会根据当前属性值更新
三、解决步骤
将LICENSE_SERVER_ENV_VAR标记为Secure属性
在Product元素下添加:<Property Id="LICENSE_SERVER_ENV_VAR" Secure="yes" />这样该属性就能在RestrictedUserControl模式下正常传递。
调整SetProperty的执行时机
将Sequence改为both,确保在首次安装和维护序列中都能执行:<SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="both"></SetProperty>确保Environment组件在修复时正确执行
可以将Environment元素放在独立的Component中,并确保该Component的KeyPath不是文件(避免文件未损坏时组件不被修复),比如用一个RegistryKey作为KeyPath:<Component Id="LicenseServerEnvVarComponent" Guid="YOUR-GUID-HERE"> <RegistryKey Root="HKLM" Key="Software\YourCompany\YourPlugin" Action="createAndRemoveOnUninstall"> <RegistryValue Name="LicenseServerConfig" Type="string" Value="1" KeyPath="yes" /> </RegistryKey> <Environment Id="LicenseServerEnVar" Action="set" Name="LIC_HOST" System="yes" Permanent="yes" Value="[LICENSE_SERVER_ENV_VAR]"/> </Component>这样即使主插件文件未损坏,修复时也会处理环境变量组件。
内容的提问来源于stack exchange,提问作者jslmsca

