Pregunta

Al desinstalar mi aplicación, me gustaría configurar la Wix para eliminar todas las archivos que se agregaron después de la instalación original . Parece que el desinstalador elimina solo los directorios y archivos que se instalaron originalmente del archivo MSI y deja todo lo demás que se agregó más tarde en la carpeta de la aplicación. En otras palabras, me gustaría purgar el directorio al desinstalar. ¿Cómo hago eso?

¿Fue útil?

Solución

Use Elemento RemoveFile con On = " desinstalar " ;. Aquí hay un ejemplo:

<Directory Id="CommonAppDataFolder" Name="CommonAppDataFolder">
  <Directory Id="MyAppFolder" Name="My">
    <Component Id="MyAppFolder" Guid="*">
      <CreateFolder />
      <RemoveFile Id="PurgeAppFolder" Name="*.*" On="uninstall" />
    </Component>
  </Directory>
</Directory>

Update

  

No funcionó al 100%. Eliminó los archivos, sin embargo, ninguno de los directorios adicionales:   los creados después de la instalación fueron eliminados. ¿Alguna idea sobre eso? - pribeiro

Lamentablemente, Windows Installer no admite la eliminación de directorios con subdirectorios. En este caso, debe recurrir a una acción personalizada. O, si sabe qué son las subcarpetas, cree un montón de elementos RemoveFolder y RemoveFile.

Otros consejos

Use RemoveFolderEx elemento de la extensión Util en WiX.
Con este enfoque, también se eliminan todos los subdirectorios (en lugar de usando el elemento RemoveFile directamente ) . Este elemento agrega filas temporales a la tabla RemoveFile y RemoveFolder en la base de datos MSI.

Para hacer esto, simplemente creé una acción personalizada que se llamará en la desinstalación.

El código WiX se verá así:

<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>

El código para el método OnBeforeUninstall en InstallerCustomActions.DLL se verá así (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

Aquí hay una variación de la sugerencia de @ tronda. Estoy borrando un archivo " install.log " que se crea mediante otra Acción personalizada, durante la Desinstalación:

<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>

Por lo que yo entiendo, no puedo usar " RemoveFile " porque este archivo se crea después de la instalación y no forma parte de un Grupo de componentes.

No es un experto en WIX, pero una posible solución (¿más simple?) para esto sería ejecutar el Acción personalizada de ejecución silenciosa que forma parte de las extensiones integradas de WIX?

Podría ejecutar el rmdir comando MS DOS con las opciones / S y / Q.

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

Y la acción personalizada que hace el trabajo es simple:

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

Luego deberá modificar InstallExecuteSequence como se documenta en muchos lugares.

Actualización: Tuve problemas con este enfoque. Terminé haciendo una tarea personalizada, pero aún así considero que es una solución viable, pero sin que los detalles funcionen.

Esta sería una respuesta más completa para la sugerencia @Pavel , para mí está funcionando al 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>

Y, en Elemento del producto:

<Feature Id="Uninstall">
    <ComponentRef Id="UninstallFolder" Primary="yes"/>
</Feature>

Este enfoque establece un valor de registro con la ruta deseada de la carpeta que se eliminará al desinstalar. Al final, tanto el INSTALLFOLDER como la carpeta de registro se eliminan del sistema. Tenga en cuenta que la ruta al registro puede estar en otra colmena y en otras ubicaciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top