WiX チュートリアル (日本語訳)

Lesson 6 COM、式の構文、その他いろいろ


6.1 違う色のコンポーネント

WiX に含まれている Heat は、様々なソース(フォルダ、ファイル、パフォーマンス・カウンター、ウェブ・サイト)からデータを収集するのに使うツールです。項目数があまりに多くて、対応する WiX のソース・ファイルを手作業で書くことが出来ないという場合に役立ちます。このツールは、主として、一度だけ走らせてデータを収集し、後は通常の方法でソース・ファイルを保守する、という使い方を意図しています。ビルド環境に組み込んで、入力データ・セットに変更があるたびに何度も繰り返して走らせる、というものではありません。それでもなお、この第二の方法で使いたいという場合は、入力データ・セットの変更が望ましくない副作用(たいていは、コンポーネントの規則に対する違反)を惹起しないように、十分に注意を払う必要があります。なるほど、そういう目的の達成を支援する機能が Heat にあるのは本当ですが、そういう機能を使う時は注意が必要です。

Heat の第一のモードは、ファイルがいっぱい入った一つまたは複数のフォルダを調べて、必要な WiX ソースを作成するのを支援するものです。

heat dir folder -cg SampleGroup -out SampleGroup.wxs

上記のコマンドは、指定されたフォルダを再帰的に調べて、-cg スイッチで指定された名前の ComponentGroup を持つ Fragment を作成します。コンポーネント・グループには、見付かったファイルの数だけのコンポーネントが入り、各コンポーネントには、規則に従って、ファイルが一つずつ入ります。そして、コンポーネント、ディレクトリ、ファイルの全てに対して、一意になるように生成された識別子が割り当てられます。これらの識別子は、同じ入力セットで再生成される場合は、同じままで変化しません。GUID は、-gg スイッチによって明示的に生成するように指示しない限り、生成されません(プレースホルダのテキストだけが作られます)。

Heat は、コンポーネント・グループだけでなく、再帰的に訪れたフォルダの一つずつに対して、ディレクトリの参照(DirectoryRef タグ)を含んだフラグメントも同時に生成します。調べる対象になったルート・ディレクトリは、特に名前を指定しない限り、TARGETDIR という識別子を与えられます。

heat dir path -dr MyDirName -cg SampleGroup -out SampleGroup.wxs

自動的に生成される識別子がこの名前をシードとして使うことに注意して下さい。この名前を変更すると、すべての識別子が変ります。不適切な時に変更すると、コンポーネントの規則に違反する悲惨な結果になる可能性があります。

もう一つ別のスイッチ、-srd を使うと、指定されたルート・フォルダに対して、識別子の生成が抑制されます。ルート・フォルダに属するファイルは、その DirectoryTARGETDIR または -dr スイッチで指定された名前で参照します。そして、ルート・フォルダに対する独立した DirectoryRef フラグメントは生成されません。

heat dir path -srd -dr MyDirName -cg SampleGroup -out SampleGroup.wxs

このツールの第二のモードは、単一のファイルを扱います。そのファイルに関連するレジストリ、あるいは、COM やそれに類する項目がある場合に、それらの全部が Heat によって抽出されるのです(ここでの主題は Shell32.dll システム・ライブラリのための相互運用アセンブリです)。

heat file file -cg SampleGroup -out SampleGroup.wxs

上記のコマンドの結果、全ての詳細が正しく抽出されて、下記と同様なソース・ファイルが作られます。

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Fragment>
      <ComponentGroup Id="SampleGroup">
        <Component Id="cmpA8B0842041500B0ACE61F7EFD0FBD893"
                   Directory="dir0F6F75DF46D1BACE2233EC573E6D4AA9"
                   Guid="PUT-GUID-HERE">
          <File Id="filDDAAB2C11E1E5AE4668D99216C3B5523" KeyPath="yes"
                Source="SourceDir\SampleHeat\Interop.Shell32.dll" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32\1.0.0.0"
                         Name="Class"
                         Value="Shell32.ShellDispatchInprocClass"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32\1.0.0.0"
                         Name="Assembly"
                         Value="Interop.Shell32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32\1.0.0.0"
                         Name="RuntimeVersion"
                         Value="v2.0.50727"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32\1.0.0.0"
                         Name="CodeBase"
                         Value="file:///[#filDDAAB2C11E1E5AE4668D99216C3B5523]"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32"
                         Name="Class"
                         Value="Shell32.ShellDispatchInprocClass"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32"
                         Name="Assembly"
                         Value="Interop.Shell32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32"
                         Name="RuntimeVersion"
                         Value="v2.0.50727"
                         Type="string" Action="write" />
          <RegistryValue Root="HKCR"
                         Key="CLSID\{0A89A860-D7B1-11CE-8350-444553540000}\InprocServer32"
                         Name="CodeBase"
                         Value="file:///[#filDDAAB2C11E1E5AE4668D99216C3B5523]"
                         Type="string" Action="write" />
          ...
        </Component>
      </ComponentGroup>
  </Fragment>
  <Fragment>
      <DirectoryRef Id="TARGETDIR">
          <Directory Id="dir0F6F75DF46D1BACE2233EC573E6D4AA9" Name="SampleHeat" />
      </DirectoryRef>
  </Fragment>
  <Fragment>
      <DirectoryRef Id="dir0F6F75DF46D1BACE2233EC573E6D4AA9" />
  </Fragment>
