Wix 在卸载时删除 appdata 文件夹

Wix remove appdata folder on uninstall

我正在使用 Wix 3.11 并尝试了多种不同的方式和方法,但似乎无法弄清楚为什么 Wix 没有删除我的 ApplicationDataFolder 文件夹.在安装期间,我在 ApplicationDataFolder 位置为用户创建文件夹。

我的应用程序使用日志记录并将其与其他一些内容一起存储在目录中。在卸载过程中,应用程序文件夹中的所有内容都被删除,但带有日志和其他文件的 appdata 文件夹保持不变。

我不知道为什么或我错过了什么。

WXS 模板

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <Product Id="*" UpgradeCode="9e578e3d-0119-425c-8633-f54ffaaa4929" Name="@product.name@" Version="@product.version@" Manufacturer="@product.company@" Language="1033">
    <Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" Comments="@product.version@" Description="@product.description@"/>
    <Media Id="1" Cabinet="SomeApp.cab" EmbedCab="yes" />

    <!-- Installer Properties -->
    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
    <PropertyRef Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED"/>

    <!-- Installer Resources -->
    <Icon Id="ApplicationIcon" SourceFile="SomeApp 4\SomeApp 4_vista.ico"/>
    <Property Id="ARPPRODUCTICON" Value="ApplicationIcon" />

    <Property Id="INSTALLDIR">
        <RegistrySearch Key="SOFTWARE\Acme\SomeApp" 
                        Root="HKCU" Type="raw" 
                        Id="APPLICATIONFOLDER_REGSEARCH" Name="installation-path" />
    </Property>

    <WixVariable Id="WixUILicenseRtf" Value="SomeApp 4\license.rtf" />
    <WixVariable Id="WixUIBannerBmp" Value="WixUIBannerBmp.bmp" />
    <WixVariable Id="WixUIDialogBmp" Value="WixUIDialogBmp.bmp" />

    <!-- Check Existing Install -->
    <Upgrade Id="9e578e3d-0119-425c-8633-f54ffaaa4929">
        <UpgradeVersion Minimum="@product.version@" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
        <UpgradeVersion Minimum="0.0.0" Maximum="@product.version@" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED"/>   
    </Upgrade>
    <Condition Message="A newer version of this software is already installed.">NOT NEWERVERSIONDETECTED</Condition>

    <!-- Prerequisites -->
    <Condition Message="This application requires .NET Framework 4.6 or newer. Please install the .NET Framework then run this installer again.">
      <![CDATA[Installed OR WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED]]>
    </Condition>

    <Condition Message="This application requires at least Windows 7 or Windows Server 2008 R2. Please upgrade your computer to a supported operating system and run this installer again.">
      <![CDATA[Installed OR (VersionNT >= 601)]]>
    </Condition>

    <!-- Define the directory structure -->
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder" Name="ProgramFiles">
        <Directory Id="INSTALLDIR" Name="@product.company@">
            @product.applicationfiles@
            @product.servicefiles@
        </Directory>
      </Directory>
      <Directory Id="ProgramMenuFolder">
        <Directory Id="ApplicationProgramsFolder" Name="@product.name@"/>
        <Directory Id="ServiceProgramsFolder" Name="@product.name@"/>
      </Directory>
      <Directory Id="DesktopFolder" Name="Desktop" /> 
      <Directory Id="LocalAppDataFolder">
        <Directory Id="ApplicationDataFolder" Name="Acme" />
      </Directory>            
    </Directory>

    <DirectoryRef Id="ApplicationProgramsFolder">
        <Component Id="ApplicationShortcut" Guid="1e578e4d-0229-425c-8633-f54ffaaa4901">
            <Shortcut Id="ApplicationStartMenuShortcut" 
                Name="SomeApp 4.6" 
                Description="@product.company@ @product.name@ @product.version@"
                Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
                WorkingDirectory="INSTALLDIR"
                Icon ="ApplicationIcon"/>       
            <Shortcut Id="ApplicationStartMenuShortcut2" 
                Name="SomeApp 4.6 (Multiple Instances)" 
                Description="@product.company@ @product.name@ @product.version@"
                Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
                Arguments="MultipleInstance=True"
                WorkingDirectory="INSTALLDIR"
                Icon ="ApplicationIcon"/>  
            <Shortcut Id="ApplicationStartMenuShortcut3" 
                Name="SomeApp 4.6 (Notifications)" 
                Description="@product.company@ @product.name@ @product.version@"
                Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe"
                Arguments="Notifications=True"
                WorkingDirectory="INSTALLDIR"
                Icon ="ApplicationIcon"/>                   
            <Shortcut Id="HelpStartMenuShortcut" 
                Name="SomeApp 4.6 Help" 
                Target="[INSTALLDIR]SomeApp 4\Documentation\SomeApp.chm"
                WorkingDirectory="INSTALLDIR"/>                 
            <Shortcut Id="UninstallProduct"             
                      Name="Uninstall SomeApp 4.6"
                      Target="[SystemFolder]msiexec.exe"
                      Arguments="/x [ProductCode]"
                      Description="Uninstall @product" />                    
            <Shortcut Id="desktopshortcut" 
                      Directory="DesktopFolder" 
                      Name="SomeApp 4.6" 
                      WorkingDirectory="INSTALLDIR" 
                      Target="[INSTALLDIR]SomeApp 4\SomeApp.UserInterface.exe" />
            <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
            <util:RemoveFolderEx On="uninstall" Property="ApplicationDataFolder" />                       
       </Component>
    </DirectoryRef>

    <DirectoryRef Id="ServiceProgramsFolder">
       <Component Id="ServiceShortcut" Guid="9e578e3d-0229-425c-8633-f54ffaaa4901">
            <Shortcut Id="ServiceStartMenuShortcut"
                Name="@product.name@ Reporting Service" 
                Description="@product.name@ Reporting Service"
                Target="[INSTALLDIR]Reporting\SomeApp.ReportingService.exe"
                WorkingDirectory="INSTALLDIR"
                Icon ="ApplicationIcon"/>
            <RemoveFolder Id="ServiceProgramsFolder" On="uninstall"/>                    
            <RegistryValue Root="HKCU" Key="Software\Microsoft\Acme\SomeApp" Name="service-installed" Type="integer" Value="1" KeyPath="yes"/>                   
       </Component>
    </DirectoryRef>   

    <DirectoryRef Id="INSTALLDIR">
        <Component Id="CleanupMainApplicationFolder" Guid="*">
            <RegistryValue Root="HKCU" Key="SOFTWARE\Acme\SomeApp" Name="installation-path" Type="string" Value="[INSTALLDIR]" KeyPath="yes" />
            <util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />                
            <util:RemoveFolderEx On="uninstall" Property="ApplicationDataFolder" />                
        </Component>
    </DirectoryRef>

    <!--  Feature: SomeApp Application -->            
    <Feature Id="Feature.Application"
                     Title="SomeApp 4 - Application"
                     Description="SomeApp is an asset management and maintenance application designed to optimize asset value and improve manufacturing productivity."
                     ConfigurableDirectory="INSTALLDIR"
                     Level="1"
                     AllowAdvertise="no">
                    @product.applicationcomponents@
                    <ComponentRef Id="ApplicationShortcut" />                    
                    <ComponentRef Id="CleanupMainApplicationFolder" />                    
    </Feature>

    <!--  Feature: Reporting Service -->
    <Feature Id="Feature.Service"
                     Title="SomeApp 4 - Reporting Service"
                     Description="This service generates and delivers reports that have been scheduled in the SomeApp Maintenance Management System."
                     ConfigurableDirectory="INSTALLDIR"
                     Level="3"
                     AllowAdvertise="no">
                    @product.servicecomponents@    
                    <ComponentRef Id="ServiceShortcut" />                    
        <Component Id="ReportingServiceInstaller" Guid="B72CAA3F-F2DB-48D2-90DD-061209AB2CE5" Directory="INSTALLDIR">
            <CreateFolder />
            <File Id="ReportingService.exe" Name="ReportingService.exe" KeyPath="yes" Source="@product.sourcedir@\Reporting\SomeApp.ReportingService.exe"/>
            <ServiceInstall Id="ReportingServiceInstaller"
                Type="ownProcess"
                Vital="yes"
                Name="SomeApp Reporting Service"                    
                DisplayName="SomeApp - Reporting Service"
                Description="This service generates and delivers reports that have been scheduled in the SomeApp Maintenance Management System."
                Start="auto"
                Account="NT AUTHORITY\LocalService"
                ErrorControl="ignore"
                Interactive="no" />
        </Component>     

    </Feature>

    <CustomAction Id="Cleanup_logfile" Directory="INSTALLDIR" 
    ExeCommand="cmd /C &quot;rmdir %LOCALAPPDATA%\Acme /s /q&quot;" 
    Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />

    <InstallExecuteSequence>
      <Custom Action="Cleanup_logfile" After="RemoveFiles" >
        REMOVE="ALL" 
      </Custom>
    </InstallExecuteSequence>

    <InstallExecuteSequence>
        <RemoveExistingProducts After="InstallValidate"/>
    </InstallExecuteSequence>   

    <UIRef Id="WixUI_FeatureTree" />
    <UI>
      <DialogRef Id="FilesInUse" />
      <DialogRef Id="MsiRMFilesInUse" />
      <!-- Add the GUI logic for installation -->
    </UI>
  </Product>
