Supprimer des fichiers lors de la désinstallation de WiX
-
10-07-2019 - |
Question
Lors de la désinstallation de mon application, j'aimerais configurer le programme Wix pour supprimer tous les fichiers ajoutés après l'installation d'origine . Il semble que le programme de désinstallation supprime uniquement les répertoires et les fichiers initialement installés du fichier MSI et conserve le reste des éléments ajoutés ultérieurement dans le dossier de l'application. En d'autres termes, j'aimerais purger le répertoire lors de la désinstallation. Comment je fais ça?
La solution
Utilisez élément RemoveFile avec On = " désinstaller " ;. Voici un exemple:
<Directory Id="CommonAppDataFolder" Name="CommonAppDataFolder">
<Directory Id="MyAppFolder" Name="My">
<Component Id="MyAppFolder" Guid="*">
<CreateFolder />
<RemoveFile Id="PurgeAppFolder" Name="*.*" On="uninstall" />
</Component>
</Directory>
</Directory>
Mettre à jour
Cela n'a pas fonctionné à 100%. Il a supprimé les fichiers, mais aucun des répertoires supplémentaires - ceux créés après l'installation - ont été supprimés. Des idées à ce sujet? - pribeiro
Malheureusement, Windows Installer ne prend pas en charge la suppression de répertoires avec des sous-répertoires. Dans ce cas, vous devez recourir à une action personnalisée. Ou, si vous connaissez les sous-dossiers, créez un groupe d’éléments RemoveFolder et RemoveFile.
Autres conseils
Utilisez RemoveFolderEx
un élément de l'extension Util dans WiX.
Avec cette approche, tous les sous-répertoires sont également supprimés (par opposition à utiliser directement l'élément RemoveFile
). . Cet élément ajoute des lignes temporaires aux tables RemoveFile
et RemoveFolder
de la base de données MSI.
Pour ce faire, j'ai simplement créé une action personnalisée à appeler lors de la désinstallation.
Le code WiX ressemblera à ceci:
<Binary Id="InstallUtil" src="InstallUtilLib.dll" />
<CustomAction Id="DIRCA_TARGETDIR" Return="check" Execute="firstSequence" Property="TARGETDIR" Value="[ProgramFilesFolder][Manufacturer]\[ProductName]" />
<CustomAction Id="Uninstall" BinaryKey="InstallUtil" DllEntry="ManagedInstall" Execute="deferred" />
<CustomAction Id="UninstallSetProp" Property="Uninstall" Value="/installtype=notransaction /action=uninstall /LogFile= /targetDir="[TARGETDIR]\Bin" "[#InstallerCustomActionsDLL]" "[#InstallerCustomActionsDLLCONFIG]"" />
<Directory Id="BinFolder" Name="Bin" >
<Component Id="InstallerCustomActions" Guid="*">
<File Id="InstallerCustomActionsDLL" Name="SetupCA.dll" LongName="InstallerCustomActions.dll" src="InstallerCustomActions.dll" Vital="yes" KeyPath="yes" DiskId="1" Compressed="no" />
<File Id="InstallerCustomActionsDLLCONFIG" Name="SetupCA.con" LongName="InstallerCustomActions.dll.Config" src="InstallerCustomActions.dll.Config" Vital="yes" DiskId="1" />
</Component>
</Directory>
<Feature Id="Complete" Level="1" ConfigurableDirectory="TARGETDIR">
<ComponentRef Id="InstallerCustomActions" />
</Feature>
<InstallExecuteSequence>
<Custom Action="UninstallSetProp" After="MsiUnpublishAssemblies">$InstallerCustomActions=2</Custom>
<Custom Action="Uninstall" After="UninstallSetProp">$InstallerCustomActions=2</Custom>
</InstallExecuteSequence>
Le code de la méthode OnBeforeUninstall dans InstallerCustomActions.DLL ressemblera à ceci (en VB).
Protected Overrides Sub OnBeforeUninstall(ByVal savedState As System.Collections.IDictionary)
MyBase.OnBeforeUninstall(savedState)
Try
Dim CommonAppData As String = Me.Context.Parameters("CommonAppData")
If CommonAppData.StartsWith("\") And Not CommonAppData.StartsWith("\\") Then
CommonAppData = "\" + CommonAppData
End If
Dim targetDir As String = Me.Context.Parameters("targetDir")
If targetDir.StartsWith("\") And Not targetDir.StartsWith("\\") Then
targetDir = "\" + targetDir
End If
DeleteFile("<filename.extension>", targetDir) 'delete from bin directory
DeleteDirectory("*.*", "<DirectoryName>") 'delete any extra directories created by program
Catch
End Try
End Sub
Private Sub DeleteFile(ByVal searchPattern As String, ByVal deleteDir As String)
Try
For Each fileName As String In Directory.GetFiles(deleteDir, searchPattern)
File.Delete(fileName)
Next
Catch
End Try
End Sub
Private Sub DeleteDirectory(ByVal searchPattern As String, ByVal deleteDir As String)
Try
For Each dirName As String In Directory.GetDirectories(deleteDir, searchPattern)
Directory.Delete(dirName)
Next
Catch
End Try
End Sub
Voici une variation de la suggestion de @ tronda. Je supprime un fichier " install.log " créé par une autre action personnalisée lors de la désinstallation:
<Product>
<CustomAction Id="Cleanup_logfile" Directory="INSTALLFOLDER"
ExeCommand="cmd /C "del install.log""
Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="Cleanup_logfile" Before="RemoveFiles" >
REMOVE="ALL"
</Custom>
</InstallExecuteSequence>
</Product>
Pour autant que je sache, je ne peux pas utiliser "RemoveFile". car ce fichier est créé après l’installation et ne fait pas partie d’un groupe de composants.
Ce n'est pas un expert WIX, mais une solution possible (plus simple?) consiste à exécuter le Action personnalisée d’exécution silencieuse qui fait partie des extensions intégrées de WIX?
Peut exécuter la commande rmdir avec les options / S et / Q.
<Binary Id="CommandPrompt" SourceFile="C:\Windows\System32\cmd.exe" />
Et la personnalisation du travail est simple:
<CustomAction Id="DeleteFolder" BinaryKey="CommandPrompt"
ExeCommand='/c rmdir /S /Q "[CommonAppDataFolder]MyAppFolder\PurgeAppFolder"'
Execute="immediate" Return="check" />
Ensuite, vous devrez modifier InstallExecuteSequence comme indiqué dans de nombreux endroits.
Mise à jour: Eu des problèmes avec cette approche. Nous avons fini par créer une tâche personnalisée à la place, mais cela reste une solution viable, mais sans que les détails fonctionnent.
Ce serait une réponse plus complète pour la suggestion @Pavel . Pour moi, cela fonctionne à 100%:
<Fragment Id="FolderUninstall">
<?define RegDir="SYSTEM\ControlSet001\services\[Manufacturer]:[ProductName]"?>
<?define RegValueName="InstallDir"?>
<Property Id="INSTALLFOLDER">
<RegistrySearch Root="HKLM" Key="$(var.RegDir)" Type="raw"
Id="APPLICATIONFOLDER_REGSEARCH" Name="$(var.RegValueName)" />
</Property>
<DirectoryRef Id='INSTALLFOLDER'>
<Component Id="UninstallFolder" Guid="*">
<CreateFolder Directory="INSTALLFOLDER"/>
<util:RemoveFolderEx Property="INSTALLFOLDER" On="uninstall"/>
<RemoveFolder Id="INSTALLFOLDER" On="uninstall"/>
<RegistryValue Root="HKLM" Key="$(var.RegDir)" Name="$(var.RegValueName)"
Type="string" Value="[INSTALLFOLDER]" KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
Et sous l'élément Produit:
<Feature Id="Uninstall">
<ComponentRef Id="UninstallFolder" Primary="yes"/>
</Feature>
Cette approche définit une valeur de registre avec le chemin souhaité du dossier à supprimer lors de la désinstallation. À la fin, INSTALLFOLDER et le dossier de registre sont supprimés du système. Notez que le chemin d'accès au registre peut se trouver sur d'autres ruches et d'autres emplacements.