</Wix>

ここで、いくらか言葉を追加しなければなりません。レジストリなどの変更を全てインストーラ・パッケージに書くべきか、それとも、インストールされたコンポーネント(例えば DLL)が自分自身を登録する(最初に起動される時にレジストリ・エントリを追加したり、その他のセットアップ作業を実行する)ようにすべきか、という問題について悩む人がかなりいるようです。答えは簡単です。決して自己登録を使ってはいけません。Windows Installer は、製品のバージョンや更新を追跡記録したり、製品を完全かつ確実に削除したりすることが出来るように、レジストリへの登録やファイルの変更をすべて追跡して記録することが出来なければなりません。重要なデータをインストーラの管轄外に置くことは、このメカニズムを台無しにして、ユーザーに問題を与えるだけの事です。自己登録は Microsoft も使わないことを非常に強く推奨していますので、どんなことがあっても避けるべきです。

第三のモードは、Visual Studio のプロジェクト・ファイル(またはそれと互換性のあるファイル)を調べて、指定されたタイプの全てのファイルに対する参照を作成します。ファイルのタイプは、Binaries, Symbols, Documents, Satellites, Sources あるいは Content です。例えば、Binaries を指定すると、プロジェクトによってビルドして配置される全てのバイナリ・ファイルが収集され、全て対応するコンポーネントとディレクトリに入れられます。その結果を最終的な WiX のソースに取り込むことは、簡単な参照を使うだけで出来ます。

heat project projectfile -pog:Binaries -cg SampleGroup -out SampleGroup.wxs

これまでの例では、後で完全なセットアップ・パッケージに組み込むための断片を生成するために Heat を使いました。しかし、私たちはこのツールに対して、フラグメントではなく モジュール または独立した 製品 を生成するように指示することも出来ます。比較的小さなパッケージであれば、実際には Heat が WiX ソース・ファイルの大半を書いてくれて、いくつかの項目(GUID やテキストによる説明)だけを手作業で追加しなければならない、ということになるかも知れません。

heat ... -template:module -cg SampleGroup -out SampleGroup.wxs
heat ... -template:product -cg SampleGroup -out SampleGroup.wxs

タイプ・ライブラリは WiX で直接にサポートされています。タイプ・ライブラリの全ての内部情報を収集するために、Heat やその他のツールを使う必要はありません。

<File Id="file.dll" Name="file.dll" KeyPath="yes">
  <TypeLib Id="YOURGUID-0BFE-4B1A-9205-9AB900C7D0DA" Language="0" />
</File>

6.2 式の構文

私たちは既に条件式を使った事があります。中でも、Condition タグと Publish タグで、条件式を使いました。NOT, AND, OR のような論理演算子も、<, >, = のような比較演算子も知っています。以下に優先順位に従って、すべての演算子を記載します。

論理演算子
NOT 前置単項演算子。次に来る項の論理値を反転させる。
AND 論理積(両方が なら、)
OR 論理和(どちらかまたは両方が なら、)
XOR 排他的論理和(どちらか一方だけが なら、)
EQV 等値(どちらも か、どちらも なら、)
IMP 含意( か、 なら、)
比較演算子
= 等しい
<> 等しくない
> より大きい
>= より大きいか、または、等しい
< より小さい
<= より小さいか、または、等しい
˜= 等しい(大文字と小文字を区別しない)
˜<> 等しくない(大文字と小文字を区別しない)
˜> より大きい(大文字と小文字を区別しない)
˜>= より大きいか、または、等しい(大文字と小文字を区別しない)
˜< より小さい(大文字と小文字を区別しない)
˜<= より小さいか、または、等しい(大文字と小文字を区別しない)
部分文字列演算子(文字列間のみ)
>< を含んでいる
<< から始まっている
>> で終っている
ビット演算子(整数間のみ)
>< ビット単位の AND
<< の上位16ビットが に等しい
>> の下位16ビットが に等しい