</Wix>

我有一个使用 util:RemoveFolderEx 的项目,它运行正常。我能看到的唯一区别是我在运行时明确地将 属性 设置为安装目录的值。我的猜测是 "INSTALLDIR" 和 "ApplicationDataFolder" 实际上不是属性,因为它们存储在您的 msi 的目录 table 而不是 属性 table 中。 (使用 ORCA 检查)

试试

<SetProperty Id='AcmeAppDataFolderToRemove' Value='[ApplicationDataFolder]' After='AppSearch'/>

然后将 util:RemoveFolderEx 更改为

<util:RemoveFolderEx On="uninstall" Property="AcmeAppDataFolderToRemove" />

看看是否可行。 (您可能需要使用 Value='ApplicationDataFolder' 而没有 [] 不确定。)


为了回应您的编辑,我查看了 RemoveFolderEx 页面,这看起来很重要

The custom action that implements RemoveFolderEx does so by writing temporary rows to the RemoveFile table for each subfolder of the root folder you specify. Because it might dramatically affect Windows Installer's File Costing, the temporary rows must be written before the CostInitialize standard action. Unfortunately, MSI doesn't create properties for the Directory hierarchy in your package until later, in the CostFinalize action.

我认为将它设置到目录会起作用,但显然当 RemoveFolderEx 操作实际执行时这些目录还没有值。因此,当这尝试解析属性或设置属性时,它们实际上只是空的。

说的我的安装程序所做的和它实际做的不同是我通过注册表搜索获得了我设置属性的值。

<Property Id="INSTALLDIR">
    <RegistrySearch 
        Id='InstallDirRegistrySearch' 
        Type='raw'
        Root='HKLM' 
        Key='SOFTWARE$(var.OEMRegistryRootKeyName)' 
        Name='SDKPath' />
</Property>
<SetProperty Id='SDKFolderToRemove' Value='[INSTALLDIR]$(var.OEMProduct) SDK' After='AppSearch'/>

所以我会尝试将 appdata 目录写入注册表项并通过注册表搜索将值放入 属性 然后在你的 removefolderex 中使用那个 属性,你可能不需要set属性,我只是使用它,因为我需要一个位于 INSTALLDIR 下的文件夹,但在你的情况下,你可以将注册表项设置为正确的文件夹。