卸载WiX时删除文件
卸载我的应用程序时,我想configurationWix安装程序以删除原始安装后添加的所有文件。 看起来卸载程序只删除最初从MSI文件安装的目录和文件,并保留稍后在应用程序文件夹中添加的所有内容。 换句话说,我想卸载时清除目录。 我怎么做?
在On =“ uninstall ”中使用RemoveFile元素 。 这是一个例子:
<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%。 它删除了这些文件,但是没有任何附加的目录(安装后创build的目录)被删除。 对此有什么想法? – pribeiro
不幸的是,Windows安装程序不支持删除包含子目录的目录。 在这种情况下,你必须诉诸自定义行动。 或者,如果您知道哪些子文件夹,请创build一堆RemoveFolder和RemoveFile元素。
在WiX中使用Util扩展中的RemoveFolderEx
元素。
通过这种方法,所有的子目录也被删除(而不是直接使用RemoveFile
元素 )。 此元素将临时行添加到MSI数据库中的RemoveFile
和RemoveFolder
表。
为了做到这一点,我只是简单地创build了一个自定义的操作来卸载。
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>
InstallerCustomActions.DLL中的OnBeforeUninstall方法的代码将如下所示(在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
不是WIX的专家,但是可能的解决方法是运行静态执行自定义操作 ,这是WIX的内置扩展的一部分?
可以使用/ S和/ Q选项运行rmdir MS DOS命令。
<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" />
那么你将不得不修改InstallExecuteSequencelogging许多地方。
更新:有这个方法的问题。 结束了做一个自定义的任务,但仍然认为这是一个可行的解决scheme,但没有得到的细节工作。
这是@ trondabuild议的一个变种。 我正在删除由另一个自定义操作在卸载期间创build的文件“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”,因为这个文件是在安装之后创build的,而不是组件组的一部分。
这将是@Pavelbuild议的更完整的答案,对我来说它是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>
此方法设置一个registry值与卸载时要删除的文件夹的所需path。 最后,从系统中删除INSTALLFOLDER和registry文件夹。 请注意registry的path可以在其他configuration单元和其他位置。