iPX社員によるブログ

iPX社員が"社の動向"から"自身の知見や趣味"、"セミナーなどのおすすめ情報"に至るまで幅広い話題を投下していくブログ。社の雰囲気を感じ取っていただけたら幸いです。

Windows アプリケーションの展開方法を学ぼう(前編)

半年ぶりとなりました。最近は Microsoft から続々と発表される新デバイスにワクワクしっぱなしのコクブンです。 HoloLensSurface Dial も非常に楽しみです。 ^^
さて今回は、最近私の中でホットだった Windows アプリケーションのインストーラのお話しを書きたいと思います。

そもそもなぜインストーラが必要か

皆さん、アプリケーションを自作した際にそのアプリケーションを配布するにはどの様な方法を使っていますでしょうか。

実際には結構 4 番目が多いのかもしれません。
しかし、 4 番目の方法は手軽である反面、

  • インストール(展開)されているかどうかの管理がしにくい
    • バージョンアップやアンインストールの際の手間にもつながります
  • アプリケーションが操作可能でない場所(フォルダ)に展開されてしまう可能性がある
    • アプリケーションの機能によっては正しく動作しない可能性も出る

等、アプリケーションにとって致命的になり得る問題が多く潜んでいます。
特に業務アプリケーションに於いては、こうした潜在的な問題を排除する事は非常に重要な事であり、そのためにはやはり(多少開発コストは上がるとしても)展開用のインストーラを用意することが重要になると思われます。

Windows アプリケーションのインストーラ

では実際にインストーラを用意するとして、どうやって作ればよいでしょうか。
もちろん、インストーラをひとつのアプリケーションとして全て自前で作成する事も可能だと思いますが、 Windows 上のアプリケーションのインストール(メンテナンス)を行うエンジンとして Windows IntallerMicrosoft から提供されているので、通常はこのエンジンを利用してインストーラを作成します。
とはいえ、このエンジンを使ったとしても、やはりインストーラを自作するのはそれ相応の労力を要してしまいます。
そこで、もっと簡易にインストーラを作成するためのヘルパー製品として、 InstallShield の様なインストーラ開発ソフトが各メーカーから販売されています。
しかし、 InstallShield 等の製品ではどうしてもそれらの製品の制約に縛られてしまうため、ある種画一的なインストーラになりがちな面もあります。
社内向けツール等の局所的な配布範囲が限られるケースでは大きな問題になる事は少ないないかもしれませんが、一般提供するアプリケーション等の場合は、やはりある程度の差別化を図りたい局面もあると思われます。
そうした「インストーラを自作する程の労力はかけたくないけど少しはカスタマイズしたインストーラを作成したい」要求を満たす手段の一つとして、今回挙げる WiX (Windows Installer XML) Toolset があります。

WiX Toolset とは

f:id:ipx-writer:20161129004750p:plain:w480
WiX Toolset は、 XML ドキュメントから Windows Installer パッケージ*2を作成するためのソフトウェアツールセットで、 Microsoft Reciprocal License (Ms-RL) の下で公開されています。
元々 Microsoft によって開発され、 Outercurve Foundation ( Microsoft が設立した NGO非営利団体) の手を経て現在は .NET Foundation によってメンテナンスが行われています。

開発環境の構築

WiX Toolset によるインストーラの開発を行う際は、以下の環境が必要となります。

なお、本記事では開発環境に Visual Studio 2015 (VS2015) を使用していますが、 Visual Studio のインストールに関しては割愛します。必要に応じてインストールを行っておいてください。*3

Windows SDK のインストール

Windows SDK は VS2015 がインストールされている環境であれば既に導入済になっています。
VS2015 がインストールされていない環境では、 Windows Developer Center からお使いの環境の Windows SDK を入手してインストールしてください。

.NET Framework のインストール

こちらも VS2015 がインストールされている環境であれば導入済と思われますが、インストールされていない場合は「 Windows の機能の有効化または無効化」から「 .NET Framework 3.5 ( .NET 2.0 および 3.0 を含む)」を有効化してください。
f:id:ipx-writer:20161129004631p:plain:w380

WiX Toolset のインストール

WiX Toolset の公式ページからダウンロードしてインストールしてください。
基本的には最新バージョンの利用をお勧めします。(本記事執筆時は v3.10.3 )

WiXVisual Studio 拡張機能について

