最終更新日 2005/08/24


WiX Tips
▼WiXとは
▼SharpDevelop WiX
▼テンプレートの画面推移
▼MSI作成
▼あとがき



WiXとは
WiXとは「Windows Installer XML(WiX) toolset」の略です。
これは、Windowsインストールパッケージ(.msi)をXMLソースコードから 作成するためのツール群のことです。

このWiXは、Microsoftの社員が開発に携わり、しかもこのツールセットのソースコードをオープンソース化 したことで注目を集めています。
(同社初のオープンソースソフトウェアらしいです。ただし、よく聞くGPLではなく CPL(Common Public License)というライセンス形式なので注意が必要です。)

このWiX本体とソースコードは↓に公開されています。

SourceForge:WiX Project


WiXには5つのexeファイルがありますが、↓のような働きをします。

candle.exe : コンパイラ
light.exe  : リンカー
lit.exe   : ライブラリツール
dark.exe  : 逆コンパイラ
tallow.exe : (RCファイルからの)ダイアログ情報取得ツール

ただし、基本的にはcandle.exeとlight.exeとXMLファイル(拡張子は.wxs)によってMSIファイルを作成します。



▲このページのトップへ戻る

SharpDevelop WiX
WiXはXMLファイルからMSIファイルを作成するだけのツールなので、実際のXMLファイルは自力で 作成しなければなりません。
ただし、これを0から作るとなるとかなりの労力を必要としてしまいます。

SharpDevelopには、WiXを利用してMSIファイルを作成する機能が用意されています。
上で紹介したcandle.exeやlight.exeなどもSharpDevelopに付属していますので、WiX本体を別途用意する 必要はありません。
(ただし、WiXのヘルプファイルは付属していません)


MSIファイルを作成するには、まず「ファイル」−「新規作成」−「コンバイン」を選択します。
新規プロジェクト作成ダイアログが表示されますので、「カテゴリ」の中の「セットアップ」を選択します。
そして、「テンプレート」の中の「セットアッププロジェクト」を選択し、適当な名前を付け、 「新規」ボタンを押します。

新規プロジェクトダイアログ


すると、「Setup.wxs」以下5つのファイルが作成されます。
これは、SharpDevelopが用意してくれているテンプレートです。
その内容については後述しますので、まずはビルドボタンを押してみてください。

実はこれだけでMSIファイルが作成されています。
プロジェクト「bin」フォルダの中を確認してください。



▲このページのトップへ戻る

テンプレートの画面推移
では、実際にそのMSIファイルを動かして見ましょう。

MSIファイルをダブルクリックするか、SharpDevelopの実行ボタンを押してください。

まず最初に「Preparing to Install ...」的な画面が表示されますが、一瞬で消えて次の画面に行ってしまいます。
とりあえず・・、次に行きましょう。


次の画面は、「ようこそ ...」の画面です。
「Next」ボタンを押してください。

図@
「ようこそ ...」画面


次の画面は、ライセンス同意書画面です。
「I accept ...」ラジオボタンをチェックすると「Next」ボタンが有効になりますので、次に進んでください。

図A
ライセンス同意書画面


次の画面は、インストール先指定画面です。
「Next」を押してください。

図B
インストール先指定画面


次の画面は、インストールの準備完了画面です。
「Install」ボタンを押して次に進んでください。
(実際には何もインストールされないので気にしなくていいですよ・・)

図C
インストールの準備完了画面


実際には、次にファイルコピー中プログレスバーが表示され、現在の進行状態が表示されます。
ただし、今回は何もファイルコピーしないので一瞬で消えてしまいます。


次の画面は、インストール完了画面です。
「Finish」ボタンを押すと終了します。
(ここでは実際にインストールするファイルがないのでエラーになっています)

図D
インストール完了画面


一応、↑ですべて完了なのですが、インストールの途中でキャンセルボタンを押すと ↓のキャンセル画面が表示されます。

図E
キャンセル画面


次項では、この画面を元にXMLファイルについて説明します。



▲このページのトップへ戻る

MSI作成
ここでは、拙作ソフト(CsEditor)をインストールするMSIファイルを作成することを 前提として解説していきます。


プロジェクト一式 WixCsEditor.zip

ソースファイル(メイン) CsEditor.wxs

ソースファイル(UI) UserInterface.wxs



まず、新規作成プロジェクトにて、「セットアッププロジェクト」を選択し「WixCsEditor」という プロジェクト名にします。
「Setup.wxs」というファイルが作成されますが、「CsEditor.wxs」に変更します。


