При удалении моего приложения я хотел бы настроить Wix для удаления всех файлов, которые были добавлены после исходная установка. Похоже, что деинсталлятор удаляет только каталоги и файлы, которые изначально были установлены из файла MSI, и он оставляет все остальное, которое было добавлено позже в папке приложения. Другими словами, я хочу очистить каталог при удалении. Как это сделать?
Удаление файлов при удалении WiX
Ответ 1
Используйте элемент RemoveFile с On = " удалить". Вот пример:
<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%. Он удалил файлы, однако ни один из дополнительных каталогов - созданные после установки - были удалены. Любые мысли по этому поводу? - pribeiro
К сожалению, установщик Windows не поддерживает удаление каталогов с помощью подкаталогов. В этом случае вам нужно прибегнуть к пользовательским действиям. Или, если вы знаете, что такое подпапки, создайте кучу элементов RemoveFolder и RemoveFile.
Ответ 2
Используйте RemoveFolderEx
элемент из расширения Util в WiX.
При таком подходе все подкаталоги также удаляются (в отличие от непосредственно с помощью элемента RemoveFile
). Этот элемент добавляет временные строки в таблицу RemoveFile
и RemoveFolder
в базе данных MSI.
Ответ 3
Чтобы сделать это, я просто создал настраиваемое действие для вызова при удалении.
Код 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="[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>
Код метода 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
Ответ 4
Не эксперт WIX, но может ли это быть возможным (более простым?) решением для выполнения Quiet Execution Custom Action, которое является частью встроенные расширения 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, как описано во многих местах.
Update: Были проблемы с этим подходом. Завершилось создание пользовательской задачи вместо этого, но все же считает это жизнеспособным решением, но не получая детали для работы.
Ответ 5
Здесь вариация на предложение @tronda. Я удаляю файл "install.log", который создается другим пользовательским действием во время удаления:
<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>
Насколько я понимаю, я не могу использовать "RemoveFile", потому что этот файл создается после установки и не является частью группы компонентов.
Ответ 6
Это будет более полный ответ для @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, так и папка реестра удаляются из системы. Обратите внимание, что путь к реестру может быть в другом улье и в других местах.