Ribbit.work

VBAでエラー処理とThrow処理を両方行う方法

ExcelVBA

last modified date2021-8-17

publish date2021-8-16

一般的にエラー処理は、各関数では最低限行い、後は呼び出し元にThrowするのが一般的かと思いますが、VBAではそれを簡単には実装できません。

エラーハンドラを作ってしまうとエラーを握りつぶしてしまい、そこから再度Err.Raiseしようとすると、その関数内でエラーを拾い無限ループになるからです。

具体的な例を挙げると、

  • Open関数でファイルを開いた後、エラーになった場合でもCloseは発生させたい。
  • その上で、エラーを呼び出し元に伝達したい。

といった場合です。

On Error GoTo 0
Call Err.Raise(Err.Number)

解決には上記のコードを使います。解説とサンプルを紹介致します。

On Error GoTo 0

On Error GoTo 0 を使用すると、使用した以前に定義していたOn Errorを打ち消すことができます。

通常、エラーハンドラでErr.Raiseを書いてしまうと、

  1. エラーを拾う
  2. エラーハンドラに飛ぶ
  3. エラーを投げる
  4. 1に戻る

上記のループになってしまいますが、On Error GoTo 0 を入れることで、

  1. エラーを拾う
  2. エラーハンドラに飛ぶ
  3. エラーハンドラの打ち消し
  4. エラーを呼び出し元にスロー

とすることができます。これにより、他のプログラム言語で言うところの、catchにthrowを含むようなTry-Catch-Finallyを再現できます。

コードサンプル

エラー処理 → Throwだけでいい場合

Public sub Caller()
	On Error GoTo ERROR_HANDLER
	Call Called

ERROR_HANDLER:
	Debug.Print(Err.Number)
End Sub
Public sub Called()

	On Error GoTo ERROR_HANDLER
	Dim errNumber as Long

	' エラーの起こり得る処理を書く

    Exit Sub

ERROR_HANDLER:
	errNumber = Err.Number
	On Error GoTo 0

	' ここにエラー発生後の処理を書く

	' 呼び出し元にエラーを伝達します
	Call Err.Raise(errNumber)

End Sub

Try-Catch-Finallyを再現する

結構長い記述が必要です。

Public sub Caller()

	On Error GoTo ERROR_HANDLER

	Call Called

ERROR_HANDLER:
	Debug.Print(Err.Number)
End Sub

Public sub Called()

	On Error GoTo ERROR_HANDLER
	Dim errNumber as Long

	' エラーの起こり得る処理を書く

FINALLY:

	If errNumber <> 0 then
		Err.Raise(errNumber)
	End if

	Exit Sub
ERROR_HANDLER:
	errNumber = Err.Number
	On Error GoTo 0

	' ここにエラー発生後の処理を書く

 	Resume FINALLY
End Sub

実例サンプル

Try-Catchのみの場合

'------------------------------------------------
'
' 関数を呼ぶ関数
'
'------------------------------------------------
Public Sub Caller()
	On Error GoTo ERROR_HANDLER
	Call Called

ERROR_HANDLER:

	Debug.Print "呼び出し元 : Catch"

End Sub
'------------------------------------------------
'
' 呼び出される(Throwを行う)関数
'
'------------------------------------------------
Public Sub Called()

	On Error GoTo ERROR_HANDLER
	Dim errNumber as Long

	Dim n As Long: n = 1 / 0

	Exit Sub

ERROR_HANDLER:
	errNumber = Err.Number
	On Error GoTo 0

	Debug.Print "呼び出し先 : Catch"

	' 呼び出し元にエラーを伝達します
	Call Err.Raise(errNumber)

End Sub

実行結果

呼び出し先 : Catch
呼び出し元 : Catch

Try-Catch-Finallyを再現した場合

'------------------------------------------------
'
' 関数を呼ぶ関数
'
'------------------------------------------------
Public sub Caller()

	On Error GoTo ERROR_HANDLER

	Call Called

ERROR_HANDLER:

	Debug.Print "呼び出し元 : Catch"

End Sub

'------------------------------------------------
'
' 呼び出される(Throwを行う)関数
'
'------------------------------------------------
Public sub Called()

	On Error GoTo ERROR_HANDLER

	Dim errNumber as long

	Dim n as long: n = 1 / 0

FINALLY:

	Debug.Print "呼び出し先 : Finally"

	If errNumber <> 0 then
		Err.Raise(errNumber)
	End if

	Exit Sub
ERROR_HANDLER:
	errNumber = Err.Number
	On Error GoTo 0

	Debug.Print "呼び出し先 : Catch"

 	Resume FINALLY
End Sub

実行結果

呼び出し先 : Catch
呼び出し先 : Finally
呼び出し元 : Catch

この記事を読んだ方におすすめの記事

Excel VBAの高速化はこれだけでOK!コピペで使えるコードを紹介
2021-9-3

Excel VBAの高速化はこれだけでOK!コピペで使えるコードを紹介

VBA
ExcelからChatworkにメッセージを送る
2021-9-3

ExcelからChatworkにメッセージを送る

VBA
ExcelからChatworkのユーザ一覧を取得する
2021-9-3

ExcelからChatworkのユーザ一覧を取得する

VBA
VBAでマジックナンバーをスマートに消したい!
2021-9-1

VBAでマジックナンバーをスマートに消したい!

VBA
【参照設定不要】Base64フォーマットにエンコードする
2021-8-16

【参照設定不要】Base64フォーマットにエンコードする

ExcelVBA

最新の記事

特定のHTML要素のclassListを全て削除(リセット)する方法
2021-10-14

特定のHTML要素のclassListを全て削除(リセット)する方法

JavaScript
KintoneからChatworkのユーザ一覧を取得する
2021-9-15

KintoneからChatworkのユーザ一覧を取得する

JavaScriptKintone
TypeScriptで楽天ブックス書籍検索APIを使う📚
2021-9-13

TypeScriptで楽天ブックス書籍検索APIを使う📚

TypeScriptJavaScript
【kintone】Webフォントを適用する
2021-9-8

【kintone】Webフォントを適用する

KintoneJavaScript
KintoneからChatworkにメッセージを送る
2021-9-6

KintoneからChatworkにメッセージを送る

JavaScript