Windows Installer で Session.Message メソッドを使う

MSI を作成している最中、デバッグ用途にカスタムアクション内に VBScript で MsgBox を入れ込むということを
よくやると思います。デバッグ用にはこれで十分なのですが、リリース版で何等かのメッセージボックスを表示したいと
いう場合、同様にカスタムアクションで VBscript の MsgBox で表示すると次の現象が発生します。

  • VBScript で作成したメッセージボックスがモードレスになり、インストールウィザードの後ろに隠れてしまう
    MsgBox に 4096(vbSystemModal) を加えても変わらない
  • メッセージボックスを表示中でもインストールウィザードを操作することができてしまう

リリース版で、この動きになってしまうと、ユーザーに悪い印象を与えかねません。
この原因ですが、以前、このブログでも紹介したように、カスタムアクション用の msiexec.exe が
別に起動されてしまうことによる影響です。

    WindowsInstallerアーキテクチャ図

ところが、Custom Action Types をよく見ると、Type 19 というものがあります。説明には、

Displays a specified error message and returns failure, terminating the installation.

と記述があり、何やら、メッセージを表示することができるようです。

この投稿の続きを読む

MSI の各上限値

自分用のメモです。

  • コンポーネント数の最大数: 65535
  • 機能に関連付けできるコンポーネント数の最大数: 1600
  • 機能階層の深さ: 16階層
  • 最大ファイル数(Fileテーブルに格納できる上限): 32767
  • 1 ファイルの最大サイズ: 2GB
  • MSI データベース内部で使用される CAB ファイルの上限サイズ: 2GB

インストーラーのエクスペリエンス

突然ですが、インストーラーに UX(エクスペリエンス)は必要か?と問わせて、どう答えますか?
色々な考え/意見があると思いますが、ひとつの答えとして、Microsoft が

提供しています。
Windows 関連製品を開発する際には、ぜひとも、読んでおくべき内容だと思います。

Windows Installer のカスタムアクションをデバッグする

結構、便利なので紹介します。元ネタは

です。
今回は、MSI でカスタムアクションを実装することができる人向けということを前提としています。
ちょっとディープな内容になってしまうかもしれません。

MSI を作っているときに、標準アクションではどうしてもできない処理があり、カスタムアクションを用意することが
あります。もちろん、カスタムアクションを作る際にきちんとデバッグしておくわけですが、そのデバッグを通り抜けて
しまったバグをどうやってデバッグ/調査しようかと悩むことがあるかもしれません。
Windows Installer は、非常によくできていて、カスタムアクションのデバッグを支援する仕組みを持っています。
その方法ですが、次のような流れになります。

  1. システム環境変数に MsiBreak 変数を用意して、カスタムアクション名を値に設定する。
  2. 管理者権限でコマンドプロンプトを開き、msiexec コマンドでインストーラーを実行する。
  3. WinDBG でカスタムアクション用の msiexec.exe にプロセスアタッチしてカスタムアクションをデバッグする。

MsiBreak システム変数で設定してカスタムアクションが実行されるときに、Windows Installer が一度、Break してくれると
いう仕組みを持っているわけです。
以前、カスタムアクションは、カスタムアクション用の msiexec.exe が起動されて、その中で実行されると紹介しましたが
その msiexec.exe にデバッガでアタッチしてデバッグしようというわけです。

この投稿の続きを読む

Windows Installer でカスタムアクションを使用する際の注意

2010 年最初のネタは、Windows Installer です。
インストーラーは極力シンプルな構造にするのは鉄則ですが、どうしても内部処理を行うために
カスタムアクションを使用しなければならないという場合、重要な注意事項があります。

  • 前提条件
    Windows Installer のカスタムアクションで、EXE や DLL を使用する
  • OS
    Windows Vista 以降の OS すべて(クライアント系、サーバー系共に)

この条件に当てはまる場合には、使用する EXE や DLL は必ず、ランタイムライブラリをスタティックリンク(/MT オプション)
したものを使うようにしてください。

この理由ですが、カスタムアクションの EXE や DLL が、再頒布インストールするランタイムを使用してしまう場合、
Windows Installer のインストール処理はトランザクションになっているために、カスタムアクションが動作する際には
再頒布インストールする C ランタイムが使える状態(再頒布インストールするランタイムのマージモジュールが
コミットされていない)になっていない場合があるからです。