======== CsEditor.wxs ========

@「CsEditor.wxs」のソースを見ると、まず最初に

<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
・・・
</Wix>


という記述があります。
これはまあ・・おまじないみたいなものです。
WiXを使うときにはまず最初に必ずこれを書き、<Wix>〜</Wix>の間に実際の処理を書くことになります。


※もし、日本語を使いたい場合は
<?xml version="1.0" encoding="shift-jis"?>

のように日本語対応のencodingを追加します。



A次を見ていくと<Product></Product>というタグがあります。
これはC言語でいうところのmain()みたいなものです。
つまりこのProductタグは必ず必要で、この間に実際の処理を書いていくことになります。

属性値については↓のような意味になります。

Id      :製品コード(128ビットID)
UpgradeCode  :アップグレードコード(128ビットID)
Name     :製品名
Language   :言語ID
Version    :製品バージョン
Manufacturer :会社名
Codepage   :コードページ


Id、UpgradeCodeにはGUIDを設定します。
GUIDを生成するGuidGen.exeはVisual Studioに付属していますのでそれを使いましょう。


言語IDは、1033が英語(U.S.)で、1041が日本語になります。
詳細は、レジストリの「HKEY_CLASSES_ROOT\MIME\Database\Rfc1766」を見て下さい。


コードページには対応するコードを入力します。
今回はShift-JISで作るので"932"を入力します。


ちなみにヘルプファイルに(min: 1, max: 1)みたいな記述がありますが、これは

min :0・・・なくてもよい、1・・・1つ以上必要
max :1・・・最大で1つ、unbounded・・・数の指定なし

という意味になります。



B次を見ると<Package><Package>という記述があります。
これは作成されるMSIファイルのプロパティ情報のことです。

↓プロパティ画面
プロパティ画面


IdにはプロパティコードIDをつけるのですが、製品コードIDと同じでいいと思います。
「????????-????-????-????-????????????」にしておくと自動的に付けてくれるようです。


Compressedはインストールするファイルを圧縮するかどうかのフラグです。


InstallerVersionはWindows Installerのバージョンを指定します。
この場合だと、Windows Installer 2.0を利用することになります。
当然、利用する側のコンピュータにも同じバージョンのWindows Installerが入っている必要があります。



C次の<Media />では、圧縮方法などを指定します。
Cabinet属性で一時的なキャビネットファイル名を指定し、EmbedCabでは そのキャビネットファイルを埋め込むかどうかを指定してます。
ここはこのままでいいでしょう。



D次の<Directory><Directory>では、TARGETDIRというIDを定義しています。
TARGETDIRはデフォルトで「..\Program Files\製品名\」となります。
(インストール先が変更されたらTARGETDIRも変更されます)

そして、このタグの子ノードに実際にインストールするファイルを登録します。
コピーするファイルの数だけ<Component>タグを追加します。

<Component Id="MainExe" Guid="5E5A2FF2-766E-4aa6-B99A-B0BA0D689DED">
  <File Id="CsEditor.exe" Name="CsEditor.exe" DiskId="1" src="CsEditor/CsEditor.exe"/>
</Component>

Idは適当でいいですが、重複しないようにしましょう。
Guidは製品IDと一緒でいいと思います。

FileタグのName属性には、インストール後のファイル名を入力します。
ただ、ここは8.3形式にする必要があります。
この形式に合わない場合は、LongName属性を追加しましょう。



E次の<Feature><Feature>は重要です。
ここに<ComponentRef />を書いたものだけがインストール実行されます。

Idには対応するComponentタグのId値を指定します。



F最後の<FragmentRef Id="UserInterfaceInclude"/>はソースを分割したときに使います。
この場合だと、Idに"UserInterfaceInclude"と設定されたFragmentタグを参照します。
(つまり「UserInterface.wxs」のこと)



======== UserInterface.wxs ========

続いてはユーザーインターフェース部です。


@<Property><Property>は、C言語でいうところの定数宣言みたいなものです。
「ある値や文字列を(自分にとって)分かりやすい名前で定義しておく」という感じで使います。

例えば、<Property Id="AcceptLicense">No</Property>は ライセンス同意書のデフォルトチェック位置をNoの側(同意しない側)にするという意味になります。

