がらぱっぱ

自分用覚え書き中心(モバイル関係中心だったはずが)

Tips【WSH】VBSCRIPTでコンソール出力(wscriptとcscriptで切り替え)

WSHではWScript.echoというメソッドでコンソール出力がおこなえるが
Cscript(コンソール)の場合はコンソールに出力、WScriptの場合はメッセージダイアログに出力という余計なお節介便利な実装となっている。
またコンソール出力する方法としてWScript.StdOut.WriteLine というメソッドもあるのだが、これはcscript専用で、WScriptで実行すると「ハンドルが無効です」というエラーとなってしまう。

デバッグ目的や処理の経過を出力しようとした場合WScript.echoの度にダイアログが出力されるのはよろしくないので何らかの方法を考えましょう。というのがこのエントリ

 

 

  1. CScriptの時だけコンソールに出力してWScriptの時は出力しない
  2. CScriptの時だけコンソールに出力してWScriptの時はファイルに出力する
  3. CScriptの時もWScriptの時もファイルに出力する

3は別の機会のネタに取っておくとして1について考察

方法としては2通り(もっとあるかも)

  1. とりあえず出力してみてエラーなら出力しない
  2. CScriptかWScriptかを判断して出力するしないを切り替える

とりあえず出力してみてエラーはスキップ

On Error Resume Nextでエラースキップできるので

Sub DebugPrint(text)
  On Error Resume Next
  WScript.StdOut.WriteLine text
End Sub

うん。シンプルですね。

CScriptかWScriptかを判断して出力するしないを切り替える

最初にCScriptかどうかを判断してIf文で出力するかしないかを切り替える。

自分自身はCScriptかWScriptかは、WScript.FullNameでわかるらしいので

CSCRIPT_EXE="cscript.exe"
If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then
  isCSCRIPT = True
Else
  isCSCRIPT = False
End If
Sub DebugPrint(text)
  If isCSCRIPT Then
    WScript.StdOut.WriteLine text
  End If
End Sub

ってな具合に判断する。

なんか関数に収まりきらないでハンドリングが悪いので、毎回判断するオーバーヘッドを顧みず毎回CScriptかどうかを判断すると

Sub DebugPrint(text)
  CSCRIPT_EXE="cscript.exe"
  If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then
    WScript.StdOut.WriteLine text
  End If
End Sub

 

 

で、どれがいいのか

性能

10万回ほどループで回して時間を測定してみましょう。

こんな感じのテストプログラム

startTime = Timer
FOR i=0 To 1000000
  DebugPrint "bbb"
Next
WScript.echo Timer - startTime

 

マシンスペックやらなんやらで変わるとは思いますが

WScriptで実行

  1回目 2回目 3回目 平均 一回当たり(ns)
①エラースキップ 3.292969 3.292969 3.243906 3.276615 33
②判断 0.296875 0.273438 0.254906 0.275073 3
③毎回判断 2.625 1.703125 1.574219 1.967448 20


CScriptで実行

  1回目 2回目 3回目 平均 一回当たり(ns)
①エラースキップ 11.15234 10.88281 10.82031 10.95182 110
②判断 12.45313 10.125 10.30469 10.96094 110
③毎回判断 11.88672 12.73828 12.25391 12.29297 123

※これは実際に文字列を出力している時間も含まれる

WScriptの場合はエラーが発生するため、そのオーバーヘッドが出てくる感じですかね。CScriptの場合は差がほとんどなくなって余分な処理が入っている③が一番時間がかかる。

どれも1回あたりの時間は大した違いがないのでどの方法でもいんでないかい?

ハンドリング

呼び出し側からの使いよさは①=③>②、初期処理で入れといたりグローバル変数になる②はいまいち

拡張性

CScriptの時はコンソールに出して、WScriptの時はファイルに出すとかするって事をしたくなった時とか、②=③>①

 結論

 ③を採用!

Sub DebugPrint(text)
  CSCRIPT_EXE="cscript.exe"
  If LCase(Right(WScript.FullName, Len(CSCRIPT_EXE))) = CSCRIPT_EXE Then
    WScript.StdOut.WriteLine text
  End If
End Sub