I literally spent a day trying to do the simplest thing. (Man, MSI/WiX is a handful!)
My goal is very simple. I need to remove the installation folder when my app is uninstalled. I create it as such (using WiX):
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='InstallFolder'>
<Directory Id='idCompany.com' Name='$(var.CompanyName)'>
<Directory Id='INSTALLDIR' Name='$(var.ProductThis)' >
<Component Id='CompIDMyEXE1' Guid='{--GUID1--}'>
<File Id='idMyEXE1' Name='MyExe1.exe' DiskId='1' Source='MyExe1.exe' Vital='yes' KeyPath='yes' />
<ServiceControl Id="idSrvc" Name="SrvcName" Stop="both" Wait="yes" />
</Component>
<Component Id='CompIDMyEXE2' Guid='{--GUID2--}'>
<File Id='idMyEXE2' Name='MyExe2.exe' DiskId='1' Source='MyExe2.exe' Vital='yes' KeyPath='yes' />
</Component>
<!-- and so on -->
</Directory>
</Directory>
</Directory>
I first tried to use RemoveFolder WiX keyword as it was suggested here, but no matter what I did my installation folder didn't want to go. What made matters worse is that there's no way of knowing why it didn't work. Did is simply not see my tag, or what ... arghhh!
So I decided to add a custom action written in C and delete the folder from there since I would have much more control there. So I did this:
<CustomAction Id="CA_SetProperties_UninstallFinalize" Property="CA_msiOnUninstallFinalize" Value="[INSTALLDIR]" />
<CustomAction Id='CA_msiOnUninstallFinalize' BinaryKey='CADll' DllEntry='msiOnUninstallFinalize' Execute='deferred' Impersonate='no' />
<InstallExecuteSequence>
<!-- Need to run it for uninstalls only -->
<Custom Action="CA_SetProperties_UninstallFinalize" Before="InstallFinalize">
NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE AND REMOVE
</Custom>
<Custom Action="CA_msiOnUninstallFinalize" After="CA_SetProperties_UninstallFinalize">
NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE AND REMOVE
</Custom>
<!-- ... -->
</InstallExecuteSequence>
but when I called RemoveDirectory API from my msiOnUninstallFinalize
method on my empty installation folder it kept returning ERROR_SHARING_VIOLATION
error.
So I put a break inside my msiOnUninstallFinalize
method (by simply adding a MessageBox
call) and checked the folder itself. It turns out, the folder at that point was already empty, but when I checked to see if there's a lock on it, it turns out that MSI itself is holding it:
So what's the rub here? How the heck to do this simple task????