VBScriptでGUIプログラム作りたかったのでとりあえず作ってみた、のその後

#本題の前に
<a href="https://qiita.com/SZKT8816/items/1b32995f56b88e7245e3">この記事</a>のその後について記載します
vbsから.netのフォームライブラリで作成したリストボックスや複数項目あるインプットボックスを利用できるライブラリもどきです
win10なら動くと思います、vbsでGUIっぽいツール作るときに使ってください
（基本的に自分用ですが）

#できたもの
*  ファイル構成は以下、各ソースファイルの内容は後述の通り　以下を1つのフォルダにまとめると良いです
（構成間違ってたので書き直し）
 * setup.vbs
 * FormLibrary.vbs
        * easygui
            * arg(フォルダ)
                * (ファイル無し) 
            * ps(フォルダ)
                * MultiInputBox.ps1
                * SingleListBox.ps1 

  
こんな感じです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521980/a5602a7a-e021-cdd8-7d5e-d6ccf1534282.png)
          
* 各ファイルの内容　コピペしてください

```MultiInputBox.ps1
using namespace System.Windows.Forms
using namespace System.Collections.Generic
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[Application]::EnableVisualStyles()

#実行中のパス取得サンプルソース
$path = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $path

#指定のパスへ置換
$path = $path.Replace('ps', 'arg')
$path = $path + "\" + $Args[0]

# フォームを先に作成する
$frame = New-Object Form
$frame.Text = $Args[2]

#テキストボックスの数を決定する変数（2未満にはならず、最大5）
$Formcnt = [int]$Args[1]

#ラベルの名称配列 文字は「,」区切りで受ける
$Tlab = $Args[3].Split(",")

#ラベルの初期高さを変数へ格納
$Hlab = 20

#テキストボックスの初期高さを変数へ格納
$Htxt = 40

#ボタンの高さを計算して変数へ格納
$Hbtn = 120 + ($Formcnt - 2) * 40

#フォーム自身の高さを計算して変数へ格納
$Hform = 220 + ($Formcnt - 2) * 40

#フォームのサイズを決定する
$frame.Size = "500, " + [string]$Hform

#テキストボックスのリストオブジェクトを生成(各テキストを参照する場合は配列内の要素のtextプロパティを参照する)
$txts = New-Object List[System.Windows.Forms.TextBox]

# ラベルを動的生成するループ
for($i=1; $i -le $Formcnt; $i++) {
	$label = New-Object Label
	$label.Text = $Tlab[$i - 1]
	$label.Name = "Label" + [string]$i
	$label.Font = New-Object Drawing.Font("Meiryo UI",8)
	$label.Location = "20, " + [string]$Hlab
	$label.AutoSize = $True
	$Hlab = $Hlab + 40
	$frame.Controls.Add($label)
}

# テキストを動的生成するループ
for($j=1; $j -le $Formcnt; $j++) {
	$txt = New-Object TextBox
	$txt.Name = "textbox" + [string]$j
	$txt.Location = "20, " + [string]$Htxt
	$txt.Size = "350, 40"
	$Htxt = $Htxt + 40
	$frame.Controls.Add($txt)
	$txts.Add($txt)
}

# ボタン
$btn = New-Object Button
$btn.Text = "OK"
$btn.Font = New-Object Drawing.Font("Meiryo UI",18)
$btn.Size = "120, 50"
$btn.Location = "350, " + [string]$Hbtn

# ボタンイベント
$btn_Click = {
	#入力した文字列を回収
	$result = ""
	$cnt = $Formcnt - 1
	for($k=0; $k -le $cnt; $k++) {
		$result = $result + $txts[$k].Text
		If($k -le $cnt - 1){
			$result = $result + "`r`n" #ループの最後以外は改行を加える
		}
	}
	#戻り値をテキストファイルへ出力(SJISで出力)
	Add-Content -path $path -value $result -encoding String
	$frame.Close()
}
$btn.Add_Click($btn_Click)

#ボタンの要素をフォームへ加える
$frame.Controls.Add($btn)

#フォーム表示
$frame.ShowDialog()
```

