Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
776 views
in Technique[技术] by (71.8m points)

msbuild - Make WIX installer place files in AppData

I'm writing a dapp for ethereum client for windows. In order to make dapp available for user I have to place specific files in the folder in appdata. So I just should place some files in %appdata%ParityEthereumdappsmydappname. But I always get weird errors with WIX, the last one is

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

I have following 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)MicrosoftWiXv3.xWix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)MicrosoftWiXv3.xWix.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>

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

I found that I have to use heat task to create a correct files tree, but now I'm stuck with simple task "copy these files on user machine".

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I am unfamiliar with this type of application (dapp for ethereum client for windows) - so the advice has to be generic I am afraid.

Per-User Files & Registry Settings: In general deploying files to the user profile and HKCU settings is difficult with MSI. As Chris points out it basically just works for the user installing the MSI, unless you actively add constructs to get files copied to all user profiles, and even then it is sort of clunky.

Approaches: I wrote a long answer a long time ago on the subject: Create folder and file on Current user profile, from Admin Profile (long and elaborate, but without any automagic solutions).

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


Errors: The specific problem you report has to do with the need for a per-user registry key path and a RemoveFolder entry for all folders targeting userprofile locations:

  <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="SoftwareTestManufacturerTestApp">
              <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.



与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...