エラー 1935。  An error occurred during the installation of assembly component {9DA4DC8A-9731-3F0E-8BD5-FC17CA6848AD}. HRESULT: 0x800736FD. assembly interface: IAssemblyCacheItem, function: Commit, assembly name: policy.9.0.Microsoft.VC90.CRT,publicKeyToken="1fc8b3b9a1e18e3b",type="win32-policy",version="9.0.30729.4148",processorArchitecture="x86"
MSI (s) (54:54) [11:22:00:570]: 製品 : 俺様サンプル — エラー 1935。  An error occurred during the installation of assembly component {9DA4DC8A-9731-3F0E-8BD5-FC17CA6848AD}. HRESULT: 0x800736FD. assembly interface: IAssemblyCacheItem, function: Commit, assembly name: policy.9.0.Microsoft.VC90.CRT,publicKeyToken="1fc8b3b9a1e18e3b",type="win32-policy",version="9.0.30729.4148",processorArchitecture="x86"

という具合に、1935 エラーが発生する可能性があります。

上記のブログは、VC++ 8.0 ですが、VC++ 9.0 でも同様です。
カスタムアクションを使用するのであれば、EXE や DLL を使うのではなく、VB スクリプトや J スクリプトを使う方がよいです。

Windows Installer スキーマバージョン

Windows 7 & Windows Server 2008 R2 にバンドルされている Windows Installer は バージョン 5 になります。
この辺で、スキーマ番号の一覧をアップデートしておこうと思います。

Windows Installer のバージョン スキーマ番号
5.0 500
4.5 405
4.0 400
3.1 301
3.0 300
2.0 200
1.1 110

Windows Installer のバージョンの確認方法ですが、コマンドプロンプトを開いて

msiexec

と入力してください。すると

のような画面が表示されます。(これは、Windows 7 RTM で実行した結果)
また、MSI ファイルのスキーマ番号を確認したい場合には、Orca で確認することができます。

Windows Installer 5.0 では、MSIINSTALLPERUSER プロパティが追加されたので、ALLUSERS プロパティとの
組み合わせを少し意識しておく必要があります。(スキーマ番号に 500 を使う場合ですが)

Windows Installer のカスタムアクションを管理者権限で動かしたい

8月になりました。毎日、暑いですね~。この暑さでジョギングもすっかり、ご無沙汰です。
先日、散歩していたところ、あることに気が付きました。ガソリン高騰の影響だと思うのですが、道を走っている車が
気のせいか少なくなったように思います。ガソリン高騰、一体、どうなるんでしょう。

さて、話題を変えて、今回は Windows Installer に関係するネタです。

少し前に Windows Installer 4.5 がリリースされましたが、
Windows Vista / 2008 では、Windows Installer 4.0 が標準バンドルされており、
MSI のスキーマは 400 にすることが推奨されています。(最低でも、301)インストーラーはユーザーに対して一番最初に見せるプログラムであり、失敗することは許されません。
インストーラーでエラーになったら、それだけで使うのが嫌になってしまいますよね。

  • ファイルコピー
  • レジストリ登録
  • メニュー登録

できれば、これくらいで抑えておきたいものです。
MSI 作成に限らず、インスールパッケージを作成する際、インストールパッケージ自体にあまり多くの機能を
入れ込まず、可能な限り、外出しのプログラム(セットアップやライブラリ化)にしておくのがよい実装です。

ただ、どうしても、MSI パッケージ内に独自の処理を入れなければならない場合もあります。
この場合は、カスタムアクション を用意することになります。
カスタムアクションとは、ユーザー定義のインストール動作です。
これは、標準動作では足りない部分を補うことができるように用意されているものです。
例えば、外部の EXE や DLL を実行したり、VBScript、JScript などのスクリプトを実行することもできます。

では、Windows Vista / 2008 で管理者権限のカスタムアクションを実装する際のポイントを解説します。
まず、カスタムアクションを使うために必ず知っておかなければならないことがあります。

  1. カスタムアクションの種類
  2. カスタムアクションがどのようなアーキテクチャで動作しているのか
  3. カスタムアクションの実装方法

では、まずは (1) から解説します。Windows Installer で用意されているカスタムアクションは、以下のものがあります。

この一覧は非常に重要なもので、カスタムアクションを実装する際には必ず参照すると思います。
この Custom Action Types 一覧では、どのような Custom Action Type があるのかをじっくりと読んでおいてください。
例えば、Custom Action Type 1 はバイナリテーブルに格納した DLL をカスタムアクションで
使用することです。同様に Custom Action Type 2 は、DLL ではなく EXE を使用することです。

