Windows Installer手引書 Part.7 アップグレード・インストールの種類

[**前の記事へ**](https://qiita.com/tohshima/items/32e6130dd8158020bf75)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/ea93453dd79cd833ef18)

## Windows Installerのアップグレード方式
Windows Installerにはアップグレードインストールのために下記３段階のアップグレード方式が用意されています。

- メジャー・アップグレード
- マイナー・アップグレード
- スモール・アップグレード

気を付けなければいけないのは、これらの言葉は、「今回は機能が大幅に追加されたからメジャー・アップグレード」、「次回はバグフィックスだからマイナー・アップグレード」というインストールする物の話ではなく、３種類の決められた動作を説明する、言わばWindows Installer用語である、ということです。また、一つのインストーラー単独で、「これはメジャー・アップグレード構成のインストーラー」とか「これはマイナー・アップグレード構成のインストーラー」とか言うことではなくて、インストール済みのバージョンとの関係でどれかのアップグレード方式が選ばれることになります。例えば、インストール済みのインストーラーがこういう構成だから、今回こういう構成にすると両者の関係はメジャー・アップグレードになる、といった使い方になります。

## アップグレード方式を決定づける要素

どのアップグレード方式が選ばれるかどうかは、下記の３つのPropertyがどう変化したかどうか、によって判断することができます。

- UpgradeCode
- ProductCode
- ProductVersion

UpgradeCodeとProductCodeにはGUIDが格納され、ProductVersionにはドットで区切ったバージョン番号が格納されます。Windows Installerはドットで区切った3つ目の番号まで認識し、4つ目以降の番号があっても無視します。そのため、4つ目の番号を変えても同じバージョンだと認識されます。UpgradeCodeはインストール済みの製品を判別するために利用されるため、アップグレード・インストール時には変更しません。UpgradeCodeを変えると別製品としてインストールされ、古い製品は残されます[^1]。例えば、複数のバージョンを1つの環境にインストールしたいときは、UpgradeCodeも変更します。これ以降、どのプロパティを変更するとどのアップグレード方式になるのか、どのような挙動を示すのか、説明していきます。

## メジャー・アップグレード

アップグレード元のソースからProductCodeを変更しProductVersionの数字を上げます。動作を大雑把に説明すると、古いインストール済みの製品がアンインストールされ、その後新しいバージョンの製品がインストールされます。下記のようなWiXのソースがあったとすると、Productエレメントの
　UpgradeCode属性がUpgradeCode Property、
　Id属性がProductCode Property、
　Version属性がProductVersion Property、
となります。PackageエレメントのInstallerVersionは製品のバージョンと関係はなく、どのバージョンのWindows Installerを使うかを示しています。

```xml
 1: <Product Id="d69b42bf-f2be-4d5c-ab30-f40cb72e61a3" Name="prTxtA" Language="1033" Version="1.0.0" Manufacturer="papa" UpgradeCode="59c98e8a-37d4-4195-8017-7de66ceaef0f">
 2:   <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
 3: 
 4:   <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
 5:   <MediaTemplate />
 6:              :
 7:              :
```

メジャー・アップグレードするためには、これらの値を変えればよいのですが、アップグレードインストールするには4行目～5行目のMajorUpgradeエレメントも必要です。このエレメントはデフォルトで「ダウングレードインストールとなる場合は、メッセージを表示してインストールを中止する」動作となりますが、[属性の設定により動作の変更が可能](http://wixtoolset.org/documentation/manual/v3/xsd/wix/majorupgrade.html)です。[WiXチュートリアル](http://wix-tutorial-ja.github.io/index.html)では、MajorUpgradeエレメントではなく[Upgradeエレメントを使って](http://wix-tutorial-ja.github.io/ch04/01-checking-for-oldies.html)いますが、バージョンが変わったときにこの属性に設定したバージョンも気にする必要があり、メンテナンス性が悪いためMajorUpgradeエレメントの使用をお勧めします（[変数](http://wixtoolset.org/documentation/manual/v3/overview/preprocessor.html)を使って改善することはできます）。ただしUpgradeエレメントは、インストール済み製品のバージョンを検出して特別な動作を実装するために、MajorUpgradeエレメントと併用することもできるので、使い方を覚えておいて損はないでしょう。

メジャー・アップグレードでは、インストーラー起動時メジャー・アップグレード動作となる条件が揃っていると、前回インストールしたバージョンのMSIファイルを使ってアンインストール処理を実行(UIはユーザーが起動した方のMSIが表示します)し、ユーザーが起動したインストーラーに戻ってインストール処理を続行します。そのため、細かい設計ミスがあっても、比較的寛容な動作をします。特別な理由がない限りメジャー・アップグレードだけを使う、というポリシーを採用してもよいと思います。その他にも一般に公開する製品ではマイナー・アップグレード、スモール・アップグレードを避ける理由がありますが、これは後述します。

## マイナー・アップグレード

アップグレード元のソースからProductVersionの数字を上げます。ProductCodeとUpgradeCodeは変更しません。基本的な動作は上書きインストールです。マイナー・アップグレードでは新しい機能やコンポーネントを追加できますが、機能とコンポーネントの関係を変更することはできません。

マイナー・アップグレードを実行するには、msiexecにいくつかのオプションを指定する必要があります。これは、単にMSIファイルをダブルクリックするだけではアップグレード・インストールが実行できないことを示します。例えば、こんな感じでアップグレード・インストールを実行します（[WiXチュートリアル](http://wix-tutorial-ja.github.io/index.html)から引用）。

```
msiexec /i SampleUpgrade.msi REINSTALL=ALL REINSTALLMODE=vomus
```

また、新規にインストールする場合はREINSTALLプロパティを指定してはいけません。これを一般的なユーザーに間違いなく実行するよう要求することは無理な話です。マイナー・アップグレードを一般に公開する製品で利用するには、MSIファイルの他にインストーラーを起動する別のプログラムがインストール状況を検出して、適切なコマンドラインオプションを指定してmsiexecを起動する必要があるわけです。InstallShieldではmsiexec.exeを起動するセットアップランチャーを自動的に構成してくれるので、あまり心配せずマイナーアップグレードを利用できますが、WiXでインストーラーを作成する場合は色々と面倒な実装が必要になってきます。WiXにこだわるなら、Package Bundleを使う手もあります[^2]。
 
さて、実際にマイナー・アップグレードを利用するには、コマンドラインに指定するプロパティの意味を理解しておく必要があります。[REINSTALLにはALL、または、Featureの名前を「,(カンマ)」で区切って指定します](https://docs.microsoft.com/en-us/windows/desktop/msi/reinstallmode)。ALLを指定した場合は、全てのFeatureが再インストールされます。REINSTALLMODEプロパティは、ファイルが既にある場合バージョンを比較するかどうかや、レジストリをインストールするかどうか、ショートカットを更新するかどうか、MSIファイルをシステムに再キャッシュするかどうか等を、アルファベットの組み合わせで指定します。マイクロソフトによる解説は[こちら](https://docs.microsoft.com/en-us/windows/desktop/msi/reinstallmode)にありますが、[こちら](https://www.civil-design.net/free/coach/dev/wi/wi_upgrade.html)に日本語で解説されている方がいらっしゃいます。
 
これらの解説を読み解くために、Windows Installerのいくつかの動作を知っておく必要があります。最初に[REINSTALLMODEプロパティに指定するアルファベットのうち`o,e,d,a`で使われるファイルバージョンについて説明します](https://docs.microsoft.com/en-us/windows/desktop/msi/file-versioning-rules)。拡張子が.EXEや.DLLなどであればリソースとしてバージョン番号を持つことができ、最初にこのバージョン番号を比較します。エクスプローラでファイルのプロパティを開き、`ファイルバージョン`の項目があれば、これが使われます。もし`ファイルバージョン`を持っていなければ、ファイルの更新日時が比較されます。最後に、システムの言語とファイルのリソースが指定する言語が一致するかどうか確認され、一致する方のファイルが優先的にインストールされます。次に、REINSTALLMODEプロパティに指定するアルファベットのうち`v`で使われるlocal packageのre-cacheについて説明します。Windows Installerはインストールで使用したMSIファイルの主にテーブルの情報を`C:\Windows\Installer`フォルダに保管します。また、レジストリにも、`Feature`や`Component`の構成が保管されます。これらの情報を書き換えるのがre-cacheです。Windows Installerは、インストールに使用したMSIファイルが既に使用した場所に存在しないとき、このキャッシュされた情報を使って修復・変更・削除といったメンテナンス処理を実行します。

## スモール・アップグレード

UpgradeCode、ProductCode、ProductVersionのどれも変更しません。厳密にはこれまで説明してこなかったPackageCodeに格納されたGUIDが変更[^3]され、他のビルドと区別されます。[１～２個のファイルが差し替えになったとき利用される](https://docs.microsoft.com/en-us/windows/desktop/Msi/small-updates)ようです。インストール時にmsiexecに対するオプションが必要な点は、マイナー・アップグレードと同じです。開発の現場でちょっとした修正が必要になった時に使えそうですが、バージョン番号を見てもアップグレード前後で違いがなく容易に区別できなくなるので、運用には注意が必要です。


[**前の記事へ**](https://qiita.com/tohshima/items/9c992f16d08f9b3b962d)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/ea93453dd79cd833ef18)

[^1]: 意味を考えるとUpgradeCodeとProductCodeは逆だろう、と思ったりしますが・・・
[^2]: が、使い込むと結構難解なので、私は好きではありません。
[^3]: デフォルトではWiXがコンパイル時に勝手に変更します。