```SingleListBox.ps1
using namespace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
 
[Application]::EnableVisualStyles()

#実行中のパス取得サンプルソース
$path = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $path

#指定のパスへ置換
$path = $path.Replace('ps', 'arg')
$path = $path + "\" + $Args[0]

#フォームの上側部分

  # ラベル
  $label = New-Object Label
  $label.Text = $Args[1] 
  $label.Name = "Label1"
  $label.Font = New-Object Drawing.Font("Meiryo UI",8)
  $label.Location = "10, 10"
  $label.AutoSize = $True

  # リストボックスの設定
  $listBox = New-Object ListBox
  $listBox.Location = "10, 30"
  $listBox.Size = "480, 210"

  #リストボックスへ一覧を格納
  #対象の値を「,」区切りで受ける
  $Arrlist = $Args[4].Split(",")
  #配列を一覧へ入れていく
  foreach($a in $Arrlist){
    [void] $listBox.Items.Add($a)
  }

#フォームの下側部分

  # ラベル
  $label2 = New-Object Label
  $label2.Text = $Args[2] 
  $label2.Name = "Label2"
  $label2.Font = New-Object Drawing.Font("Meiryo UI",8)
  $label2.Location = "10, 250"
  $label2.AutoSize = $True

  # 入力欄
  $txt = New-Object TextBox
  $txt.Name = "textbox1"
  $txt.Size = "480, 40"
  $txt.Location = "10, 270"
  $txt.Enabled = $False

  # ボタン
  $btn = New-Object Button
  $btn.Text = "OK"
  $btn.Font = New-Object Drawing.Font("Meiryo UI",18)
  $btn.Size = "100, 50"
  $btn.Location = "390, 320"
  
  # ボタンイベント
  $btn_Click = {
    #入力した文字列を回収
      $result = $txt.Text
    #戻り値をテキストファイルへ出力(SJISで出力)
    Add-Content -path $path -value $result -encoding String
    $frame.Close()
  }
  $btn.Add_Click($btn_Click)

# リストボックスイベント
  #クリックしたとき
  $listBox_Click = {
    $txt.Text = $listBox.SelectedItem
  }
  $listBox.Add_Click($listBox_Click)

  # キー選択したとき（離した時のイベント）
  $keyEvent = {
    $txt.Text = $listBox.SelectedItem
  }
  $listBox.Add_KeyUp($keyEvent)

# フォーム
$frame = New-Object Form
$frame.Text = $Args[3]
$frame.Size = "515, 420"
#一旦最後に入れることを意識する
$frame.Controls.AddRange(@($label2, $label, $btn, $txt, $listBox))#配列で入れる
$frame.ShowDialog()
```
```FormLibrary.vbs
'マルチインプットボックス
'////2～5個の入力欄を持つインプットボックスを表示し入力欄の値を返す関数
'///////////////////////////////////////////////////////////////////////////
'////////第一引数 boxcnt		Integer(テキストボックスの数を決定する、2～5)
'////////第二引数 headername	String(フォームのヘッダー名)
'////////第三引数 boxnames		String(全テキストボックスの名前、「,」区切りの文字列を指定)
'////////戻り値   String(テキストボックスの入力値、boxcntの値と同じ数の列を持つ)
'///////////////////////////////////////////////////////////////////////////
Function MultiInputBox(boxcnt, headername, boxnames)

	'参照する環境変数について
	livpass = CreateObject("WScript.Shell").Environment("USER").Item("EASYGUI")

	'戻り値の初期化
	MultiInputBox = ""

	'引数の正当性チェック
	'１：いずれか引数が空文字
	If boxcnt = "" Or headername = "" Or boxnames = "" Then 
		MultiInputBox = "err_1"
		Exit Function
	End If
	'２：boxcntが2～5であること
	If boxcnt > 5 Or boxcnt < 2 Then
		MultiInputBox = "err_2"
		Exit Function
	End If
	'３：boxcntとboxnamesの要素数が同じであること
	If Not boxcnt = (UBound( Split(boxnames, ",") ) + 1) Then
		MultiInputBox = "err_3"
		Exit Function
	End If

	'フォーム生成用のオブジェクト
	Set objShell = CreateObject("WScript.Shell")
	'戻り値受け取り用ファイル名
	argfilename = replace( replace( replace( now() , ":" , "" ) , "/" , "" ) , " " , "" ) & ".txt"
	'テキストボックスのラベル名を加工
	boxnames = """" & """" & """" & boxnames & """" & """" & """"
	'フォームパスを生成
	psfullfilename = livpass & "\ps\MultiInputBox.ps1"
	'フォームを同期処理で起動
	objShell.Run "powershell -WindowStyle hidden -ExecutionPolicy Bypass -command " & psfullfilename & " " _
				 & argfilename & " " & boxcnt & " " & headername & " " & boxnames, 0, true
	Set objShell = nothing

	'ファイルシステムオブジェクト
	Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
	'戻り値ファイルのパスを生成
	argfullfilename = livpass & "\arg\" & argfilename
	'戻り値ファイルの存在をチェック
	If objFSO.FileExists(argfullfilename) Then
		'ファイルを取り込んで書き出す
		Set objFile = objFso.OpenTextFile(argfullfilename)
    	MultiInputBox = objFile.ReadAll
		'ファイルを閉じて削除する
		objFile.Close
		objFSO.DeleteFile(argfullfilename) 
		Set objFile = nothing
	End If
	Set objFSO = nothing
	
End Function

'シングルリストボックス
'////1個のリストボックスを持ち、選択した値を入力欄へ表示、入力欄に値がある場合OKを押すとその値を返す
'///////////////////////////////////////////////////////////////////////////
'////////第一引数 listname		String(リストボックスのリスト名)
'////////第二引数 resultname	String(リストボックス結果入力欄名)
'////////第三引数 headername	String(フォームのヘッダー名)
'////////第四引数 listarray		String(リストボックスに表示するための値、「,」区切りの文字列を指定)
'////////戻り値   String(リストボックス結果入力欄の値)
'///////////////////////////////////////////////////////////////////////////
Function SingleListBox(listname, resultname, headername, listarray)

	'参照する環境変数について
	livpass = CreateObject("WScript.Shell").Environment("USER").Item("EASYGUI")

	'戻り値の初期化
	SingleListBox = ""

	'引数の正当性チェック
	'１：いずれか引数が空文字
	If livpass ="" Or listname = "" Or resultname = "" Or headername = "" Or listarray = "" Then 
		MultiInputBox = "err_1"
		Exit Function
	End If

	'フォーム生成用のオブジェクト
	Set objShell = CreateObject("WScript.Shell")
	'戻り値受け取り用ファイル名
	argfilename = replace( replace( replace( now() , ":" , "" ) , "/" , "" ) , " " , "" ) & ".txt"
	'テキストボックスのラベル名を加工
	listarray = """" & """" & """" & listarray & """" & """" & """"
	'フォームパスを生成
	psfullfilename = livpass & "\ps\SingleListBox.ps1"
	'フォームを同期処理で起動
	objShell.Run "powershell -WindowStyle hidden -ExecutionPolicy Bypass -command " & psfullfilename & " " _
				 & argfilename & " " & listname & " " & resultname & " " & headername & " " & listarray, 0, true
	Set objShell = nothing

	'ファイルシステムオブジェクト
	Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
	'戻り値ファイルのパスを生成
	argfullfilename = livpass & "\arg\" & argfilename
	'戻り値ファイルの存在をチェック
	If objFSO.FileExists(argfullfilename) Then
		'ファイルを取り込んで書き出す
		Set objFile = objFso.OpenTextFile(argfullfilename)
    	SingleListBox = objFile.ReadAll
		'ファイルを閉じて削除する
		objFile.Close
		objFSO.DeleteFile(argfullfilename) 
		Set objFile = nothing
	End If
	Set objFSO = nothing
	
End Function
```