余談ですが、最新の Windows Installer 4.5 ではカスタムアクションに .NET で作成したマネージコードの
DLL や EXE を実行することもできます。

では、カスタムアクションはどのようなアーキテクチャで動作しているのでしょう。
(2) を解説していきます。

Windows Installer は、クライアント/サーバー型のサービスプログラムであると、以前 (Windows Installer その1) に
記載しました。 Windows Installer がカスタムアクションを実行する際、カスタムアクション用にクライアントプロセスの
msiexec.exe をもう一つ起動します。

つまり、

————————————————————————–
msiexec.exe (サーバープロセス:Local System)

  ↓ プロセス起動

  msiexec.exe (クライアントプロセス:管理者権限 or 各ユーザー権限)

   →  カスタムアクション用の msiexec.exe (クライアントプロセス:各ユーザー権限)
————————————————————————–

という構造をとります。
例えば、カスタムアクションには DLL を実行する機能があります。その DLL をホストする EXE が必要になりますよね。
そこで、クライアントプロセス用の msiexec.exe を使ってもいいのですが、それでは、クライアントプロセス用の
msiexec.exe が止まってしまいます(メッセージループが止まる)。スレッドにしてもいいのですが、それでは複雑になり
エラー要因が増えてしまいます。何よりも DLL に問題が起った際には、クライアントプロセス用の msiexec.exe 自体が
落ちてしまいます。これでは信頼性を保つことはできません。

カスタムアクション用の msiexec.exe が動作しているかどうかは、タスクマネージャーでも確認できます。
ただ、msiexec.exe が複数起動しているので、識別するのは困難ですけど。

カスタムアクションの種類とアーキテクチャを理解したら、いよいよ (3) の実装です。
これを説明するために、以下をサンプルシナリオにします。ただし、簡単に説明するためにエラー時のロールバックは無視します。

(シナリオ)

  • Windows Vista 用の MSI パッケージを作成する。Vista 専用であるため、スキーマは 400 を指定する。
  • 標準アクションで不足する部分をカスタムアクションにて実装する。カスタムアクションは
    DLL(MyExpt.dll) を呼び出すことで動作させる。使用する DLL の関数名は MyDataApi() とする。
    なお、MyDataApi() の実行は管理者権限でなければならない。
  • スクリプト内実行は、即時実行とする。
  • 実行スケジュールは、1 プロセスにつき、1 回実行とする。
  • 戻り値の処理は、終了コードを確認して同期処理を行う。
  • カスタムアクションのシーケンス名は MYDATA と定義する。

このシナリオでは、カスタムアクションを DLL で実装するとありますので
Custom Action Types 一覧から、Custom Action Type 1 になることがわかります。
そして、Type が 1 であることを覚えておいてください。

つぎに、Custom Action Reference から Custom Action In-Script Execution Options を参照します。
スクリプト内実行は、即時実行とするので、表から、0 であることがわかります。
そして、DLL を管理者権限で実行する必要があるので、msidbCustomActionTypeNoImpersonate も指定することになります。

先ほど、アーキテクチャを説明しましたが、Windows Vista では以下のようになります。(Windows Server 2008 も同じ)

————————————————————————–
msiexec.exe (サーバープロセス:Trusted Installer)

  ↓ プロセス起動

  msiexec.exe (クライアントプロセス:管理者権限(PA) or 各ユーザー権限(LUA))

   → カスタムアクション用の msiexec.exe (クライアントプロセス:各ユーザー権限(LUA))

PA:Privileged Administrator
LUA:Least-privilege User Access
————————————————————————–

上記を見ると、カスタムアクション用の msiexec.exe が LUA で動作することがわかります。
つまり、MSI に管理者権限が必要だという設定を行い、msiexec.exe の起動時に UAC により管理者権限に
昇格しても、カスタムアクション用の msiexec.exe は LUA(中 IL)で動作してしまうのです。
そのため、PA にならず、クライアントプロセス用の msiexec.exe と同じ権限で動作するように
msidbCustomActionTypeNoImpersonate を指定するわけです。

続いて、実行スケジュールですが、1 プロセスにつき、1 回実行としたので、
msidbCustomActionTypeOncePerProcess を指定します。最後に、戻り値の処理は、終了コードを確認して同期処理を行うとしたので、0 を指定します。以上より、今回のシナリオでは、Custom Action In-Script Execution Options
 : 即時実行(0)
 : msidbCustomActionTypeNoImpersonate(0x00000800)Custom Action Execution Scheduling Options
 : msidbCustomActionTypeOncePerProcess(0x00000200)Custom Action Return Processing Options
 : 同期実行(0)が必要なオプションになります。これらの数値を加えて、0 + 0x00000800 + 0x00000200 + 0 = A00
