Component
Key PathとComponentに所属するファイルの関係
Windows Installerで特別なことをせずインストールできるものは、
- ファイル
- レジストリ
- ショートカット
の3つで、これらはComponentに定義します。ここではファイルのインストールについて解説します。1つのComponentには1つのDirectoryしか設定できないので、必然的にインストール先フォルダの数以上のComponentが必要になります。
下図のように4つのファイルをインストールしたいとしましょう。
ファイルが置かれたフォルダは「Product1」と「Data」の2つですので、Componentも2つで事足ります。実際、素直にComponent2つでインストーラーを構成しても希望の通りにファイルを配置するインストーラーを作成できます。しかし、ここでは「Product.exe」と「Product.dll」を別のComponentに分割するべきなのです。ファイルをどのようにComponentに分割するべきかは、MSDN Libraryの下記のページに説明があります。
Defining Installer Components - Microsoft Docs
では、なぜ".exe"ファイルと".dll"ファイルを別のComponentでインストールする必要があるのでしょうか。それは、ソフトウェアのバージョンアップと関係があります。すでに古いバージョンのソフトウェアがインストールされている環境で、バージョンアップ版のインストーラーを起動するケースを考えてみましょう。Componentでは、属するファイル(またはレジストリ)のうち1つだけKey Pathという指定をする必要があります。アップグレードインストールとなった場合、Windows InstallerはComponentに属するKey Pathの新旧を比較し、新しくなる場合に限ってComponent全体をインストールします。これは、Key Pathに指定されなかったファイルは、例え新しくなっても差し替えられない可能性がある、ということを示しています。例えば上記の例で、「Product.exe」と「Product.dll」を1つのComponentに所属させ、「Product.exe」をKey Pathに指定したとします。この仕組みでは、バージョンアップ版のインストーラーで「Product.dll」だけが新しくなった場合、このファイルが置き換わらないことになってしまいます。特に、".exe"ファイルや".dll"ファイルはプログラムコードを含むため、別々にバージョンアップする可能性もあり、特別にComponentを分離するよう注意が促されていますが、Windows Installerは拡張子を判別してファイルの新旧比較をしているわけではありません。".exe"ファイルや".dll"ファイル以外でも、個別にファイルがバージョンアップされる可能性があるならComponentを分離してKet Pathに指定するべきです。また、スタートメニューやデスクトップ等にショートカットを置く場合は、1つのComponentには1つのショートカットしか所属できないという制約にも注意が必要です。面倒を避けたいなら、1つのComponentには1つのファイルしか所属させないのも悪くない手です。その代わり、Componentがファイルの数だけ存在することになるのでWiXのソース行数が多くなり、インストールするファイル数が多くなると段々ソースの見通しが悪くなってきます。これに備えて最初からソースの書き方を工夫したり、ソースファイルを分割するなどの工夫をすると良いでしょう。上記の例ではファイルが4つあるのでComponentも4つ作成する、というのが将来最も困ることがない方法であると言えます。
Componentの設計に失敗したら
思いもしないことが発生するのがソフトウェア開発です。特にチームで開発していると、よく理解せずに設計されたソースをメンテナンスする必要に迫られることがあります。前節の懸念の通りに、Key Pathに指定しなかったファイルを更新するアップグレード版インストーラーを作成する必要があったらどうすればよいのでしょうか。このようなときは理想的なComponentに再設計し直し、以前のインストーラーからメジャーアップグレードするインストーラーを構成すれば解決します。ここで言う「メジャーアップグレード」とはWindows Installerで特別な意味を持った用語であり、バージョン番号が大きく上がったことを示すものではありません。主に一般ユーザーに使ってもらうアップグレード版のインストーラーで使われる形式には「メジャーアップグレード」と「マイナーアップグレード」があります。他にも「スモールアップデート」や「パッチ」などの形式がありますが、最初の2つを覚えておけば困ることはないはずです。メジャーアップグレードすると、インストール済みの旧バージョンをアンインストールしたあと新バージョンをインストールする、という動作になります。そのため、古い設計のインストーラーを全部ご破算にして、新しい設計のインストーラーに差し替えることが可能になります。アップグレードに関しては、別の機会に説明したいと思います。
設計チェック
設計時の注意事項をまとめます。例えばインストーラーの機能を確認する目的など、使い捨ての1回きりのインストーラーなら従う必要はありません。
- ComponentエレメントのId属性
WiXの仕様上、Componentエレメントに1つも属性がなくてもコンパイルができます。しかし、Id属性は指定するべきです。Windows Installerは、ComponentのIdとGUIDでComponentを管理しています。仮にId属性を指定しなかった場合はWiXのコンパイラが勝手にIdを設定しますが、これは何か設計を変えるとIdが変わってしまうことを意味します。Componentの互換性が失われると、将来アップグレード版を作成する際、問題が起きるかもしれません。ComponentのIdとGUIDは、異なるインストーラー間で同じファイルやレジストリを共有する際にも使用します。また、Featureエレメントを構成する際にも、ComponentのIdを利用することがある(他にComponentGroupエレメントのIdを利用する方法もあります)ので、トラブル時に採れる手段が増えます。
- ComponentエレメントのGUID属性
上記の通り、Windows InstallerがComponentを適切に管理するためにGUID属性も指定するべきです。GUID属性を指定しなかった場合は、コンパイル時に毎回新しいGUIDが割り当てられます。GUID属性を指定しなかった時点で、そのComponentはコントロール不能になっています。
- Key Path
Component内のFileまたはRegistryのどれか一つを必ずKey Pathに指定します。ComponentにKey Pathがない場合、WiXのコンパイラは何もしません。Warninngすら出さないのでチェックが漏れがちになり、注意が必要です。Windows InstallerはComponentにKey Pathがないとき、Componentに指定したDirectoryをKey Pathとして使用します。これもアップグレードインストールを正常に実行する妨げとなります。
- 他のインストーラーからソースを流用してきたら
ComponentのIdとGUIDを変更することを忘れないでください。流用元のインストーラーと流用先のインストーラーを1つのPCで利用できなくなります。基本的に流用の際にはソース上のGUIDを全て変更する必要があります。特に複数のバージョンを1つのPCに共存できるようにアップグレード版を構成するとき、変更を忘れがちです。また、複数の製品から同一の場所にある同一のファイルを利用する場合、両製品で同じ仕様のComponentを利用する必要があります。この場合はIdとGUIDを変えてはいけません。管理が悪いと間違えやすいので、このような共有ファイルがある場合は、同一のソースやコンパイル済みのオブジェクトコードを利用するよう工夫するべきです。
- FileエレメントのName属性は不要
FileエレメントのSource属性にはファイル名を含めることができるので、2重に指定する可能性があり危険です。うっかりName属性にSource属性のファイルと違う名前を設定すると、インストール時にName属性のファイル名に変更されます。簡単にミスを発見できないことがあるので、Name属性は使うべきでないと思います。File ElementのName属性の説明を読むと分かるように、過去のWiXとの互換性のためなのか挙動が複雑です。ここに登場する"ShortName"と"LongName"について説明します。"ShortName"は、ファイル名・フォルダ名の名前部分が8文字、拡張子部分が3文字の形式で、かつてMS-DOSの時代に使われていた形式です。現代のWindowsでは、"ShortName"形式の制限を超えるファイル名を使用すると勝手に"ShortName"形式のファイル名も生成します。コマンドプロンプトで
dir /X ¥
を実行したときに表示されるPROGRA~1
等が自動生成された"ShortName"です。他のファイル名と重複すると数字の部分が増えていきます。Windows Installerが"LongName"と"ShortName"を区別して扱えるようにしているのは、"LongName"が扱えないシステムへインストールするケースに対応するためだと考えられます。もはやこの時代に気にする必要もないでしょう。