VS2015 がインストールされている環境に WiX Toolset をインストールすると、 Visual Studio拡張機能が一緒にインストールされます。
もし、 WiX Toolset のインストール後に VS2015 のインストールを行った場合は、 WiX Toolset のインストーラを再度起動して「 Repair 」を実行する事で VS2015 の拡張機能が追加インストールされます。
f:id:ipx-writer:20161129005231p:plain:w300

インストーラプロジェクト (Visual Studio)

さて、 WiX Toolset のインストールが完了したら、早速インストーラプロジェクトを作成してみます。
VS2015 の「新しいプロジェクト」に「 Windows Installer XML 」テンプレートが追加されているので、この中から「 Setup Project 」を選択してプロジェクトを新規作成します。
f:id:ipx-writer:20161129005334p:plain:w480
f:id:ipx-writer:20161129005432p:plain:w280
このプロジェクトをビルドすると、インストーラ (*.msi) ファイルが作成されます。*4
ここから必要な設定を追加して、実際のインストーラを作成していく事になります。

プロジェクトの設定

まずは VS2015 でプロジェクトのプロパティを参照してみましょう。
f:id:ipx-writer:20161129005609p:plain:w480
f:id:ipx-writer:20161129005722p:plain:w480
「 Installer 」タブの「 Output name 」欄に、インストーラファイルの名称を設定する事ができます。(デフォルトはプロジェクト名)
「 Output type 」では、インストーラの種類を、

  • Windows Installer Package (.msi)
  • Merge Module (.msm)
  • WiX Library (.wixlib)
  • Execute Package (.exe)

から選択する事ができます。
通常のインストーラであれば一番上 (Windows Installer Package) を選択しておけば問題ありません。(本記事では Windows Installer Package 以外は基本的に扱いません)
また、「 Tool Settings 」タブでは WiXコンパイラに指定するオプション等を設定する事ができます。
詳細は割愛しますが、必要な場合はここで設定してください。

プロジェクトに含まれるファイル

ソリューションには 1 つの設定ファイル (Product.wxs) が含まれています。
このファイルにインストールに必要な情報を記載していく事になります。*5

最小のインストーラ

まずは、単純に 1 つの実行ファイル (*.exe) を Program Files (x86) 配下に展開するインストーラの設定を見てみましょう。

  • Product.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" Name="SampleSetup" Language="1041" Version="1.0.0.0" Manufacturer="iPX" Codepage="932">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" SummaryCodepage="932" />
    <Media Id="1" Cabinet="SampleSetup.cab" EmbedCab="yes" />
    <Feature Id="ProductFeature" Title="SampleSetup" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>
  </Product>
  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="ProductFolder" Name="iPX">
          <Directory Id="INSTALLFOLDER" Name="SampleApp" />
        </Directory>
      </Directory>
    </Directory>
  </Fragment>
  <Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <Component Id="ApplicationExeComponent" Guid="{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}">
        <File Id="ApplicationExeFile" Name="SampleApplication.exe" Source="SampleApplication.exe"/>
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

非常にシンプルな内容ですが、最小のインストーラとしてはこれだけで十分機能します。*6
これを作成した Product.wxs にコピーしてビルドする( File タグの Source は実際に展開する実行ファイルが保存されているパスに書き換えてください)と、「 SampleSetup.msi 」が作成されます。
その「 SampleSetup.msi 」を実行すると、(権限昇格ダイアログが表示された後)「 Program Files (x86)\iPX\SampleApp\ 」の下に SampleApplication.exe ファイルが配置されます。

インストーラがやってくれる事

上記インストーラは「 1 つのファイルを展開する」ものですが、実際には以下の機能も有しています。

  • システム管理フォルダ (Program Files) に展開するための管理者権限昇格機能*7
  • 「プログラムと機能」へのアプリケーションの登録
  • アプリケーションのアンインストール機能

※なお、この最小サンプルは、インストールとアンインストールは行えますがアップデートに対応できていません。アップデートへの対応については後述します。
では、上記設定ファイルの中身をひとつずつ見ていきましょう。
※各タグの属性については上記サンプルで省略しているものも含めて紹介しています。

インストーラの設定情報

インストーラの設定は Product, Package, Media 等のタグで記述します。

  • Product タグ

※ CodePage 以外の属性は全て必須指定項目です。

