2016年3月23日

Universal CRT in WiX Bootstrapper


Visual Studio 2013 の Visual C++ の各種ライブラリを配布するには以下の方法があります。
  1. スタティックリンクでビルドする
  2. マージモジュールを使用する (Microsoft_VC120_CRT_x86.msm, Microsoft_VC120_CRT_x64.msm など)
  3. Visual C++ 再頒布可能パッケージをインストールする (vcredist_x86.exe, vcredist_x64.exe)
  4. インストーラーにDLLを同梱する (msvr120.dll, msvcp120.dll など)
Visual Studio 2015 の Visual C++ では Universal CRT が導入された影響で配布方法に若干の変更が入っています。

Introducing the Universal CRT | Visual C++ Team Blog
https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/

既に解説されている方々がおられるのでいくつかリンクしておきます。

VC++2015製のアプリを配る際のランタイムDLLの扱い | イグトランスの頭の中
http://dev.activebasic.com/egtra/2015/08/30/831/

Visual C++ 14 (VS2015RC)のランタイムをインストールする | espresso3389の日記
http://espresso3389.hatenablog.com/entry/2015/05/08/033946



上記1番のスタティックリンクと3番の再配布可能パッケージについては、まあ従来通りですね。

上記4番のDLL同梱では、"%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\redist" ディレクトリ内のファイル (vcruntime140.dll, msvcp140.dll など) に加えて、"%ProgramFiles(x86)%\Windows Kits\10\Redist" ディレクトリ内のファイル (ucrtbase.dll, api-ms-win-core-******.dll, api-ms-win-crt-******.dll) を同梱します。

上記2番のマージモジュールでは、従来のマージモジュールに加えて以下の Universal CRT の msu ファイルをインストーラーに含めてインストールするために、WiX であれば Bootstrapper にしてしまうのが良さそうです。再頒布可能パッケージと同じような方法ですね。

Windows 10 Universal C Runtime (KB2999226) (10.0.10240)
https://www.microsoft.com/ja-JP/download/details.aspx?id=48234
https://support.microsoft.com/en-us/kb/2999226

Windows 10 Universal C Runtime (KB3118401) (10.0.10586)
https://www.microsoft.com/ja-JP/download/details.aspx?id=50410
https://support.microsoft.com/en-us/kb/3118401

msu ファイルには現在2つのバージョンがあるのですが、Windows Update で降ってくるのはKB3118401、Visual Studio 2015 Update 1 の Visual C++ 再頒布可能パッケージに含まれているのはKB2999226になっています。どちらでも使えそうなのですが、とりあえず新しいKB3118401のほうを 使ってみます。

Visual Studio 2015 Update 1 の Visual C++ 再頒布可能パッケージ
https://www.microsoft.com/ja-jp/download/details.aspx?id=49984

XP 用の msu ファイルが見当たらないですが、XP 用の Universal CRT はマージモジュール (Microsoft_VC140_CRT_x86.msm, Microsoft_VC140_CRT_x64.msm) に含まれているようです。

で、msu ファイルを含めた Bootstrapper をさっくりと作ってみました。msu ファイルのシステム要件のチェックも入れつつ、インストール済みかどうかも一応チェックしています。msi ファイルについてはマージモジュールを含んだものとします。所々枠からはみ出してしまっていますがご容赦を。

追記 : 下記のwxsを書き直しました。
Universal CRT in Wix Bootstrapper (2)


