WiX のカスタムアクション


msi/WiX で元々用意されている機能以外のことを実行したい場合、「カスタムアクション」を駆使する。
かなり自由度は高いが、管理者権限で操作したい場合はいろいろな制限がある(Vista以降)。

WiX 記事一覧

カスタムアクション

本記事では DLL によるカスタムアクションのみを扱っている。

  • Windows Installer のカスタムアクションは、インストーラの挙動をかなり自由に記述する仕組み。主に C/C++ で DLL を書く方法と、exe を呼ぶ方法の2種類がある。
    • VBScript などで書くことも出来る(出来た?)が、ウィルスチェックに引っかかるという理由で推奨されていない。
    • Managed code はいろいろ理由があってサポートされていないが、WiX v3.x に含まれる DTF ( Deployment Tools Foundation ) という仕組みを使えば .NETインストーラをビシバシ書けるみたいなんで、要件が許せばそっちに行くのもありかも(まだまだ開発中っぽいけど)。
  • C++ で カスタムアクション DLL を書くには、msiAPI をいろいろ叩く必要がある。
    • が、かなり原始的な API なので、生で使うのは結構大変。プロパティの値を取得するだけでも10行ちょっと必要だったり……
    • WiX には wcautil (WiX Custom Action Utilities かな?) という msi API をラップしてくれているライブラリがある。独自のインストールログを出力する機能が用意されていたりとかなり便利なのだが、残念ながらドキュメントがまだ無い。ヘッダファイルにも特に説明はないので、ソースを読むしか……。
    • でもソースを読んででも、生 msi API を叩くよりはまし*1なので、wix のソースは必須。ま、WixUIExtension の各国語リソース(日本語含む)がソースにしか入っていないので、どっちにしても必要やねんけどね。

管理者権限でカスタムアクションを実行する(UAC、セキュリティ関連)

Windows Vista からは UAC (User Account Control) が導入され、セキュリティ的な制限が色々加わった。

  • カスタムアクションを管理者権限で動作させる(権限昇格)には、CustomAction Element に Execute="deferred" と Impersonate="no" を指定する必要がある。
    • Execute="deferred" を指定されたカスタムアクションと、限られたプロパティしか受け取れないという制限がある ( http://msdn.microsoft.com/en-us/library/aa370543 必読 )。そこで、deferred で実行されるカスタムアクションより前に、カスタムアクション名と同じ名前のプロパティに渡したい値を設定する必要がある(そのカスタムアクションが実行されるときに、同名のプロパティの値が CustomActionData プロパティに設定されて呼び出される)。
    • 任意のプロパティに値を設定するには Custom Action Type 51 を使う、ってリファレンスで当たり前のように番号で語るのはやめて欲しい。さすがにもう慣れたけど(苦笑)。
  • まとめると、
    • 「deferred custom action に渡すプロパティは、カスタムアクション名のプロパティに値を設定しておき、CustomActionData プロパティで受け取る」
    • 「プロパティへの値の設定はCustom Action Type 51 を使う。プロパティへのアクセスが必要なので、もちろん immediate 実行」
<CustomAction Id="SetCustomActionData" Return="check"
    Property="値を渡したいdeferredなカスタムアクション名" Value="[渡したいプロパティ名],[渡したいプロパティ名],……" />
	:
<Custom Action="SetCustomActionData" Before="値を渡したいdeferredなカスタムアクション名"></Custom>
  • UI や msiexec の起動オプションから渡されたプロパティ ( public property ) はそのままではカスタムアクションからアクセスすることは出来ないので、プロパティの定義に Secure="yes" を付けるか、SecureCustomProperties プロパティに対象となるプロパティ名を明示する。

インストール時にファイアウォールに穴を開けたい


WiX 記事一覧

*1:でもさらに、wcautil のままではリソースの解放は明示しないといけなかったり、例外安全ではなかったり、と自前で C++ class でくるまなきゃいけなかったりするんだけどね。インストーラなんて例外起きたらその後すぐ死ぬんだから、ちょっとのリークくらい目をつぶる……とかでもいいのかなあ