属性名 設定する値
Id アプリケーション(製品)を識別する GUID を指定します。
CodePage インストーラの内部データのコードページを指定します。
Language に英語以外を指定した場合は必ず指定します。
(日本語の場合は "932" )
Language インストーラの対応言語を指定します。
(日本語の場合は "1041" となります)
Manufacturer 開発元を指定します。
Name 「アプリと機能」に表示される製品の名称を指定します。
UpgradeCode 製品のグループを識別するための GUID を指定します。
※ UpgradeCode についてはアップデートへの対応の項で解説します。
Version 製品のバージョンを指定します。
"Major.Minor.Build" の 3 つの数値で構成されます。
  • Package タグ

※ Id 以外の属性は任意指定項目です。

属性名 設定する値
AdminImage インストールイメージが admin の場合は "yes" を指定します。
Comments インストーラのオプションコメントを指定します。
Compressed 格納ファイルを圧縮するかどうかを指定します。
圧縮する場合は "yes" 、圧縮しない場合は "no" を指定します。
省略した場合は "no" となります。
各ファイルレベルで個別に指定された場合はそちらの設定が優先されます。
Description インストーラの概要を指定します。
Id インストーラファイルを識別する GUID を指定します。
必須項目ですが記載を省略する事でビルド時に自動的に付与する事が可能です。
InstallerVersion インストーラの実行に必要なランタイムのバージョンを指定します。
9x 系や NT4.x 系をサポートする場合は "200"を指定します。
但し、 2000 や XP 以降を対象する場合でも通常は "200" を指定して問題ありません。
InstallPrivileges Windows Vista 以降の UAC 昇格の設定を指定します。
昇格が必要な場合は "elevated" 、昇格しない場合は "limited" を指定します。
InstallScope インストールするスコープを指定します。
すべてのユーザーに対してインストールを行う場合は "perMachine" 、インストール実行ユーザに限定してインストールを行う場合は "perUser" を指定します。
Keywords インストーラの検索キーワードを指定します。
Languages サマリーの言語を指定します。
Manufacturer サマリーの開発元を指定します。
通常は Product の Manufacturer と同じ値を指定します。
Platform インストール対象のプラットフォームを "x86", "ia64", "x64", "arm" の中から指定します。
ReadOnly インストールパッケージを読み取り専用で開く場合は "yes" を指定します。
ShortNames ソースにショートネームを使用する場合は "yes" を指定します。
SummaryCodepage サマリーのコードページを指定します。
  • Media タグ

※インストールメディアを複数に分ける(サイズ分割、グループ分け等)の場合は、ひとつのインストーラファイルに対して複数の Media タグを記述する事になります。
※ Id 以外の属性は任意指定項目です。

属性名 設定する値
Id "1" から順にメディアの ID を指定します。
Cabinet 圧縮する場合の圧縮ファイルの名称を指定します。
圧縮する場合は必ず指定します。
CompressionLevel 圧縮する場合の圧縮レベルを "high", "low", "medium", "mszip", "none" の中から指定します。
省略した場合は "mszip" となります。
DiskPrompt CD や DVD 等のメディアで配布を行う際のメディア表示名を指定します。
EmbedCab に "yes" を指定した場合は DiskPrompt に指定された値は無視されます。
Layout 圧縮を行わない場合のインストール用ファイルの出力先ディレクトリを指定します。
相対パスが指定された場合、インストーラファイルの出力先をルートとした相対パスとして出力されます。
Source 圧縮ファイルをインストーラファイルに埋め込まない場合の圧縮ファイルが配置されているパスを指定します。
空の場合はインストール先のルートとなります。
EmbedCab 圧縮ファイルをインストーラファイルに埋め込むかどうかを指定します。
埋め込む場合は "yes" 、埋め込まない場合は "no" を指定します。
VolumeLabel CD や DVD 等のメディアで配布を行う際のメディアのボリュームラベルを指定します。
EmbedCab に "yes" を指定した場合は VolumeLabel に指定された値は無視されます。
インストール手順の設定

インストールの手順に係る情報は Feature タグで記述します。
Feature はインストールの種類(グループ)単位に作成します。

  • Feature タグ

※ Id 属性と Level 属性は必須指定項目です。