もし後で、やっぱりYesの側(同意する側)をデフォルトにしようと思った場合、 わざわざソースの深いところを探さなくても、このプロパティ値をYesに変えるだけで 済むので変更しやすくなります。



A次のFONT DEFINITIONのところではフォントの定義をしています。
まずTextStyleタグでフォント名、フォントサイズ、太字を指定しておいてPropartyタグでIDを 定義する2段構えになっています。



B続いてはDIALOG DEFINITIONです。
ここでは1つのダイアログ画面ごとに<Dialog><Dialog>を記述します。


[WelcomeDialog]
まず最初は「ようこそ ...」画面の定義です。
Dialogタグの属性値で、ID値、幅、高さ、タイトルなどを指定しています。
そして、このDialogタグの間にそのダイアログで使用されるコントロールを 指定していきます。


各種コントロールは、<Control><Control>で定義します。
属性値のTypeでコントロールの種類を指定しますが、下記のようなものがあります。

Type :PushButton、Bitmap、Line、Text、RadioButtonGroup、ScrollableText、
    PathEdit、ProgressBar、Icon、DirectoryCombo、DirectoryList、VolumeCostList


最初のコントロールは、「Next」ボタンです。
Default属性値は、"yes"になっているコントロールが初期選択されます。
Text属性値の[Button_Next]はPropertyタグで定義した値を利用しています。


次の<Publish></Publish>タグには、イベント処理などを記述します。
Event属性値の"NewDialog"は、今表示しているダイアログを破棄して新しいダイアログを 表示するという意味になります。
Value属性値には、新しく表示するダイアログのIDを指定します。


Publishタグの間の値は、そのイベントが発生するかどうかのフラグです。
この場合は、1が指定してあるので、必ずNewDialogイベントが発生します。


次のコントロールは、「Cancel」ボタンです。
PublishタグのEvent属性値は"SpawnDialog"になってますが、これは子ダイアログを 表示するという意味になります。


コントロールTypeが"Text"の場合、その子ノードに<Text></Text>タグを
追加し、その間に実際に表示する文字列を記述します。



[ViewLicenseAgreement]
次のダイアログは、ライセンス同意書画面です。

まず最初に"RadioButtonGroup"コントロールが定義されています。
そのProperty属性値を見ると"AcceptLicense"と書かれています。
これは何かというと、このDialogタグの直後に書かれている

<RadioGroup Property="AcceptLicense">
・・・
</RadioGroup>

を参照してくださいという意味になります。
ところでAcceptLicenseはもう1つ定義されていましたね。
Propertyタグのところです。
これにより、デフォルトチェック位置はNoの側になります。


次は・・、「Next」ボタンのところを見て下さい。
今度は、<Condition><Condition>タグが追加されています。
これはコントロールの状態を定義するときに使います。
ここではAcceptLicenseラジオボタンがYesのときは「Next」ボタンは有効、 Noのときは「Next」ボタンは無効となります。


次は、ScrollableTextコントロールです。
このコントロールによってライセンス同意文書が表示されます。
ただ、ライセンス同意文書は通常かなり長い文章になってしまうので、別途RTFファイルを
用意して、それに文書内容を記述することになります。



[SelectFolderDialog]
次は、インストール先指定ダイアログ画面です。

まずは、「PathEdit」コントロールを見て下さい。
ここのデフォルト値はProperty="TARGETDIR"が利用されます。
TARGETDIRは、「CustomAction.wxs」で値が設定されています。


次に、「Browse」ボタンを見て下さい。
ここでは、まず"_BrowseProperty"にTARGETDIRの値が代入された後でBrowseDialogダイアログが表示されます。 (順番に注意)



[VerifyReadyDialog]
次は、インストール準備完了画面です。
実は最初の画面から「Next」ボタンで切り替えてきた画面は、ここで完了となります。
つまり、「Install」ボタンを押した時点で後戻りはできなくなります。

じゃあ、進行状況画面やインストール完了画面はどうやって表示するのかという話になりますが、それは後述します。

ここでは、「Install」ボタンに注目してください。
ここのイベント処理では、ディスクスペースが十分かどうかのチェックをしています。
十分なスペースがある場合は、Event="EndDialog"、つまりダイアログを閉じます。
もし十分なスペースがない場合は、ディスク容量不足ダイアログを表示します。



[ProgressDialog]
次は、インストール進行状況ダイアログ画面を見ていきます。
一応、「Back」、「Next」ボタンは表示されますが、無効になっています。

