for WPF developers
Home Profile Tips 全記事一覧

モダンなインストーラへの道 3 ~ カスタム UI を msi インストーラパッケージと紐付ける ~

(2017/04/05 14:35:06 created.)

(2017/05/24 15:14:16 modified.)

前回までで、簡単なインストーラを作成するこ]とができるようになりました。
今回は、いよいよカスタム UI をインストーラとして使用できるようにしたいと思います。

WiX では Bootstrapper Project によって msi インストーラパッケージやカスタム UI の dll ファイルをすべてペイロードとして exe パッケージを作成します。
イメージとしては次のようになります。


そんなわけでカスタム UI の参照は DLL 経由となります。
そこで、まずインストーラとして使用する UI を作成するためのプロジェクトを追加しましょう。
ここでは WPF カスタムコントロールライブラリのプロジェクトを "InstallerUI" という名前で追加します。


WPF カスタムコントロールライブラリのプロジェクト構成はデフォルトでは次のようになっています。


インストーラ用の UI として WiX と紐付けるために、参照設定などを次のように変更します。

  • Themes フォルダならびに CustomControl1.cs を削除
  • 参照設定に以下を追加
    BootstrapperCore.dll
    Microsoft.Deployment.WindowsInstaller.dll
    どちらも C:\Program Files\WiX Toolset v3.10\SDK\ にあります。
  • アプリケーション構成ファイル BootstrapperCore.config を追加
  • ウィンドウとして MainView クラスを追加
  • YKBootstrapperApplication クラスを追加


アプリケーション構成ファイルの中身は次のようにします。

BootstrapperCore.config
  1. xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.   <configSections>
  4.     <sectionGroup name="wix.bootstrapper" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperSectionGroup, BootstrapperCore">
  5.       <section name="host" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.HostSection, BootstrapperCore" />
  6.     </sectionGroup>
  7.   </configSections>
  8.  
  9.   <startup>
  10.     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
  11.   </startup>
  12.  
  13.   <wix.bootstrapper>
  14.     <host assemblyName="InstallerUI" />
  15.   </wix.bootstrapper>
  16. </configuration>

また、YKBootstrapperApplication クラスは Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperApplication クラスを基本クラスとして次のように定義します。

YKBootstrapperAplication.cs
  1. namespace InstallerUI
  2. {
  3.     using Microsoft.Tools.WindowsInstallerXml.Bootstrapper;
  4.     using System.Windows.Threading;
  5.  
  6.     public class YKBootstrapperApplication : BootstrapperApplication
  7.     {
  8.         protected override void Run()
  9.         {
  10.             var dispatcher = Dispatcher.CurrentDispatcher;
  11.             var w = new MainView();
  12.             w.Closed += (_, __) => dispatcher.InvokeShutdown();
  13.  
  14.             this.Engine.Detect();
  15.             w.Show();
  16.             Dispatcher.Run();
  17.             this.Engine.Quit(0);
  18.         }
  19.     }
  20. }

WiX の Bootstrapper Project からこの WPF カスタムコントロールライブラリの DLL ファイルを参照されるようになりますが、
実は、このときのエントリポイントが BootstrapperApplication クラスの Run() メソッドになります。
したがって、通常の WPF アプリケーションプロジェクトで Application クラスの Startup() メソッドでおこなっていたような処理を、この Run() メソッドでおこなうことになります。
ここでは MainView ウィンドウを表示するようにしています。
14 行目の Detect() メソッドは Microsoft.Tools.WindowsInstallerXml.Bootstrapper.Engine クラスに用意されているメソッドで、インストール条件がすべて満たされているかどうかを確認しています。

それでは、WiX の Bootstrapper Project のプロジェクトをソリューションに追加しましょう。


Bundle.wxs というファイルでインストーラの exe ファイルを生成するための XML コードを記述します。
デフォルトのままでは少し足りないので、次のような変更をしています。

  • References に WixUtilExtension.dll への参照を追加
    "References" を右クリックし、「参照の追加」メニューから簡単に追加できます。
  • .NET Framework のインストーラ dotNetFx40_Full_x86_x64.exe をプロジェクトに追加


WiX によって生成するインストーラは、通常は .NET Framework を必要としないインストーラですが、
カスタム UI を使用する場合は .NET Framework が必要となるため、インストーラ用に .NET Framework のインストーラが必要になります。
web 経由で指定することもできるようですが、ここではローカルに .NET Framework のインストーラを保存し、これを参照するようにするため、ダウンロードしてきた .NET Framework のインストーラをプロジェクトのファイルとして含めています。
このファイルはこちらからダウンロードできます。