属性名 設定する値
Id Feature の識別子を指定します。
識別子として任意の文字列を指定可能ですがインストーラの中で一意となる値を指定する必要があります。
Absent Feature を無効に出来るかどうかを、 "allow" (無効化可能) , "disallow" (無効化不可) の中から指定します。
この指定はカスタムインストール以外の場合でも適用されます。
AllowAdvertise アドバタイズインストールをサポートするかどうかを "yes" (サポートする) , "no" (サポートしない) , "system" ( OS シェルに依存) の中から指定します。
ConfigurableDirectory インストール先の変更を行う際のターゲットとなるディレクトリエントリ ID を指定します。
Description カスタムインストール時に表示される説明文を指定します。
カスタムインストールをしないのであれば省略可能です。
Display カスタムインストール時のツリー上の表示方法を、 "collapse" (閉じた状態で表示) , "expand" (展開された状態で表示) , "hidden" (非表示) の中から指定します。
省略された場合は "collapse" となります。
InstallDefault デフォルトのインストール・実行条件を、 "source" (ソースから実行) , "local" (ローカルにインストール) , "followParent" (上位の Feature の設定に従う) の中から指定します。
Level デフォルトインストールのレベルを指定します。
必ずインストールされるものは "1" を指定します。
"0" を指定するとインストール対象から除外されます。
Title カスタムインストール時にツリーに表示される名称を指定します。
カスタムインストールをしないのであれば省略可能です。
TypicalDefault デフォルトのアドバタイズ状態を "install" (アドバタイズなし) , "advertise" (アドバタイズ)の中から指定します。
AllowAdvertise に "no" を指定した場合は TypicalDefault に "advertise" を指定することはできません。
  • Fragment タグ

インストーラの追加情報は Fragment タグで記述します。
※このサンプルにある Fragment の内容は Product タグの中に直接記述することも可能です。
※ Fragment タグの属性は任意指定項目です。

属性名 設定する値
Id Fragment の識別子を指定します。
インストールするファイルの設定

インストール先のディレクトリ階層の情報は Directory タグで記述します。
ディレクトリの情報はルートディレクトリからの階層構造で表現します。
展開するコンポーネント情報は Component タグで記述します。 Component は Component タグによってグループ化する事が出来ます。
実際に展開するファイルの情報は File タグで記述します。

  • Directory タグ

※ Id 属性は必須指定項目です。

属性名 設定する値
Id ディレクトリエントリの識別子を指定します。
識別子として任意の文字列を指定可能ですがインストーラの中で一意となる値を指定する必要があります。
ComponentGuidGenerationSeed Program Files 等の標準ディレクトリ以外に展開する場合に設定される GUID を指定します。
DiskId 対象ディレクトリ下のファイルが格納されているディスクの識別子を指定します。
FileSource 対象ディレクトリ下にファイルシステム上のソースを配置する際に使用します。
Name インストール先のディレクトリ名を指定します。
上位の Directory と同一階層のディレクトリを表す場合は、 Name 属性を指定しないでください。
ShortName インストール先のディレクトリ名を 8.3 形式で指定します。
Name 属性が 8.3 形式で収まる場合や Windows によって自動生成される 8.3 形式名で競合しない場合は指定する必要はありません。
ShortSourceName ソースメディア上のディレクトリ名を 8.3 形式で指定します。
SourceName 属性が 8.3 形式で収まる場合や Windows によって自動生成される 8.3 形式名で競合しない場合は指定する必要はありません。
ShourceName ソースメディア上のディレクトリ名を指定します。
省略された場合は Name 属性と同一の値を指定されているものとします。
  • ComponentGroup タグ

※ Id 属性は必須指定項目です。

属性名 設定する値
Id コンポーネントグループの識別子を指定します。
識別子として任意の文字列を指定可能ですがインストーラの中で一意となる値を指定する必要があります。
Directory グループ化するコンポーネントの展開先のディレクトリ識別子を指定します。
Source ファイルシステム上のソースを配置する際に使用します。
  • Component タグ

※ Component タグの属性は任意指定項目です。