10進数に変換すると、2560 になります。最後に、Custom Action Type 1 の Type は 「1」 であるため、2560 に 1 を加えて 2561 になります。
あとは、この 2561 を CustomAction Table で該当する カスタムアクション の Type に指定すれば完了です。

つまり、CustomAction Table には

 Action  MYDATA
 Type   2561
 Source  MyExpt.dll
 Target  MyDataApi

という定義を行うことで、実装完了です。
今回の例を応用して、管理者権限が必要なカスタムアクションを実装してください。ただ、初めにもお話しましたが、可能な限りカスタムアクションは使わない方がいいものです。
複雑なものを作りこめば、その分、エラーは発生しやすくなります。
プログラムは、 Simple is best !! です。それでは、今回はこの辺で。

Windows Installer 4.5 がリリースされました

最新の Windows Installer である Windows Installer 4.5 が 2008/06/02 付けでリリースされました。

以下の URL よりダウンロードできます。
http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=5a58b56f-60b6-4412-95b9-54d056d6f9f4

なお、時期はまだ未定ですが、Windows Update の「優先度の高い更新」でも更新される予定になっています。

Windows Installer の Version 4 世代は、Windows Vista (SP1) & Windows Server 2008 で
Windows Installer 4.0 が標準バンドルであり、使用することができます。
また、Windows XP、Windows Server 2003 では Windows Installer の Version 3 世代が最新のものでした。
(Windows XP、Windows Server 2003 では Updateによって Windows Installer 3.1 が最新になる)

今回の Windows Installer 4.5 は、Windows Vista & Windows Server 2008 だけでなく
Windows XP、Windows Server 2003 もサポート OS に含まれました。
この結果、Windows Installer 4.5 は以下の OS で使用することができます。

  • Windows Vista (SP1) : x86、x64
  • Windows Server 2008 : x86、x64、IA64
  • Windows XP SP2、SP3 : x86、x64
  • Windows Server 2003 SP1、SP2 : x86、x64、IA64

Version 4 世代が、XP や 2003 でも使えるようになったのは大きいですね。
共通の MSI で対応することができるようになりましたから。

また、今回のリリースに合わせて、Windows Installer SDK もアップデートされました。

Windows Installer 4.5 Software Development Kit
http://www.microsoft.com/downloads/details.aspx?familyid=6A35AC14-2626-4846-BB51-DDCE49D6FFB6&displaylang=ja

なお、Windows Installer 4.5 のスキーマバージョンですが、405 になっています。
既存バージョンのスキーマバージョンは、 「Windows Installer その1」 をご参考にそうぞ。

では。

Windows Installer その2

今回は、MSI のバージョンアップについてのネタです。

Windows Installer MSI パッケージには、3 タイプのバージョンアップが用意されています。
一度、リリースした製品に対して、バージョンアップ用のインストールパッケージを
作成する際には、この 3 つの中から、どれが適切なのかを選択して、作成する必要があります。

  • メジャーアップグレード
    メジャーアップグレード処理では、旧バージョンをサイレントアンインストールしてから新バージョンを
    インストールします(REMOVE="ALL"でサイレント実行する)。
    もし、何かの情報を引き継ぎたいということであれば、自前で何らかの処理を加える必要もあります。
    どんなときにメジャーアップグレードを使うかというと、
    ・製品のバージョンアップ(v1.0 → v2.0)
    ・既存の製品からファイルが増えた(新しいコンポーネントが増えた)
    ・既存の製品からファイルが減った
    ・MSI の構成(インストールする機能の構成)が変わった
    こんな場合になるかと思います。
  • マイナーアップグレード
    マイナーアップグレードの目的は、製品自体のマイナーアップグレードです。
    製品のマイナーバージョン番号以降を更新して、ファイルを更新します。
    マイナーアップグレードでは、ファイルの増減はできません。必ず、旧バージョンと同じファイル数にしておく
    必要があります。
  • スモールアップデート
    スモールアップグレードは、特定のファイルのみを変更するアップグレードタイプです。
    製品自体のバージョンは一切変更しません。
    スモールアップグレードは、マイナーアップグレードと同様にファイルの増減はできません。
    必ず、旧バージョンと同じファイル数にしておく必要があります。

    特定のファイルのみということでパッチに近い考え方なのですが、「パッチは差分のみを提供するもの」
    「アップグレードはフルパッケージを提供するもの」という違いがあります。
    すべてのアップグレードタイプは、旧バージョンがインストール済みでなければ、そのバージョンのみを
    インストールするフルパッケージになります。
    パッチは、差分のみの提供になりますので、必ず、対象製品がインストール済みでなければなりません。
    (パッチについては別の機会で書きたいと思います)

