今回は、VBAプログラムにおける例外処理について、説明したいと思います。例外処理とは、プログラムにおいて、想定外の動作(例外)が発生した時の処理のことです。想定外の動作の例をあげると、ほんの一部ですが、以下のようなものがあります。
例えば、スタックがオーバーフローした時などは、エクセルが以下のような画面を表示しますが、これが例外処理と呼ばれるもので、通常、この処理はExcelに委ねられています。
※サンプルファイルの【スタックオーバーフロー(通常)】ボタンを押すことで、この処理を確認することができます。
サンプルのダウンロード
実は、エクセル任せになっているこの例外処理を、VBAでは自分でプログラミングすることが出来るのです。以下がそのサンプルプログラムです。
'再帰呼び出しにより、スタックをオーバーフローさせる関数。
Private Sub TestStackOverFlow(ByVal a As Long)
'再帰呼び出し
TestStackOverFlow 1
End Sub
'スタックオーバフロー(例外)
Private Sub CBtnStackOverFlow2_Click()
On Error GoTo LABEL_ERR_CBtnStackOverFlow2
'再帰呼び出しにより、スタックを
'オーバーフローさせます。
TestStackOverFlow 1
Exit Sub
LABEL_ERR_CBtnStackOverFlow2:
'ここから下は、正常な処理の場合、
'実行されないパスです。
UFormMessage.ShowDlg "スタックがオーバーフローしました。"
End Sub
プログラムを簡単に説明すると、CBtnStackOverFlow2_Click関数内の、On Error GoTo ラベル名ステートメントが、この記述以降、例外が発生した場合に、処理がLABEL_ERR_CBtnStackOverFlow2ラベルの位置まで、一気にジャンプするというものです。この箇所に例外が発生した場合の、処理を記述すればよいわけですが、ここでは、スタックがオーバーフローしたというメッセージを表示する処理にしてあります。これを実行すると以下のような画面が表示されます。
※サンプルファイルの【スタックオーバーフロー(例外)】ボタンを押すことで、この処理を確認することができます。
同じような、例外処理で、メモリアクセス違反と、エラーセルへのアクセスの例を、サンプルファイルに実装してありますので、こちらの方も確認してみてください。
次に、ユーザ定義型の例外処理のサンプルについて説明したいと思います。『ユーザ定義型って、何?』と思われるかもしれませんが、難しく考える必要はありません。これは簡単に言うと、自分で、意図的に例外を発生させるプログラムが記述できるということです。以下がそのサンプルプログラムです。
'ユーザ定義のエラー値
Public Enum EnumUserDefinedError
EUDEF_ERROR1 = vbObjectError + 1
EUDEF_ERROR2
EUDEF_ERROR3
'必要に応じて、エラー値を追加してください。
End Enum
'ユーザ定義の例外1
Private Sub CBtnErr1_Click()
On Error GoTo LABEL_ERR_CBtnErr1
'意図的に例外を発生させます。
Err.Raise EUDEF_ERROR1
Exit Sub
LABEL_ERR_CBtnErr1:
'ここから下は、正常な処理の場合、
'実行されないパスです。
'エラー番号からメッセージを取得し表示。
UFormMessage.ShowDlg ErrGetErrorMessage(Err.Number)
End Sub
初めに記述しているEnumUserDefinedError列挙値が、ユーザが定義した例外の番号です。必要に応じて、追加・変更してみてください。vbObjectErrorは、VBAで標準で定義されている定数値で、ユーザが使用するエラー値は、これを含まない以降の値を定義してください。
次に、例外の発生方法ですが、これはErrオブジェクトのRaiseメソッドを呼び出すことにより実現します。このメソッドを呼び出すと、例外が発生し、LABEL_ERR_CBtnErr1ラベルに、強制的に処理がジャンプします。
最後の例外処理では、ErrオブジェクトのNumberプロパティから、エラーメッセージを検索し、例外の内容を通知する処理となっています。Numberの値からは、エラー番号が取得できる仕様ですが、ここではRaiseメソッドの引数に渡したエラー値が取得できるはずです。
※サンプルファイルの【ユーザ定義の例外1】ボタンを押すことで、この処理を確認することができます。また、同等の処理を【ユーザ定義の例外2】、【ユーザ定義の例外3】ボタンの処理にも実装していますので、こちらも確認してみてください。
もう一つだけ、サンプルコードを紹介したいと思います。以下がそのサンプルコードなのですが、On Error Resume Nextステートメントを記述することで、例外が発生しても、発生箇所の次のコードから、プログラム実行を継続できるようになります。すなわち、スタックがオーバーフローしても、アクセス違反が発生しても、プログラムが止まることなく、処理が継続されます。
'例外のレジューム
Private Sub CBtnResume_Click()
Dim bufs(1 To 256) As Byte
On Error Resume Next
'再帰呼び出し
TestStackOverFlow 1
'メモリアクセス違反
bufs(0) = 100
UFormMessage.ShowDlg "例外箇所で、処理が継続して実行されます。"
End Sub
ちなみに、On Errorステートメントの有効範囲は、関数内で、ステートメントを記述した箇所から、その関数を抜けるまでの間となります。
以下から、今回の豆知識で紹介した内容のエクセルファイルがダウンロードできます。
サンプルのダウンロード
説明の最後の、Resumeステートメントですが、これについては、個人的には、使用しない方が良いかと思います。プログラムは、おかしくなったタイミングで異常が発生する方が、原因が究明しやすく、修正が効率的に行えるからです。
人間も一緒だと思うんです…。おかしなことをやってたら、おかしいと、注意してくれる方がいいですよね。黙って見過ごされると、後が怖いですよねぇ~。
サンプルに含まれるデータは、私の創作によるものです、サンプルデータに含まれる個人名、会社名などの情報は、実在の人物とはまったく関係ありません。
ご意見・ご要望等ありましたら、画面最下部のメールアドレスまでご連絡ください。