そこでOn Errorステートメントとラベルを使う。
一番簡単な例外処理(エラーハンドリング)は以下のとおり。
Sub ErrHandlingTest()
On Error GoTo ErrorHandler
Dim value As Long
value = 2 / 0 '-- ゼロ除算のためエラー発生
Exit Sub
ErrorHandler:
'-- 例外処理
MsgBox Err.Number & ":" & Err.Description, vbCritical & vbOKOnly, "エラー"
End Sub
このようにすると、エラーが発生した時点で「On Error GoTo ラベル名」に指定したラベル名(上記の例ではErrorHandler)に飛ぶ。 エラーごとにキャッチしたい
ひとつの例外しか発生しないなら、前述のとおりで良いんだけど、Catchでエラー別に取得したいときがある。
C#やJavaなどのプログラミング言語では、必ず「Catchだけですべての例外を取得しない。エラーごとにCatchする」と習うだろう。
VBAでは若干面倒だが、以下の2つの方法で対応することができる。
自分で例外をスローする
Sub ErrHandlingTest()
On Error GoTo ErrorHandler
Dim value As Long
Dim div As Long
div = 0
If div = 0 Then
GoTo DivisionByZero
Else
value = 2 / div
End If
Exit Sub
DivisionByZero:
'-- ゼロ除算の場合にのみここにくる
MsgBox "ゼロ除算ですよ"
Exit Sub
ErrorHandler:
'-- 例外処理
MsgBox Err.Number & ":" & Err.Description, vbCritical & vbOKOnly, "エラー"
End Sub
こんな感じに、あらかじめわかっている処理なら自分で例外を流ればよい。
(業務エラーとかの場合はコレを使う)
ポイントは、通常処理の最後とDivisionByZeroラベルの最後に「Exit Sub」があること。
これがないと、続けてDivisionByZeroやErrorHandlerまで実行されてしまうので注意。
キャッチしたあとで振り分ける
Sub ErrHandlingTest()
On Error GoTo ErrorHandler
Dim value As Long
Dim div As Long
div = 0
value = 2 / div
Exit Sub
DivisionByZero:
'-- ゼロ除算の場合にのみここにくる
MsgBox "ゼロ除算ですよ"
Exit Sub
ErrorHandler:
'-- 例外処理(必ずここに来る)
Select Case Err.Number
Case 11
GoTo DivisionByZero
Case Else
MsgBox Err.Number & ":" & Err.Description, vbCritical & vbOKOnly, "エラー"
End Select
End Sub
エラーが発生するとErrオブジェクトにエラー情報が格納される。
その中の「Err.Numberプロパティ」に従い、処理を振り分ける方法。
ただ「Err.Number = 11」と書いてもよくわからないので「Const ERROR_DIVISION_BY_ZERO As Long = 11」のように定数化しておくことをオススメする。
Err.Numberについては、Office TANAKA - Excel VBAの実行時エラーを参照。
Finallyで終了処理がしたい
Finallyを使って終了処理をしたいことがある。
たとえば、CreateObjectでExcelを操作するとき、CloseやQuitをしないとプロセスに「EXCEL.EXE」が残ってしまう。
一番簡単な方法としては、以下のように冗長的に書くこと。
Sub ErrHandlingTest()
On Error GoTo ErrHandler
Dim obj As Object
Set obj = CreateObject("Excel.Application")
obj.Application.Workbooks.Open Filename:="C\:test.xlsx"
'-- いろんな処理
'-- 正常終了の場合は
obj.Close
obj.Quit
Exit Sub
ErrHandler:
'-- エラーが発生した場合
obj.Close
obj.Quit
End Sub
個人的に大嫌いな書き方。冗長的で、いかにも頭が悪そうに見える。
そんなときは、惜しげも無くGoToを使ってしまおう。
といっても、GoToを使用するのは極力さけたいので、エラー処理と終了処理以外では、使用しないほうが良いだろう。
Sub ErrHandlingTest()
On Error GoTo ErrHandler
Dim obj As Object
Set obj = CreateObject("Excel.Application")
obj.Application.Workbooks.Open Filename:="C\:test.xlsx"
'-- いろんな処理
GoTo Finally
ErrHandler:
'-- エラーが発生した場合
Resume Finally
Finally:
If Not obj Is Nothing Then
obj.Close
obj.Quit
End If
End Sub
ErrHandlerのなかで「Resume Finallly」と書いているのは、例外をスローするため。ただし、Finallyで処理しなければエラーがもみ消されてしまうので注意。
(できれば、Finallyに投げる前に処理を済ませて置いたほうが良い)
さきほど「Exit Sub」だった場所を、「GoTo Finally」にかえることで必ずFinally(終了処理)を実行することができる。
ちなみに「ErrHandler」の「Resume Finally」がなくてもFinallyは実行される。
違いはエラー情報をFinallyに渡すかどうか。
違いはエラー情報をFinallyに渡すかどうか。
おまけ
エラーをキャッチせずに無理やり処理を続行したい場合は、「On Error GoTo ラベル」を「On Error Resume Next」を使うとエラーを無視して処理を続けることができる。
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