これらの式においては、プロパティ名を使うことが出来ます(プロパティ名は大文字と小文字を区別することを思い出して下さい)。存在しないプロパティ名は空の文字列として扱われます。プロパティの論理値は、プロパティが設定されているか否か、という事を示します — つまり、単にプロパティを使うだけでは、その論理値をチェックすることは出来ない、という事です。

PROPERTY
プロパティが設定されていて何らかの値を持っていれば、たとえその値がであっても、と評価されます。
NOT PROPERTY
プロパティが全く設定されていない場合にと評価されます。
PROPERTY = TRUE
PROPERTY = FALSE
これらの式が、論理値を持つプロパティの値をチェックする正しい方法です。

いくつかの特殊な文字を名前の前に付けると、特別な意味になります。

 
% 環境変数(名前は大文字と小文字を区別しません)
$ コンポーネントのアクション後の状態
? コンポーネントの現在のインストール状態
& 機能のアクション後の状態
! 機能の現在のインストール状態

後の四つは次の整数値を取り得ます。

 
-1 どんなアクションも実行されない
1 アドバタイズされている (機能についてのみ該当)
2 インストールされていない
3 ローカル・コンピュータ上にインストールされている
4 ソースから実行される

より明確にするために、いくつか例を挙げましょう。

(&FeatureName = 3) AND NOT (!FeatureName = 3)
製品がローカルにインストールされる場合にだけアクションを実行します。再インストールの場合はアクションを実行しません。
&FeatureName = 3 という項は、アクションがその機能をローカルにインストールするものであることを意味します。
NOT (!FeatureName = 3) という項は、その機能がローカルにインストールされていないことを意味します。
(&FeatureName = 2) AND (!FeatureName = 3)
その機能がアンインストールされる場合にだけアクションを実行します。
この条件式は、機能がローカルにインストールされている状態から存在しない状態へと遷移する場合だけを捕まえます。
(?ComponentName = 3) AND ($ComponentName = 2 OR $ComponentName = 4)
コンポーネントがローカルにインストールされていて、そうでない状態へと遷移する場合にだけ、アクションを実行します。
?ComponentName = 3 という項は、コンポーネントがローカルにインストールされていることを意味します。
$ComponentName = 2 という項は、コンポーネントのアクション後の状態が「存在しない」であることを意味します。
$ComponentName = 4 という項は、コンポーネントのアクション後の状態が「ソースから実行される」であることを意味します。コンポーネントに対しては、「アドバタイズされている」という状態は当てはまらないことに注意して下さい。
?ComponentName = $ComponentName
コンポーネントが(現在と同じ状態で)再インストールされる場合にだけアクションを実行します。

6.3 書式指定文字列

コントロールのテキストに表示されるテキストは書式指定をすることが出来ます。角括弧に入れたプロパティ名は既に使用しましたが、そのあたりにはもう少し複雑な規則もあります。まず、[Property] においてプロパティ名が有効でない場合は、全体の部分文字列が変更されずに残されます。

この規則は角括弧が入れ子になっている場合はいくらか違うものになります。[[Property]] という書式は、最初に Property を検索して、その値を別のプロパティ名として使い、その第二のプロパティを検索します。二つのプロパティ名のうちのどちらかでも見付からなかった場合には、全体の部分文字列は空文字であると見なされます。

特別な意味を持った文字(たとえば角括弧)を通常の文字として示すためには、バックスラッシュをエスケープ文字として使って、角括弧に入れます。

† 訳註:例えば、"[""[\[]""]""[\]]"

[~] という部分文字列は、ヌル文字に置き換えられます。これによって、REG_MULTI_SZ のレジストリ文字列をコンパイルすることが可能になります。

