知らずに落ちると抜け出せなくなるVBAの落とし穴です。
- Callしたプロシージャが最後まで処理されない
- On Error Resume Nextでスキップしたはずなのに次の行が実行できない
あたりにお悩みの方は、この罠に落ちていないかご確認ください。
発生する現象
タイトルの通りですが、On Error Resume Next下においては、
Callしたプロシージャ内でエラーが発生すると即座にCall元に戻ります。
単純化したコードを置いておきますので眺めてみてください。
Sub 親プロシージャ() On Error Resume Next Call 子プロシージャ End Sub Sub 子プロシージャ() Cells(0, 0).Select ' ← エラーが起きる処理 MsgBox "このコードは実行されないよ" End Sub
この親プロシージャを実行した場合は、
MsgBoxは表示されることなくマクロは実行を終えます。
解決策
子プロシージャにもOn Error Resume Nextを書くだけでOKです。
Sub 親プロシージャ() On Error Resume Next Call 子プロシージャ End Sub Sub 子プロシージャ() On Error Resume Next ' ← これを追加 Cells(0, 0).Select ' ← エラーが起きる処理 MsgBox "このコードは実行されるよ" End Sub
これならMsgBoxはちゃんと表示されます。
ちなみに当たり前のことですが、
これは「エラーが起きるかどうか試して処理を分岐したい」など、
On Error Resume Nextを狙って使うときの解決策です。
狙ってるわけではなく、普通に(?)エラーが起きてしまった時の対処法は、
当然ながらどんなエラーが起きるかを調べて対策するしかありません。
その時は逆に親プロシージャのOn Error Resume Nextを外して、
起きるエラーをしっかり調べて対策してください。
On Error Goto でも同じ現象が起きます
今回の仕様はちょっと概念的なもので説明が難しいのですが、
↓これを見ると少し整理できるかもしれません。
Sub 親プロシージャ() On Error GoTo エラー時 Call 子プロシージャ Exit Sub エラー時: MsgBox "このコードAは実行されるよ" End Sub Sub 子プロシージャ() Cells(0, 0).Select ' ← エラーが起きる処理 MsgBox "このコードBは実行されないよ" End Sub
このようにOn Error GoTo 下においてCallした場合も、
エラーが起きた瞬間に子プロシージャを抜けて、
「エラー時」ラベルに飛んで処理が実行されます。
対してOn Error Resume Nextを書いた場合は、
Sub 親プロシージャ() On Error GoTo エラー時 Call 子プロシージャ Exit Sub エラー時: MsgBox "このコードAは実行されないよ" End Sub Sub 子プロシージャ() On Error Resume Next Cells(0, 0).Select ' ← エラーが起きる処理 MsgBox "このコードBは実行されるよ" End Sub
このようにコードBのMsgBoxを処理されることができます。
そして注目すべきはコードAのMsgBoxが実行されないこと、
すなわち「親プロシージャにとってエラーは起きていない扱い」なことです。
子プロシージャで「エラーは無視してOK」と言ってやった処理は、
いわゆる「想定内」の出来事であり、親プロシージャにとって例外ではない。
という捉え方をするとわかりやすいでしょうか。
OnError○○ はどのプロシージャで指定しているかが重要になるコードです。
エラー処理を書いたプロシージャをCallする場合は注意して扱ってください。
詳しくはこちらの記事にまとめてありますので、
複雑なエラー処理を行う必要がある方はご覧ください。
www.limecode.jp