【VBA入門】エラーを処理する方法(On Error、Resume、GoTo)

エラー処理って使っていますか?

エラー処理といえば、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

実行結果:

OnError01

このサンプルコードでは、ゼロでの割り算でエラーが発生します。エラーが発生すると、ラベル先に処理がスキップしています。

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

実行結果:

OnError03

このサンプルコードでは、ゼロでの割り算でエラーが発生します。エラーが発生すると、ラベル先に処理がスキップしています。

ラベル先の処理が終わると、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

実行結果:

OnError06jpg

このサンプルコードは、2での割り算の余り、つまり0もしくは1で割り算を行っています。余りが0の場合はゼロでの割り算となり、エラーが発生します。

この処理をForステートメントを使って繰り返しループで処理していますが、ErrLabel部分でエラー処理を行い、Resume Nextステートメントで次の処理から継続するようにしています。

もしNextを抜かしてしまうと、Excelが応答しなくなることもありますので注意しましょう。

メッセージを取得する方法

エラーが発生した場合、エラーコードの番号やエラー内容を確認してその後の対応を決めることがよくあります。

そのためにはエラーメッセージを取得して出力する必要があります。エラーメッセージはErrオブジェクトのプロパティから取得します。

プロパティ名説明
Descriptionエラーの説明
HelpContextヘルプファイルのコンテキストID
HelpFileヘルプファイルへの絶対パス
LastDLLErrorDLLの呼び出しにより作成されたエラーコード
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

実行結果:

OnError04

このサンプルコードでは、ErrオブジェクトのSource、Number、Descriptionプロパティを使ってエラーメッセージを表示しています。

ちなみに、主なエラー番号について以下の表にまとめました。

番号メッセージ
3Returnに対応するGoSubがありません。
5プロシージャの呼び出し、または引数が不正です。
6オーバーフローしました。
7メモリが不足しています。
9インデックスが有効範囲にありません。
10この配列は固定されているか、または一時的にロックされています。
110で除算しました。
13型が一致しません。
14文字列領域が不足しています。
17要求された操作は実行できません。
18ユーザーによる割り込みが発生しました。
20エラーが発生していないときにResumeを実行することはできません。
28スタック領域が不足しています。
35SubまたはFunctionが定義されていません。
51内部エラーです。
52ファイル名または番号が不正です。
53ファイルが見つかりません。
54ファイルモードが不正です。
55ファイルは既に開かれています。
57デバイスI/Oエラーです。
58既に同名のファイルが存在しています。
59レコード長が一致しません。
61ディスクの空き容量が不足しています。
62ファイルにこれ以上データがありません。
63レコード番号が不正です。
67ファイルが多すぎます。
68デバイスが準備されていません。
70書き込みできません。
71ディスクが準備されていません。
74ディスク名は変更できません。
75パス名が無効です。
76パスが見つかりません。
91オブジェクト変数またはWithブロック変数が設定されていません。
92Forループが初期化されていません。
93パターン文字列が不正です。
94Nullの使い方が不正です。
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

実行結果:
OnError06

OnError07

このサンプルコードでは、存在しないファイルを開いたのちに、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

実行結果:
OnError05

エラー処理をサブルーチンにまとめる

先ほどはOn Error GoTo 0ステートメントを使って、On Errorステートメントを複数回使用できる方法について述べました。

1つのプロシージャで複数のエラー処理を記述する必要がある場合は、エラーを処理するラベルを1箇所にまとめ記述しています。

このように、エラー処理の記述をサブルーチンにまとめるとコードが読みやすくなるのでオススメです。

まとめ

ここでは、エラー処理について説明しました。

エラー処理を記述しなければ、途中で処理が停止し最後まで処理が行われなかったり、意図しない値が出力される場合があり、不具合の原因となります。

そうならないためにエラー処理を使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次