今回はVBScriptにおける「エラー処理」について説明していきます。
エラー処理とは
プログラミングでは、様々なケースを想定して処理を作るのですが、プログラム作成者が想定していない例外が発生することは付き物です。
VBScriptの場合、エラーが発生すると、エラーメッセージがポップアップで表示され、プログラムの実行が中断してしまいます。
動かしている処理内容によっては、これでは非常に困る場合もあります。
また、想定外のエラーへの考慮の他にも、プログラムのなかで考えられる全てのイレギュラーケース毎に対応する処理を作るのが困難だったり無駄な場合もあります。
だったら想定外のケースや、ある範囲のイレギュラーケースが発生してエラーとなった場合、プログラム内でエラーとして検出して、プログラムを中断させることなく、メールでシステム管理者に通知をしたうえで、安全にプログラムを終了させたり、処理を分岐してプログラムの実行を継続させるなどの、個別の処理を入れましょうというのが「エラー処理」です。
サンプルコードと解説
今回の記事では、プログラム内でわざとエラーを発生させて、それに対する対策として、段階的にプログラムを書き足して説明していきます。
なお、今回もサンプルコードはコピペしてもらえれば、どんな環境でも動くように作ってあるので、実際にvbsファイルを作成して、実際にプログラムを起動させながら試してもらうと分かりやすいと思います。
エラーが発生するサンプルコード
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0
このvbsファイルを実行して頂くと以下のエラーが表示されます。
これがVBScriptでの通常のエラーメッセージです。
エラーが発生している行数や何文字目か。
エラー内容も表示されます。
ただ、前述したとおり、このエラーメッセージが出ると、プログラムはその該当の処理で中断します。
今回はこれを「エラー処理」で何とかしていきます。
数学のルールでは、数値を0で割ることはできないのですが、プログラミングの世界でも同様です。
プログラム内で数値を0で割ろうとすると必ずエラーになります。これはVBScriptだけではなく、私の知る限り全てのプログラミング言語で共通の仕様です。※多分・・・
「On Error Resume Next」でエラーを無視して処理を継続
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0
今回は7行目に「On Error Resume Next」という処理を追加しました。
この処理はコメントにも記載していますが、「この行以降の処理はエラーが出ても無視して次の処理に移る」という意味の処理です。
このサンプルコードでvbsファイルを実行した場合、On Error Resume Nextの後ろにエラーを発生させる処理が記載されているため、このOn Error Resume Nextが効いて、エラーメッセージは表示されません。
エラーが出なくなり、プログラム的には一見これで良いようにも思えるかも知れませんが、エラーが発生しても無視されてポップアップで表示されないだけであって、内部的にはエラーが発生しています。
しかも、エラーが発生してもそれを無視して次の処理に移っている為、例えばこのエラーが発生した処理の次の処理では、前の処理が正常に動いていることを前提に処理が作られている可能性があります。
そうなると、単純にエラーが出たらそれを無視して次の処理に移ってはいけないことになります。
例えば、VBScriptと同じVB6系のVBAではラベルが使えます。
On Error Goto ラベル名
と記述することで、以降の処理でエラーが発生したら、ラベルで定義したエラー用の処理に飛ばすことが出来ます。
また、JAVAや.NETなどではtry-catch構文が使えます。
エラー検出範囲の最初にtryを記述し、エラーが発生した場合にcatchで記述した処理に飛びます。
VBScriptでは、前述の通りエラーを無視することしかできません。よって、ラベルでもなく、例外をcatchする以外の対処が必要になります。
「Err.Number」でエラーの有無を判定して処理を分岐
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "エラーが発生しました。" End If
13行目に新しい処理が追加されました。
IF文で「Err.Number」が0か否かを判定しています。
このErr.Numberはそれまでの処理で何らかのエラーが発生すると、エラー内容固有のエラー番号を保持します。
また、エラーが何も発生していなければ0が入っています。
よって、この「Err.Number」の値が0であればエラーは発生していない。0以外の値であれば、何らかのエラーが発生したということになります。
サンプルコードでは、10行目でわざとエラーを発生させて、その後Err.Numberの値でエラーを検出し、メッセージボックスでメッセージを表示しています。
ただ、今回のサンプルコードでは、Errという変数は宣言しておらず、Createobjectでインスタンス化もしていません。
なぜインスタンス化もsetでの代入もしていないオブジェクトが使用できるのでしょうか?
このErrというオブジェクトは、VBScriptが実行される際に自動的に生成される特殊なオブジェクトで、エラーに関する情報を取得します。
Numberはプロパティで、名前の通りエラー番号を保持しており、他にもいくつかのプロパティを持っています。
VBScriptのエラー処理ではこのErrオブジェクトを使ってエラーを管理します。
「On Error Resume Next」を指定した以降は何度エラーが出ても無視される
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "エラーが発生しました。" End If '再度エラーを出すために、わざと文字列の値をCInt関数で数値型に変換します。 CInt("文字列")
今回は、18行目を追加しました。
これはこれまでのサンプルコードで発生させていた0除算によるエラーではなく、別の種類のエラーを発生させるための記述です。CIntは引数の値を数値型に変換する関数ですが、文字列を引数に指定してCIntを呼んでいるため変換が行えず、型変換のエラーが発生します。
このサンプルコードを実行すると、今回新しく追加した18行目のエラーは、7行目で指定しているOn Error Resume Nextが効いており無視されます。
ただ、直観的には、13行目でその前に発生したエラーは検出した為、今回のエラーについては無視してほしくはない感じがします。
「On Error Goto 0」でエラーを無視する範囲終了
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "エラーが発生しました。" End If '上記で指定した「On Error Resume Next」は以下の行までとします。 On Error Goto 0 '再度エラーを出すために、わざと文字列の値をCInt関数で数値型に変換します。 CInt("文字列")
今回は18行目に「On Error Goto 0」が追加されています。
前述したVBScriptのエラー処理に関する解説にて、VBScriptではVBAの様にラベルが使えないと説明しました。
VBAにおけるラベルとは、「On Error Goto ラベル名」と指定することで、以降にエラーが発生した場合は、対象のラベル名で指定した箇所の処理に飛ぶという仕様です。
VBScriptでは「On Error Goto ラベル名」という処理はできませんが、「On Error Goto 0」という記述は可能です。
この記述をすると、「On Error Resume Next」でエラーを無視するという指定をその行で終了させることができます。
今回のサンプルコードを実行すると。18行目の「On Error Goto 0」でエラーを無視する指示が終了している為、21行目の処理実行する際にエラーが発生して処理が中断します。
「On Error Goto 0」と「Err.Clear」でエラー処理範囲を管理
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "エラーが発生しました。" End If '上記で指定した「On Error Resume Next」は以下の行までとします。 On Error Goto 0 'エラー発生時は再度エラーを無視して次の処理に移るようにします。 On Error Resume Next Err.Clear '再度エラーを出すために、わざと文字列の値をCInt関数で数値型に変換します。 CInt("文字列") 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "またエラーが発生しました。" End If 'エラーを無視する範囲は以下の行までとします。 On Error Goto 0
当コードを実行すると、最初に0除算をした際のエラーを取得してメッセージボックスを表示します。
次に文字列を数値型に変換する処理でエラーが発生し、それをメッセージボックスに表示します。
今回のコードでは、22行目に「Err.Clear」という処理が追加されています。これは、前述したErrという特殊なオブジェクトが保持していたエラー番号等のデータをクリアするメソッドです。
この処理を入れておかないと、その後に再度Err.Numberの値でエラーの有無を検出しようとした際に、古いエラー発生時のデータが残り、エラーが発生していないのに、0以外の値が入っていることによりエラーが発生したと判定されてしまいます。
エラー処理の開始は「On Error Resume Next」を記述し、エラー処理範囲の終了時には「On Error Goto 0」を記述する。
また、エラーの発生有無はIf文でErr.Numberの値が0か否かで判定し、エラー処理を再開する場合は、念のため「Err.Clear」を記述しておくというのがVBScriptにおける基本的なエラー処理の実装方法です。
「Err.Description」でエラー内容を取得する
Option Explicit '簡単な割り算の結果をメッセージボックスで表示 msgbox 2 / 1 'エラー発生時はエラーを無視して次の処理に移ります。 On Error Resume Next 'エラーを出すためにわざと0除算をします。 msgbox 2 / 0 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "エラーが発生しました。" 'エラー内容をメッセージボックスで表示します。 msgbox "エラー番号:" & Err.Number & " " & "エラー内容:" & Err.Description End If '上記で指定した「On Error Resume Next」は以下の行までとします。 On Error Goto 0 'エラー発生時は再度エラーを無視して次の処理に移るようにします。 On Error Resume Next Err.Clear '再度エラーを出すためにわざと文字列の値をCInt関数で数値型に変換します。 CInt("文字列") 'エラーが発生しているかをチェックします。 If Err.Number <> 0 Then msgbox "またエラーが発生しました。" 'エラー内容をメッセージボックスで表示します。 msgbox "エラー番号:" & Err.Number & " " & "エラー内容:" & Err.Description End If 'エラーを無視する範囲は以下の行までとします。 On Error Goto 0
今回のコードを実行すると、メッセージボックスが4回表示されます。前項のサンプルコードではエラーが発生したことを通知するメッセージボックスを表示し、そのエラー内容まではそのメッセージからはわかりませんでしたが、今回のコードではメッセージボックスにエラー内容の表示させています。
サンプルコードの16行目と32行目がその処理の記述です。
因みに以下のメッセージを表示します。※右側が16行目、左側が32行目のメッセージです。
Errというオブジェクトでは、Number以外にもプロパティを持っており、今回使用した「Err.Description」はエラー内容を保持しています。
今回のサンプルコードの様に、Descriptionの値をNumberと併せて取得してエラー発生時にメッセージボックスで表示したり、ログファイルなどに出力するといった処理を入れることで、エラーの原因がわかりやすくなります。
参考としてMicrosoftのErrオブジェクトのリファレンスページを紹介しておきます。
当ページを見て頂くと、メソッドやプロパティが今回紹介したもの以外にもあるのがわかりますが、実際にVBScriptでプログラムを作る際に必要になるErrオブジェクトのメソッドやプロパティは、今回紹介したものだけを使用して頂ければ十分です。
最後に
今回はプログラミングでとても重要な「エラー処理」について紹介しました。
前述したとおり、プログラミングではエラーは付き物であり、どんなプログラミング言語であっても、想定外のエラーが発生した場合は、対象の処理は中断したり、アプリケーションは強制終了します。
WindowsアプリケーションやWebアプリケーション、バッチ処理などすべてのプログラムにおいて、エラーが発生することは避ける必要があり、それを管理するのが今回のエラー処理です。
例えばデータベースに対して更新を掛ける処理があった場合、プログラム内でエラーを検出したら、実行した更新処理をロールバックするエラー処理も併せて組み込んでおきます。
エラー処理自体は必ず実装しないといけないものではありませんが、データベースへの更新を掛けるような処理だったり、エラーで中断してしまうことが問題になるクリティカルな処理の場合は、必ず組み込んでおくことが必要です。
是非活用してみてください。
今回も読んで頂きましてありがとうございました。
↓次回の記事はこちら
↓前回の記事はこちら
Windows10で文字化けしたり想定外の場所でエラーが出る場合
Windows10でテキストファイルを作成した場合の規定の文字コードがVBScriptに対応していないことが原因です。
詳しい原因の解説と、その対応方法を記事にしてあるので参照してください。