VcXsrvの二重起動を防止するVBScriptをささっと作る

# はじめに
Windows10は良い，実に良い。WSL (Windows Subsystem for Linux) が使えるからだ。Linux を常用している人には不満かもしれないが，自分のようにたまに使う程度であれば，これで十分だと思う。Windows とのデータ交換も便利だし，何より Linux 用の HDD を用意しなくて済む。

X サーバに VcXsrv を使用している人も多いだろう。VcXsrv の起動には付属の XLaunch を使用していると思うが，起動するたびに以下のような設定画面が毎回表示されて実に鬱陶しいのだ。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/5e7b0c1e-5113-5ed8-ff48-beb06a8e4db8.gif">

解決策はさほど難しくない。まず上記の起動画面にて設定ファイルを適当な名前で適当なフォルダに保存する。設定ファイルは XML 形式となっている。

```xml:config.xlaunch
<?xml version="1.0" encoding="UTF-8"?>
<XLaunch WindowMode="MultiWindow" ClientMode="NoClient" LocalClient="False" Display="-1"
LocalProgram="xcalc" RemoteProgram="xterm" RemotePassword="" PrivateKey="" RemoteHost=""
RemoteUser="" XDMCPHost="" XDMCPBroadcast="False" XDMCPIndirect="False" Clipboard="True"
ClipboardPrimary="True" ExtraParams="" Wgl="False" DisableAC="True" XDMCPTerminate="False"/>
```

次に XLaunch を起動するショートカットを作成し，`-run` オプションを付けて先の設定ファイルを指定すれば良い。

```
C:\Program Files\VcXsrv\xlaunch.exe -run c:/users/********/config.xlaunch
```

ところがだ・・・こうすると VcXsrv は一瞬で起動するうえ，とても静かに起動する・・・が，逆に何のメッセージも表示されないため，クリックミスを疑って多重起動してしまうというミスを多発してしまった。メモリが溢れない限り，気にしない人も多いかもしれない。

# 解決方法
VcXsrv を起動する XLaunch を起動する VBScript を作成し，二重起動をチェックする。また，起動を目立たせるためスプラッシュウィンドウを表示させる。

# スプラッシュ画面の表示
コチラは簡単である。`WScript.Shell` オブジェクトの `PopUp` メソッドを使えば良い。このメソッドは指定したメッセージを指定した時間だけ表示した後，自動的に閉じてくれる。また，メソッドの終了を待たなくて良い。参考資料も多い。

```vb:スプラッシュ画面の表示
Dim	shell: Set shell = CreateObject("WScript.Shell")
Dim	msg(1)
msg(0) = "VCXSRV.EXE を起動しています・・・"
msg(1) = "（このウィンドウは自動的に閉じます）"
shell.PopUp Join(msg, vbCrLf), 5, "二重起動防止スクリプト", vbOkOnly
```

# 二重起動チェック

コチラは WMI (Windows Management Infrastructure) を使う。まずは WMI サーバーオブジェクトを取得する。取得方法は二種類あるようだ。

```vb:WMI サーバーオブジェクトの取得方法その１
Dim loc: Set loc = CreateObject("WbemScripting.SWbemLocator") 
Dim wmic: Set wmic = loc.ConnectServer(".", "root\cimv2")
```

```vb:WMI サーバーオブジェクトの取得方法その２
Dim wmic: Set wmic = GetObject("winmgmts:\\.\root\cimv2")
```

次に得られた WMI サーバーオブジェクトを用いてプロセスを検索すればよい。プロセスリストを取得して検索しても良いが，この場合はプロセス名の大文字・小文字に注意する必要がある。

```vb:プロセス検索方法その１
Dim	list: Set list = wmic.ExecQuery("Select * From Win32_Process")
Dim	proc
For Each proc in list
	If UCase(proc.Name) = "VCXSRV.EXE" Then
		MsgBox "既に VCXSRV.EXE は起動しています!!", vbExclamation
		WScript.Quit
	End If
Next
```

一方，名前付きでプロセスを検索するときは大文字・小文字の区別はないようだ。

```vb:プロセス検索方法その２
Dim	list: Set list = wmic.ExecQuery("Select * From Win32_Process Where Name='VCXSRV.EXE'")
If list.Count > 0 Then
	MsgBox "既に VCXSRV.EXE は起動しています!!", vbExclamation
	WScript.Quit
End If
```

# 実装コード

以上をまとめると次のようなコードになる。VcXsrv を起動する XLaunch を起動するスクリプトなので XLaunch Launch，すなわち XLaunch² である。

```vb:XLaunch2.vbs
Option Explicit
'-------------------------------------------------------------------------------
' VCXSRV.EXE の二重起動チェック
'-------------------------------------------------------------------------------
Dim	wmic: Set wmic = GetObject("WinMgmts:Root\Cimv2")
Dim	list: Set list = wmic.ExecQuery("Select * From Win32_Process Where Name='VCXSRV.EXE'")
If list.Count > 0 Then
	MsgBox "既に VCXSRV.EXE は起動しています!!", vbExclamation, "二重起動防止スクリプト"
	WScript.Quit
End If
'-------------------------------------------------------------------------------
' スプラッシュウィンドウの表示　※5秒間表示する
'-------------------------------------------------------------------------------
Dim	shell: Set shell = CreateObject("WScript.Shell")
Dim	msg(1)
msg(0) = "VCXSRV.EXE を起動しています・・・"
msg(1) = "（このウィンドウは自動的に閉じます）"
shell.PopUp Join(msg, vbCrLf), 5, "二重起動防止スクリプト", vbOkOnly
'-------------------------------------------------------------------------------
' VCXSRV.EXE の起動
'-------------------------------------------------------------------------------
shell.CurrentDirectory = "C:\Program Files\VcXsrv"
shell.Run "xlaunch.exe -run c:/users/*******/config.xlaunch"
```

# 起動画面

VcXsrv が既に起動されていなければ次のような起動画面が５秒間表示される。ちなみに「OK」ボタンを押すとスプラッシュ画面は閉じられるが，VcXsrv はそのまま起動される。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/2f03222a-a834-ea04-65b8-2ab9abb212a6.png">

多重起動の場合は次のようなエラー画面が表示される。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/7acfe89b-a96d-c23f-a0e1-0f6e12a26938.png">

# 参考文献
スプラッシュ画面関連
- [第7回　WshShellオブジェクトの詳細(3) - atmarkit](https://atmarkit.itmedia.co.jp/ait/articles/0410/21/news099_3.html)
- [第13回　WshShellオブジェクトを利用する(2) - atmarkit](https://atmarkit.itmedia.co.jp/ait/articles/0711/28/news140_3.html)
- [VBScript で、すぐに消えるダイアログを表示する - Qiita](https://qiita.com/KazTag/items/f5a227c33bdf5bd0fb07)

WMI (Windows Management Infrastructure) 関連
- [WMI スクリプトの作成 - Microsoft](https://learn.microsoft.com/ja-jp/windows/win32/wmisdk/creating-a-wmi-script)
- [WMI - マイクロソフト系技術情報 Wiki](https://techinfoofmicrosofttech.osscons.jp/index.php?WMI)
- [【VBScript】実行中のプロセス一覧を取得する方法 - 秋拓技術学院](https://syutaku.blog/vbscript-wbemscripting-swbemlocator-get-win32process/)