0
votes

I've seen some similar questions asked on here, but none of the solutions given were very clear or worked for me.

I have an installer (created with WiX) which installs certain files and folders. However, when running the installed application, this creates some folders and copies some files into it. These files and folders are not removed on uninstall.

Edited to Show Code so Far:

This INSTALLDIR property:

<Property Id="INSTALLDIR">
        <RegistrySearch Id='Registry' Type='raw' Root='HKLM' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
    </Property>

This Component which should set the install location in the registry:

<Component Id="Registry" Guid="*">
                    <RegistryKey Root="HKMU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
                        <RegistryValue  Name="Location" 
                                        Type="string" 
                                        Value="[INSTALLDIR]" 
                                        Action="write" 
                                        KeyPath="yes" />
                    </RegistryKey>
                    <util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />
                </Component>

This does create a record in the registry with the install location, but I'm not sure how to adapt this code to making note of the 'public' directory and removing it - I don't know where the util:RemoveFolderEx should go either (inside which component)

2
"I don't know the names of all the files and folders which are being created, so I can't specify them by name." - if you don't know the name there is hardly a way to remove them, so you need to come up with a way of identifying what needs to be deleted first. Then, you may remove these folders on uninstall, e.g. using a custom action. However, be aware that removing files in users' profile folders is not really supported for per-machine installations. - Dirk Vollmar
I know into which directory these files and folders are being created. Essentially, when running the application, some plugins are copied over to a 'public' directory. But the number of plugins can and will vary, and it would be impractical to list every single one by name - Vanita

2 Answers

1
votes

The clearest tutorial I've seen is this one (except that it does have an apparent error).

Replace this block:

<!-- 
  RemoveFolderEx requires that we "remember" the path for uninstall.
  Read the path value and set the APPLICATIONFOLDER property with the value.
-->
<Property Id="APPLICATIONFOLDER">
  <RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>

with this one:

<!-- 
  RemoveFolderEx requires that we "remember" the path for uninstall.
  Read the path value and set the FOLDERTOREMOVE property with the value.
-->
<Property Id="FOLDERTOREMOVE">
  <RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>

and this block:

<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />

with this one:

<util:RemoveFolderEx On="uninstall" Property="FOLDERTOREMOVE" />

and you should have a working test.

The reason for using two different properties is given here and here (among with other places).

If you can derive the path from other values you may have set during installation that Windows Installer will preserve for you, such as ARPINSTALLLOCATION, then you can adjust the above implementation to get what you need without having to create your own registry keys.

1
votes

Builds on B. Murri's answer:

Example: your application installs new files or folders in 'installdir/public'. These files aren't being deleted as they weren't added by the installer.

First, you need to create a registry value which will store where your public directory is installed. This is in case the user changes the install directory.

<!-- Note that the RegistryValue Value is being set to the 'public' directory ID -->
<DirectoryRef Id='INSTALLDIR'>
        <Component Id="RemovePublicDir" Guid="your-guid-here">
            <RegistryKey Root="HKCU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
                <RegistryValue  Name="Location" 
                                Type="string" 
                                Value="[PUBLIC]" 
                                Action="write" 
                                KeyPath="yes" />
            </RegistryKey>
            <CreateFolder Directory="PUBLIC"/>
            <util:RemoveFolderEx Property="FINDPUBLICDIR" On="uninstall"/>
            <RemoveFolder Id="PUBLIC" On="uninstall"/>
        </Component>
    </DirectoryRef>

You now need to add a property which will search for this registry value later on. Make sure your Root value above matches the one below:

<Property Id="FINDPUBLICDIR">
    <RegistrySearch Id='Registry' Type='raw' Root='HKCU' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>

Add your manufacturer name and product name to variables, like this:

<?define Manufacturer = "My Company"?>
<?define ProductName = "Test Application"?>

Now make sure you call this Component in your Feature tag:

<Feature Id="FeatureId">
    <ComponentRef Id="RemovePublicDir" />
</Feature>