それでは、Bundle.wxs の中身について見てみましょう。

Bundle.wxs
  1. xml version="1.0" encoding="UTF-8"?>
  2. <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  3.   <Bundle Name="AppSetup" Version="1.0.0.0" Manufacturer="YKSoftware" UpgradeCode="b8dbe519-5748-4e6e-a73d-9404b7fccbec">
  4.     <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost">
  5.       <Payload SourceFile="../InstallerUI/BootstrapperCore.config" />
  6.       <Payload SourceFile="../InstallerUI/bin/Release/InstallerUI.dll" />
  7.       <Payload SourceFile="C:/Program Files/WiX Toolset v3.10/SDK/Microsoft.Deployment.WindowsInstaller.dll" />
  8.     </BootstrapperApplicationRef>
  9.  
  10.     <Chain>
  11.       <PackageGroupRef Id="Netfx4Full" />
  12.       <MsiPackage Id="SampleWpfApplicationInstallerPackage" SourceFile="../Installer/bin/Release/Installer.msi" Cache="yes" Vital="no" />
  13.     </Chain>
  14.   </Bundle>
  15.  
  16.   <Fragment>
  17.     <WixVariable Id="WixMbaPrereqPackageId" Value="Netfx4Full" />
  18.     <WixVariable Id="WixMbaPrereqLicenseUrl" Value="NetfxLicense.rtf" />
  19.  
  20.     <util:RegistrySearch Root="HKLM" Key="SOFTWARE/NET Framework Setup/NDP/v4/Full" Value="Version" Variable="Netfx4FullVersion" />
  21.     <util:RegistrySearch Root="HKLM" Key="SOFTWARE/NET Framework Setup/NDP/v4/Full" Value="Version" Variable="Netfx4x64FullVersion" Win64="yes" />
  22.  
  23.     <PackageGroup Id="Netfx4Full">
  24.       <ExePackage Id="Netfx4Full" Cache="no" Compressed="yes" PerMachine="yes"
  25.                   Permanent="yes" Vital="yes" SourceFile="../../dotNetFx40_Full_x86_x64.exe"
  26.                   DetectCondition="Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)"
  27.                   InstallCondition="(VersionNT < v6.0 OR VersionNT64 < v6.0) AND (NOT (Net4FullVersion OR Net4x64FullVersion))" />
  28.     </PackageGroup>
  29.   </Fragment>
  30. </Wix>

ペイロードするものをすべて BootstrapperApplicationRef に登録しています。
ここではカスタム UI のアプリケーション構成ファイルと生成物である dll ファイルを指定しています。
また、カスタム UI に必要な外部参照ファイルを指定しなければいけないため、Microsoft.Deployment.WindowsInstaller.dll も追加しています。

Chain 要素にインストーラパッケージを詰め込みます。
ここではインストーラに必要な .NET Framework のインストーラと、本来の目的である Installer.msi ファイルを登録しています。
.NET Framework のインストーラは、条件によってはインストールする必要がないため、 PackageGroupRef 要素を使って ExePackage を参照させることで条件を付加しています。
その条件とは、Windows Vista 以降か、または .NET Framework 4.0 以降がインストール済みかどうか、をレジストリを探索することで確認しています。

それではビルドしてみましょう。プロジェクトの依存関係を適切に設定しておくことで、ビルド順序を自動的に判別して各プロジェクトをビルドしてくれるので、必ず設定しておきましょう。


すると exe ファイルが生成されます。


それでは早速 exe ファイルを実行してみましょう。


MainView ウィンドウが表示されれば成功です。
.NET Framework 4.0 以降がインストールされていない PC で実行すると、まず .NET Framework 4.0 のインストーラが起動するはずです。

ちょっと冒頭のイメージ図で状況を整理しておきましょう。


WiX の Bootstrapper Project は本来インストールさせたい SampleWpfApplication という WPF アプリケーションのインストーラパッケージである msi ファイルと、そのインストーラの UI として使用する WPF カスタムコントロールライブラリの dll を持っています。また、インストーラが必要とする .NET Framework のインストーラも持っています。
実際のインストール処理は元々の msi ファイルがおこないますが、そのキックをかけるのは BootstrapperApplication クラスを持つカスタム UI になります。
したがって、今後はカスタム UI を編集していくことで、インストーラを作り上げていくことになります。

これでいよいよ好きな UI でインストーラを作成することができるようになってきました。
次回はここで作成した MainView ウィンドウでインストール/アンインストールを実行できるようにカスタマイズしていきます。