Windows Installer手引書 Part.8 次のバージョンを出す、こんな時どうする

[**前の記事へ**](https://qiita.com/tohshima/items/2dfa841cbab3d8488641)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/0a197917042d705e5568)

## インストーラー作成は2回目以降が難しい

最初のバージョンのソフトウェアをリリースしてから後が、インストーラー技術者の腕の見せ所になってきます。次のバージョンではファイル構成が変わったり、古いバージョンのソフトウェアを残して別のバージョンを入れられるようにしたり、一部のモジュールを他のソフトウェアでも共用したくなったり、いろいろ変化が起きます。既存のインストーラーのどこをどう変えれば、すんなり次のバージョンをインストールできるでしょうか。

## ファイル構成が変わらない

- ファイル構成が前のバージョンと同じ
- 変更部分は、ファイル名そのまま、内容が新しいものに差し替えるだけ
- 旧バージョンが入っていたら新バージョンに置き換えればよい

インストーラーにとっては、最も簡単な状況です。メジャー・アップグレードを選択すれば、ほぼ何も考える必要はありません。WiXでうまく作ってあれば、インストーラーのバージョン番号を上げて、製品コードのGUIDを変えるだけです。以下の様にMajorUpgradeエレメントを使っていれば、ProductエレメントのVersion属性の数値を上げ、Id属性のGUIDを差し替えるだけで完了です。Windows Installerでは、バージョン番号を「.(ドット)」で区切った3つ目の数値までしか認識しないことに注意が必要です[^1]。そのため、バージョン番号を上げるには、1つ目から3つ目までのいずれかの数値を上げる必要があります。バージョン番号に4つ目の数値を入れてもエラーは起きませんが、この数値を変えてもWindows Installerは無視します。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="C49162AE-383D-4D6C-9E3D-BFBC914E51D0" Name="Part8_01" Language="1033" 
      Version="1.0.0" Manufacturer="VenderName" UpgradeCode="617798cf-bcf0-448b-868e-4f0927a95c41">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />
　　　　：
　　　　：
```

## インストールするファイルが増えた

やるべきことは、コンポーネントの再設計です。マイナー・アップグレードではKey Pathに指定したファイルが更新されなければコンポーネントに属するファイルは上書きされませんから、既存のファイルに更新がなければ新たなコンポーネントを追加することになります。メジャー・アップグレードを使えばこういったことを気にする必要はなくなりますが、将来何が起きるかわからないのがインストーラー。Featureを使って機能別にインストールできるようにしていたり、他のインストーラーとコンポーネントを共有していると影響を受けます。また、時間が無いのにメジャー・アップグレードできない不具合が発症する、なんてときもあります[^2]。きちんと[マイクロソフトの指針](https://docs.microsoft.com/en-us/windows/desktop/Msi/organizing-applications-into-components)を守ってコンポーネントを再設計しましょう。改造元のソースの設計ポリシーがよく分からないなら、コンポーネントを追加して、メジャー・アップグレードしてしまったほうが安全です。同じフォルダに複数のコンポーネントでファイルをインストールしても問題はありません。

## インストールするファイルが減った

マイナー・アップグレードではコンポーネントのKey Pathに指定したファイルの新旧が比較され、新しくなった時、所属するコンポーネント全体を適用する（ファイルを差替えたり追加する）ことになります。これは、Key Path以外のファイルをMSIから削除したらマイナー・アップグレードではファイルが削除できないだけでなく、削除しようとしたファイルのインストール情報が失われるので、アンインストール時にファイルが残る現象が起きる、ということです。また、Key Pathに指定したファイルを削除したら、どれか別のファイルをKey Pathに指定する必要があり、これはもはや別のコンポーネントにする（コンポーネントコードのGUIDを変える）必要があります。結局、インストールするファイルを減らすなら、メジャーアップグレードすることになります。メジャーアップグレードすると一旦旧バージョンがアンインストールされてから新バージョンがインストールされるので、Key Pathのファイルが無くなろうが、コンポーネントが減ろうが、コンポーネントコードを変える必要すらなくなります。

ただ、それでも、他のプログラムのインストーラーとファイル共有したり、旧バージョンと同一環境にインストールできるようにしたり、他のインストーラーと影響しあう可能性はありますので、コンポーネントを構成する際の[マイクロソフトの指針](https://docs.microsoft.com/en-us/windows/desktop/Msi/organizing-applications-into-components)はしっかり守る必要があります。

## アップグレードついでに製品名(ProductName)を変更したい

Windows10の「アプリと機能」やWindows7の「プログラムと機能」に表示する製品名(`ProductName`プロパティ)は自由に変えることができます。また、MSIファイルのファイル名を変えても問題ありません。Windows Installerが製品を判別するために使用する情報は`UpgradeCodeプロパティ`と`ProductCodeプロパティ`、そして`ProductVersionプロパティ`です。

## 古いバージョンも新しいバージョンも同じPCにインストールしたい

当然インストールするプログラム側で両者を同時に使っても問題ないよう配慮されていなければなりません。また、プログラムの動作面だけでなくバージョンが異なる場合は別のフォルダにファイルを置く必要があるでしょう。スタートメニューに置くショートカットも複数のバージョンが置かれることを前提にインストールしておく必要があります。

Windows Installerから見ると、両者をまったく別製品としてインストールする必要があります。「アプリと機能」や「プログラムと機能」にも両方のバージョンが表示されることになります。古いバージョンのインストーラーのソースを元に新しいバージョンのインストーラーを作成する際には、両バージョンが共存したときに不都合な情報が残らないようにする必要があります。別バージョンの全ファイルが別のフォルダにインストールされる（バージョンごとにフォルダを作って、そこにインストールする）なら、全コンポーネントのComponent Code（WiXではComponentエレメントのGuid属性）を変える必要があります。そうしないと、仕様の異なる２つのコンポーネントが別の場所にファイルを置こうとするので、異常な状態になります。別製品のインストーラーであっても、仕様の異なるコンポーネントはPC上で唯一のGUIDを持つ必要があるのです。もし複数の製品で共有するファイルがあるのなら、同じComponent Code、同じKey Path指定を持つ同一仕様のコンポーネントを両製品で使用すれば、同じ場所にある同じファイルを複数の製品が利用できます。両方の製品をアンインストールしなければ共有ファイルが消えることはありません。

## ダウングレード・インストールする

Windows Installerの基本的な動作はアップグレード（バージョンアップ）であり、ダウングレード（バージョンダウン）しようとするとインストールが阻止されます。だから一般的に、前のバージョンに戻すには一度アンインストールすることになります。ダウングレード・インストールするにはアプリ側がダウングレードに対応している必要があります[^3]。例えば、新しいバージョンのデータを古いバージョンのソフトウェアで読み込めるのか、といったことを気にする必要があります。また、インストー後にソフトウェアが作ったファイルがコンピューターに残っていると、正常に動作できないことがあるかもしれません。新しいバージョンのデータファイルは、古いバージョンにとっては未知のファイルで、エラーを引き起こすものかもしれないのです。

実際にメジャー・アップグレードの関係にあるインストーラーでダウングレード許可するとわかりますが、ダウングレード後に一部のファイルが消える[^4]、などの怪現象が起きます。マイナー・アップグレードの関係にあるインストーラーなら、REINSTALLMODEプロパティの指定で正しく動くようになるかもしれませんが、もはやWindows Installerのダウングレードの仕組みに頼るのはバクチに近いと感じます。もし、どうしてもダウングレード・インストールする必要に迫られたら、セットアップランチャーからMSI形式のインストーラーを呼び出すように構成し、セットアップランチャーがダウングレードすることを検出したら、まずアンインストール。その後にインストールする、といったように、一度にインストール処理を進めない構成が望ましいと思います。

[**前の記事へ**](https://qiita.com/tohshima/items/2dfa841cbab3d8488641)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/0a197917042d705e5568)

[^1]: Visual Studio向けWiX Toolset拡張機能を導入すると、「新しいプロジェクト」ダイアログにWiXのテンプレートが追加されます。このテンプレートで新規にSetup Projectを作成すると、ProductエレメントのVersion属性に"1.0.0.0"が入っているんです。アップグレード版のインストーラーを作成する際に、"1.0.0.1"とか入れても正常に動作しないし、ミスの元になりますよね。私は必ず、"1.0.0"の様に番号を3つに減らして使っています。ただ、リスクを承知で、きちんと管理できるのなら4つ目のフィールドにビルド番号を入れるのもアリかな、とも思います。ソフトウェアの開発期間中に何度もインストーラーを作り直すことはよくあることです。これらのインストーラーをビルド番号で区別すれば、間違ったインストーラーを使ってしまうミスを防ぐこともできます。
[^2]: 以前、メジャー・アップグレードするとフォントファイルが消える、という問題が起きたことがあります。どうやらWindows Installerがフォントのバージョンをうまく取得できていなかったようで、原因究明と対応にかなり時間がかかりました。このとき、マイナーアップグレードなら問題なかったので、時間があるならいつでもマイナーアップグレード版を出せる準備をしておくのも良いのではないかと思います。
[^3]: こんな要求はめったにあることではなく、私自身ダウングレード・インストールできる製品は作ったことがありません。
[^4]: 私が試したところでは、バージョンリソースを持つ.exeファイルが消えてしまいました。そのあと、コントロールパネルの「プログラムと機能」で「修復」を実行すると正しくインストールされました。