```setup.vbs
'セットアップ実行
Call setup()

'セットアップ処理実態
Sub setup()

'////処理準備////
'変数宣言
Dim Fso
Dim Flg
Dim SetUpPass
Dim StrEnv
Dim WshEnv

'代入処理
Set Fso = Wscript.CreateObject("Scripting.FileSystemObject")
SetUpPass = "C:\Users\" & WScript.CreateObject("WScript.Network").username & "\Documents"
Flg = 0

'////実行判断ブロック////
'展開先確認
If Not Fso.FolderExists(SetUpPass) Then
	MsgBox("展開先が存在しません" & VbCrLf & SetUpPass)
	Exit Sub
End If

'展開済確認
If Fso.FolderExists(SetUpPass & "\easygui") Then
	MsgBox("展開済です" & VbCrLf & SetUpPass & "\easygui")
	Exit Sub
End If

'実行前確認
If MsgBox("実行しますか？" & VbCrLf & "(環境変数も追加します)", vbYesNo) = vbNo Then Exit Sub

'////環境変数設定////
Set WshEnv = CreateObject("WScript.Shell").Environment("USER")
For Each StrEnv In WshEnv
    If Split(StrEnv,"=")(0) = "EASYGUI" Then Flg = 1
Next

If Flg = 0 Then
	WshEnv.Item("EASYGUI") = SetUpPass & "\easygui"
	MsgBox("環境変数を設定しました")
Else
	msgbox("環境変数は設定済です")
End If

'////フォルダ展開////
Call Fso.CopyFolder(Fso.getParentFolderName(WScript.ScriptFullName) & "\easygui", SetUpPass & "\easygui", False)

MsgBox("設定が完了しました、展開先を確認してください" & VbCrLf & SetUpPass & "\easygui")

End Sub
```
#セットアップ方法
前項で記載したファイル構成の通りファイルを準備したらsetup.vbsを実行して順番にOKするだけです

