使 WIX 安装程序将文件放置在 AppData 中

Make WIX installer place files in AppData

我正在为 windows 的以太坊客户端编写 dapp。为了让 dapp 可供用户使用,我必须将特定文件放在 appdata 的文件夹中。所以我应该将一些文件放在 %appdata%\Parity\Ethereum\dapps\mydappname 中。但是我总是在使用 WIX 时遇到奇怪的错误,最后一个是

Error 93 ICE64: The directory dapp is in the user profile but is not listed in the RemoveFile table.

我关注myapp.wixproj

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProductVersion>3.10</ProductVersion>
    <ProjectGuid>8beed2e4-8784-4cb5-8648-cdf55c5defe6</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputName>FairsDapp</OutputName>
    <OutputType>Package</OutputType>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <OutputPath>bin$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>Debug</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj$(Configuration)\</IntermediateOutputPath>
  </PropertyGroup>
  <PropertyGroup>
    <DefineConstants>HarvestPath=dapp</DefineConstants>
  </PropertyGroup>      
  <ItemGroup>
    <Compile Include="Product.wxs" />
    <Compile Include="Dapp.wxs" />
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
  <Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
    <Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
  </Target>
  <Target Name="BeforeBuild">
  <HeatDirectory
    DirectoryRefId="INSTALLFOLDER"
    OutputFile="Dapp.wxs"
    Directory="dapp"
    ComponentGroupName="SourceComponentGroup"
    ToolPath="$(WixToolPath)"
    PreprocessorVariable="var.HarvestPath"
    AutogenerateGuids="true" />
  </Target>
</Project>

以及以下 wxs:

<?xml version="1.0" encoding="UTF-8"?>
<Wix
    xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="Dapp" Language="1049" Version="1.0.0.3" Manufacturer="Me" UpgradeCode="fb09dccc-6606-4b5d-8dcb-28146c28663a" Codepage="1251">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
        <MediaTemplate EmbedCab="yes"/>
        <Feature Id="ProductFeature" Title="FDapp" Level="1">
            <ComponentGroupRef Id="ProductComponents" />
        </Feature>
    </Product>
    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="AppDataFolder">
                <Directory Id="Parity">
                    <Directory Id="dapps">
                        <Directory Id="INSTALLFOLDER" Name="F2"></Directory>
                    </Directory>
                </Directory>
            </Directory>
        </Directory>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"></ComponentGroup>
    </Fragment>
</Wix>

我发现我必须使用 heat 任务来创建正确的文件树,但现在我被简单的任务 "copy these files on user machine".

困住了

我不熟悉这种类型的应用程序(windows 的以太坊客户端的 dapp)- 恐怕建议必须是通用的。

每用户文件和注册表设置:一般来说,使用 MSI 很难将文件部署到用户配置文件和 HKCU 设置。正如克里斯指出的那样,它基本上只适用于安装 MSI 的用户,除非您主动添加构造以将文件复制到所有用户配置文件,即使那样它也有点笨拙。

Approaches:我很久以前就这个主题写了一个很长的回答:Create folder and file on Current user profile, from Admin Profile(又长又详细,但没有任何自动解决方案)。

Preferred Approach: Before getting involved in too much complexity, the easiest approach is generally to use your application to copy the userprofile files in place for every user on first launch - instead of using the setup to install user-specific files.

This requires that there is a separate application executable to launch, generally via its own shortcut - which it might not be? It generally does not work for addins for example.

  • Approach 1: Install template files per-machine and then copy them to each user's userprofile on application launch.

  • Approach 2: Alternatively I like to download files directly from a server or database and put in the userprofile - also on first launch.

Apply Updates?: There are ways to ensure that you can re-copy files if there are changes to your templates as described here: http://forum.installsite.net/index.php?showtopic=21552 (Feb 2019 converted to WayBack Machine link).


错误:您报告的具体问题与需要每个用户的注册表项路径和 RemoveFolder 条目有关对于以用户配置文件位置为目标的所有文件夹:

  <Directory Id="AppDataFolder">
    <Directory Id="Parity">
      <Directory Id="dapps">
        <Directory Id="INSTALLFOLDER" Name="F2">
          <Component Guid="{77777777-7777-7777-7777-7777777777DD}" Feature="MainApplication">

            <RegistryKey Root="HKCU" Key="Software\TestManufacturer\TestApp">
              <RegistryValue Name="Flag" Value="1" Type="string" KeyPath="yes" />
            </RegistryKey>

            <RemoveFolder Id="RemoveINSTALLFOLDER" Directory="INSTALLFOLDER" On="uninstall" />
            <RemoveFolder Id="RemoveParity" Directory="Parity" On="uninstall" />
            <RemoveFolder Id="Removedapps" Directory="dapps" On="uninstall" />

            <File Source="Test.exe" />
          </Component>
        </Directory>
      </Directory>

This is just one of MSI's conventions and quirks. As already stated, install all files per-machine and copy them to the userprofile with the application instead. It will dis-entangle them from any setup interference in the future. Then you do not need to deal with these RemoveFolder issues.


我发现并验证了该解决方案在添加 CustomAction 时有效,该 CustomAction 使用 PowerShell 遍历所有用户配置文件并将“模板 appdata 文件夹”复制到它们。模板文件夹由 WIX MSI 安装程序运送并安装到 [ProductDir]appdata,例如“C:\Program Files (x86)\myApplication\appdata”。

这是我为实现此目的而作为 CustomAction 添加到 WXS WIX 脚本中的内容:

<CustomAction 
    Id="ExecPsXcopyCmd" 
    Directory='ProductDir' 
    Execute='deferred' 
    Impersonate='no' 
    ExeCommand='[SystemFolder]WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy "ByPass" -Command "$productDir = &apos;[ProductDir]&apos;; $userRoot = (Split-Path $Env:PUBLIC); Foreach ($profile in Get-ChildItem -Path $userRoot -Directory -Exclude &apos;Public&apos; -Force -ErrorAction SilentlyContinue) { $srcPath = Join-Path -Path $productDir -ChildPath &apos;appdata&apos;; $dstPath = Join-Path -Path $profile.Fullname -ChildPath &apos;AppData\Roaming\myApplication&apos;; xcopy /S /E /I /R /H /Y $srcPath $dstPath}"'
    Return='check'/>

<InstallExecuteSequence>
    <RemoveExistingProducts Before="InstallInitialize" />
    <Custom Action="ExecPsXcopyCmd" After="WriteRegistryValues">NOT REMOVE</Custom>
    <LaunchConditions After="AppSearch"/>
</InstallExecuteSequence>

这假定您的产品安装目录名为“ProductDir”。