含NSSM服务的软件卸载失败问题求助
解决Wix安装包卸载时因服务运行触发的回滚问题
使用Wix制作的安装包,安装阶段可成功部署并启动XXXService服务,但执行卸载操作时失败并触发回滚,推测原因是XXXService服务仍处于运行状态,导致main.exe文件无法被删除。
原Wix配置代码如下:
<?xml version="1.0" encoding="UTF-8"?> <?if $(env.ARCH) = x64 ?> <?define ProductName = "Uninstall Bug (64 bit)" ?> <?define Win64 = "yes" ?> <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?> <?else ?> <?define ProductName = "Uninstall Bug" ?> <?define Win64 = "no" ?> <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?> <?endif ?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Product Id="1edc84cf-3a2b-4be9-ab5d-a1553c37e8ef" Name="Uninstall Bug" Language="1033" Version="1.0.0.0" Manufacturer="Example" UpgradeCode="2a82c6fe-9e93-4ccd-8e6c-c04de9a8289b"> <Package InstallerVersion="200" Compressed="yes" /> <MediaTemplate EmbedCab="yes" /> <Feature Id="ProductFeature" Title="Uninstall Bug" Level="1"> <ComponentGroupRef Id="MyComponentGroupId" /> </Feature> <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="$(var.PlatformProgramFilesFolder)"> <Directory Id="INSTALLDIR" Name="Uninstall Bug" /> </Directory> </Directory> <ComponentGroup Id="MyComponentGroupId"> <Component Id="MyComponent" Directory="INSTALLDIR" Guid="dfb1e839-1f62-4613-b323-daa3166caab5" KeyPath="yes"> <File Id="MainFile" Source="src/main.exe" /> <?if Win64 = "yes" ?> <File Id="NSSMFIle" Source="distrib/nssm/win64/nssm.exe" /> <?else ?> <File Id="NSSMFIle" Source="distrib/nssm/win32/nssm.exe" /> <?endif ?> </Component> </ComponentGroup> <CustomAction Id="CreateService" Directory="INSTALLDIR" Execute="deferred" Impersonate="no" ExeCommand='"[INSTALLDIR]nssm" install XXXService "[INSTALLDIR]main.exe" xxx' /> <CustomAction Id="SetServiceDirectory" Directory="INSTALLDIR" Execute="deferred" Impersonate="no" ExeCommand='"[INSTALLDIR]nssm" set XXXService AppDirectory [INSTALLDIR]' /> <CustomAction Id="StartService" Directory="INSTALLDIR" Execute="deferred" Impersonate="no" ExeCommand='"[INSTALLDIR]nssm" start XXXService' /> <CustomAction Id="StopService" Directory="INSTALLDIR" Execute="deferred" ExeCommand='"[INSTALLDIR]nssm" stop XXXService' Impersonate="no" Return="ignore" /> <CustomAction Id="UninstallService" Directory="INSTALLDIR" Execute="deferred" ExeCommand='"[INSTALLDIR]nssm" remove XXXService confirm' Impersonate="no" Return="ignore" /> <InstallExecuteSequence> <Custom Action="CreateService" After="InstallServices" /> <Custom Action="SetServiceDirectory" After="InstallServices" /> <Custom Action="StartService" After="StartServices" /> <Custom Action="UninstallService" Before="DeleteServices" /> <Custom Action="StopService" Before="StopServices" /> </InstallExecuteSequence> </Product> </Wix>
解决方案
1. 调整卸载动作的执行顺序
当前自定义动作的时序存在逻辑问题,需确保服务先停止、再卸载,且这两个动作都在文件删除前完成。修改InstallExecuteSequence部分:
<InstallExecuteSequence> <Custom Action="CreateService" After="InstallServices" /> <Custom Action="SetServiceDirectory" After="InstallServices" /> <Custom Action="StartService" After="StartServices" /> <!-- 仅在卸载时执行,先停止服务再卸载,都放在文件删除步骤之前 --> <Custom Action="StopService" Before="DeleteFiles">REMOVE="ALL"</Custom> <Custom Action="UninstallService" After="StopService">REMOVE="ALL"</Custom> </InstallExecuteSequence>
2. 使用Wix原生ServiceControl管理服务(推荐)
依赖自定义nssm命令容易出现时序偏差,改用Wix原生的ServiceInstall和ServiceControl元素,能让MSI更可靠地处理服务生命周期:
<ComponentGroup Id="MyComponentGroupId"> <Component Id="MyComponent" Directory="INSTALLDIR" Guid="dfb1e839-1f62-4613-b323-daa3166caab5" KeyPath="yes"> <File Id="MainFile" Source="src/main.exe" /> <?if Win64 = "yes" ?> <File Id="NSSMFIle" Source="distrib/nssm/win64/nssm.exe" /> <?else ?> <File Id="NSSMFIle" Source="distrib/nssm/win32/nssm.exe" /> <?endif ?> <!-- 注册服务基本信息,让Wix识别该服务 --> <ServiceInstall Id="XXXServiceInstall" Name="XXXService" DisplayName="XXXService" Type="ownProcess" Start="auto" ErrorControl="normal" Vital="no" /> <!-- 自动处理服务启停与卸载,Wait="yes"确保操作完成后再继续流程 --> <ServiceControl Id="XXXServiceControl" Name="XXXService" Start="install" Stop="both" Remove="uninstall" Wait="yes" /> </Component> </ComponentGroup>
修改后可直接移除自定义的StartService、StopService、UninstallService动作。
3. 确保服务完全停止(自定义动作场景)
如果仍需使用nssm自定义动作,可修改StopService命令,增加超时等待确保服务完全停止:
<CustomAction Id="StopService" Directory="INSTALLDIR" Execute="deferred" ExeCommand='"[INSTALLDIR]nssm" stop XXXService timeout 10' Impersonate="no" Return="check" />
timeout 10表示等待10秒,Return="check"会在服务停止失败时反馈状态(可根据需求调整为ignore)。
内容的提问来源于stack exchange,提问作者porton
相关产品推荐
相关产品推荐