そして、バージョンアップの話を進める前に、Windows Installer 内部では
どのように製品を区別しているのかを理解する必要があります。

Windows Installer では、3 つの GUID と製品バージョン を使用しています。

  • パッケージコード
    MSI ファイルを一意に識別するためのコードです。
  • 製品コード
    製品(プロダクト)を一意に識別するためのコードです。
    例えば、製品A v1.5 を製品A v2.0 をバージョンアップしたいという場合には、
    同じ製品コードのままにしておきます。もし、製品A v1.5 を製品A v2.0 を共存させたいと
    いった場合には、異なる製品コードにします。
  • アップグレードコード
    アップグレードコードは、製品ファミリーを一意に識別するために使用します。
    このコードは、旧バージョンのアンインストールの際に判定する材料です。
  • 製品バージョン
    Windows Installer では、aa.bb.cccc という形式で数値のみで識別します。
    aa は、メジャーバージョン番号を、bb は、マイナーバージョン番号を、cccc は、ビルド番号を示します。
    aa と bb は、255 以下でなければなりません。cccc は、65535 以下になります。

Windows Installer では、これらの識別子を用いて、バージョンアップの判定を行います。
では、これらをどのように使ってバージョンアップ用の MSI を作るのかというと…

  パッケージコード 製品バージョン 製品コード アップグレードコード
メジャーアップグレード 変更する 変更する 変更する そのまま
マイナーアップグレード 変更する 変更する そのまま そのまま
スモールアップグレード 変更する そのまま そのまま そのまま

のように、設定します。

ちなみに、マイナーアップグレードとスモールアップグレードの MSI ファイルは、そのまま実行する
(ダブルクリック)とエラーになります。
Windows Installer は、インストール実行時に同一の製品コードがあるかどうかを検索して、もし、
同一の製品コードが見つかった場合には、すでにインストールキャッシュされている MSI を使ってしまいます。
このため、マイナーアップグレードとスモールアップグレードを作成する場合には、セットアップランチャー
(setup.exe)を用意するか、以下のコマンドで実行する必要がありますので、注意しましょう。

msiexec /i product.msi REINSTALLMODE=voums REINSTALL=ALL

さて、アップグレードの際には、ファイルを更新するわけですから、ファイルのバージョンアップルールを
簡単に書いておきます。(詳細は、http://msdn.microsoft.com/en-us/library/aa368599(VS.85).aspx

Windows Installer では、バージョン、日付、言語の 3 つを主に判定材料にしています。

File Versioning Rule

  1. 比較対象ファイルの両方にバージョンがある
    ・バージョンの高い方を保持する
     バージョンの低いファイルよりもバージョンの高いファイルが優先される。
    ・バージョンが同じ場合
     インストール済みファイルの言語とインストールするファイルの言語を調べ
     異なる場合には、インストールするファイルを優先する。
  2. 比較対象ファイルのバージョンがない
    Windows Installer 2.0 以降はファイルハッシュ値も判定材料にしています。
    ・既存ファイルの作成日付と更新日付が異なる
     既存ファイルを優先(残し)し、ファイルのインストールは行わない。(ユーザーが更新したと見なします)
    ・既存ファイルの作成日付と更新日付が同じ
     ファイルハッシュが同じ場合には、既存ファイルを残し、ファイルハッシュが異なる場合には
     インストールするファイルを優先する。
  3. 比較対象ファイルの片方のみにバージョンがある
    ・バージョンがある方を保持する
     リソースにバージョンがあるファイルの方がバージョンの無いファイルよりも優先される。

非常に簡単に書きましたが、実際には、いろいろなことをやっています。

この辺を理解した上で、どのような動きになるのかをきちんとドキュメントに残しておくと保守の際に役立つと思います。


今回は、MSI のバージョンアップについての概要を紹介しました。
製品をリリースした以上は、次の何からのリリースがあると思います。
きちんと内部動作を理解した上で、作成するバージョンアップインストーラーをどのタイプにするかを
よーく考える必要があります。
ただ、迷ったら、メジャーアップグレードにしておくのが無難です。