вторник, 27 января 2015 г.

Работа с файлами в инсталяторах на WiX Toolset

В прошлой статье про проекты инсталяторов в Visual Studio я привел маленький пример, позволяющий добавить в MSI только exe файл нашего проекта. Сегодня предлагаю посмотреть как добавить другие файлы из проекта.


В прошлый раз мы остановились на том, что задали вот такую настройку для добавления файлов в проект (привожу текстом, т.к. в прошлый раз была картинка):
<Fragment>
  <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <Component Id="ProductComponent">
        <File Source="$(var.EyeOfSauron.TargetPath)" />
      </Component>
  </ComponentGroup>

</Fragment>
Теперь добавим копирование файла конфигурации и, например, dll которая используется в этом проекте и распространяется методом копирования. Для этого, в ту же ComponentGroup добавляем еще два компонента:
<Component Id="EyeOfSauron.exe.config">
  <File Source="$(var.EyeOfSauron.TargetDir)\EyeOfSauron.exe.config" />
</Component>
<Component Id="Hardcodet.Wpf.TaskbarNotification.dll">
  <File Source="$(var.EyeOfSauron.TargetDir)\Hardcodet.Wpf.TaskbarNotification.dll" />
</Component>
Обратите внимание, что вместо TargetPath (указывает на exe файл) используется TargetDir (папка куда выполнялось построение).
Ну и весьма полезный список поддерживаемых переменных (в скобках примеры того, что там в ней может быть):
$(var.MyProject.Configuration)  - конфигурация проекта (Debug или Release)
$(var.MyProject.FullConfiguration) - кроме конфигурации содержит еще и платформу под которую идет компиляция (Debug|AnyCPU)
$(var.MyProject.Platform) - только платформа (AnyCPU, Win32, x64 or ia64)
$(var.MyProject.ProjectDir) - путь до папки с проектом (C:\users\myusername\Documents\Visual Studio 2013\Projects\MyProject\)
$(var.MyProject.ProjectExt) - спорная переменная, которая позволяет получить расширение файла с проектом (.csproj)
$(var.MyProject.ProjectFileName) - имя файла проекта (MyProject.csproj)
$(var.MyProject.ProjectName) - аналогично предыдущему, но без расширения (MyProject)
$(var.MyProject.ProjectPath) - путь к файлу проекта (C:\users\myusername\Documents\Visual Studio 2013\Projects\MyProject\MyApp.csproj)
$(var.MyProject.TargetDir) - как раз эту переменную я использовал в примере выше (C:\users\myusername\Documents\Visual Studio 2013\Projects\MyProject\bin\Debug\)
$(var.MyProject.TargetExt) - расширение файла собираемого на основе проекта (.exe)
$(var.MyProject.TargetFileName) - имя собираемого файла (MyProject.exe)
$(var.MyProject.TargetName) - аналогично предыдущему, но без расширения (MyProject)
$(var.MyProject.TargetPath) - тоже есть в примере, это полный путь до результата сборки (C:\users\myusername\Documents\Visual Studio 2013\Projects\MyProject\bin\Debug\MyProject.exe)
$(var.SolutionDir) - папка в которой лежит решение (C:\users\myusername\Documents\Visual Studio 2013\Projects\MySolution\)
$(var.SolutionExt) - расширение решения (.sln)
$(var.SolutionFileName) - имя файла решения (MySolution.sln)
$(var.SolutionName) - аналогично предыдущему, но без расширения (MySolution)
$(var.SolutionPath) - Полное имя решения (C:\users\myusername\Documents\Visual Studio 2013\Projects\MySolution\MySolution.sln)

Воспользоваться этим можно, например, вот так:
if $(var.EyeOfSauron.Configuration) = "Debug" ?>
  <Component Id="EyeOfSauron.exe.config">
    <File Name="EyeOfSauron.exe.config" Source="$(var.EyeOfSauron.ProjectDir)\App.Debug.config" />
  </Component>
else?>
  <Component Id="EyeOfSauron.exe.config">
    <File Source="$(var.EyeOfSauron.TargetDir)\EyeOfSauron.exe.config" />
  </Component>
