如何使WIX自定义操作仅在首次安装执行,而非重大更新?
解决WIX自定义操作仅在首次安装执行的问题
你遇到的这个问题很典型——MajorUpgrade的执行流程是先卸载旧版本再安装新版本,在新版本安装阶段Installed变量会变为false,这就导致你原本的NOT Installed条件被错误触发。要实现自定义操作**仅在首次安装(即该产品从未被安装过的场景)**执行,这里有两种可靠的方案,都不需要手动操作注册表:
方案一:利用WIX内置升级检测变量
WIX的MajorUpgrade会自动设置WIX_UPGRADE_DETECTED变量:当检测到已有旧版本需要升级时,这个变量会被赋值为旧版本的产品代码。我们可以通过这个变量直接排除升级场景:
修改步骤:
- 添加一个即时自定义操作,用来标记是否需要执行你的deferred操作:
<CustomAction Id="SetRunHWA" Property="RUN_HWA" Value="1" Execute="immediate" />
- 更新
InstallExecuteSequence,先在即时阶段判断首次安装条件,再在deferred阶段执行操作:
<InstallExecuteSequence> <!-- 在安装初始化前完成首次安装判断 --> <Custom Action="SetRunHWA" Before="InstallInitialize">NOT Installed AND NOT WIX_UPGRADE_DETECTED</Custom> <!-- 只有标记了需要执行时才运行自定义操作 --> <Custom Action='HWA' After='InstallFinalize'>RUN_HWA</Custom> </InstallExecuteSequence>
方案二:使用永久注册表标记(更稳定通用)
如果需要兼容非WIX工具的升级场景,或者想要更可靠的执行标记,可以创建一个永久注册表项来记录自定义操作是否已经执行过:
修改步骤:
- 在你的
Fragment中添加一个永久组件,用来创建标记注册表:
<Component Id="FirstRunMarker" Guid="YOUR-NEW-GUID-HERE" Permanent="yes" Transitive="no"> <RegistryValue Root="HKLM" Key="Software\[Manufacturer]\[ProductName]" Name="FirstRunCompleted" Type="integer" Value="1" KeyPath="yes" /> </Component>
- 将这个组件添加到你的Feature中:
<Feature Id="ProductFeature" Title="TestWiXSetup" Level="1"> <ComponentRef Id="Component" /> <ComponentRef Id="FirstRunMarker" /> </Feature>
- 同样添加即时自定义操作来判断条件:
<CustomAction Id="SetRunHWA" Property="RUN_HWA" Value="1" Execute="immediate" />
- 更新执行序列的判断条件:
<InstallExecuteSequence> <Custom Action="SetRunHWA" Before="InstallInitialize"> NOT Installed AND NOT EXISTS RegistryValue(HKLM, 'Software\[Manufacturer]\[ProductName]', 'FirstRunCompleted') </Custom> <Custom Action='HWA' After='InstallFinalize'>RUN_HWA</Custom> </InstallExecuteSequence>
关键注意点:
- 为什么不能直接在deferred操作中写条件?因为deferred自定义操作运行在系统上下文,无法访问即时阶段的变量(比如
Installed、WIX_UPGRADE_DETECTED),所以必须先在即时阶段把判断结果保存到属性中,再在deferred阶段检查这个属性。 - 方案一依赖WIX的
MajorUpgrade机制,适合纯WIX项目;方案二更通用,能兼容所有Windows Installer升级场景。
内容的提问来源于stack exchange,提问作者George Lanetz
相关产品推荐
相关产品推荐

