For the following installer package, I have the service XXXService
successfully installed and running, when I install my package.
But uninstallation fails with an error and reverts. I suspect, that the service is still running blocking removal of main.exe
file.
Please, help to make uninstallation work.
The complete minimal source to reproduce this bug is available.
<?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>
Instead of NSSM you can use modified srvany-ng.
The WiX syntax is as follows:
<Component Id="ServiceComponent" Guid="XXX" Directory="SrvAnyDIR">
<File Id="SrvAnyFile" Source="srvany-ng\src\srvany-ng.exe" KeyPath="yes" />
<ServiceInstall
Id="MyServiceInstall"
Type="ownProcess"
Vital="yes"
Name="XXX"
DisplayName="XXX"
Description="XXX"
Start="auto"
Account="LocalSystem"
ErrorControl="normal"
Arguments='"[NETHERMIND_DIR]Nethermind.Runner.exe" --config [ConfigDir]config.cfg --datadir [MyAppFolder]data --Init.LogDirectory [MyAppFolder]log --Init.StaticNodesPath [MyAppFolder]static-nodes.json' />
<ServiceControl
Id="MyServiceControl"
Name="XXX"
Stop="both"
Remove="uninstall"
Wait="yes" />
</Component>
This is the correct way to install executables used as a Windows service, because all (un)installation is done by the installer itself, without calling external commands as custom actions.