【BAT】Microsoft Visual C++ 再頒布可能パッケージのインストール確認

# はじめに
「[WinFormsでChromiumブラウザコンポーネント(CefSharp)を使ってみる](https://qiita.com/yaju/items/97b61d0d8bc3f9ed044d)」の記事に書いたのですが、CefSharpを使うには、「Visual Studio C++ 2015 redistributables(再頒布可能パッケージ)」以上が必要となります。
ユーザーにCefSharpを使用したアプリケーションを配布する際、オフライン向けのインストール用バッチを作成することにしました。

# インストール済の確認
今回の.NETアプリケーションはAnyCPUとしているので、32bit(x86) か 64bit(x64) かの判断も行います。
また、2015以上が既にインストールされている場合はインストール済みとします。

* Visual Studio C++ 2015 Redistributable (x86)
* Visual Studio C++ 2015 Redistributable (x64)

インストール済みかの判断は、レジストリのアンインストール情報を取得します。

|CPU|レジストリのアンインストール情報|
|:--|:--|
|32bit|HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall|
|64bit|HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall|

vc_redistフォルダ配下にVisual Studio C++ 2015 redistributables(再頒布可能パッケージ)を配置しておきます。

* vc_redist.x86.exe
* vc_redist.x64.exe

## 注意
2012からRedistributable (x99) 形式で統一されているのですが、それより前は統一されていませんでした。
今回は、2015以上インストール済みかなので Redistributable (x99)形式で抽出しています。
また、2015以上かどうかはバージョン番号ではなく年(2015)で判断しています。最初はメジャーバージョンで判断してたのですが、2015と2017と2019は同じ14だった。

|CPU|レジストリのアンインストール情報|
|:--|:--|
|32bit|Visual Studio C++ 2005 Redistributable|
|64bit|Visual Studio C++ 2005 Redistributable (x64)|
|32bit|Visual Studio C++ 2008 Redistributable - x86 9.0.xxxxx|
|64bit|Visual Studio C++ 2008 Redistributable - x64 9.0.xxxxx|
|32bit|Visual Studio C++ 2010 x86 Redistributable - 10.0.xxxxx|
|64bit|Visual Studio C++ 2010 x64 Redistributable - 10.0.xxxxx|
|32bit|Visual Studio C++ 2012 Redistributable (x86) - 11.0.xxxxx|
|64bit|Visual Studio C++ 2012 Redistributable (x64) - 11.0.xxxxx|
|32bit|Visual Studio C++ 2013 Redistributable (x86) - 12.0.xxxxx|
|64bit|Visual Studio C++ 2013 Redistributable (x64) - 12.0.xxxxx|
|32bit|Visual Studio C++ 2015 Redistributable (x86) - 14.0.xxxxx|
|64bit|Visual Studio C++ 2015 Redistributable (x64) - 14.0.xxxxx|
|32bit|Visual Studio C++ 2017 Redistributable (x86) - 14.16.xxxxx|
|64bit|Visual Studio C++ 2017 Redistributable (x64) - 14.16.xxxxx|
|32bit|Visual Studio C++ 2019 Redistributable (x86) - 14.23.xxxxx|
|64bit|Visual Studio C++ 2019 Redistributable (x64) - 14.23.xxxxx|


## バッチ版
最初にバッチのみで作成したのですが、レジストリ情報の検索(REG QUERYコマンド)が遅いんですよね。
自分のPCは確かに開発用にいろいろインストールされているのですが、インストール済みの判定だけで1分以上かかります。

```bat:Install.bat
@echo off
cd /d %~dp0
set vcInstall=0
set vcVersion=2015

setlocal enabledelayedexpansion

echo Microsoft Visual C++ 再頒布可能パッケージ 2015のインストール

if "%PROCESSOR_ARCHITECTURE%" equ "x86" (
            call :DetectVC x86 HKEY_LOCAL_MACHINE\Software
            if !vcInstall!==0 start /wait vc_redist\vc_redist.x86.exe
)
if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" (
            call :DetectVC x64 HKEY_LOCAL_MACHINE\Software\Wow6432Node
            if !vcInstall!==0 start /wait vc_redist\vc_redist.x64.exe
)

endlocal
exit /b

REM -------------------------------------------------------
REM Microsoft Visual C++ 再頒布可能パッケージ 2015以上の検出 
REM -------------------------------------------------------
:DetectVC
set "vcfindname=Redistributable (%1)"

for /f "TOKENS=1,2,*" %%A in ('REG QUERY "%2\Microsoft\Windows\CurrentVersion\Uninstall" /s ^| find "DisplayName"') do (
echo %%C | find "%vcfindname%" >NUL
if not ERRORLEVEL 1 (
	set str=%%C
	set vcver=!str:~21,4!
	set vcver=!vcver:ab=0!
	if !vcver! geq %vcVersion% (
		set vcInstall=1
	)
)
)

if %vcInstall%==1 (
	echo.
	echo Microsoft Visual C++ 再頒布可能パッケージ 2015以上インストール済み
) else (
	echo.
	echo Microsoft Visual C++ 再頒布可能パッケージ 2015以上未インストール
)

exit /b
```

## VBScript版
VBScriptにしたら数秒でインストール済みの判定ができました。
vc_redistフォルダ配下にCheckVCRedist.vbsを配置します。

```VB:CheckVCRedist.vbs
Option Explicit
'On Error Resume Next
Const HKEY_LOCAL_MACHINE = &H80000002
Const SubKeyName = "Microsoft\Windows\CurrentVersion\Uninstall\"
Const VCVersion = 2015

Dim WshShell, arch, reg, firstkey, keys, key, ret, display_name
Set WshShell = WScript.CreateObject("WScript.Shell")
arch = WshShell.Environment("Process").Item("PROCESSOR_ARCHITECTURE")

If arch = "x86" Then
    firstkey = "SOFTWARE\"
Else
    firstkey = "SOFTWARE\Wow6432Node\"
    arch = "x64"
End If

Set reg = CreateObject("WbemScripting.SWbemLocator").ConnectServer(, "root\default").Get("StdRegProv")
reg.EnumKey HKEY_LOCAL_MACHINE, firstkey & SubKeyName, keys

For Each key In keys
   display_name = ""  
   ret = reg.GetStringValue(HKEY_LOCAL_MACHINE, firstkey & SubKeyName & key, "DisplayName", display_name)
   If Instr(display_name, "Redistributable (" & arch & ")") > 0 Then
       If CInt(Mid(display_name, 22, 4)) >= VCVersion Then
           Wscript.Quit(1)
       End If
   End If
Next

Wscript.Quit(0)
```

検出の内容を「cscript //nologo vc_redist\CheckVCRedist.vbs」に変更します。

```bat:Install.bat
@echo off
cd /d %~dp0
set vcInstall=0
set vcVersion=2015

echo Microsoft Visual C++ 再頒布可能パッケージ 2015のインストール
call :DetectVC

if "%PROCESSOR_ARCHITECTURE%" equ "x86" (
            if %vcInstall%==0 start /wait vc_redist\vc_redist.x86.exe
)
if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" (
            if %vcInstall%==0 start /wait vc_redist\vc_redist.x64.exe
)

exit /b

REM -------------------------------------------------------
REM Microsoft Visual C++ 再頒布可能パッケージ 2015以上の検出 
REM -------------------------------------------------------
:DetectVC

cscript //nologo vc_redist\CheckVCRedist.vbs

set vcInstall=%ERRORLEVEL%

if %vcInstall%==1 (
	echo.
	echo Microsoft Visual C++ 再頒布可能パッケージ 2015以上インストール済み
) else (
	echo.
	echo Microsoft Visual C++ 再頒布可能パッケージ 2015以上未インストール
)

exit /b
```

# 最後に
REG QUERYコマンドがこんなに遅いとは、インストールは最初の1回だけとはいえユーザーが不安になるレベルの遅さなの、VBScript版が速くて良かった。

# 参照
* [リモートレジストリサービスを使った64bit版Windows 7端末のUninstall情報の取得について](https://social.msdn.microsoft.com/Forums/ja-JP/694bb2a1-1b85-4eb8-8f5e-b696d7f9887f/12522125141254012488125241247212473124881252212469125401249912?forum=vcgeneralja)
* [WMIを使用したレジストリのサブキー列挙 - moug.net](https://www.moug.net/faq/viewtopic.php?t=77807)