ここで注目するのは、ActionTextとProgressBarのところです。
ActionTextには、今コピー中のファイル名を表示し、ProgressBarには現在の進行状況を表示します。

<Subscribe />タグは、(ユーザーのアクションなしに)順次進められていく イベント処理を記述するんじゃないかと思います。



[CancelDialog]
次は、キャンセルダイアログ画面です。
これを見ると、「Yes」ボタンと「No」ボタンでイベント処理の属性値が違っています。
「Yes」ボタンを押すと親ダイアログも一緒に終了します。
「No」ボタンを押すとこのキャンセルダイアログのみ終了します。



[BrowseDialog]
次は、ブラウズダイアログ画面です。
[SelectFolderDialog]の「Browse」ボタンから呼び出されます。
その際、_BrowsePropertyにインストール先フォルダが代入されますが、その値はPathEditコントロールの デフォルト値として利用されます。

また、この_BrowsePropertyは「DirectoryCombo」、「DirectoryList」コントロールのデフォルト値にも使われます。
これにより、変更された値がすべてのコントロールに反映されることになります。

また、「Cancel」ボタンのイベントにEvent="Reset"というものがあります。
これは、このダイアログ中で変更された内容をリセットします。

また、「OK」ボタンを押したときに、_BrowsePropertyに格納されていた変更内容がTARGETDIRに反映されます。



[UserExit]
ユーザーがキャンセルしたときの終了ダイアログ画面です。
[ProgressDialog]中(ファイルコピー中)にキャンセルされたときに表示されます。



[ExitDialog]
インストールが正常終了したときの終了ダイアログ画面です。



[OutOfDiskDlg]
[ProgressDialog]中(ファイルコピー中)にディスク容量が足りなくなったとき、かつ、ロールバック用の ディスクスペースも足りないときに表示されます。
(ロールバック機能とは、インストール前の状態に戻す機能のことです。
 ロールバック用ディスクスペースとは、ロールバック機能を実現するために
 必要なディスクスペースのことになります。)

また、VolumeCostListコントロールのTextタグにある{120}{70}・・・の値は、リストビューコントロールの 各列の幅の値になります。



[OutOfRbDiskDlg]
[ProgressDialog]中(ファイルコピー中)にディスク容量が足りなくなったとき、
かつ、ロールバック用のディスクスペースが足りているときに表示されます。

「Yes」ボタンを押すことにより、ロールバック機能を実行して終了します。
「No」ボタンを押すとロールバック機能は実行されずに終了します。



[FatalError]
[ProgressDialog]中(ファイルコピー中)に何らかのエラーが発生したときに表示されるダイアログ画面です。



C以上で、メインのダイアログ定義が終わりました。
次の<InstallUISequence><InstallUISequence>には、インストール処理全体の 流れが記述されています。

まず最初は、TARGETDIRの初期化処理を行っています。

続いて、[WelcomeDialog]ダイアログを表示します。
[WelcomeDialog]からの一連の画面切り替えの中で、EndDialogが実行されたとき次の状態に進みます。

続いて、[ProgressDialog]ダイアログを表示します。

最後に、終了ダイアログを表示します。
ただし、[ProgressDialog]がどのように完了したかによって表示が変わります。
ユーザーによるキャンセルで完了したときは[UserExit]ダイアログが、正常終了したときは[ExitDialog]ダイアログが、 エラーによって終了したときは[FatalError]ダイアログが表示されます。



D<AdminUISequence><AdminUISequence>は、管理者(Administrators)で ログイン中にインストール処理を実行したときの流れです。

それ以外のときはCの処理が実行されます。



E最後の<Binary />では、画像の定義をしています。
また、$(var.DATADIR)は「...\SharpDevelop\data」を指しています。

自分で用意した画像を利用することも出来ます。



▲このページのトップへ戻る

あとがき
約1年ぶりにWiXを触ってみました。
当時は日本語化に対応が出来ずに挫折しましたが、今回はあっさりとできました。
(当時は未対応だったのかな?)

一応、今回は実際にインストールするサンプルを作ってみました。
それなりに動いていると思います。

ただ、インストールすると「プログラムの追加と削除」に追加されてしまいますので アンインストールもそちらから行ってください。

日本語のヘルプはまだないようですが、内容はかなり充実していると感じました。
ちょっと頑張れば凝ったインストーラも作れるんじゃないでしょうか。
ぜひチャレンジしてみてください。




■トップへ戻る
▲このページのトップへ戻る