#利用サンプル
* 以下のように書いてもらえれば利用できます　ライブラリ参照用コードを書いてもらえれば直感的な関数として利用できます

```call.vbs
'///////ライブラリ参照用コード///////
Dim libpass:libpass = CreateObject("WScript.Shell").Environment("USER").Item("EASYGUI"):Function Include(strFile):Dim objFso, objWsh, strPath:Set objFso = Wscript.CreateObject("Scripting.FileSystemObject"):Set objWsh = objFso.OpenTextFile(strFile):ExecuteGlobal objWsh.ReadAll():objWsh.Close:Set objWsh = Nothing:Set objFso = Nothing:End Function:Include(libpass & "\FormLibrary.vbs")
'//////////////////////////////////

'マルチインプットボックス
'////2～5個の入力欄を持つインプットボックスを表示し入力欄の値を返す関数
'///////////////////////////////////////////////////////////////////////////
'////////第一引数 boxcnt		Integer(テキストボックスの数を決定する、2～5)
'////////第二引数 headername	String(フォームのヘッダー名)
'////////第三引数 boxnames		String(全テキストボックスの名前、「,」区切りの文字列を指定)
'////////戻り値   String(テキストボックスの入力値、boxcntの値と同じ数の列を持つ)
'///////////////////////////////////////////////////////////////////////////
msgbox MultiInputBox(3, "名前・年齢・性別入力", "名前,年齢,性別")

'シングルリストボックス
'////1個のリストボックスを持ち、選択した値を入力欄へ表示、入力欄に値がある場合OKを押すとその値を返す
'///////////////////////////////////////////////////////////////////////////
'////////第一引数 listname		String(リストボックスのリスト名)
'////////第二引数 resultname	String(リストボックス結果入力欄名)
'////////第三引数 headername	String(フォームのヘッダー名)
'////////第四引数 listarray		String(リストボックスに表示するための値、「,」区切りの文字列を指定)
'////////戻り値   String(リストボックス結果入力欄の値)
'///////////////////////////////////////////////////////////////////////////
msgbox SingleListBox("いろんな一覧", "選択名", "選択してください" ,"りんご,ごりら,らっぱ,ぱんだ,だるま,まゆげ,げざい,いんこ,こども,もすら,らいと,とまと,といれ")

```

・ 実行したときのサンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521980/c080a197-0e44-b158-8d86-dbf97311d7aa.png)
　複数入力欄のあるインプットボックス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521980/9d4e9587-804e-e46b-e718-b4db3a6849fa.png)
　入力した値を改行して返します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521980/6c2c6c7e-4584-6018-ec22-245ba397e736.png)
　リストボックス、呼び出し時の引数をリストにして表示します、選択すると選択名に選択内容が入力されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521980/a4abb12e-ed6b-091d-87d1-37b887513afe.png)
　選択した値を返します

#最後に
どうしてもvbsで何か作りたい人向けなのでどうせならC#なりpowershell使った方がいいですね、あはは
ライブラリを消す場合はセットアップ時に環境変数を設定しているのでその設定を削除と展開されたフォルダを消せばOKです