[#filekey] という表記法は、指定された Id を持つファイルのフル・パスを返します。ただし、これは、 CostInitialize, FileCost または CostFinalize が走った後に限ってのことです。パスは、ファイルが含まれるコンポーネントがローカルにインストールされるか、ソースから実行されるかによって、左右されます。

[$componentkey] という表記法は、指定されたコンポーネントのインストール先ディレクトリを返します。ただし、これも、 CostInitialize, FileCost または CostFinalize が走った後に限ってのことです。パスは、コンポーネントがローカルにインストールされるか、ソースから実行されるかによって、左右されます。

[!filekey] という表記法は、通常は [#filekey] と等価な表記法ですが、Registry または IniFile のタグの Value 属性の値として使われた場合には、ファイルの短い形式(8.3形式)のフル・パスを返します。

ツールセットのいろいろな部分(コンパイラやリンカ)は固有のプリプロセッサを持っていて、外部的に(つまり、コマンド・ラインで)定義した文字列をソースに注入して使うことが出来るようになっています。コンパイラ Candle$(var.Foo) という構文を使います。ソース・ファイル自身の中で値を設定するためには、下記のように記述します。

<?define Foo=bar?>

コマンド・ライン・スイッチで設定する場合は、次のようにします。

candle -dFoo=bar

Light、すなわちリンカも同様な仕組みを持っていますが、構文がほんの少し異なっていて、!(wix.Foo) となります — コマンド・ラインは同じです。

light -dFoo=bar

地域化される文字列は、!(loc.Foo) という表記法を使います。リンカは、これらの文字列が .wxl 地域化ファイルの中で、下記の構文で定義されているものとします。

<String Id="Foo" Overridable="yes">bar</String>

地域化ファイルもコマンド・ラインで指定します。

light -loc path path

地域化文字列とその他の文字列の主な違いは、地域化文字列はオーバーライド可能な性格を持っていることです。ライブラリや拡張モジュールが地域化文字列の既定値を持つことが出来る一方で、それを後のリンクの過程でオーバーライドすることが出来ます。

これらの値を Windows Installer の通常のプロパティに割り当てるためには、どの場合も、Property タグを使って下さい。

<Property Id="Foo1" Value="$(var.Foo)" />
<Property Id="Foo2" Value="!(wix.Foo)" />
<Property Id="Foo3" Value="$(env.Foo)" />

環境変数は、コンパイラでもリンカでも、$(env.Foo) という構文でアクセスすることが出来ます。

6.4 DDE 接続

DDE (Dynamic Data Exchange) を使うシェル接続は、下記のようにしてセットアップ出来ます。

<ProgId Id='Program.xyz' Description='Program handling .xyz' Advertise='yes'>
  <Extension Id='xyz' ContentType='text/sql'>
    <Verb Id='open' Sequence='1' Command='Open' Argument='"%1"'/>
  </Extension>
  <Extension Id='xyz0' ContentType='text/sql'>
    <Verb Id='open' Sequence='1' Command='Open' Argument='"%1"'/>
  </Extension>
</ProgId>

<Component Id='regSetup' Guid='YOURGUID-6D8A-4AE2-9D9F-3E074F13A029'>
  <Registry Root='HKLM' Key='SOFTWARE\Classes\Program.xyz\shell\open\ddeexec'
            Type='string' Value='[\[]open("%1")[\]]' KeyPath='yes'/>
  <Registry Root='HKLM' Key='SOFTWARE\Classes\Program.xyz\shell\open\ddeexec\application'
            Type='string' Value='Program.xyz' />
  <Registry Root='HKLM' Key='SOFTWARE\Classes\Program.xyz\shell\open\ddeexec\topic'
            Type='string' Value='System' />
</Component>

6.5 ディレクトリの作成

場合によっては、ファイルをインストールせずに、ディレクトリだけを新しく作らなければならないことがあります。以下がその方法です。

<Directory Id="TARGETDIR" Name="SourceDir">
  <Directory Id="ProgramFilesFolder" Name="PFiles">
    <Directory Id="test" Name="test">
      <Component Id="test" Guid="YOURGUID-4884-4A01-AA04-84B92D222428"
                 SharedDllRefCount="no" KeyPath="no" NeverOverwrite="no"
                 Permanent="no" Transitive="no" Win64="no" Location="either">
        <CreateFolder/>
      </Component>
    </Directory>
  </Directory>
</Directory>

<Feature Id="test" Title="testfolder" Level="1">
  <ComponentRef Id="test"/>
</Feature>

6.6 複数メディアのインストール

複数メディアのインストール(例えば、一枚の CD にファイルが収まらない場合)については、既にレッスン 1 で言及しました。その場合、個々の物理メディアを示すために、ソース・ファイルに複数の Media タグを記述することが必要になります。これまでのインストーラとは違って、ファイル・アーカイブを .msi ファイルに埋め込むことは、もちろん出来ません。また、ユーザーの便宜のために、人間が読むことが出来る(必要なら、地域化可能な)プロンプトを指定し、さらに、ボリューム・ラベルを指定しなければなりません。このボリューム・ラベルは、物理メディアの実際のボリューム・ラベルと一致しなければなりません。インストーラはボリューム・ラベルを見て、要求されているメディアをユーザーが挿入したかどうかを判断します。

<Media Id='1' Cabinet='Sample1.cab' EmbedCab='no'
       DiskPrompt="CD-ROM #1" VolumeLabel="HOGE_DISK1" />

<Media Id='2' Cabinet='Sample2.cab' EmbedCab='no'
       DiskPrompt="CD-ROM #2" VolumeLabel="HOGE_DISK2" />

ユーザーに正しいメディアを挿入するように促す実際のメッセージを作るために、Windows Installer は DiskPrompt プロパティをも必要とします。DiskPrompt プロパティには、下記のように、書式指定文字列を使う必要があります。[1] は対応する Media タグの DiskPrompt 属性の内容で置き換えられます。

<Property Id='DiskPrompt' Value="ぴよソフトのほげ 1.0 インストーラ [1]" />

6.7 プログラムの追加と削除の項目

コントロール・パネル > プログラムの追加と削除 の中で、プログラムは、「サポート情報を参照するには、ここをクリックして下さい」という項目の下に、電話番号やインターネットの連絡先など、いろんな項目を保持することが出来ます。それらを指定するためには、下記のプロパティをソース・ファイルに追加して下さい。

<Property Id='ARPCOMMENTS'>コメント</Property>
<Property Id='ARPCONTACT'>問い合わせ先</Property>
<Property Id='ARPHELPLINK'>ヘルプ・リンク</Property>
<Property Id='ARPURLINFOABOUT'>製品情報のURL</Property>
<Property Id='ARPURLUPDATEINFO'>製品の更新情報のURL</Property>
<Property Id='ARPHELPTELEPHONE'>ヘルプ電話番号</Property>
<Property Id='ARPREADME'>説明ファイルのパス</Property>
<Property Id='ARPSIZE'>アプリケーションのサイズ(KB単位)</Property>

ARPSIZE は一見すると余分なものに思われます。しかし、テストをしてみると分ることですが、Windows Installer は非常に小さなパッケージに対しては、完全に嘘の値(4 GB以上)をレポートします。その場合、パッケージ・サイズを手動で設定しておくことで、この鬱陶しいけれども無害な障害を回避することが出来ます。

† 訳註:Windows Vista では、「サポート情報を参照するには、ここをクリックして下さい」がありません。これらの項目は「詳細表示の設定」で選択されているものだけがを表示されます。詳細表示の設定を変更するためには、まず、整理 > レイアウト > メニューバーによってメニューバーを表示して、次にメニューバーで、表示 > 詳細表示の設定を選びます。

アプリケーション項目の左に表示されるアイコンを指定するためには、(Shortcut タグで見たように)アイコンの Id 属性への参照を使います(識別子に同じ拡張子を追加することも忘れないでください)。また、現在の所は、プログラムの追加と削除にバグがあって、ユーザーごとのインストール(すなわち ALLUSERS プロパティが 2 に設定されたインストール)の後では、アイコンが表示されないということも覚えておいて下さい。

<Property Id='ARPPRODUCTICON'>appicon.ico</Property>
...
<Icon Id="appicon.ico" SourceFile="Application.ico" />

その他、アプリケーションがプログラムの追加と削除においてどのような振る舞いをするかを制御するためのプロパティが二~三あります。変更ボタンの表示を抑止する(あるいは、Windows 2000 より前では、インストーラに製品のメンテナンスをさせず、削除だけが出来るようにする)ためには、以下のようにします。

<Property Id='ARPNOMODIFY'>1</Property>

削除ボタンを無効化する(あるいは、Windows 2000 より前では、そのアプリケーションをリストから完全に削除する)ためには、以下のようにします。

<Property Id='ARPNOREMOVE'>1</Property>

Windows 2000 や XP で、このリストからアプリケーションを完全に削除するためには、上記の代りに、以下のようにしなければなりません。

<Property Id='ARPSYSTEMCOMPONENT'>1</Property>

修復機能を抑止するためには、以下のようにします。

<Property Id='ARPNOREPAIR'>1</Property>

6.8 新顔のユーザー

WiX ツールセットの追加のライブラリには、新しいユーザー・アカウントを追加する、というような追加の仕事をインストーラが出来るようにするものもあります。

<Component>
  <user:User Id='NewUser' Name='username' Password='password' />
</Component>

インストーラ・パッケージをリンクするときに、適切な WiX 拡張モジュールをリンクしなければなりません。

light.exe -ext WixUtilExtension -out Sample.msi Sample.wixobj

このライブラリは、フォルダの共有を作成する手段も提供しています。次のコードの断片を Component の中に置くだけで、そのコンポーネントがインストールされるフォルダに共有を設定することが出来ます。

<user:User Id='Everyone' Name='Everyone' CreateUser='no'
           FailIfExists='no' RemoveOnUninstall='no' />
<user:FileShare Id='MainExecutableShare' Description='ほげ 1.0 の共有フォルダ'
                Name='ほげ共有フォルダ'>
  <user:Permission GenericRead='yes' ReadPermission='yes' Read='yes' GenericExecute='yes'
                   User='Everyone' />
</user:FileShare>

FileShare の属性は自ずから明らかでしょう。共有に伴うアクセス許可を指定するためには Permission 要素を使う必要がありますが、そのためには User が指定されていなければなりません。ここでは、新しいユーザーを作ることは求めていませんし(CreateUserを見て下さい)、製品を削除する時にユーザーを削除することも求めていません(RemoveOnUninstallを見て下さい)。実際のアクセス許可としては、Delete, Execute, Read, Write, GenericExecute, GenericRead, GenericWrite, TakeOwnership, ReadAttributes, WriteAttributes などの属性の中から選ぶことが出来ます。使用可能な全ての属性を知るためには、ヘルプ・ファイルを参照して下さい。

CreateFolder 要素の中でも Permission タグを使うことが出来ることに注意して下さい。いくつかの追加の属性(CreateChild, CreateFile, DeleteChild, Traverse)は、その場合のために予約されているものです。

† 訳註:上記の例をソース・ファイルに記述するためには、最初に、Wix の開始タグの中で、WixUtilExtension 拡張モジュールに言及する必要があります。<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:user='http://schemas.microsoft.com/wix/UtilExtension'>

6.9 環境に優しく

環境変数をインストールするためには、コンポーネントの中で Environment タグを使います。

<Environment Id='UpdatePath' Name='PATH' Action='create' System='yes'
             Part='last' Value='[INSTALLDIR]' />

Action 属性によって、コンポーネントがインストールされる時に何をすべきかを指定します。指定できる値は、create, set および remove です。Part 属性が新しい値の割り当て方を左右します。all は新しい値で元の値を置き換え、first は新しい値を元の値の前に追加し、last は新しい値を元の値の後ろに追加します。Permanent='yes' にすると、その環境変数は製品が削除されても残りますが、そうでなければ、一緒に削除されます。System は、環境変数がシステムの環境空間に追加されるか、ユーザーの環境空間に追加されるかを指定します。環境変数の名前には、必ず、すべて大文字を使って下さい。

6.10 XML

今日では、古い .ini 形式でなく、XML ベースの設定ファイルを使用するプログラムがますます増えています。WiX は、インストールやアンインストールの際にそういう設定ファイルを修正するための、作成済みカスタム・アクションを持っています。ここで、アプリケーションと一緒に Settings.xml というファイルをインストールすると仮定しましょう。最初は、ファイルの中身は一番外側のタグだけです。

<settings>
</settings>

インストーラに新しいノードをいくつか追加させることにします。そして、ノードの一つには属性値を持たせます。

<settings>
  <add key="a_key" value="a_value">key_item
    <inside>inside_item</inside>
  </add>
</settings>

これを実現するためには、XmlFile タグを使うことが出来ます。IdFile のような通常の属性とは別の、Action, Name および Value 属性が XML ファイルの中で何をするかを決定し、ElementPath 属性がどこでそれをするかを決定します。この最後の属性は、標準的な XPath 仕様言語 を使って、実際の操作が適用される XML ノードを記述します。

Action Name Value 操作
createElement name ElementPath で指定されたノードの中に、新しいノードが作成される
setValue value ElementPath で指定されたノードの中のテキスト値がセットされる
setValue name value ElementPath で指定されたノードに name という名前で value という値を持った属性が与えられる
deleteValue ElementPath で指定されたノードの中のテキスト値が削除される
deleteValue name ElementPath で指定されたノードから、name という名前の属性が削除される

という訳で、計画した修正を実行するために、下記の項目を記述します(自分自身で操作の順序を指定しなければならないことに注意して下さい。このことは、アンインストールの時に、正しい逆順で変更が削除されることを保証するために、重要なことです)。

<Component Id='Settings' Guid='YOURGUID-574D-4A9A-A266-5B5EC2C022A4'>
  <File Id='XmlSettings' Name='settings.xml' DiskId='1' Source='settings.xml' Vital='yes' />
  <util:XmlFile Id='XmlSettings1' File='[INSTALLDIR]settings.xml'
                Action='createElement' Name='add' ElementPath='//settings'
                Sequence='1' />
  <util:XmlFile Id='XmlSettings2' File='[INSTALLDIR]settings.xml'
                Action='setValue' Name='key' Value='a_key' ElementPath='//settings/add'
                Sequence='2' />
  <util:XmlFile Id='XmlSettings3' File='[INSTALLDIR]settings.xml'
                Action='setValue' Name='value' Value='a_value' ElementPath='//settings/add'
                Sequence='3' />
  <util:XmlFile Id='XmlSettings4' File='[INSTALLDIR]settings.xml'
                Action='setValue' Value='key_item' ElementPath='//settings/add'
                Sequence='4' />
  <util:XmlFile Id='XmlSettings5' File='[INSTALLDIR]settings.xml'
                Action='createElement' Name='inside' ElementPath='//settings/add'
                Sequence='5' />
  <util:XmlFile Id='XmlSettings6' File='[INSTALLDIR]settings.xml'
                Action='setValue' Value='inside_item' ElementPath='//settings/add/inside'
                Sequence='6' />
</Component>

XML ファイルの中に同じ名前を持った複数のノードが有る場合は、どのノードを参照しているのかを特定するために、よくある 'node[@attr="value"]' という XPath の形式を使うことが出来ます。ElementPath は書式指定文字列を受け入れますので、角括弧を使う時は、プロパティとして評価されないように、バックスラッシュでエスケープしなければいけません([\[] および [\]])。

この機能は標準のユーティリティー・モジュールに入っていますので、それをリンクしなければなりません。

light.exe -ext WixUtilExtension -out Sample.msi Sample.wixobj

6.11 COM+ アプリケーション

WiX ツールセットにあるカスタム・アクション・ライブラリを使うと、インストーラが COM+ パッケージを作ったり、それにコンポーネントを追加したり、ロールの作成と設定をしたりすることが出来るようになります。

注記: Visual Studio で COM+ カスタム・アクションに対するインテリセンス機能が欲しい場合は、ダウンロードしたソースの "src\ca\pubca\pcaext\Xsd\pubca.xsd" というファイルを Visual Studio 2005 なら "\Program Files\Microsoft Visual Studio 8\Xml\Schemas" に、また、Visual Studio 2003 なら "\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml" にコピーする必要があります。

インストーラ・パッケージをビルドするときは、適切な WiX ライブラリを含めてコンパイルおよびリンクしなければなりません。そのための CandleLight のコマンド・ラインは以下のようになります。

candle -ext WixComPlusExtension Sample.wxs
light -ext WixComPlusExtension Sample.wixobj

また、WiX のソースで、下記のように COM+ スキーマを参照する必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:complus="http://schemas.microsoft.com/wix/ComPlusExtension">

COM+ パッケージ(My COM+ Application)を作成して、そのパッケージに標準的な COM DLL(MyCOM.dll)を追加するためには、下記のように記述します。

<Component Id="MyCOM_dll" DiskId="1" Guid="YOURGUID-242F-4B82-BDC7-588E59E9F393">
  <File Id="MyCOM_dll" Name="MyCOM.dll" Source="MyCOM.dll" KeyPath="yes"
        Vital="yes" />
  <complus:ComPlusApplication Id="MyCOM" Name="My COM+ Application">
    <complus:ComPlusAssembly Id="MyComPlusAssembly" Type="native" DllPath="[#MyCOM_dll]">
      <complus:ComPlusComponent Id="MyCOM" CLSID="YOURCLSID-CA74-4DC7-BAEF-25AF03BC5F67" />
    </complus:ComPlusAssembly>
  </complus:ComPlusApplication>
</Component>

COM+ パッケージ(My COM+ Application)を作成して、グローバル・アセンブリ・キャッシュ(GAC)に無い .NET アセンブリをそのパッケージにパッケージに追加する場合は、以下のように記述します。

<Component Id="MydotNet_dll" DiskId="1" Guid="YOURGUID-242F-4B82-BDC7-588E59E9F393">
  <File Id="MydotNet_dll" Name="MydotNet.dll" Source="MydotNet.dll" KeyPath="yes"
        Assembly="no" />
  <complus:ComPlusApplication  Id="MydotNet" Name="My COM+ Application">
    <complus:ComPlusAssembly Id="MyComPlusAssembly" DllPath="[#MydotNet_dll]"
                             TlbPath="[#MydotNet_tlb]" Type=".net" RegisterInCommit="yes">
      <complus:ComPlusComponent Id="CheckInterface"
                                CLSID="YOURCLSID-241E-4472-8C71-61A22BAF9914"/>
    </complus:ComPlusAssembly>
  </complus:ComPlusApplication>
</Component>

<Component Id="MydotNet_tlb" DiskId="1" Guid="YOURGUID-242F-4B82-BDC7-588E59E9F394">
  <File Id="MydotNet_tlb" Name="MydotNet.tlb" Source="MydotNet.tlb" KeyPath="yes" />
</Component>

COM+ パッケージ(My COM+ Application)を作成して、グローバル・アセンブリ・キャッシュ(GAC)に有る .NET アセンブリをそのパッケージに追加する場合は、以下のように記述します。

<Component Id="MydotNet_dll" DiskId="1" Guid="YOURGUID-242F-4B82-BDC7-588E59E9F393">
  <File Id="MydotNet_dll" Name="MydotNet.dll" Source="MydotNet.dll" KeyPath="yes"
        Assembly=".net" />
  <complus:ComPlusApplication Id="MydotNet" Name="My COM+ Application">
    <complus:ComPlusAssembly Id="MyComPlusAssembly" TlbPath="[#MydotNet_tlb]"
                             Type=".net" DllPathFromGAC="yes" RegisterInCommit="yes">
      <complus:ComPlusComponent Id="CheckInterface"
                                CLSID="YOURCLSID-241E-4472-8C71-61A22BAF9914"/>
    </complus:ComPlusAssembly>
  </complus:ComPlusApplication>
</Component>

<Component Id="MydotNet_tlb" DiskId="1" Guid="YOURGUID-242F-4B82-BDC7-588E59E9F394">
  <File Id="MydotNet_tlb" Name="MydotNet.tlb" Source="MydotNet.tlb" KeyPath="yes" />
</Component>

Neil Sleightholm

6.12 バージョンごとに

Package タグの InstallerVersion 属性は、インストーラ・パッケージが必要としているインストーラのバージョンを記述します。チュートリアルでは、最小公分母を示したかったために、100 という値(バージョン 1.0 の意味)を使って来ました。実際のバージョンを、対応する Windows のバージョンと対比して、下の表で示します。

† 訳註:InstallerVersion 属性は、Major Version × 100 + Minor Version という値で指定します。例えば、バージョン 3.1 なら、301 です。

Version Windows 機能
1.x XP より前 基本的な MSI サポート、32-bit のみ
2.0 XP, 2000 Server SP3 64-bit サポート
3.0 XP SP2 パッチ機能の改善
3.1 XP SP3, 2003 Server SP2 ユーザー・インタフェイスの改善
4.0 Vista, Server 2008 UAC、再起動マネージャ、MSI 連鎖
4.5 Vista, Server 2008 SP2 パッチ機能の改善
5.0 Windows 7, 2008 Server R2 アクセス許可の設定、サービス制御の改善、UIの改善、ユーザーごとのインストールと全ユーザーのためのインストールの統合

一般的な規則としては、新しいバージョンが本当に要求されるのでない限り、バージョン 3.1 以下を指定することをお奨めします。バージョン 3.1 の Windows Installer は、Windows 2000 でもサポートされています。

さらに詳細な変更履歴説明が Microsoft のサイトにあります。これらの文書には、どのパッケージが Windows Update によっては自動的に更新されないけれども再配布可能なダウンロードとして入手できるか、ということも述べられています。

Copyright © 2004-2012, Gábor DEÁK JAHN, Tramontána
何よりもコメントと寄稿を歓迎します。
日本語翻訳 Copyright © 2010, 2013, Nobuo Kihara, softark
読みやすくて正確な翻訳を目指しましたが、解釈の誤りと技術的な間違いが含まれていないという保証は出来ません。間違いの指摘や修正案の提示を歓迎します。github のリポジトリ ( https://github.com/softark/wix-j ) をご利用下さい。