Windowsインストーラーを作れるwixtoolsetの概要(v4)

# はじめに

Windows用インストーラーパッケージであるMSIが作成できるWixToolsetが、バージョン4.0.0をリリースした。
[WiX v4 and HeatWave v1 Released](https://www.firegiant.com/blog/2023/4/5/wix-v4-and-heatwave-v1-released/)

そこで、wixとはまず何なのかについて、解説をしていく。
[WixToolsetのドキュメントもあるのでそちらも参考に](https://wixtoolset.org/docs/intro/)

念のために書いておくが、ウェブサイト構築ツールのwix.comとは何の関係も無いので注意。

公式サイトは https://wixtoolset.org/

# WixToolsetとは

最初に書いたように、WixToolsetでは、Windowsのインストーラーパッケージ形式の一つであるMSIがビルドできる。
メインとなるMSI以外にも、パッチパッケージ、いくつかのMSIをまとめたブートストラッパー等も作成可能。
ファイル構成や、インストール、アンインストール時に行う処理の順番等をXMLを使って書いていく。

**前提としてMSIの知識が必須で、特に事前説明無しに用語が出てくるので、適宜公式ドキュメントを参照すること。**
https://learn.microsoft.com/en-us/windows/win32/msi/windows-installer-portal

# WixToolsetで使うファイル

ファイルの種類としては以下のようなものがある

* wixproj: プロジェクトファイル
* wxs: メインのソースファイル
* wxi: プリプロセッサ処理を書くファイル
* wxl: ローカライゼーションファイル

## wixproj

v4から、[MSBuild SDK](https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022)でビルドが可能になった。
なので、まずプロジェクトファイルとしてmsbuildファイルを用意する。拡張子は`*.wixproj`とする。
最低限のwixprojは以下のような内容になる。

```xml
<Project Sdk="WixToolset.Sdk/[バージョン]">
</Project>
```

使用可能なSDKバージョンについては、[WixToolset.Sdk nugetパッケージ](https://www.nuget.org/packages/WixToolset.Sdk)を参照する。
.NETフレームワークの導入確認や、UIダイアログの拡張に関してはnugetパッケージとして提供されているので、ItemGroup/PackageReferenceに追加していく。

例えば、[wixtoolsetが提供するUIライブラリ](https://wixtoolset.org/docs/tools/wixext/wixui/)を使用したい場合は、以下のようになる。

```xml
<Project Sdk="WixToolset.Sdk/4.0.1">
  <ItemGroup>
    <PackageReference Include="WixToolset.UI.wixext" Version="4.0.1" />  
  </ItemGroup>
</Project>
```

その他に追加可能なItemGroupやPropertyGroupは https://wixtoolset.org/docs/tools/msbuild/ に記載がある。
このwixprojを起点に各種記述を行っていく。

## wxs

メインとなるソースで、パッケージに含まれるファイル、ディレクトリ、カスタムアクション等を追加していく。
基本的には以下のような構造となる。基本的に[`<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">`](https://wixtoolset.org/docs/schema/wxs/)を頂点とする。

例えば、 `%ProgramFiles%\wixv4test` 以下に"test.txt"というファイル一つだけを配置する"wixv4test"というパッケージを作る場合は以下のようになる。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
    <!-- 
    [put-guid-here]の部分は適宜guidを生成して置き換えること 
    UpgradeCodeは無くても一応作成は可能だが、後のバージョンアップを考えるとあった方が良い
    ProductCodeはマイナーアップグレードを行うならば指定しておいた方が良い
    -->
    <Package InstallerVersion="500" Name="wixv4test"
        Manufacturer="testmanuf"
        UpgradeCode="[put-guid-here]"
        ProductCode="[put-guid-here]"
        Version="1.0.0.0">
        <!-- EmbedCab="yes"が無いと、MSIとファイルが入っているcabファイルが別に出力される -->
        <Media Id="1" EmbedCab="yes" Cabinet="cab1.cab" />
        <!-- ディレクトリ構造を宣言する。IdはComponent要素などで参照用に使う -->
        <StandardDirectory Id="ProgramFilesFolder">
            <Directory Id="INSTALLFOLDER" Name="wixv4test">
            </Directory>
        </StandardDirectory>
        <!-- 
        MSIはComponentを一つの単位としてファイル管理を行うが、WixではComponentGroupを作り、
        その中に各Componentを書いていった方が管理しやすい
        -->
        <ComponentGroup Id="Group1" Directory="INSTALLFOLDER">
            <!--
            Componentの中ではインストールするファイル、レジストリ等を記述する。
            Idは必須項目で、Guidはマイナーアップグレードを行うならば入れておいた方が良い
            -->
            <Component Id="test_txt" Guid="[put-guid-here]">
                <File Id="test_txt" Name="test.txt" KeyPath="yes" Source="test.txt" />
            </Component>
        </ComponentGroup>
        <!-- Featureは最低一つは必要で、グループ単位でインストール有無を決めたい場合は複数定義する -->
        <Feature Id="All">            
            <ComponentGroupRef Id="Group1" />
        </Feature>    
    </Package>
</Wix>
```

Wix配下には以下のような要素を置くことになる。

* [Package](https://wixtoolset.org/docs/schema/wxs/package/)
    * MSIパッケージを作る場合
        * インストーラー本体
* [Bundle](https://wixtoolset.org/docs/schema/wxs/bundle/)
    * ブートストラッパーパッケージを作る場合
        * 生MSIをラップして、独自UIを作ったり依存パッケージ(.NET Frameworkとか)をまとめることができる
* [Module](https://wixtoolset.org/docs/schema/wxs/module/)
    * [MSM(マージモジュール)](https://learn.microsoft.com/en-us/windows/win32/msi/about-merge-modules)を作る場合
* [Patch](https://wixtoolset.org/docs/schema/wxs/patch/)
    * [MSP(パッチモジュール)](https://learn.microsoft.com/en-us/windows/win32/msi/patch-packages)を作る場合
* [PatchCreation](https://wixtoolset.org/docs/schema/wxs/patchcreation/)
    * [PCP(パッチクリエーションモジュール)](https://learn.microsoft.com/en-us/windows/win32/msi/creating-a-patch-creation-properties-file)を作る場合
* [Fragment](https://wixtoolset.org/docs/schema/wxs/fragment/)
    * WXSファイルを分割したい場合に使う
    * ライブラリを作る時にも使う

上記で挙げた要素のうち、Fragment以外は各プロジェクト一つにつき一つだけ存在することが許可されるので注意する。
また、Fragment以外の要素は一つのプロジェクト内に共存ができない。
つまり、PackageとBundleを一つのプロジェクトにまとめるということはできない。

## wxl

ローカライゼーションファイル。他言語対応の場合はこのファイルに各言語に対応したメッセージを書いていく。
ファイル形式は`[ファイル名].[カルチャー].wxl(カルチャーは"en-us"や"ja-jp"等)`にする必要があり、ビルド時にカルチャー指定すると、他のカルチャー設定のwxlは無視される。
`<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl">`を頂点として、配下に下記の要素を置いていく。

* [String](https://wixtoolset.org/docs/schema/wxl/string/)
    * 実際に置き換える文字列のIDと内容を書いていく
* [UI](https://wixtoolset.org/docs/schema/wxl/ui/)
    * ダイアログ等のUIで、国別に幅などを調整したい場合に使用する

例:

```xml
<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
  <String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." />
</WixLocalization>
```

## wxi

C言語で言う所のヘッダファイルに当たる。
[`<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">`](https://wixtoolset.org/docs/schema/wxs/include/)要素を頂点として、配下にwxsに挿入するファイル内容を書いていく。
[wxiはコンパイル時にプリプロセッサで処理される。](https://wixtoolset.org/docs/tools/preprocessor/)
なので、例えばビルド時に引数等で条件を与えて、要素を丸ごと使うか使わないかを選択することができる。

```xml
<?if $(SomeVariable) = "ABC" ?>
  <?include A.wxi?>
<?endif?>
```

多用するとビルドエラーがどこで起こっているかわかりにくくなったりするので、
単純にComponentを分割したい場合等、wxsのFragment要素で実現可能な場合はFragmentを使用した方が良い。
ただし、Fragment要素と異なり、配下に入れられる要素はXMLであれば特に制約は無いので、Fragmentで実現できない場合に関しては使用を検討することになる。

例:

```xml
<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
    <!-- 任意のXML要素の挿入 -->
</Include>
```

# プロジェクトのビルド

[dotnet SDK](https://dotnet.microsoft.com/ja-jp/)をインストールして、`dotnet build`を行う。
成功すれば、`[wixprojディレクトリ]/bin/[アーキテクチャ]/[Configuration]/[カルチャー]/[出力ファイル]`に出力される。
`dotnet clean`でクリーン可能。

# 単体ファイルのビルド、あるいはユーティリティ

[dotnet global tool](https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools-how-to-use)として、[wixコマンド](https://www.nuget.org/packages/WiX/)が提供されている。
このツールで単体のwxsをコンパイルできるほかに、MSIファイルからWXSへの逆コンパイル、拡張キャッシュの取得等を行うことができる。
コマンドラインリファレンス: https://wixtoolset.org/docs/tools/wixexe/

# Visual Studio拡張

Visual Studio拡張として、[HeatWave](https://www.firegiant.com/wix/heatwave/)がある。
導入すれば、VS上での新規プロジェクト作成、補完、拡張の管理、ビルド等が可能になる。
Visual Studioを用いて開発できるならば、導入しておいて損は無いだろう。

# 終わりに

この記事では、wixtoolsetのv4についての概要について説明した。
v4になって、専用パッケージを入れなくても良くなったので、導入は各段に楽になったと思う。
MSIを作りたいという需要は正直どこまであるかわからないが、これが誰かの役に立てたら嬉しい。

今回書いたのは本当にさわりだけなので、時間があれば、MSIの作り方等の詳細記事も書いていきたい。