VBAのエラー – エラー処理のベストプラクティス
In this Article
VBAエラーのチートシート
エラー
VBAのエラー処理
VBAのエラー処理とは、VBA実行時エラー(ランタイムエラー)を予測し、検出し、解決するプロセスのことです。VBAのエラー処理プロセスは、実際にエラーが発生する前に、コードを書くときに発生します。
VBA実行時エラーとは、コードの実行中に発生するエラーのことです。実行時エラーの例としては、以下のようなものがあります。
- 存在しないワークブック、ワークシート、またはその他のオブジェクトを参照している。(実行時エラー1004)
- 無効なデータ、例えば、エラーを含むExcelセルを参照している。(型の不一致 – 実行時エラー13)
- ゼロで割ろうとしている
VBA On Errorステートメント
VBAのエラー処理のほとんどは、On Errorステートメントで行われます。On Errorステートメントは、VBAがエラーに遭遇した場合の処理を指示します。On Errorステートメントには、3つの種類があります。
- On Error GoTo 0
- On Error Resume Next
- On Error GoTo Line
On Error GoTo 0
On Error GoTo 0はVBAのデフォルト設定です。以下のコード行を追加することで、このデフォルト設定を復元することができます。
On Error GoTo 0
On Error GoTo 0でエラーが発生した場合、VBAはコードの実行を停止し、標準のエラーメッセージボックスを表示します。
多くの場合、On Error Resume Nextエラー処理(次のセクション)を追加した後にOn Error GoTo 0を追加します。
Sub ErrorGoTo0()
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
'さらなるコードの実行
End Sub
On Error Resume Next
On Error Resume Nextは、エラーを含むコード行をスキップして、次の行に進むようにVBAに指示します。
On Error Resume Next
注:On Error Resume Nextは、エラーを修正したり、解決したりするものではありません。これは、エラーを含むコード行が存在しないかのように処理を進めるようにVBAに指示するだけです。On Error Resume Nextの不適切な使用は、意図しない結果をもたらす可能性があります。
On Error Resume Nextを使うのに最適なのは、存在するかどうかわからないオブジェクトを扱うときです。例えば、ある図形を削除するコードを書きたいが、その図形がすでに削除されているときにそのコードを実行すると、VBAはエラーを投げることになります。代わりに、On Error Resume Nextを使用して、図形が存在する場合にそれを削除するように VBA に指示することができます。
On Error Resume Next
ActiveSheet.Shapes("Start_Button").Delete
On Error GoTo 0
エラーの可能性があるコードの行の後にOn Error GoTo 0を追加していることに注意してください。これは、エラー処理をリセットするものです。 次のセクションでは、Err.Numberを使ってエラーが発生したかどうかをテストする方法を紹介し、より高度なエラー処理のオプションを提供します。
Err.Number、Err.Clear、そしてエラーの捕捉
エラーを含む行を単にスキップするのではなく、On Error Resume NextとErr.Number を使用してエラーをキャッチすることができます。 Err.Numberは検出されたエラーの種類に対応するエラー番号を返します。エラーがない場合は、Err.Number= 0です。 例えば、このプロシージャでは、発生したエラーは実行時エラー’11‘なので、”11 “を返します。
Sub ErrorNumber_ex()
On Error Resume Next
ActiveCell.Value = 2 / 0
MsgBox Err.Number
End Sub
Err.Numberによるエラー処理
Err.Numberの真の威力は、エラーが発生したかどうか(Err.Number<> 0)を検出する能力にあります。 以下の例では、Err.Numberを使って、シートが存在するかどうかをテストする関数を作成しました。
Sub TestWS()
MsgBox DoesWSExist("test")
End Sub
Function DoesWSExist(wsName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(wsName)
'エラーが発生すれば、そのワークシートは存在しない
If Err.Number <> 0 Then
DoesWSExist = False
Else
DoesWSExist = True
End If
On Error GoTo -1
End Function
注:最後にOn Error GoTo –1を追加し、Err.Numberを0にリセットしています(2つ下のセクションを参照ください)。 On Error Resume Nextと Err.Numberを使えば、他のプログラミング言語にある「Try」「Catch」機能を再現することができます。
On Error GoTo Line
On Error GoTo Lineは、エラーが発生したときに、ラベルの付いたコード行に「移動」するようにVBAに指示します。 Go Toステートメントは次のように宣言します。(errHandlerは移動先の行ラベルです。)
On Error GoTo errHandler
そして、次のような行ラベルを作成します。
errHandler:
注:これは、通常のVBAのGoToステートメントで使用するラベルと同じです。 以下では、On Error GoTo Lineを使ってプロシージャを終了させるデモを行います。
On Error Exit Sub
On Error GoTo Line を使って、エラーが発生したときにサブプロシージャを終了させることができます。 エラー処理用の行ラベルをプロシージャの末尾に配置することで実現できます。
Sub ErrGoToEnd()
On Error GoTo endProc
'あるコード
endProc:
End Sub
またはExit Subコマンドを使用します。
Sub ErrGoToEnd()
On Error GoTo endProc
'あるコード
GoTo skipExit
endProc:
Exit Sub
skipExit:
'その他のコード
End Sub
Err.Clear、On Error GoTo -1、およびErr.Numberのリセット
エラー処理後は、今後のエラー処理の問題を防ぐために、一般的にエラーをクリアする必要があります。
エラー発生後、 Err.ClearとOn Error GoTo -1の両方を使用してErr.Number を0 にリセットできますが、1つだけ非常に重要な違いがあります。Err.Clearは、実際のエラーそのものをリセットするのではなく、Err.Numberをリセットするだけです。
どういうことでしょうか? Err.Clearを使用すると、エラー処理の設定を変更することができなくなります。この違いを見るには、このコードをテストして、On Error GoTo -1をErr.Clear に置き換えてみてください。
Sub ErrExamples()
On Error GoTo errHandler:
'「型が一致しません」エラー
Error(13)
Exit Sub
errHandler:
' エラーをクリアする
On Error GoTo -1
On Error GoTo errHandler2:
'「アプリケーション定義またはオブジェクト定義の」エラー
Error(1034)
Exit Sub
errHandler2:
Debug.Print Err.Description
End Sub
通常、Err.Clearを使用する正当な理由がない限り、On Error GoTo -1 を常に使用することをお勧めします。
VBAエラー時のMsgBox
また、エラー時にメッセージボックスを表示させたい場合もあります。 この例では、エラーが発生した場所によって、異なるメッセージボックスを表示します。
Sub ErrorMessageEx()
Dim errMsg As String
On Error GoTo errHandler
'ステージ1
errMsg = "コピー&ペーストステージでエラーが発生しました。"
'Err.Raise (11)
'ステージ2
errMsg = "データ検証ステージでエラーが発生しました。"
'Err.Raise (11)
'ステージ3
errMsg = "損益計算書作成および上書きコピーステージでエラーが発生しました。"
Err.Raise (11)
'ステージ4
errMsg = "セットアップページでインポートを記録しようとしたときにエラーが発生しました。"
'Err.Raise (11)
GoTo endProc
errHandler:
MsgBox errMsg
endProc:
End Sub
ここでは、Err.Raise (11)を実際のコードに置き換えます。
VBA IsError
エラーを処理するもう一つの方法は、VBAのISERROR関数を使ってエラーをテストすることです。ISERROR関数は、式にエラーがあるかどうかをテストし、エラーが発生した場合はTRUEまたはFALSEを返します。
Sub IsErrorEx()
MsgBox IsError(Range("a7").Value)
End Sub
If Error VBA
ExcelのIFERROR関数を使ってエラーを処理することもできます。 IFERROR関数には、WorksheetFunctionクラスを使ってアクセスする必要があります。
Sub IfErrorEx()
Dim n As Long
n = WorksheetFunction.IfError(Range("a10").Value, 0)
MsgBox n
End Sub
これは、セルA10の値を出力し、値がエラーの場合は、代わりに0を出力します。
VBAのエラーの種類
実行時エラー
上記の通りです。 VBA実行時エラーとは、コードの実行中に発生するエラーのことです。実行時エラーの例としては、以下のようなものがあります。
- 存在しないワークブック、ワークシート、またはその他のオブジェクトを参照している
- 無効なデータ、例えばエラーを含むExcelのセルを参照した場合
- ゼロで割ろうとする
実行時エラーを「エラー処理」するには、前述した方法を使用します。
シンタックスエラー
VBA Syntax Errorsは、コードの記述に伴うエラーです。シンタックスエラーの例としては、以下のようなものがあります。
- 誤字脱字
- 句読点の欠落または不正確な句読点
VBAエディタは、多くの構文エラーを赤いハイライトで識別します。
VBA Editorには、「Auto Syntax Check」というオプションもあります。
これをチェックすると、コード入力後に構文エラーを警告するメッセージボックスが生成されます。
個人的には非常に煩わしいので、この機能は無効にしています。
コンパイルエラー
プロシージャを実行しようとする前に、VBAはそのプロシージャを「コンパイル」します。コンパイルは、プログラムをソースコード(目に見えるもの)から実行形式(目に見えないもの)に変換するものです。 VBAのコンパイルエラーは、コードがコンパイルできないエラーです。
コンパイルエラーの典型的な例は、変数宣言の欠落です。
その他にも、以下のような例があります。
- Forに対してNextがない
- Selectに対してEnd Selectがない
- Ifに対してEnd Ifがない
- 存在しないプロシージャを呼び出している
シンタックスエラー(前項)は、コンパイルエラーのサブセットです。
デバッグ > コンパイル
コンパイルエラーは、プロシージャを実行しようとしたときに表示されます。しかし、理想的には、プロシージャを実行しようとする前に、コンパイルエラーを確認することです。 これは、前もってプロジェクトをコンパイルしておくことで可能です。これを行うには、[デバッグ] > [VBAプロジェクトをコンパイル]を選択します。
コンパイラは、最初のエラーに “Go to”します。そのエラーを修正したら、プロジェクトを再度コンパイルします。すべてのエラーが修正されるまで、これを繰り返してください。 VBAプロジェクトのコンパイルがグレーアウトするので、すべてのエラーが修正されたことが分かります。
オーバーフローエラー
VBAのオーバーフローエラーは、大きすぎる値を変数に入れようとしたときに発生します。例えば、整数型変数には、-32,768から32,767までの値しか入れることができません。それ以上の値を入力すると、オーバーフローエラーになります。
この場合、Long型変数を使用して大きな数値を格納する必要があります。
その他のVBAエラー用語
VBA キャッチエラー
他のプログラミング言語と異なり、VBAにはCatchステートメントがありません。しかし、On Error Resume Nextや If Err.Number <> 0 Thenを使えば、Catchステートメントを再現することができます。これについては、「Err.Numberを使ったエラー処理」で説明しています。
VBA エラーを無視する
VBAでエラーを無視するには、単純に On Error Resume Nextステートメントを使用します。
On Error Resume Next
ただし、前述のとおり、この文はエラーを修正するものではなく、エラーを含むコード行を単に無視するだけなので、使用には注意が必要です。
VBA Throw Error / Err.Raise
VBAでエラーを処理するには、Err.Raiseメソッドを使用します。 このコードの行は、「実行時エラー’13’: 型が一致しません」を発生させます。
Err.Raise (13)
VBAエラートラッピング
VBAエラートラッピングは、VBAエラー処理の別名です。
VBAのエラーメッセージ
VBAのエラーメッセージは次のようなものです。
「デバッグ」をクリックすると、エラーを発生させているコードの行が表示されます。
VBA ループ内のエラー処理
ループ内でエラー処理を行うには、On Error Resume NextとErr.Numberを使ってエラーが発生したかどうかを検出します(エラーが発生するたびにErr.Clear を使ってエラーをクリアすることを忘れないでください)。
以下の例では、2つの数値(A列とB列)を割ってC列に結果を出力しています。
Sub test()
Dim cell As Range
On Error Resume Next
For Each cell In Range("a1:a10")
'セルの値を設定する
cell.Offset(0、2).Value = cell.Value / cell.Offset(0, 1).Value
'Cell.ValueがErrorの場合、0をデフォルトとする
If Err.Number <> 0 Then
cell.Offset(0, 2).Value = 0
Err.Clear
End If
Next
End Sub
AccessのVBAエラー処理
上記の例はすべて、Access VBAでもExcel VBAとまったく同じように動作します。
Function DelRecord(frm As Form)
'この関数は、フォームからテーブルのレコードを削除するために使用される
On Error GoTo ending
With frm
If .NewRecord Then
.Undo
Exit Function
End If
End With
With frm.RecordsetClone
.Bookmark = frm.Bookmark
.Delete
frm.Requery
End WIth
Exit Function
ending:
End
End Function