TestUCRT.wxs

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
  xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
  xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

  <Bundle Name="program name" Version="1.0.0.0" Manufacturer="author name"
    UpgradeCode="12345678-9012-3456-7890-123456789012"
    Condition="VersionNT &gt;= v5.1" >

    <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
      <bal:WixStandardBootstrapperApplication
        LicenseFile="license.rtf" SuppressOptionsUI="yes" />
    </BootstrapperApplicationRef>

    <!-- v6.0 Service Pack 2 -->
    <bal:Condition Message="This application requires Service Pack 2 for Windows Vista / Server 2008.">
      (VersionNT &lt;&gt; v6.0) OR ((VersionNT = v6.0) AND (ServicePackLevel &gt;= 2))
    </bal:Condition>

    <!-- v6.1 Service Pack 1 -->
    <bal:Condition Message="This application requires Service Pack 1 for Windows 7 / Server 2008 R2.">
      (VersionNT &lt;&gt; v6.1) OR ((VersionNT = v6.1) AND (ServicePackLevel &gt;= 1))
    </bal:Condition>

    <!-- v6.3 KB2919355 -->
    <util:FileSearch Id="HAL.DLL" Path="[WindowsFolder]System32\hal.dll"
      Result="version" Variable="NT603HALVER" Condition="VersionNT = v6.3" />
    <bal:Condition Message="This application requires S14 Update (KB2919355) for Windows 8.1 / Server 2012 R2.">
      (VersionNT &lt;&gt; v6.3) OR ((VersionNT = v6.3) AND (NT603HALVER &gt; v6.3.9600.16500))
    </bal:Condition>

    <!-- installed ucrtbase.dll version -->
    <util:FileSearch Id="UCRTBASE.DLL_SYS" Path="[WindowsFolder]System32\ucrtbase.dll"
      Result="version" Variable="UCRTVERSYS" />
    <util:FileSearch Id="UCRTBASE.DLL_X86" Path="[WindowsFolder]SysWOW64\ucrtbase.dll"
      Result="version" Variable="UCRTVERX86" Condition="VersionNT64" />
    <!-- KB3118401 ucrtbase.dll version -->
    <Variable Name="UCRTVER" Type="version" Value="10.0.10586.9" />

    <Chain>

      <!-- Windows Vista / Windows Server 2008 (x86) -->
      <MsuPackage Name="Windows6.0-KB3118401-x86.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows6.0-KB3118401-x86.msu"
        InstallCondition="(VersionNT = v6.0) AND (NOT VersionNT64) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER))" />

      <!-- Windows Vista / Windows Server 2008 (x64) -->
      <MsuPackage Name="Windows6.0-KB3118401-x64.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows6.0-KB3118401-x64.msu"
        InstallCondition="(VersionNT64 = v6.0) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER) OR (NOT UCRTVERX86) OR (UCRTVERX86 &lt; UCRTVER))" />

      <!-- Windows 7 (x86) -->
      <MsuPackage Name="Windows6.1-KB3118401-x86.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows6.1-KB3118401-x86.msu"
        InstallCondition="(VersionNT = v6.1) AND (NOT VersionNT64) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER))" />

      <!-- Windows 7 / Windows Server 2008 R2 (x64) -->
      <MsuPackage Name="Windows6.1-KB3118401-x64.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows6.1-KB3118401-x64.msu"
        InstallCondition="(VersionNT64 = v6.1) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER) OR (NOT UCRTVERX86) OR (UCRTVERX86 &lt; UCRTVER))" />

      <!-- Windows 8 (x86) -->
      <MsuPackage Name="Windows8-RT-KB3118401-x86.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows8-RT-KB3118401-x86.msu"
        InstallCondition="(VersionNT = v6.2) AND (NOT VersionNT64) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER))" />

      <!-- Windows 8 / Windows Server 2012 (x64) -->
      <MsuPackage Name="Windows8-RT-KB3118401-x64.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows8-RT-KB3118401-x64.msu"
        InstallCondition="(VersionNT64 = v6.2) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER) OR (NOT UCRTVERX86) OR (UCRTVERX86 &lt; UCRTVER))" />

      <!-- Windows 8.1 (x86) -->
      <MsuPackage Name="Windows8.1-KB3118401-x86.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows8.1-KB3118401-x86.msu"
        InstallCondition="(VersionNT = v6.3) AND (NOT VersionNT64) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER))" />

      <!-- Windows 8.1 / Windows Server 2012 R2 (x64) -->
      <MsuPackage Name="Windows8.1-KB3118401-x64.msu"
        DisplayName="Universal CRT" KB="KB3118401" Permanent="yes" Cache="no"
        SourceFile="Windows8.1-KB3118401-x64.msu"
        InstallCondition="(VersionNT64 = v6.3) AND ((NOT UCRTVERSYS) OR (UCRTVERSYS &lt; UCRTVER) OR (NOT UCRTVERX86) OR (UCRTVERX86 &lt; UCRTVER))" />

      <!-- x64 modules -->
      <MsiPackage Id="X64" DisplayName="x64 modules" ForcePerMachine="yes"
        Compressed="yes" SourceFile="x64.msi" InstallCondition="VersionNT64" />

      <!-- x86 modules -->
      <MsiPackage Id="X86" DisplayName="x86 modules" ForcePerMachine="yes"
        Compressed="yes" SourceFile="x86.msi" />

    </Chain>
  </Bundle>
</Wix>

で、ビルトはこんな感じで。
> candle.exe TestUCRT.wxs -out TestUCRT.wixobj -ext WixBalExtension -ext WixUtilExtension
> light.exe TestUCRT.wixobj -out TestUCRT.exe -ext WixBalExtension -ext WixUtilExtension

msu ファイルの替わりにExePackageタグを使って再配布可能パッケージを入れてもいいのですが、再配布パッケージに含まれる msu ファイルが VC_redist.x86.exe と VC_redist.x64.exe とで重複してしまうので、x86とx64両方のバイナリをインストールする必要がある場合はファイルサイズがその分大きくなってしまうのが難点ですね。
再配布パッケージの内容物は次のコマンドで展開することで確認できます。
> dark.exe VC_redist.x86.exe -x x86
> dark.exe VC_redist.x64.exe -x x64