В прошлой статье про проекты инсталяторов в 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:usersmyusernameDocumentsVisual Studio 2013ProjectsMyProject)
$(var.MyProject.ProjectExt) — спорная переменная, которая позволяет получить расширение файла с проектом (.csproj)
$(var.MyProject.ProjectFileName) — имя файла проекта (MyProject.csproj)
$(var.MyProject.ProjectName) — аналогично предыдущему, но без расширения (MyProject)
$(var.MyProject.ProjectPath) — путь к файлу проекта (C:usersmyusernameDocumentsVisual Studio 2013ProjectsMyProjectMyApp.csproj)
$(var.MyProject.TargetDir) — как раз эту переменную я использовал в примере выше (C:usersmyusernameDocumentsVisual Studio 2013ProjectsMyProjectbinDebug)
$(var.MyProject.TargetExt) — расширение файла собираемого на основе проекта (.exe)
$(var.MyProject.TargetFileName) — имя собираемого файла (MyProject.exe)
$(var.MyProject.TargetName) — аналогично предыдущему, но без расширения (MyProject)
$(var.MyProject.TargetPath) — тоже есть в примере, это полный путь до результата сборки (C:usersmyusernameDocumentsVisual Studio 2013ProjectsMyProjectbinDebugMyProject.exe)
$(var.SolutionDir) — папка в которой лежит решение (C:usersmyusernameDocumentsVisual Studio 2013ProjectsMySolution)
$(var.SolutionExt) — расширение решения (.sln)
$(var.SolutionFileName) — имя файла решения (MySolution.sln)
$(var.SolutionName) — аналогично предыдущему, но без расширения (MySolution)
$(var.SolutionPath) — Полное имя решения (C:usersmyusernameDocumentsVisual Studio 2013ProjectsMySolutionMySolution.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)Imagesfire_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)Imagesfire_eye_alien.ico" KeyPath="yes"/>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>