スクリプト内で発生したエラーの対処方法を説明する。
エラー処理
スクリプトの実行中にエラーが起きた場合、通常、その時点でスクリプトは強制終了される。
エラーが起きた場合に強制終了ではなく独自の処理を行うときは、On Error ステートメントと Err オブジェクトを使う。
独自のエラー処理を行えるようにするには、On Error Resume Next ステートメントを使ってエラー処理を有効にする。
エラー処理を有効にすると、実行時エラーが起きても強制終了せず、そのまま処理を継続するようになる。
エラー処理を無効に戻すときは On Error GoTo 0 ステートメントを使う。
実行時エラーの発生有無は Err オブジェクトの Number プロパティで判定できる。
Number プロパティは正常なら 0 に、そうでないなら 0 以外になる。
基本的なエラー処理の流れは次のとおり。
- エラーの発生が想定される処理の前に On Error Resume Next ステートメントを置いて、エラー処理を有効化
- 処理を実行
- Err.Number <> 0 だったらエラー処理する
- On Error GoTo 0 ステートメントでエラー処理を無効化
不適切なエラー処理はスクリプトの暴走につながる。注意すること。
次のサンプルは、ユーザーに入力された数値で 100 を割り、結果を表示する。
エラーが起きた場合は、エラー情報を通知して終了する。
Dim y
y = InputBox("100を割る数を入力してください")
'★エラー処理を有効化
On Error Resume Next
Dim ret
ret = 100 / y
If Err.Number <> 0 Then
'★エラー処理
WScript.Echo "Error # " & CStr(Err.Number) & " : " & Err.Description
WScript.Quit 1
End If
'★エラー処理を無効化
On Error GoTo 0
'計算結果を表示
WScript.Echo "100 ÷ " & y & " = " & ret
本来であれば計算の前に入力チェックするべきだが、まぁサンプルということで。
エラー情報(Errオブジェクト)
実行時エラーの内容は Err オブジェクトに格納される。
Err オブジェクトは以下のプロパティとメソッドを持つ。
Numberプロパティ
エラー番号。正常なら 0 、異常なら 0 以外。
Descriptionプロパティ
エラーの説明。
HelpFileプロパティ
ヘルプファイルのパス。
HelpContextプロパティ
ヘルプファイルのトピックを表すコンテキスト番号。
HelpFile プロパティを指定した場合、HelpContext プロパティで指定したトピックが自動的に表示される。
Sourceプロパティ
エラーを最初に発生させたオブジェクトの名前。
Clearメソッド
Err オブジェクトが持つすべてのプロパティの値をクリアする。
Raiseメソッド
実行時エラーを生成する。
Err.Raise number [, source] [, description] [, helpFile] [, helpContext]
-
number:
エラーの番号を Long 型の数値で指定する。
0 ~ 65535 の範囲が指定可能。
0 ~ 512 は VBScript の組み込みエラー、513 ~ はユーザー定義エラーとなる。ユーザー定義エラーは定数 vbObjectError 以上の数値にする。
たとえば、エラー番号 1050 を発生させるには vbObjectError + 1050 とする。 -
source:
エラーを生成したオブジェクトまたはアプリケーションの名前を指定する。
省略可能。 -
description:
エラーの説明を指定する。
省略可能。 -
helpFile:
ヘルプファイルのパスを指定する。
省略可能。 -
helpContext:
ヘルプファイル内のトピックを識別するコンテキストIDを指定する。
省略可能。
エラー処理の適用範囲
On Error Resume Next ステートメントは使用したプロシージャにのみ適用される。
エラー処理が無効なプロシージャで実行時エラーが発生した場合、エラー処理が有効なプロシージャまで処理が渡る。
もしエラー処理が有効なプロシージャがなければ、そのままエラー情報が表示され、スクリプトは終了される。
例: エラー処理が有効なプロシージャからエラー処理が無効なプロシージャを呼び出した場合
FuncA → FuncB で呼び出し、FuncB で実行時エラーが起きた場合、FuncA に処理が渡る。
'エラー処理が有効なプロシージャ FuncA
Sub FuncA
On Error Resume Next
Dim ret
ret = FuncB
'FuncB で実行エラーが起きた場合、ここ(FuncB を呼び出した行の次行)に処理が渡る
'エラー処理
If Err.Number <> 0 Then
WScript.Echo "Error # " & CStr(Err.Number) & " : " & Err.Description
WScript.Quit 1
End If
End Sub
'エラー処理が無効なプロシージャ FuncB
Function FuncB
'ゼロ除算エラーを起こす
FuncB = 100 / 0
End Function
例: 呼び出しの階層が深くなっても考え方は同じ
FuncA → FuncB → FuncC で呼び出し、FuncC で実行時エラーが起きた場合、FuncA に処理が渡る。
'エラー処理が有効なプロシージャ FuncA
Sub FuncA
On Error Resume Next
Dim ret
ret = FuncB
'FuncB/C で実行エラーが起きた場合、ここ(FuncB を呼び出した行の次行)に処理が渡る
'エラー処理
If Err.Number <> 0 Then
WScript.Echo "Error # " & CStr(Err.Number) & " : " & Err.Description
WScript.Quit 1
End If
End Sub
'エラー処理が無効なプロシージャ FuncB
Function FuncB
FuncB = FuncC
End Function
'エラー処理が無効なプロシージャ FuncC
Function FuncC
'ゼロ除算エラーを起こす
FuncC = 100 / 0
End Function
エラー処理メモ
確実にエラー処理できるようにするには
実行時エラーによってスクリプトを強制終了されないようにするには、メインルーチンで On Error Resume Next ステートメントを使うのが確実である。
そうすることで処理されなかったすべてのエラーを、メインルーチンでキャッチできるようになる。
'メインルーチン
On Error Resume Next
Call Main
If Err.Number = 0 Then
'正常終了
WScript.Quit 0
Else
'異常終了(処理されなかったすべてのエラーをここでキャッチできる)
WScript.Echo "Error # " & CStr(Err.Number) & " : " & Err.Description
WScript.Quit 1
End If
On Error GoTo 0
'サブルーチン
Sub Main
'TODO: 処理を書く
End Sub
サブルーチンのエラーをメインルーチンで処理する
サブルーチンで発生したエラーを、メインルーチンで処理するようにもできる。
そうする場合、サブルーチンはエラー処理を有効化しておく。
メインルーチンは無効のままで良い。
'メインルーチン
WScript.Echo Divide(100, 0)
If Err.Number <> 0 Then
'★サブルーチンで発生したエラーの処理
WScript.Echo "Divide Error # " & CStr(Err.Number) & " : " & Err.Description
WScript.Quit 1
End If
'サブルーチン
Function Divide(ByVal a, ByVal b)
'★エラー処理を有効化
On Error Resume Next
'実行時エラーが起きるかもしれない処理を実行
Divide = a / b
End Function
VBScriptではラベルによるエラー処理はできない
VBScript では VB6 や VBA にあるラベルによるエラー処理は利用できない。
以下のように On Error GoTo 〈ラベル名〉 と指定して、エラー発生時に指定したラベルへ飛ばす書き方は VBScript では不可能。
'Notice: VBScript ではサポートされていない書き方
'エラーが起きたら ErrHandler ラベルに飛ばす
On Error GoTo ErrHandler
Dim ret
ret = 100 / 0
MsgBox ret
ExitHandler:
Exit Sub
ErrHandler:
MsgBox "Error # " & CStr(Err.Number) & " : " & Err.Description
GoTo ExitHandler
try-catchのようにエラー処理をする
VBScript では C# や Java のような tru-catch での例外処理はサポートされていない。
が、少し工夫するだけでそれっぽくエラー処理をすることはできる。
まず VBScript におけるエラー処理で覚えておくべきポイント3つを以下に挙げる。
- エラーを処理するには On Error Resume Next ステートメントでエラー処理を有効化する。
- On Error Resume Next ステートメントによる設定は、そのプロシージャ内でのみ適用される。
- エラー処理を有効にしていないプロシージャで実行時エラーが起きた場合、エラー処理が有効なプロシージャまで処理が戻る。
エラー処理が有効なプロシージャがなかった場合はスクリプトが終了する。
これらのポイントをふまえて、try-catch のようなエラー処理にしたのが次のスクリプト。
'try...catch...finally のサンプル
Sub TryCatchExample
'エラー処理を有効化
On Error Resume Next
Dim errorHasOccurred
errorHasOccurred = False
'Try にあたる処理を呼び出す
Call Try
'Try で実行時エラーが発生した場合の処理を分岐内に書く
If Err.Number <> 0 Then
errorHasOccurred = True
'TODO: catch にあたる処理を書く
End If
'TODO: finally にあたる処理を書く
'実行時エラーが発生していた場合はここで処理終了
If errorHasOccurred Then
Exit Sub
End If
End Sub
Sub Try
'TODO: try にあたる処理を書く
End Sub
TryCatchExample プロシージャは On Error Resume Next ステートメントでエラー処理を有効化している。
TryCatchExample プロシージャから呼び出される Try プロシージャは、エラー処理は無効なまま。
なので Try プロシージャで実行時エラーが発生した場合、TryCatchExample プロシージャの Call Try の次の行に制御が渡る。
そこで Err.Number プロパティを見て、実行時エラーが発生していた場合はエラー処理をする。