イントロダクション
前回(第16回)は、On Error GoTo でエラーをラベルへジャンプさせ、Err オブジェクトで原因を調べる基本形を学んだ。
今回は、エラー処理のもう一つの柱である「エラーを無視して先へ進む」On Error Resume Next と、「エラーの後に処理を再開する」Resume を取り上げる。あわせて、Err.Clear と On Error GoTo 0 の使い方も押さえておこう。
On Error Resume Nextとは
On Error Resume Next を書くと、エラーが起きてもマクロを止めず、次の行へ進むようになる。エラーの内容は Err オブジェクトに残るため、後から調べることもできる。
使いどころとして分かりやすいのが、「指定したシートが存在するかどうかの確認」である。
存在しないシートを指定すると、通常は実行時エラー(9)になる。この性質を逆手に取って、エラーになるかどうかで存在を判定する。
Function シートが存在する(シート名 As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Worksheets(シート名)
On Error GoTo 0
シートが存在する = Not ws Is Nothing
End FunctionWorksheets(シート名) が失敗しても、エラーは無視されて次の行へ進む。その場合、ws には何も代入されないので Nothing のままである。これを Not ws Is Nothing で判定している。
Sub シート確認()
If シートが存在する("Sheet1") Then
MsgBox "Sheet1は存在します。"
Else
MsgBox "Sheet1は存在しません。"
End If
End Sub
シート名を、存在するものと存在しないものに変えて試してみよう。
On Error GoTo 0でエラー処理を解除する
先ほどのコードには、On Error GoTo 0 という行があった。これはそれまでのエラー処理の設定を解除する命令である。
On Error Resume Next を書いたまま放置すると、その後に起きたエラーもすべて無視されてしまう。マクロは止まらないが、途中で失敗しているのに気づけないため、原因の特定が難しくなる。
そのため、On Error Resume Next は次の使い方を守りたい。
- 無視してよい1行〜数行だけを囲む
- 囲み終わったらすぐ
On Error GoTo 0で解除する
「マクロ全体の先頭に On Error Resume Next を書いておく」という使い方は避けよう。
Err.Clearでエラー情報をリセットする
On Error Resume Next の後でエラーが起きると、Err.Number にエラー番号が残る。この状態を放置すると、次の判定で「まだエラーが起きている」と誤って判断してしまう。
複数のシートを順番に確認する例で見てみよう。
Sub 複数シートの確認()
Dim シート名 As Variant
Dim ws As Worksheet
On Error Resume Next
For Each シート名 In Array("売上", "経費", "集計")
Set ws = Nothing
Set ws = ThisWorkbook.Worksheets(シート名)
If Err.Number <> 0 Then
Debug.Print シート名 & " シートが見つかりません"
Err.Clear
Else
Debug.Print シート名 & " シートがあります"
End If
Next シート名
On Error GoTo 0
End Subポイントは次の2つである。
Set ws = Nothing:前のループで取得したシートが残らないよう、毎回リセットしているErr.Clear:見つからなかったシートの後で、エラー情報を消している。これがないと、次のシートが存在していてもErr.Numberが0にならず、「見つかりません」と表示されてしまう
なお、On Error GoTo 0 は、それまで設定していたエラー処理を解除する命令である。
エラー情報を明示的に消したい場合は、Err.Clear を使用する。
そのため、複数の処理を On Error Resume Next で順番に確認する場合などは、必要に応じて Err.Clear を実行して、前の処理で発生したエラー情報をリセットする。
エラーの有無で処理を分ける
On Error Resume Next と Err.Number を組み合わせれば、「失敗したら別の処理をする」という書き方ができる。ブックを開く例を見てみよう。
Sub ブックを開く()
Dim wb As Workbook
On Error Resume Next
Set wb = Workbooks.Open("C:\test\データ.xlsx")
If Err.Number <> 0 Then
MsgBox "ブックを開けませんでした。" & vbCrLf & _
Err.Description, vbExclamation
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
MsgBox wb.Name & " を開きました。"
End Sub
ファイルが存在しなければメッセージを表示して終了し、存在すれば後続の処理へ進む。On Error GoTo 0 は、どちらの流れでも解除されるように2か所に書いている。
Resumeでエラーの後に処理を再開する
ここからは、On Error GoTo で飛んだエラー処理ルーチンの中で使う命令である。エラー処理を終えたあとの再開位置を、Resume で指定できる。
Resume:エラーが起きた行をもう一度実行するResume Next:エラーが起きた行の次の行から再開するResume ラベル名:指定したラベルへジャンプして再開する
On Error Resume Next(エラー発生前に書く設定)と、Resume Next(エラー処理ルーチンの中で書く再開命令)は別物なので、混同しないようにしよう。
Resume の例として、ブックが開けないときに「再試行」できるマクロを作ってみる。
Sub ブックを開くやり直し()
Dim wb As Workbook
On Error GoTo エラー処理
Set wb = Workbooks.Open("C:\test\データ.xlsx")
MsgBox wb.Name & " を開きました。"
Exit Sub
エラー処理:
If MsgBox("ブックを開けませんでした。" & vbCrLf & _
"ファイルを配置してから、再試行しますか?", _
vbRetryCancel + vbExclamation) = vbRetry Then
Resume
End If
End Subファイルが見つからないとエラー処理に飛び、「再試行 / キャンセル」のダイアログが表示される。ここで、別のウィンドウからファイルを所定の場所に置いて[再試行]を押すと、Workbooks.Open の行がもう一度実行される。[キャンセル]を押せば、そのままマクロが終了する。
Resume は、エラーの原因が解消されないまま実行すると、同じエラーが繰り返されて無限ループになる。今回のように、ユーザーが[キャンセル]で抜けられる仕組みを用意しておこう。
3つの書き方の使い分け
ここまでの内容を整理しておく。
| 書き方 | 動作 | 主な使いどころ |
|---|---|---|
On Error GoTo ラベル | エラー時にラベルへジャンプする | 想定外のエラーへの備え、メッセージ表示 |
On Error Resume Next | エラーを無視して次の行へ進む | 失敗してもよい処理、存在確認 |
On Error GoTo 0 | エラー処理の設定を解除する | Resume Next の範囲を閉じる |
Resume | エラーの行をやり直す | 再試行(エラー処理ルーチン内) |
まとめ
今回は、エラーを無視する・やり直す方法を学んだ。
On Error Resume Nextは、エラーを無視して次の行へ進む- 使うときは範囲を最小限にし、
On Error GoTo 0で必ず解除する - 複数回の判定では、
Err.Clearでエラー情報を消す Resumeはエラーの行をやり直し、Resume Nextは次の行から再開するResumeは、無限ループにならないよう抜け道を用意する
次回(第18回)は、Err.Raise を使った「エラーを呼び出し元に伝える」方法を解説する。Function の中で起きた問題を、呼び出したSubの側で処理する設計と、途中で失敗しても画面更新などの設定を元に戻す「後始末」の書き方を学んでいこう。


コメント