属性名 設定する値
ComPlusFlags COM+ エントリーを作成するために使用します。
インストーラファイルの生成で使用される export フラグを指定します。
Directory コンポーネントを展開するディレクトリの識別子を指定します。
DisableRegistryReflection コンポーネントの展開によって影響を受けるすべての(既存・新規とも)レジストリキーに対するレジストリへの反映を抑制する場合は "yes" を指定します。
この設定は Windows Installer 4.0 以降でのみ有効です。
32 bit システムでは無視されます。
DiskId コンポーネント内のファイルが格納されているディスクの識別子を指定します。
Feature コンポーネントが属する Feature の識別子を指定します。
Component は複数の Feature に属する事が出来ますが、この属性は単一の Feature のみを指定可能なことに注意が必要です。
Guid コンポーネントを一意に識別する GUID を指定します。
省略した場合は WiX (リンカ)によって自動生成された GUID が設定されますが、アップデートの管理が不可能になるため基本的には必ず指定することが推奨されます。
Id コンポーネントの識別子を指定します。
識別子として任意の文字列を指定可能ですがインストーラの中で一意となる値を指定する必要があります。
KeyPath コンポーネントディレクトリをキーパスに設定する場合は "yes" を指定します。
ファイルやレジストリ値をキーパスに設定する場合は Component 下の子要素( File 等)に対して KeyPath 属性を設定します。
Location コンポーネントが実行される環境を "local" (ソースやネットワークからの実行不可) , "source" (ソースからのみ、ユーザのコンピュータからの実行不可) , "either" (ソース or ローカルから実行)の中から指定します。
既定値は "local" です。
MultiInstance インスタンス毎に異なる GUID を設定する場合は "yes" を指定します。
マルチインスタンスコンポーネントに含まれるすべてのリソースは、インスタンスの設定に基づいて異なるパスにインストールする必要があります。
NeverOverwrite コンポーネントのキーパスファイルまたはキーパスレジストリエントリが既に存在している際にコンポーネントのインストールを抑制する場合は "yes" を指定します。
Parmanent アンインストール実行時に対象のコンポーネントを削除しない場合は "yes" を指定します。
Parmanent に "yes" を指定した場合でも対象のコンポーネントのアップデートを行うことは可能です。
Shared 複数の Product で共有するコンポーネントに対しての高度なパッチ適用を行う場合は "yes" を指定します。
この設定は Windows Installer 4.5 以降でのみ有効です。
SharedDllRefCount 対象のコンポーネントとして展開されるファイルの共有 DLL レジストリー参照カウントを +1 します。
Transitive 再インストール時にインストール条件のステートメントを再評価する場合は "yes" を指定します。
Transitive に "yes" が設定されている場合、前回のインストール時にインストール対象であったコンポーネントが再インストール時にインストール対象外になっていると、該当のコンポーネントが他の Product で使用されている場合でもインストーラによって削除されます。
UninstallWhenSuperseded パッチによって置き換えが発生した際にコンポーネントのアンインストールを行う場合は "yes" を指定します。
この設定は Windows Installer 4.5 以降でのみ有効です。
Win64 コンポーネントを 64bit としてマークする場合は "yes" を指定します。
既定値は InstallPlatform の指定に従います。
  • File タグ

※ File タグの属性は任意指定項目です。

