1

I have created the following installation routine with the WIX toolset. The installation takes place as desired, but only the TopShelf service is uninstalled. However, the program folder and the files contained in it remain. What is missing so that the program folder + files are also removed during the uninstallation?

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="GC Log Collector Config" Language="1033" Version="1.0.0.0" Manufacturer="xyz" UpgradeCode="ff65ecf3-f59d-4d29-bb3b-ce159892a107">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

        <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
        <MediaTemplate EmbedCab="yes" />

        <Icon Id="appicon.ico" SourceFile="$(var.GC Log Config.ProjectDir)Resources\gclcc.ico" />
        <Property Id="ARPPRODUCTICON" Value="appicon.ico" />

        <Feature Id="ProductFeature" Title="GC Log Collector Config" Level="1">
            <ComponentRef Id="ProductComponents" />
            <ComponentRef Id="ServiceComponents"/>
            <ComponentGroupRef Id="DllComponents" />
            <ComponentRef Id ="DesktopShortcut"/>
        </Feature>
    </Product>

    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLFOLDER" Name="GC Log Collector Config" />
            </Directory>
            <Directory Id="DesktopFolder" Name="Desktop"/>
        </Directory>

        <CustomAction Id="InstallService" Directory="INSTALLFOLDER" Execute="commit" Return="check" Impersonate="no" ExeCommand="[INSTALLFOLDER]GC Log Collector.exe install"/>
        <CustomAction Id="UninstallService" Directory="INSTALLFOLDER" Execute="commit" Return="check" Impersonate="no" ExeCommand="[INSTALLFOLDER]GC Log Collector.exe uninstall"/>
        
        <InstallExecuteSequence>
            <Custom Action="InstallService" After="InstallFiles">
                NOT Installed
            </Custom>
            <Custom Action="UninstallService" After="InstallInitialize">
                REMOVE ~= "ALL" AND NOT UPGRADINGPRODUCTCODE
            </Custom>
        </InstallExecuteSequence>

        <Component Id="ProductComponents" Directory="INSTALLFOLDER">
            <File Id="GcLogCollectorConfigExe" Source="$(var.GC Log Config.TargetPath)" KeyPath="yes">
            </File>
        </Component>

        <Component Id="ServiceComponents" Directory="INSTALLFOLDER">
            <File Id="GcLogCollectorService" Source="$(var.GC Log Collector.TargetPath)" KeyPath="yes">
            </File>
        </Component>

        <ComponentGroup Id="DllComponents" Directory="INSTALLFOLDER">
            <Component Id="BootstrapIcons">
                <File Id="BootstrapIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.BootstrapIcons.dll"></File>
            </Component>
            <Component Id="BoxIcons">
                <File Id="BoxIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.BoxIcons.dll"></File>
            </Component>
            <Component Id="Codicons">
                <File Id="CodiconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Codicons.dll"></File>
            </Component>
            <Component Id="Core">
                <File Id="CoreDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Core.dll"></File>
            </Component>
            <Component Id="IconPacks">
                <File Id="IconPacksDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.dll"></File>
            </Component>
            <Component Id="Entypo">
                <File Id="EntypoDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Entypo.dll"></File>
            </Component>
            <Component Id="EvaIcons">
                <File Id="EvaIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.EvaIcons.dll"></File>
            </Component>
            <Component Id="FeatherIcons">
                <File Id="FeatherIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.FeatherIcons.dll"></File>
            </Component>
            <Component Id="FileIcons">
                <File Id="FileIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.FileIcons.dll"></File>
            </Component>
            <Component Id="Fontaudio">
                <File Id="FontaudioDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Fontaudio.dll"></File>
            </Component>
            <Component Id="FontAweseome">
                <File Id="FontAwesomeDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.FontAwesome.dll"></File>
            </Component>
            <Component Id="ForkAwesome">
                <File Id="ForkAwesomeDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.ForkAwesome.dll"></File>
            </Component>
            <Component Id="Ionicons">
                <File Id="IoniconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Ionicons.dll"></File>
            </Component>
            <Component Id="JamIcons">
                <File Id="JamIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.JamIcons.dll"></File>
            </Component>
            <Component Id="Material">
                <File Id="MaterialDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Material.dll"></File>
            </Component>
            <Component Id="MaterialDesign">
                <File Id="MaterialDesignDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.MaterialDesign.dll"></File>
            </Component>
            <Component Id="MaterialLight">
                <File Id="MaterialLightDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.MaterialLight.dll"></File>
            </Component>
            <Component Id="Microns">
                <File Id="MicronsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Microns.dll"></File>
            </Component>
            <Component Id="Modern">
                <File Id="ModernDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Modern.dll"></File>
            </Component>
            <Component Id="Octicons">
                <File Id="OcticonsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Octicons.dll"></File>
            </Component>
            <Component Id="PicolIcons">
                <File Id="PicolIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.PicolIcons.dll"></File>
            </Component>
            <Component Id="PixelartIcons">
                <File Id="PixelartIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.PixelartIcons.dll"></File>
            </Component>
            <Component Id="RadixIcons">
                <File Id="RadixIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.RadixIcons.dll"></File>
            </Component>
            <Component Id="RemixIcon">
                <File Id="RemixIconDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.RemixIcon.dll"></File>
            </Component>
            <Component Id="RPGAwesome">
                <File Id="RPGAwesomeDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.RPGAwesome.dll"></File>
            </Component>
            <Component Id="SimpleIcons">
                <File Id="SimpleIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.SimpleIcons.dll"></File>
            </Component>
            <Component Id="Typicons">
                <File Id="TypiconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Typicons.dll"></File>
            </Component>
            <Component Id="Unicons">
                <File Id="UniconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Unicons.dll"></File>
            </Component>
            <Component Id="VaadinIcons">
                <File Id="VaadinIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.VaadinIcons.dll"></File>
            </Component>
            <Component Id="WeatherIcons">
                <File Id="WeatherIconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.WeatherIcons.dll"></File>
            </Component>
            <Component Id="Zondicons">
                <File Id="ZondiconsDll" Source="$(var.GC Log Config.TargetDir)MahApps.Metro.IconPacks.Zondicons.dll"></File>
            </Component>
            <Component Id="Json">
                <File Id="JsonDll" Source="$(var.GC Log Config.TargetDir)Newtonsoft.Json.dll"></File>
            </Component>
            <Component Id="log4net">
                <File Id="log4netDll" Source="$(var.GC Log Collector.TargetDir)log4net.dll"></File>
            </Component>
            <Component Id="log4netconfig">
                <File Id="log4netCfg" Source="$(var.GC Log Collector.TargetDir)log4net.config"></File>
            </Component>
            <Component Id="RuntimeInformation">
                <File Id="RuntimeInformationDll" Source="$(var.GC Log Collector.TargetDir)System.Runtime.InteropServices.RuntimeInformation.dll"></File>
            </Component>
            <Component Id="Topshelf">
                <File Id="TopshelfDll" Source="$(var.GC Log Collector.TargetDir)Topshelf.dll"></File>
            </Component>
            <Component Id="LiveCharts">
                <File Id="LiveChartsDll" Source="$(var.GC Log Config.TargetDir)LiveCharts.dll"></File>
            </Component>
            <Component Id="LiveChartsWpf">
                <File Id="LiveChartsWpfDll" Source="$(var.GC Log Config.TargetDir)LiveCharts.Wpf.dll"></File>
            </Component>
        </ComponentGroup>

        <DirectoryRef Id="DesktopFolder">
            <Component Id="DesktopShortcut" Guid="54c4cf2a-f3c8-41dc-95a2-79cafa7640b7">
                <Shortcut Id="desktopSC"
                          Name="GC Log Config"
                          Description="GC Log Config"
                          Target="[INSTALLFOLDER]GC Log Config.exe"
                          Icon="appicon.ico">
                </Shortcut>
                <RemoveFolder Id="RemoveDesktopFolder"
                              Directory="DesktopFolder"
                              On="uninstall" />
                <RegistryValue Root="HKCU"
               Key="Software\[Manufacturer]\[ProductName]"
               Name="installed"
               Type="integer"
               Value="1"
               KeyPath="yes" />
            </Component>
        </DirectoryRef>
    </Fragment>

