【例外処理】エラーキャッチの方法

今回の目標

  • プログラムを予期せぬエラーで止まらないようにする

説明

例外処理とは

例外処理とは、実行時エラーが発生したときに特定のコードを実行する処理のことです。
あなたが作成したツールをユーザーが使用していたとき、エラーが発生してツールが落ちてしまうことを防ぎます。
「例外(予期せぬエラー)が発生したときの処理」ということです。
なお、プログラムの構文ミス等が起因となるコンパイルエラーには対応していません。
コンパイルして問題がないことを確認してからツールを使用してもらいましょう。

On Error Goto ラベル名
    通常の処理を記載
ラベル名:
    エラー発生時の処理を記載

エラーをキャッチして、専用のプログラムを実行する

次のプログラムをF8ボタンでステップインしてみましょう。
ステップインとはプログラムを1行ずつ実行することです。
ステップインした状態で、更にF8ボタンを押すとその分だけプログラムが実行されます。
なお、ステップインは[デバッグ]→[ステップイン]からでも可能です。

Sub Sample1()
On Error Goto ErrTrap
    ' 処理を入力する
    Dim num as Integer
    num = 1000 * 800        'Integer型の最大値32,767を超えるため、エラー
    MsgBox "数値は" & num & "です。"
ErrTrap:
    If (Err.Number <> 0) Then
        ' ここにエラー発生時の専用のプログラムを入力する
        MsgBox Err.Description, vbOKOnly, "Error"
    End If
End Sub

エラーが発生すると同時に、ErrTrap(ラベル)までステップが移動します。
移動すると同時に、命令文にはありませんが、Errオブジェクトにエラー情報が格納されます(下表参照)。
そのエラー情報をもとにエラー処理を行います。

メンバ説明
Description発生したエラーに対する説明文がString型で格納されます。
エラーが発生していないときは、空の文字列(vbNullString)が格納されています。
Number発生したエラーの番号がLong型で格納されます。
エラーが発生していないときは、数値0が格納されています。
HelpFileエラー発生時、MsgBox関数の第四引数に指定する値が格納されます。
HelpContextエラー発生時、MsgBox関数の第五引数に指定する値が格納されます。

下記はMicrosoft社のリファレンスを一部引用してかみ砕いたサンプルです。
MsgBox関数の第二引数・第四引数・第五引数を使って、
エラー番号を表示し、ユーザーがヘルプを見られるようにしています。
ですが、マクロを作成できないユーザーがヘルプを見ても混乱するだけなので、表示しないべきでしょう。

' 下記はMicrosoft社のリファレンスを一部引用。
Sub SampleEx()
On Error Goto ErrTrap
    Dim num as Integer
    num = 1000 * 800
    MsgBox "数値は" & num & "です。"
ErrTrap:
    If (Err.Number <> 0) Then
        ' エラー表示の文中に番号を表示させている。
        Dim ErrMsg as String
        ErrMsg = "ErrorNumber:" & Str(Err.Number) & vbNewLine & Err.Description
        ' メッセージボックスにヘルプボタンを追加。
        MsgBox ErrMsg, vbMsgBoxHelpButton, "Error", Err.HelpFile, Err.HelpContext
    End If
End Sub

強制的にエラーを発生させる

使い道はほぼありませんが、強制的にエラーを発生させることもできます。

' On Error Goto とセットで使用しないと純粋なエラーになる
Err.Raise エラー番号

上記「エラー番号」にはエラー発生時に『Err.Number』に格納される数値を入れます。
例えば、オーバーフローの発生なら、エラー番号は「6」です。

Sub Sample4()
On Error GoTo ErrTrap
    Dim num As Integer
    Err.Raise 6
    MsgBox "エラーラベルまでスキップされるため、表示されません。"
ErrTrap:
    If (Err.Number <> 0) Then
        MsgBox Err.Description, , "Error"
    End If
End Sub

エラーを無視する

エラー発生時に、そのエラーを無視して次のステップに移動させることができます。 プロシージャ開始後に次の命令を入力します。

On Error Resume Next

次のサンプルは数値型の変数に文字列を入力してしまったサンプルです。

Sub Sample5()
On Error Resume Next
    Dim num As Integer
    num = "1000 * 800"
    MsgBox "数値は" & num & "です。"
End Sub

上記サンプルを実行してみるとわかりますが、エラーが発生した命令は次のステップに飛ばされます。
少しトリッキーな使用法ですが、次のようにGotoでラベルまでスキップした後に、
エラーが発生した次の行まで戻すことができます。

On Error Goto ErrTrap
    通常の処理①     ・・・A
    エラーが発生する処理 ・・・B
    通常の処理②     ・・・C
    Exit Sub        ・・・D
ErrTrap:
    エラー発生時の処理  ・・・E
    Resume Next      ・・・F

上記を順を追って説明します。

  1. 「A」の処理が行われます。
  2. 「B」を実行しますがエラーが発生するため、エラーラベルのある「E」へスキップします。
  3. 「E」を実行します。
  4. 「F」を実行します(=Cに戻ります)。
  5. 「C」を実行します。
  6. 「D」を実行して終了します。("Exit Sub"は、Subプロシージャの終了させる命令)。

この構文は、VBAからエクセル関数であるVlookup関数を使用する場合に用いると良いでしょう。
例えば、下図の表があるとします。


これをA列を参照して取得する場合、VBAだけで検索して値を調べると処理に手間取ります。
VLookup関数を使用すれば1行で済みますが、検索値が表に存在しないとエラーが発生してしまいます。
この致命的な弱点を補うのが、Resume Nextです。

Sub Sample6()
On Error GoTo ErrTrap
    Dim dat As String
    dat = WorksheetFunction.VLookup(1, Range("A2:B9"), 2, False)
    MsgBox dat
    Exit Sub
ErrTrap:
    dat = "データが見つかりませんでした。"
    Resume Next
End Sub

通常、検索値に「9」指定すると、エラーになりプログラムが止まってしまいますが、
この方法なら問題ありません。

デバッグを行う時の注意点

On Error構文をコメントアウトしましょう。
なぜなら、エラーが発生するとエラーラベルまでスキップしてしまい、
どこでエラーが発生したかわからなくなってしまうからです。

下記の構文でErrオブジェクトやエラー発生時のラベルへのスキップを解除(初期化)できます。

On Error Goto 0

Gotoの後ろは、数字のゼロです。
必要に応じて初期化してください。

メッセージボックスにエラーのヘルプを用意する

メッセージボックスにエラーに対するヘルプボタンを設置します。
このヘルプボタンには、エラーに対する情報が記載されています。

Sub Sample7()
    On Error GoTo ErrTrap
    ' Worksheets(-1) でエラーが発生する
    ThisWorkbook.Worksheets(-1).Cells(1, 1) = "(*'ω'*)"
ErrTrap:
    If (Err.Number <> 0) Then
        MsgBox Err.Description, vbMsgBoxHelpButton, "Error", Err.HelpFile, Err.HelpContext
    End If
End Sub

関連リンク

ページの先頭へ