Удаление файлов при удалении WiX - PullRequest
75 голосов
/ 12 октября 2008

При удалении моего приложения я хотел бы настроить Wix для удаления всех файлов, которые были добавлены после первоначальной установки . Кажется, что деинсталлятор удаляет только каталоги и файлы, которые были изначально установлены из файла MSI, и оставляет все остальное, что было добавлено позже, в папке приложения. Другими словами, я хотел бы удалить каталог при удалении. Как мне это сделать?

Ответы [ 6 ]

81 голосов
/ 13 октября 2008

Используйте Элемент RemoveFile с On = " uninstall ". Вот пример:

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

Обновление

Это не сработало на 100%. Он удалил файлы, однако ни один из дополнительных каталогов - те, которые были созданы после установки, были удалены. Есть мысли по этому поводу? - прибейро

К сожалению, установщик Windows не поддерживает удаление каталогов с подкаталогами. В этом случае вам придется прибегнуть к индивидуальным действиям. Или, если вы знаете, что такое подпапки, создайте группу элементов RemoveFolder и RemoveFile.

29 голосов
/ 07 мая 2012

Используйте RemoveFolderEx элемент из расширения Util в WiX.
При таком подходе все подкаталоги также удаляются (в отличие от с использованием RemoveFile элемента непосредственно ). Этот элемент добавляет временные строки в таблицу RemoveFile и RemoveFolder в базе данных MSI.

12 голосов
/ 07 ноября 2008

Для этого я просто создал пользовательское действие, которое будет вызываться при удалении.

Код WiX будет выглядеть так:

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

Код для метода OnBeforeUninstall в InstallerCustomActions.DLL будет выглядеть следующим образом (в 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
9 голосов
/ 07 июля 2013

Вот вариант предложения @ tronda. Я удаляю файл "install.log", который создается другим настраиваемым действием во время удаления:

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

Насколько я понимаю, я не могу использовать «RemoveFile», поскольку этот файл создается после установки и не является частью группы компонентов.

7 голосов
/ 02 февраля 2010

Не эксперт WIX, но может ли (проще?) Решить эту проблему запустить Настраиваемое действие тихого выполнения , которое является частью встроенных расширений WIX?

Может выполнить команду rmdir MS DOS с параметрами / S и / Q.

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

А пользовательское действие, выполняющее эту работу, очень просто:

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

Тогда вам придется изменить InstallExecuteSequence, как описано во многих местах.

Обновление: Были проблемы с этим подходом. Вместо этого мы завершили создание пользовательской задачи, но все еще считаем это жизнеспособным решением, но без детализации.

4 голосов
/ 16 ноября 2015

Это был бы более полный ответ на предложение @ Pavel , для меня это работает на 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>

А, под элементом товара:

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

При таком подходе задается значение реестра с указанием желаемого пути к папке, удаляемой при удалении. В конце и INSTALLFOLDER, и папка реестра удаляются из системы. Обратите внимание, что путь к реестру может быть в другом улье и других местах.

...