</Wix>
Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
patrickgc
  • 49
  • 7

1 Answers1

1

Clean Testing: You should try the package on a clean virtual to see if you have a "dirty state" on your main box - from prior experiments. It is not uncommon to find several versions of your package in Add / Remove - potentially with different names. This can happen in several ways, but usually it is because of misconfigured major upgrade settings for one or more test versions. Files are not uninstalled before all "clones" are uninstalled. There can also be other reasons for files remaining after uninstall.

List Installed Packages: You can run this script to get a list of all MSI packages installed on your machine: https://github.com/glytzhkof/all/blob/master/MsiHtmlReport-Mini-V4.vbs

Service Installation: You should not use custom actions to install services when using Windows Installer. Here is an old answer to explain why and a sample of how services are supposed to be installed:

Essentially you use the ServiceInstall and ServiceControl constructs inside the MSI.

Stein Åsmul
  • 39,960
  • 25
  • 91
  • 164
  • Thank you very much for your answer. I took it to heart and set up a virtual machine. The service of my application is a service created using the Topshelf library. I looked at the code to the github project you linked and tried to apply it to my installer, unfortunately without success. Can I install a Topshelf service like this at all? – patrickgc Aug 09 '21 at 15:44
  • Did you try to build that Github WiX sample and install it? [The crux of it is this location in the source code](https://github.com/Robs79/How-to-create-a-Windows-Service-MSI-Installer-Using-WiX/blob/master/WindowsService.Installer/Product.wxs#L34). This is where you define that the file referred to should be installed as a service. **There is no need for any custom actions at all** - just remove them with all supporting constructs. Any file that can run as a service should be possible to install this way. Just automagic out of the box from a built-in MSI construct - saves all kinds of errors. – Stein Åsmul Aug 09 '21 at 21:53
  • Looking up Topshelf I see that this is a toolkit to run regular executables as services. In this case I am not 100% sure if it makes the binary operate exactly as a service and if MSI will install it correctly. [Judging by the first comment here you have a problem](https://stackoverflow.com/a/30991222/129130) (the comment below the answer). – Stein Åsmul Aug 09 '21 at 21:57