web-dev-qa-db-fra.com

Suppression de fichiers lors de la désinstallation de WiX

Lors de la désinstallation de mon application, je voudrais configurer la configuration 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 fichiers qui ont été initialement installés à partir du fichier MSI et qu'il laisse tout le reste ajouté plus tard dans le dossier d'application. En d'autres termes, j'aimerais purger le répertoire lors de la désinstallation. Comment je fais ça?

75
pribeiro

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>

Mise à 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 - n'a été supprimé. Des réflexions là-dessus? - 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 savez ce que sont les sous-dossiers, créez un groupe d'éléments RemoveFolder et RemoveFile.

81
Pavel Chuchuva

Utilisez RemoveFolderEx élément de l'extension Util dans WiX.
Avec cette approche, tous les sous-répertoires sont également supprimés (par opposition à en utilisant directement l'élément RemoveFile ). Cet élément ajoute des lignes temporaires à la table RemoveFile et RemoveFolder dans la base de données MSI.

29
Alexey Ivanov

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=&quot;[TARGETDIR]\Bin&quot; &quot;[#InstallerCustomActionsDLL]&quot; &quot;[#InstallerCustomActionsDLLCONFIG]&quot;" />

<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
12
Friend Of George

Voici une variante de la suggestion de @ tronda. Je supprime un fichier "install.log" qui est créé par une autre action personnalisée, lors de la désinstallation:

<Product>
    <CustomAction Id="Cleanup_logfile" Directory="INSTALLFOLDER"
    ExeCommand="cmd /C &quot;del install.log&quot;"
    Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />

    <InstallExecuteSequence>
      <Custom Action="Cleanup_logfile" Before="RemoveFiles" >
        REMOVE="ALL"
      </Custom>
    </InstallExecuteSequence>
</Product>

Pour autant que je comprends, 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.

9
Pierre

Pas un expert WIX, mais une solution possible (plus simple?) Pourrait être d'exécuter Quiet Execution Custom Action qui fait partie des extensions intégrées de WIX?

Pourrait exécuter la commande rmdir MS DOS avec les options/S et/Q.

<Binary Id="CommandPrompt" SourceFile="C:\Windows\System32\cmd.exe" />

Et l'action personnalisée qui fait le travail est simple:

<CustomAction Id="DeleteFolder" BinaryKey="CommandPrompt" 
              ExeCommand='/c rmdir /S /Q "[CommonAppDataFolder]MyAppFolder\PurgeAppFolder"' 
              Execute="immediate" Return="check" />

Ensuite, vous devrez modifier le InstallExecuteSequence comme documenté de nombreux endroits.

Mise à jour: J'ai eu des problèmes avec cette approche. A fini par faire une tâche personnalisée à la place, mais considère toujours que c'est une solution viable, mais sans que les détails fonctionnent.

7
tronda

Ce serait une réponse plus complète pour @ Pavel suggestion, pour moi ça marche à 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 d'accès 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 être à d'autres Hive et à d'autres emplacements.

4
Eli