属性名 設定する値
Assembly ファイルが Global Assembly Cache (GAC) へのインストールが必要な .NET Framework アセンブリもしくは Win32 アセンブリであるかを指定します。
.NET Framework アセンブリの場合は ".net" 、 Win32 アセンブリの場合は "win32" 、それ以外のファイルの場合は "no" を指定します。
既定値は "no" です。
Assembly に ".net" か "win32" を指定する場合、対象のファイルはコンポーネントのキーパスである必要があります。
AssemblyApplication アプリケーションファイルのファイル識別子を指定します。
AssemblyApplication は Assembly に ".net" か "win32" が指定されている場合にのみ指定が可能です。
Assembly に ".net" か "win32" が指定されている場合でかつ AssemblyApplicaiton が省略されている場合、対象のアセンブリは GAC に登録されます。
AssemblyManifest 対象のアセンブリ向けのマニフェストファイルの識別子を指定します。
マニフェストファイルは対象のアセンブリと同一の Component 内に指定されているべきです。
AssemblyManifest は Assembly に ".net" か "win32" が指定されている場合にのみ指定が可能です。
BindPath インポートする DLL を検索するためのパスをセミコロンで区切ったリストで指定します。
Checksum ファイルが Portable Executable (PE) ファイルヘッダー中に保存された有効なチェックサム保有するインストールに於ける実行可能ファイルである場合は "yes" を指定します。
CompanionFile ファイルが別のファイルの子である場合は親となるファイルの識別子を指定します。
CompanionFile が指定された場合、対象のファイルのインストール状態は親となるファイルのバージョニングに依存します。
対象のファイルがキーパスに指定されている場合は CompanionFile を指定することはできません。
CompanionFile が指定されている場合は Version を指定することはできません。
Compressed ファイルを圧縮する場合は "yes" を指定します。
DefaultLanguage ファイルのデフォルト言語を指定します。
DefaultLanguage が指定されている場合、 WiX (リンカ)はファイルのデフォルト言語を指定された内容で置き換えます。
DefaultSize ファイルのデフォルトサイズを指定します。
DefaultSize が指定されている場合、 WiX (リンカ)はファイルのデフォルトサイズを指定された内容で置き換えます。
DefaultVersion ファイルのデフォルトバージョンを指定します。
DefaultVersion が指定されている場合、 WiX (リンカ)はファイルのデフォルトバージョンを指定された内容で置き換えます。
DiskId ファイルが格納されているディスクの識別子を指定します。
FontTitle ファイルを TrueType 以外のフォントとして登録する場合は Font テーブルに登録するタイトルを指定します。
Hidden 隠しファイルとして展開する場合は "yes" を指定します。
Id ファイルの識別子を指定します。
識別子として任意の文字列を指定可能ですがインストーラの中で一意となる値を指定する必要があります。
省略した場合、 Source のファイル名部分が設定されます。
KeyPath ファイルをキーパスに設定する場合は "yes" を指定します。
Name 展開するファイル名を指定します。
PatchAllowIgnoreOnError パッチが必須でない場合は "yes" を指定します。
PatchGroup パッチ毎に異なるグループ番号を指定します。
グループ番号は "0" より大きい必要があり、連続して割り当てる必要があります。
PatchGroup はパッチが追加されたファイルに対して設定する必要があります。
PatchIgnore 対象のファイルがパッチによってアップグレードされない様にする場合は "yes" を指定します。
PatchWholeFile バイナリパッチを作成せずにファイル全体をインストールする必要がある場合は "yes" を指定します。
ProcessorArchitecture アセンブリアーキテクチャを "msil" (プロセッサ非依存の .NET Framewrok アセンブリ) , "x86" ( x86 プロセッサ向けの .NET Framework アセンブリ) , "x64" ( x64 プロセッサ向けの .NET Framework アセンブリ) , "ia64" ( ia64 プロセッサ向けの .NET Framework アセンブリ) の中から指定します。の中から指定します。
ProcessorArchitecture は .NET Framework 2.0 以降のアセンブリにのみ指定可能です。
ReadOnly 読取専用として展開する場合は "yes" を指定します。
SelfRegCost ファイルを byte 単位で登録する際のコストを指定します。
ShortName 展開するファイル名を 8.3 形式で指定します。
Name 属性が 8.3 形式で収まる場合や Windows によって自動生成される 8.3 形式名で競合しない場合は指定する必要はありません。
Source インストーラをビルドする際に参照するファイルのパスを指定します。
ディレクトリと Name によってファイルのソース情報を取得できる場合は省略可能です。
System システムファイルとして展開する場合は "yes" を指定します。
TrueType ファイルを TrueType フォントとして登録する場合は "yes" を指定します。
Vital ファイルのインストールに失敗した際にインストール作業を停止させる場合は "yes" を指定します。
既定値は "yes" です。

アップデートへの対応

上記サンプルは先程も書いた通り、アップデートに対応していません。
アップデートができないとバージョンアップの度に「アンインストール→インストール」を繰り返す必要があってあまり意味がないですね。
では、上記サンプルをアップデートに対応してみたいと思います。

Windows Installer のバージョン管理

WiX でのアップデートの対応を見る前に、まずは Windows Intaller による更新(バージョンアップ)の仕組みについて見ておきます。
Windows Installer は、 4 つの製品識別情報 (ProductCode, ProductName, ProductVersion, PackageCode) 、製品更新管理情報 (UpgradeCode) と、 msi ファイル名の 6 つの要素で製品の管理を行っています。

ProductCode 製品の識別子として定義され、「インストールされているかどうか」の検出等、インストール製品の個体識別を行う際の識別子として使用されています。
ProductName 製品の表示名を一意で管理されます。
(他の製品との重複は問わない)
ProductVersion 製品のインストールバージョンとして管理されます。
通常はインストール対象の主製品と同じバージョンを用います。
ProductVersion は "Major.Minor.Build" の 3 つの数値で構成されます。
PackageCode msi ファイルの個体識別を行うためのパッケージファイル識別子として管理されます。
この値に変更がない場合は(例え中身が変更されていても)ファイルは一致するものとして扱われます。
UpgradeCode 特定の製品 1 つのライフサイクルを管理する際に使用されるアップグレード用の検索キーとして用意されているコードです。
この値が設定されている製品は将来アップグレードが可能になります。
更新計画が定かでないものでも、わずかでも更新の可能性がある限り設定しておくべきものとされています。
ファイル名 インストールする製品のパッケージファイルの参照(実体)に用いられる名称です。
ProductCode が一致する限り必ず同一のファイル名を用いなければなりません。
ファイル名は 8 文字以内の英数字(一部の記号を含む)で構成された文字列が望ましいとされています。
(但し、 8 文字以下の制限があるわけではありません)

