■ エラー処理(例外処理)1
今までエラー処理に関しては、ほとんど触れずに来ました。エラーは、プログラムをする上で避けて通れない問題であり、エラー処理を行わないプログラミングというものもあり得ません。
一般にエラーには3つの種類があるといわれています。
1.コンパイル時(前)に発生するエラー |
BASICを経験した方なら「SyntaxError」シンタックスエラーをおぼえているでしょう。
VBEの文法チェック機能はかなり優秀で、コンパイル前に文法エラーの大部分を洗い出し、指摘してくれます。VBEを開発環境として使用している限り、これらのエラーに悩まされることはほとんど無くなりました。
一般的には構文エラーと呼ばれます。 |
2.例外的なケースに発生するエラー |
たとえば、ファイルを呼び出そうとしたときに呼び出し先のドライブが用意されていなかったとか、定義されている配列の範囲を超えるインデックスが指定されたなどです。
これらのエラーの中には、ロジックの見直しやプログラムの修正で回避できるものと、できないものがあります。
一般的には実行時エラーと呼ばれます。 |
3.期待されている結果と異なるというエラー |
出力された合計値が異なっている、小数演算に誤差がある、ユーザーが指定した範囲のデータを対象にしていない。
など、プログラムそのものは正常に動作しているものの、結果としてユーザーの期待にそぐわない、開発者の意図したものと異なる動作を行うエラーの類です。
一般的には論理エラーと呼ばれます。 |
この他にも「不正な処理」「一般保護エラー」と呼ばれるエラーがありますが、これらのエラーに関しては今回は取り上げません。
今回の、エラー処理で対象にするのは2つ目の実行時エラーに関してです。構文エラーはコンパイル時にコンパイラがチェックを行いますので、コンパイルが通らなかった場合、そもそもプログラムを実行することができません。
論理エラーはエラー処理として行う類のものではなく、開発者が仕様書とにらめっこして、ロジックを修正する以外、対処する方法はありません。
エラーが発生した場合に、Excel VBAの場合、エラーメッセージが表示されコードの実行が一時停止します。そこで、ユーザーは「継続」「終了」「デバッグ」「ヘルプ」を選択することができます。
これは、Excel VBAがあくまでExcelというアプリケーション上で動作しているからです。VBのEXEファイルのように、コンパイルした実行ファイルの場合、プログラムそのものが強制終了してしまいます。Accessランタイムで作成した実行ファイルも同様です。
このようにアプリケーション側が受け皿となって、VBAの実行時エラーに対応するからといって開発者側がエラー処理を実装しなくてよい。ということには全然なりません。
エラー処理の本質は、プログラムの処理を継続させることにあります。致命的なエラーが発生した場合、中途で終了したプログラムがどこまで処理を完了していて、どこから処理を再開すればいいかなど、ユーザーはもとより開発者だって管理できるわけがありません。
ならば、中途で処理を終えるのではなく、致命的なエラーが発生する前の状態にデータを戻すか、せめて"ここまで完了した"というログを吐き出して終了すべきです。これができていないプログラムを完成品として配布することなど、もってのほかです。そのプログラムは未完成品です。
では、致命的でないエラーの場合はどうでしょう? リストを出力させようとしてプリンタの電源が入っていなかった場合、いちいちプログラムを終了させていてはユーザーから不満の嵐です。この場合、処理をウェイトさせてプリンタの電源を入れるよう、促すメッセージを表示すれば済む話でしょう。
エラー処理はこれらの、実行時に想定される様々な例外的な処理に対して最低限の機能を実装すべきです。
また、それ以外の目的でエラー処理を利用すべきではありません。ロジックの修正で対応できるなら、エラー処理を使うのではなく、素直にロジックを見直すべきです。
では早速、Excel VBAのエラー処理をみていきましょう。
On Error Resume Next
エラーが発生した行を無視(スキップ)して、次行からコードの実行を再開します。
このエラー処理を使用するときは通常、実行してもしなくてもプログラムのメイン機能に影響しない処理(ウィンドウサイズの変更や効果音の再生など)に使用します。
くれぐれもメインの処理にOn Error Resume Nextを使用することは避けてください。
On Error Goto 行ラベル
エラーが発生した場合、行ラベルで指定した行にジャンプします。
Excel VBAではTry〜Catch構文が使用できないため、エラー時の処理はプロシージャ内にエラー処理用のサブルーチンを記述しなければなりません。VBAで唯一、構造化されていない部分です。
サブルーチンからメインルーチンに戻るには、Resume 行ラベル、Resume Nextステートメントを使用します。
Resume 行ラベルの場合、指定した行ラベルから処理を再開します。
Resume Nextの場合、エラーが発生した行の次の行から処理を再開します。
ただのResumeの場合、エラーが発生した行から処理を再開します。
例:
Sub test()
Dim MyLng As Long
On Error GoTo ErrHandler
MyLng = 2 / 0
MyLng = 2 / 1
Retry:
MyLng = 2 / 2
Exit Sub
ErrHandler:
Resume Retry
End Sub
この例では、MyLng = 2 / 0 で0除算エラーが発生した後、ErrHandler: 行にジャンプします。
Resume Retry でRetry: 行から処理を再開するよう指定されているので、MyLng = 2 / 2 より処理を再開します。
Resume Retry がResume Next の場合、MyLng = 2 / 1 より処理を再開します。
Resume Retry がResume だけの場合、MyLng = 2 / 0 より処理を再開するので無限ループになります。
On Error Goto ステートメントはプロシージャ内に複数記述できます。
例:
Sub test()
On Error GoTo ErrHandler1
'構文1
Retry1:
'ErrHandler1サブルーチンからのReturn行
On Error GoTo ErrHandler2
'構文2
Retry2:
'ErrHandler2サブルーチンからのReturn行
Exit Sub
ErrHandler1:
'構文1のエラーに対する処理
Resume Retry1
ErrHandler2:
'構文2のエラーに対する処理
Resume Retry2
End Sub
この例では、構文1で発生したエラーはErrHandler1:のサブルーチン、構文2で発生したエラーはErrHandler2:のサブルーチンがそれぞれ処理し、指定された行から処理を再開させます。
On Error Goto 0ステートメントにより、現在のプロシージャのエラーハンドラが無効化されます。
つまり、On Error Goto 0を挿入する以前に記述していたOn Error〜の処理は、On Error Goto 0 ステートメント以降、無効になります。
Errオブジェクト
エラーが発生したときに、自動的にエラー情報を取得してくれるオブジェクトです。
取得できるプロパティは、以下のとおりです。
Err.Number |
エラー番号 |
Err.Source |
エラー発生元のオブジェクト名 |
Err.Description |
エラーに関する説明文 |
Err.HelpFile |
ヘルプファイルへの絶対パス |
Err.HelpContext |
ヘルプファイルのトピックに対応するコンテキスト番号 |
Err.LastDLLError |
最後にDLLを呼び出したときのエラーコード |
Errオブジェクトで取得できるエラーコード一覧表はこちらを参照してください。
※ Visual Basic for Applications でのエラートラップ http://support.microsoft.com/kb/146864/ja
次回もエラー処理の解説が続きます。
|