和風スパゲティのレシピ

日本語でコーディングするExcelVBA

OnError中にCallした関数内でエラーが起きると即呼出元に戻る

知らずに落ちると抜け出せなくなる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