上記項目のうち、 "xxxCode" となっている項目 (ProductCode, PackageCode, UpgradeCode) はいずれも GUID を識別子として利用しています。

バージョンアップの種類

Windows Installer ではアップデートの方法とその規模によっていくつかの構成が用意されています。
どの様なものがあるか、またそれぞれの構成に対応するために先の 6 項目の何を変更すればよいか(変更する必要があるか)を紹介しておきます。

  • アップデート規模による構成パターン
スモールアップデート (Small Updates)
MS アップデートでは QFE (Quick Fix Enginnering) と呼ばれるものに相当します。
修正内容自体が軽微(多数含まれるモジュールのうちの 1 つだけ等)な場合に利用されることがあります。
Windows Installer の項目では PackageCode のみを変更します。
マイナーアップグレード or マイナーアップデート (Minor Upgrades)
MS アップデートでは SP (Service Pack) と呼ばれていたものに相当します。
修正は多岐に渡るもののバグフィックス等が中心なものとなります。
Windows Installer の項目では PackageCode に加えて ProductVersion も変更します。(したがってバージョンが変わります)
メジャーアップグレード (Major Upgrades)
いわゆる「バージョンアップ」( Office 2013 → Office 2016 への更新等)に相当します。
Windows Installer の項目としては原則として UpgradeCode 以外のすべての項目を変更します。
  • アップデータの提供形式によるパターン
パッチ (Patching)
文字通り「修正をあてる (patching) 」ものであり、 msp の拡張子を持つ更新専用インストーラを提供するものです。
インストール済のものを更新するため、インストールされていない環境では動作できません。
(この記事では取り扱いません)
アップグレード (Upgrade)
msi 形式のインストーラを提供するものです。
通常のインストーラですが更新機能を提供することもできます。
WiX での設定項目

先の 6 項目を WiX の設定ファイルで指定する際は、それぞれ以下の項目で行います。

Windows Installer の管理項目 WiX の設定項目
ProductCode Product タグの Id 属性
ProductName Product タグの Name 属性
ProductVersion Product タグの Version 属性
PackageCode Package タグの Id 属性
UpgradeCode Product タグの UpgrageCode 属性
ファイル名 msi ファイル名
ファーストリリースでやっておく事

インストーラをバージョンアップ可能なものにするためには、最初のリリースの時点で「将来のバージョンアップへの対策」を施しておく必要があります。
具体的には以下の作業を行っておきます。

  • 上記 6 項目の設定
    • 各項目の規約に従って値を設定します
  • より新しいバージョンがインストールされている環境での動作抑制の設定
    • カスタムアクションを追加して、より新しいバージョンが見つかった場合はエラーメッセージを表示して処理を停止する様にします。*8
  • アップグレード情報の登録
    • Upgrade タグと UpgradeVersion タグを使用して初期リリースの情報を設定します。
<Product Id="{ProductCode(GUID)}" Name="SampleSetup" UpgradeCode="{UpgradeCode(GUID)}" ..>
  <CustomAction Id="DetectNewVer" Error="より新しいバージョンが既にインストールされているためインストールできません。" />
  <InstallExecuteSequence>
    ..
    <Custom Action="DetectNewVer" After="FindRelatedProducts">NEWPRODUCTFOUND AND NOT Installed</Custom>
    <RemoveExistingProducts Suppress="yes" />
  </InstallExecuteSequence>
  <Upgrade Id="{UpgradeCode(GUID)}">
    <UpgradeVersion Minimum="1.0.0" Property="NEWPRODUCTFOUND" OnlyDetect="yes" IncludeMinimum="yes" />
    <Property Id="NEWPRODUCTFOUND" Secure="yes" />
  </Upgrade>
</Product>
  • Upgrade タグ

UpgradeCode 単位のアップグレード情報を Upgrade タグで記述します。
※ Id 属性は必須指定項目です。

属性名 設定する値
Id 対象とする UpgradeCode を指定します。

