Windows Installer手引書 Part.11 シーケンス

[**前の記事へ**](https://qiita.com/tohshima/items/8175f25187b1a6183487)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/1be9c0673b91dfae60ff)

## シーケンスとは

シーケンスには、どういったインストール処理をどのような順番で実行するか、が書かれています。シーケンスに書かれた処理一つ一つを「アクション」と呼びます。シーケンスには「暗黙の処理」というものはなく、MSIファイルに書かれたアクションを順々に実行していきます。インストールに絶対必要なアクションがあったり、アクションを実行する順番にもルールがあったりするので、シーケンスを組み直すことは難かしいことですが、自分で作成した「カスタムアクション」を挿入することは普通に行われます。インストーラー作成者が作る「カスタムアクション」に対して、Windows Installerが最初から用意しているアクションを「標準アクション」と呼びます。

[Windows Installerのシーケンスは3種類](https://docs.microsoft.com/en-us/windows/win32/msi/using-a-sequence-table)あります。

- Simple Installation
- Administrative Installation
- Advertisement Installation

が、全てを覚える必要はありません。普段使うのは、`Simple Installation`だけです。このシーケンスに対応したテーブルは下記の2つです。この2つのテーブルが使いこなせれば、ほとんどのケースに対応できるはずです。

- InstallExecuteSequence
- InstallUISequence

普段インストーラー作成者がインストールに必要な標準アクションを選び、どの標準アクションをどんな順番で並べるか考えることはほとんどありません。それは、WiX ToolsetやInstall Shieldなどのインストーラー作成ツールがアクションを選んでテーブルに並べてくれるからです。では、なぜシーケンスを学ぶ必要があるかというと、カスタムするためです。Windows Installerが標準で用意していない機能が必要になるなど、シーケンスにアクションを追加するケースは結構あります。

## WiX Toolsetとシーケンス

WiX ToolsetのVisual Studio向けのプロジェクトのテンプレートを使ったとき、ビルドしたMSIファイルをOrcaで見ると`InstallExecuteSequence`は下記のようになっています。この表のSequence列の数字[^2]を昇順に、アクション[^1]を実行していきます。
![defaultExecSeq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83170/6df37c2f-c2a0-4142-76e4-6784534e50b4.png)
カスタムアクションを作るときは、これを見てどこにアクションを追加するか検討することになります。
また、初期状態では、`InstallUISequence`は下記のようになっています。
![defaultUISeq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83170/769ecf00-f6f7-cb23-2054-ca45449b4350.png)
WiX Toolsetでは、特にUIを記述しなくても、最低限の動作が定義されていることが分かります。さらに、`WixUIExtension`を使ってUIを記述すると、下記のように`InstallUISequence`も項目が増えます。
![WixUI_Mondo_UISeq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83170/e4159dff-24b5-37eb-0eb5-502df785c7ad.png)
このケースでもSequence列の数字順にアクションを実行していきますが、Sequence列がマイナスのアクションは、インストールの処理結果を反映して、一番最後にどれか一つが選ばれて実行されます。

## アクションの実行条件

インストーラーの処理は、インストール、アンインストール、変更、修復、アップグレードと何種類か異なる動作をしますが、すべて同じシーケンスを使います。インストーラー実行時に渡されてくるプロパティを使って、どの種類のインストールを実行したか判断し、どのアクションを実行するかプロパティで条件付けすることで、異なる動作を実現します。

例えば、前述のUIを記述したときの`InstallUISequence`を見ると、`Condition`列に条件式が書かれているアクション（`WelcomeDlg`、`MaintenanceWelcomeDlg`、`ResumeDlg`）があります。ここでは、一番最初にどのダイアログをユーザーに見せるか、`Condition`列の条件式で切り替えているのです。

## インストールウィザードのダイアログの処理

UIを記述したときの`InstallUISequence`を見て、インストール実行時に表示される全てのダイアログが定義されていないことに気付いたでしょうか。この例では、`Condition`列を評価することで
- WelcomeDlg
- MaintenanceWelcomeDlg
- ResumeDlg
のどれかが実行された後、ProgressDlgが表示されるまでの間のダイアログ処理は、`ControlEvent`テーブルに記述されます。このテーブルには、例えば[Next]ボタンを押したらどのような処理を行うか、といったUIに関わるイベント処理を記述します。各ダイアログの挙動をカスタムする場合は、シーケンスではなく`ControlEvent`に手を入れることになります。

## 実際のシーケンスの流れ

ここでは、実際にどのような順序でシーケンスやイベントが実行されていくか、見ていきます。下図は、`WixUIExtension`を使ってUIを記述したインストーラーを初めて実行したときのシーケンスとイベントの実行順を示しています。
![初回インストールのシーケンス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83170/a34cff46-67e4-9787-f9d0-4c170e5f6fd2.png)


- インストールを実行すると、`InstallUISequence`の`FindRelatedProduct`アクションから始まり、
- 初回インストールであることを示すConditionによって、`WelcomeDlg`アクションを実行
- `ControlEvent`テーブルに移り、[次へ]ボタンやSetupTypeを選択するボタンを押すことでウィザードを進め、
- `VerifyReadyDlg`で[Install]ボタンを押すことで`InstallUISequence`に戻り、`ProgressDlg`アクションを実行
- UI上はProgress Dialgを表示したまま、ExecuteActionアクションを実行することで`InstallExecuteSqquence`に移行
- `InstallExecuteSequence`のアクションをSequenceの昇順に実行
- `InstallExecuteSequence`が終わると、その結果により`InstallUISequence`の`ExitDialog`、`UserExit`、`FatalError`のいずれかを実行

、といった順で実行されます。もちろんインストールウィザードで異なるボタンを押せば、異なるルートを辿ります。また、`InstallUISequence`と`InstallExecuteSequence`を比べると、同じ名前のアクションがあることが分かります。例えば、`FindRelatedProducts`アクションは[ドキュメント](https://docs.microsoft.com/en-us/windows/win32/msi/findrelatedproducts-action)を読めば分かるように、`InstallUISequence`で実行した場合は`InstallExecuteSequence`で実行されないようになっています。これはすなわち、Conditionに書かれた条件だけがアクションを実行するための条件ではない、ということを示しています。

メジャー・アップグレードの時は、初めてインストールした時と同じシーケンスを辿ります。メジャー・アップグレードは旧バージョンをアンインストール後、新バージョンをインストールする動作となります。旧バージョンのアンインストールは、`RemoveExistingProducts`アクションで行われます。UIの表示は実行中の新バージョンのMSIが表示しますが、`RemoveExistingProducts`アクションの中で一時的にインストール済み旧バージョンのMSI内のInstallExecuteSequenceに移行します。[ドキュメント](https://docs.microsoft.com/en-us/windows/win32/msi/removeexistingproducts-action)には「製品を初めてインストールするときにのみRemoveExistingProductsアクションを実行します。」とあるので誤解しそうですが、メジャー・アップグレードでは実行されます。なぜなら、メジャー・アップグレードは旧バージョンとは異なる製品コードを使うため、Windows Installerから見ると「別製品」となり、新バージョンをインストールすることは「初めてインストールする」ことに相当するからです。

[**前の記事へ**](https://qiita.com/tohshima/items/8175f25187b1a6183487)　　[**目次へ**](https://qiita.com/tohshima/items/dc4c4721d50a2ad70c7a)　　[**次の記事へ**](https://qiita.com/tohshima/items/1be9c0673b91dfae60ff)

[^1]: 各アクションがどのような機能を持っているかは、[Standard Actions Reference](https://docs.microsoft.com/en-us/windows/win32/msi/standard-actions-reference)で知ることができます。
[^2]: Sequenseで使われる数字は飛び飛びの値になっていますが、数字が飛んでいるところに暗黙的に実行されるアクションがあるわけではありません。Orca等でMSIに直接シーケンスを挿入することを想定して飛び飛びの値になっていると思われます。この値は、WiX Toolset等のインストーラー作成ツールを使う限りは意識する必要はありません。