2008-10-12 25 views
68

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

Respuesta

72

Use RemoveFile element con On = "desinstalación". He aquí 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> 

actualización

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

Desafortunadamente, Windows Installer no admite la eliminación de directorios con subdirectorios. En este caso, debe recurrir a acciones personalizadas. O bien, si sabe qué son las subcarpetas, cree un grupo de elementos RemoveFolder y RemoveFile.

+1

Gracias Pavel. Sin embargo, no funcionó al 100%. Eliminó los archivos, sin embargo, ninguno de los directorios adicionales, los creados después de la instalación, se eliminaron. ¿Alguna idea sobre eso? – pribeiro

+0

Oh, ninguno de los archivos debajo de esos directorios fue eliminado. – pribeiro

+2

Actualicé mi respuesta para responder a su pregunta. –

12

Para hacer esto, simplemente creé una acción personalizada para ser llamada 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 
8
No

un experto WIX, pero podría una posible solución (más simple?) A ser esto para ejecutar el Quiet Execution Custom Action que es parte de la construcción en las extensiones de WIX?

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

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

Y la acción personalizada haciendo el trabajo es simple:

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

entonces tendrá que modificar el InstallExecuteSequence como documentado muchos lugares.

Actualización: Tenía problemas con este enfoque. Terminó realizando una tarea personalizada en su lugar, pero todavía considera que esta es una solución viable, pero sin que los detalles funcionen.

+0

Me gusta esta barra de opciones por el hecho de que está incluyendo cmd.exe en el instalador. ¡Seguramente cada máquina lo tendrá, solo necesita usar DirectorySearch para encontrarlo! :) –

+1

No hagas esto. 1) está integrando 'cmd.exe' en su instalador. 2) Está realizando cambios en el sistema durante la generación de scripts 3) No hay opción de deshacer 4) No trata correctamente los archivos bloqueados –

26

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

+0

Advertencia: al usar RemoveFolderEx on = "uninstall", también elimina la carpeta en una actualización (Wix 3.9). Mismo comportamiento en 'RemoveFile' y' RemoveFolder'. Si desea mantener archivos en una actualización, no puede usar todos estos enfoques. – Simon

+0

@Simon ¿Qué enfoque sugeriría si quisiera mantener los archivos en una actualización? – Bijington

+0

@Bijington: cuando desee mantener archivos específicos en su carpeta de instalación en una actualización, utilice una acción personalizada que ejecute código personalizado (por ejemplo, C# escrito HandleSetup.exe). El código personalizado entrega sus archivos durante la instalación, mantiene sus archivos actualizados y elimina los archivos durante la desinstalación. – Simon

7

Aquí hay una variación de la sugerencia de @ tronda. Estoy borrando un archivo "instalar".log" que se crea por 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 se crea este archivo después de la instalación, y no es parte de un Componente . grupo

+1

Utilicé esta solución, con algunos cambios para eliminar todo el directorio: ExeCommand = "cmd/C RD " [INSTALLFOLDER] "/s/q" – Dennis

+0

@Dennis cómo eliminar INSTALLFOLDER, en win 10 se elimina pero en Windows Server 2012 no. – eomeroff

+0

Gran solución. ¡Gracias! –

1

Esta sería una respuesta más completa para @Pavel sugerencia, para mí que 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, bajo el elemento del producto:

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

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

Cuestiones relacionadas