2

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>
porton
  • 5,214
  • 11
  • 47
  • 95
  • You might be more specific about what sort of "error" you see. Log file information around the error is likely to be helpful as well. – Rob Mensching Mar 25 '23 at 14:04
  • @RobMensching The error is `There is a problem with this Windows installer package. A program required for this install to complete could not be run. Contract your support personnel or package vendor.` – porton Mar 25 '23 at 17:53
  • Have you tried flipping the order of the last 2 steps in the install sequence (stop before uninstall)? – Jason Weber Mar 31 '23 at 07:35
  • @JasonWeber Yes, I tried. – porton Mar 31 '23 at 11:20

2 Answers2

2

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.

porton
  • 5,214
  • 11
  • 47
  • 95
1

You have to close the services viewer beforehand. Running it prevents the services from being fully deleted

If the deletion didn't work, see How to force uninstallation of windows service

Will
  • 36
  • 3
  • I already have an action intended to "close" (stop) the service: ``. You didn't address this in your answer. – porton Mar 27 '23 at 18:10