通常、 ID 属性には Product タグの UpgradeCode に指定した GUID を指定しますが、他の Product の UpgradeCode を指定することも可能です。

  • UpgradeVersion タグ

バージョン毎の設定は UpgradeVersion タグで記述します。
※ Property 属性は必須指定項目です。

属性名 設定する値
ExcludeLanguages Language に指定した言語以外を対象とする場合は "yes" を指定します。
IgnoreRemoveFailure インストール済バージョンのアプリケーションまたは製品の削除に失敗した際でもインストールを続行する場合は "yes" を指定します。
IncludeMaximum 対象バージョン範囲に Maximum で指定したバージョンを含む(「以下」扱いにする)場合は "yes" を指定します。
IncludeMinimum 対象バージョン範囲に Minimum で指定したバージョンを含む(「以上」扱いにする)場合は "yes" を指定します。
Language 対象のインストーラ言語を限定する場合は LanguageCode をカンマ区切りで指定します。
すべての言語を対象とする場合は Language を指定しません。
ExcludeLangages に "yes" が設定された場合は指定された言語以外を対象とします。
Maximum 対象とするバージョンの上限を指定します。
MigrateFeatures 以前のインストール情報を踏襲する場合は "yes" を指定します。
Miminum 対象とするバージョンの下限を指定します。
OnlyDetect 対象バージョンの検出のみを行う場合は "yes" を指定します。
Property 検出した製品の ProductCode を格納するプロパティ名を指定します。
RemoveFeatures 削除対象機能の識別子をカンマ区切りのリストで指定します。
実際に削除される機能は実行時に決定されます。
バージョンアップ時に行う事

アプリケーションのバージョンアップを行う際は、「アップデート規模による構成パターン」と「 WiX での設定項目」に記載した通り WiX の各項目を更新する事になりますが、それに加えて該当バージョンに対する UpgradeVersion タグの追加、及び前バージョン向けの UpgradeVersion タグの修正が必要になります。

  • ver 1.0.0 (初回リリースバージョン)から ver 1.1.0 へのメジャーアップグレード時の設定
  <Upgrade Id="{UpgradeCode(GUID)}">
    <UpgradeVersion Minimum="1.0.0" Maximum="1.1.0" Property="OLDPRODUCTFOUND" IncludeMinimum="yes" /> <!-- 1.1.0 以前を「旧バージョン」として検出対象にする -->
    <UpgradeVersion Minimum="1.1.0" Property="NEWPRODUCTFOUND" OnlyDetect="yes" />             <!-- 1.1.0 を「最新バージョン」とする -->
    <Property Id="OLDPRODUCTFOUND" Secure="yes" />
    <Property Id="NEWPRODUCTFOUND" Secure="yes" />
  </Upgrade>

これで必要最小限のインストーラが作成出来る様になりました。
しかし、作成したインストーラを実行してみるとわかりますが、このインストーラだとインストール時に UI が表示されません。(インストール中を示す簡単なダイアログが 1 つ表示されるだけです)
実際のインストーラでは、インストールするモジュールを指定する、インストール先を変更する、使用許諾を表示する等、 UI が必要になってくることも多いと思います。
その辺りについては、後編でご紹介したいと思います。

» Windows アプリケーションの展開方法を学ぼう(後編)

*1:最近の Visual Studio には付属しなくなってしまったのでこのケースは減ったでしょうか。

*2:インストーラファイル (*.msi) だけでなくマージファイル (*.msm) やパッチファイル (*.msp) の作成も行う事が出来ます。

*3:WiX Toolset を使用したインストーラの作成には Visual Studio は必須ではありません(コマンドラインベースの開発も可能です)が、ツールによるサポートを享受出来るので Visual Studio の利用をお勧めします。 Visual Studio 2015 Community Edition でも開発可能です。

*4:プロジェクトテンプレートで展開されるものはスケルトンのため、インストーラ作成に必要な情報の一部が足りていません。そのため、展開した状態のままビルドしてもビルドエラーとなるので注意してください。

*5:インストールの手順が増えていくとファイルが複雑になる場合があります。この場合は、ファイルを分割して定義する事も可能です。(今回は割愛します)

*6:実際にする場合は Product@Id と Component@Guid にそれぞれ GUID を生成して設定してください。

*7:権限昇格の必要がない場合は権限昇格なしで作成する事も当然可能です。

*8:カスタムアクションについては後編の中で紹介する予定です。