エラー処理って使っていますか?
エラー処理といえば、0(ゼロ)で割る処理を行うとエラーが発生します。また、ファイルへの入出力の際に不適切なパスを指定した場合などもエラーが発生します。
エラーが発生すると処理が停止して、それ以降の処理が行われないなど不具合の原因となります。そうならないためには、エラー処理を行います。
この記事では、
- エラー処理とは
- エラーを処理する方法
- ループ中のエラー処理
- メッセージを取得する方法
- On Errorを複数回使用する場合
- エラー処理をサブルーチンにまとめる方法
など基本的な内容から、応用的な内容についても解説していきます。
今回はエラー処理について、使い方をわかりやすく解説します!
エラー処理とは
エラー処理とは、プログラムが何かしらの原因で処理が行えなかったり、意図しない処理を行う場合に、不具合を最小限に抑えるための処理です。
エラー処理には、大きく分けて2つの考え方があります。
- データが壊れることやなくなることがないように、安全を第一に考え処理を中断し、その後の処理を行わない。
- 間違いが起こっても他の処理に影響しないようにする。
では、VBAではエラー処理を具体的にどのように記述するのか、くわしくみていきましょう。
エラーを処理する方法
エラー処理を行うには、On Errorステートメントを使います。
On Errorステートメントを記述することで、エラー処理を有効にし、エラー発生時の処理を指定することができます。エラー発生時の処理の指定をOn Errorステートメントのあとに記述します。
GoToステートメントを使ってラベル先に処理をスキップする方法、GoTo 0ステートメントを使ってエラー処理を無効にする方法、Resume Nextを使ってエラーの発生した次の行から処理を続ける方法などがあります。
On Error GoToで処理をスキップする方法
GoToステートメントを使うことで、次の処理を指定することができます。ラベル先にエラー処理を記述し、そこへ処理をスキップします。
ラベル先の処理にスキップするには以下のように記述します。
On Error GoTo ラベル名 (エラーが発生し得る処理) Exit Sub ラベル名: (エラー発生時の処理)
サンプルコードで確認しましょう。
Sub macro1() Dim num1 As Integer, num2 As Integer, result As Double num1 = 1 num2 = 0 On Error GoTo ErrLabel result = num1 / num2 'エラー発生 MsgBox "計算結果は " & result & " です" Exit Sub ErrLabel: MsgBox "エラーが発生しました" End Sub
実行結果:
このサンプルコードでは、ゼロでの割り算でエラーが発生します。エラーが発生すると、ラベル先に処理がスキップしています。
GoToステートメントの使い方については、こちらで詳しく解説していますので、ぜひ参考にしてください。
Resumeで処理を続ける方法
Resumeステートメントを使うと、処理を継続することができます。Resumeと記述すると発生した行に戻って継続します。
Resume Nextと記述すると次の行から継続することができます。
サンプルコードで確認しましょう。
Sub macro2() Dim num1 As Integer, num2 As Integer, result As Double Dim msg As String num1 = 1 num2 = 0 On Error GoTo ErrLabel result = num1 / num2 'エラー発生 MsgBox msg & vbCrLf & "計算結果は " & result & " です" Exit Sub ErrLabel: msg = "エラーが発生しました" Resume Next End Sub
実行結果:
このサンプルコードでは、ゼロでの割り算でエラーが発生します。エラーが発生すると、ラベル先に処理がスキップしています。
ラベル先の処理が終わると、Resume Nextステートメントでエラー発生箇所の次の行から処理を行っています。
ループ中のエラー処理について
ループ中にエラー処理を行う場合は、先ほど述べたResume Nextステートメントを使って処理を継続する必要があります。
サンプルコードで確認しましょう。
Sub macro3() Dim num1 As Integer, num2 As Integer, i As Integer, result As Double Dim msg As String num1 = 1 For i = 1 To 5 num2 = i Mod 2 On Error GoTo ErrLabel msg = msg & vbCrLf & "計算結果は " & num1 / num2 & " です" & vbCrLf Next i MsgBox msg Exit Sub ErrLabel: msg = msg & "エラーが発生しました" Resume Next End Sub
実行結果:
このサンプルコードは、2での割り算の余り、つまり0もしくは1で割り算を行っています。余りが0の場合はゼロでの割り算となり、エラーが発生します。
この処理をForステートメントを使って繰り返しループで処理していますが、ErrLabel部分でエラー処理を行い、Resume Nextステートメントで次の処理から継続するようにしています。
もしNextを抜かしてしまうと、Excelが応答しなくなることもありますので注意しましょう。
メッセージを取得する方法
エラーが発生した場合、エラーコードの番号やエラー内容を確認してその後の対応を決めることがよくあります。
そのためにはエラーメッセージを取得して出力する必要があります。エラーメッセージはErrオブジェクトのプロパティから取得します。
プロパティ名 | 説明 |
---|---|
Description | エラーの説明 |
HelpContext | ヘルプファイルのコンテキストID |
HelpFile | ヘルプファイルへの絶対パス |
LastDLLError | DLLの呼び出しにより作成されたエラーコード |
Number | エラーを指定する値 |
Source | エラーを発生させたオブジェクト、アプリ名 |
使い方をサンプルコードで確認しましょう。
Sub macro4() Dim num1 As Integer, num2 As Integer, result As Double Dim msg As String num1 = 1 num2 = 0 On Error GoTo ErrLabel result = num1 / num2 'エラー発生 MsgBox msg & vbCrLf & "計算結果は " & result & " です" Exit Sub ErrLabel: msg = "エラー発生アプリ: " & Err.Source & vbCrLf & _ "エラー番号: " & Err.Number & vbCrLf & _ "エラー内容: " & Err.Description & vbCrLf Resume Next End Sub
実行結果:
このサンプルコードでは、ErrオブジェクトのSource、Number、Descriptionプロパティを使ってエラーメッセージを表示しています。
ちなみに、主なエラー番号について以下の表にまとめました。
番号 | メッセージ |
---|---|
3 | Returnに対応するGoSubがありません。 |
5 | プロシージャの呼び出し、または引数が不正です。 |
6 | オーバーフローしました。 |
7 | メモリが不足しています。 |
9 | インデックスが有効範囲にありません。 |
10 | この配列は固定されているか、または一時的にロックされています。 |
11 | 0で除算しました。 |
13 | 型が一致しません。 |
14 | 文字列領域が不足しています。 |
17 | 要求された操作は実行できません。 |
18 | ユーザーによる割り込みが発生しました。 |
20 | エラーが発生していないときにResumeを実行することはできません。 |
28 | スタック領域が不足しています。 |
35 | SubまたはFunctionが定義されていません。 |
51 | 内部エラーです。 |
52 | ファイル名または番号が不正です。 |
53 | ファイルが見つかりません。 |
54 | ファイルモードが不正です。 |
55 | ファイルは既に開かれています。 |
57 | デバイスI/Oエラーです。 |
58 | 既に同名のファイルが存在しています。 |
59 | レコード長が一致しません。 |
61 | ディスクの空き容量が不足しています。 |
62 | ファイルにこれ以上データがありません。 |
63 | レコード番号が不正です。 |
67 | ファイルが多すぎます。 |
68 | デバイスが準備されていません。 |
70 | 書き込みできません。 |
71 | ディスクが準備されていません。 |
74 | ディスク名は変更できません。 |
75 | パス名が無効です。 |
76 | パスが見つかりません。 |
91 | オブジェクト変数またはWithブロック変数が設定されていません。 |
92 | Forループが初期化されていません。 |
93 | パターン文字列が不正です。 |
94 | Nullの使い方が不正です。 |
328 | 不正なパラメータです。配列に書き込めません。 |
380 | プロパティの値が不正です。 |
381 | プロパティ配列のインデックスが不正です。 |
382 | プロパティは、実行時には設定できません。 |
383 | プロパティは値の取得のみ可能です。 |
385 | このプロパティには配列のインデックスが必要です。 |
387 | プロパティは値を設定できません。 |
393 | プロパティは実行時に値の取得はできません。 |
394 | プロパティは設定のみ可能です。 |
422 | プロパティが見つかりません。 |
423 | プロパティまたはメソッドが見つかりません。 |
424 | オブジェクトが必要です。 |
425 | オブジェクトの使い方が不正です |
438 | オブジェクトは、このプロパティまたはメソッドをサポートしていません。 |
449 | 引数は省略できません。または不正なプロパティを指定しています。 |
744 | 検索文字列が見つかりませんでした。 |
1004 | ○○クラスの××メソッドが失敗しました。(など) |
2000 | セルのエラー:#NULL! |
2007 | セルのエラー:#DIV/0! |
2015 | セルのエラー:#VALUE! |
2023 | セルのエラー:#REF! |
2029 | セルのエラー:#NAME |
2036 | セルのエラー:#NUM! |
2042 | セルのエラー:#N/A |
31004 | オブジェクトがありません。 |
31018 | クラスが設定されていません。 |
31027 | オブジェクトをアクティブにできません。 |
31036 | ファイルへの書き込み中にエラーが発生しました。 |
31037 | ファイルの読み込み中にエラーが発生しました。 |
エラーの種類によって処理を変える
エラー番号を使って、発生するエラーごとに処理を変えることも可能です。
処理を変えるためにSelect Caseステートメントを使います。
Select Case 変数 Case 条件式1 処理1 Case 条件式2 処理2 Case Else デフォルト(どの条件にも一致しなかった場合)の処理 End Select
変数にErrオブジェクトのNumberプロパティを指定し、条件式にエラー番号を記述します。
サンプルコードで確認しましょう。
Sub macro() Dim num1 As Double, num2 As Double, result As Double num1 = 1 num2 = 0 On Error GoTo ErrLabel Workbooks.Open ("Sample.xlsx") result = num1 / num2 Exit Sub ErrLabel: Select Case Err.Number Case 11 MsgBox "0で割ることはできません" & vbCrLf & Err.Description Case 1004 MsgBox "実行できませんでした" & vbCrLf & Err.Description Case Else MsgBox "予期せぬエラーが発生しました" & vbCrLf & Err.Number & ":" & Err.Description End Select Resume Next End Sub
実行結果:
このサンプルコードでは、存在しないファイルを開いたのちに、0での除算を実行しようとしています。
存在しないファイルを開く場合、1004番のエラーが発生するのでSelect Casaeステートメントで条件式が1004の場合の処理が実行されています。
0での除算を実行する場合は、11番のエラーが発生するので同じように条件式が11の場合の処理が実行されています。
Select Caseステートメントで条件分岐を行う方法については、こちらで詳しく解説しています。
ぜひ参考にしてください。
On Errorを複数回使用する場合
1つのプロシージャのなかで、エラー処理が複数回必要な場合があります。
そんな場合はOn Error GoTo 0ステートメントを使います。On Error GoTo 0ステートメントは、有効になったエラー処理を無効にします。
一旦エラー処理を無効にして、そのあとまたエラー処理を有効にすることでOn Errorを複数回使用することができます。
サンプルコードで確認しましょう。
Sub macro5() Dim num1 As Integer, num2 As Integer, result As Double Dim msg As String num1 = 1 num2 = 0 On Error GoTo ErrLabel1 result = num1 / num2 'エラー発生 On Error GoTo 0 On Err GoTo ErrLabel2 MsgBox msg & vbCrLf & "計算結果は " & result & " です" Exit Sub ErrLabel1: msg = "エラーが発生しました" ErrLabel2: MsgBox msg & vbCrLf & "処理は修了しました" End Sub
実行結果:
エラー処理をサブルーチンにまとめる
先ほどはOn Error GoTo 0ステートメントを使って、On Errorステートメントを複数回使用できる方法について述べました。
1つのプロシージャで複数のエラー処理を記述する必要がある場合は、エラーを処理するラベルを1箇所にまとめ記述しています。
このように、エラー処理の記述をサブルーチンにまとめるとコードが読みやすくなるのでオススメです。
まとめ
ここでは、エラー処理について説明しました。
エラー処理を記述しなければ、途中で処理が停止し最後まで処理が行われなかったり、意図しない値が出力される場合があり、不具合の原因となります。
そうならないためにエラー処理を使いこなすことができるように、この記事を何度も参考にして下さいね!