endif?>
Что здесь интересного:
1. Применяем if $(var.EyeOfSauron.Configuration) = "Debug" ?>, для того, чтобы проанализировать в какой конфигурации у нас идет Build.
2. Строим путь до файла в папке проекта: Source="$(var.EyeOfSauron.ProjectDir)\App.Debug.config"
3. Меняем имя файла при копировании его в инсталятор:

Ну и заканчивая с файлами, как создавать вложенные папки при развертывании и как поместить в них файлы. Допустим, у нашего проекта есть папка Images и в ней лежит иконка, которую мы хотим скопировать. Вот так:
В файле Product.wxd кроме использованного выше фрагмента (Fragment) есть, если помните из предыдущей статьи и вот такой фрагмент:
<Fragment>
 <Directory Id="TARGETDIR" Name="SourceDir">
  <Directory Id="ProgramFilesFolder">
   <Directory Id="INSTALLFOLDER" Name="EyeOfSauron" />
  </Directory>
 </Directory>    
</Fragment>
Правим его следующим образом:
<Fragment>
  <Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="ProgramFilesFolder">
      <Directory Id="INSTALLFOLDER" Name="EyeOfSauron">
        <Directory Id="Images" Name="Images" />
      </Directory>
    </Directory>
  </Directory>    
</Fragment>
Добавляем в информацию о продукте новую ComponentGroupRef:
<Feature Id="ProductFeature" Title="EyeOfSauron" Level="1">
  <ComponentGroupRef Id="ProductComponents" />
  <ComponentGroupRef Id="Icons" />
</Feature>  
Ну и в уже знакомый нам фрагмент добавляем новый ComponentGroup:
<ComponentGroup Id="Icons" Directory="Images">
  <Component Id="fire_eye_alien.ico" >
    <File Id="fire_eye_alien.ico" Source="$(var.EyeOfSauron.ProjectDir)\Images\fire_eye_alien.ico" KeyPath="yes"/>  </Component>
</ComponentGroup>
Все, папка с файлом будут доступны в развернутом приложении.
Ну и весь пример, а то вдруг чего забыл в процессе:
xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Product Id="*" Name="EyeOfSauron" Language="1033" Version="1.0.0.0" Manufacturer="Life" UpgradeCode="fb4e9c90-2572-4d75-a219-02713e72ad0e">
  <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
 
  <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
  <MediaTemplate />
 
    <Feature Id="ProductFeature" Title="EyeOfSauron" Level="1">
     <ComponentGroupRef Id="ProductComponents" />
      <ComponentGroupRef Id="Icons" />
    </Feature>    
 </Product>
 
  <Fragment>
   <Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="EyeOfSauron">
          <Directory Id="Images" Name="Images" />
        </Directory>
    </Directory>
   </Directory>    
  </Fragment>
 
  <Fragment>
   <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
   <Component Id="ProductComponent">
        <File Source="$(var.EyeOfSauron.TargetPath)" />
      </Component>      
      if $(var.EyeOfSauron.Configuration) = "Debug" ?>
        <Component Id="EyeOfSauron.exe.config">
          <File Name="EyeOfSauron.exe.config" Source="$(var.EyeOfSauron.ProjectDir)\App.Debug.config" />
        </Component>
      else?>
        <Component Id="EyeOfSauron.exe.config">
          <File Source="$(var.EyeOfSauron.TargetDir)\EyeOfSauron.exe.config" />
        </Component>
      endif?>
      <Component Id="Hardcodet.Wpf.TaskbarNotification.dll">
        <File Source="$(var.EyeOfSauron.TargetDir)\Hardcodet.Wpf.TaskbarNotification.dll" />
      </Component>      
    </ComponentGroup>
    <ComponentGroup Id="Icons" Directory="Images">
      <Component Id="fire_eye_alien.ico" >
        <File Id="fire_eye_alien.ico" Source="$(var.EyeOfSauron.ProjectDir)\Images\fire_eye_alien.ico" KeyPath="yes"/>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

Комментариев нет:

Отправить комментарий