質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.02%

  • VBA

    1415questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1218questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。

エクセルVBA CALLで呼び出したプロシージャ内でのエラー処理

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 712

x-ryo

score 5

前提・実現したいこと

VBAでシステムを作っているのですが、メインのプロシージャがあり、その中でCALLでプロシージャを呼び出しているのですが、呼び出したプロシージャでエラーが発生した時に、メインのプロシージャでエラー番号を受け取りエラー処理はできないでしょうか。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

sub main_procedure()

on error goto エラー処理

call sub_procedure

exit sub

エラー処理:
Select Case Err.Number
Case ○○
msgbox "○○○"
case ○○
msgbox "○○○"
End Select
end sub

sub sub_procedure
ここで発生したエラーをmainで取得して処理したい
end sub

試したこと

課題に対してアプローチしたことを記載してください

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報で

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • imihito

    2018/01/23 23:43

    記述されている処理で問題無いと思います。

    キャンセル

回答 4

checkベストアンサー

+2

Raise メソッドで実行時エラーを再送できます。

Raise メソッド

コード例

Sub main_procedure()

    On Error GoTo エラー処理

    Call sub_procedure

    Exit Sub

エラー処理:
    Select Case Err.Number
    Case 11
        MsgBox Err.Source & "内で 実行時エラー:" & Err.Number & vbCrLf & Err.Description
    Case Else
        MsgBox Err.Source & "内で 実行時エラー:" & Err.Number & vbCrLf & Err.Description
    End Select
End Sub

Sub sub_procedure()
Dim x As Long, y As Long

    On Error GoTo エラー処理

    x = 0
    y = 100 / x

    Exit Sub

エラー処理:
    Err.Raise Err.Number, "sub_procedure", Err.Description
End Sub

上記で、main_procedure を実行すると下記のメッセージがでます。

sub_procedure内で 実行時エラー:11
0 で除算しました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/24 21:26

    うまくいきました!ありがとうございます

    キャンセル

+2

ごくシンプルに書けば以下のようになります。

Sub main_procedure()

On Error GoTo エラー処理

    Call sub_procedure

Exit Sub

エラー処理:
    Select Case Err.Number
        Case 5
            MsgBox Err.Number & " : " & Err.Description
        'Case "○"...
        '...
        Case Else
            MsgBox Err.Number & " : " & Err.Description
    End Select
End Sub

Sub sub_procedure()
    Dim a
    a = 1 / 0 '0除算エラー
End Sub

sub_procedureで実行時エラーが発生した場合、まずはsub_procedure内でエラー処理ルーチン(On Error~)が探索されます。

上記コードではsub_procedure内にエラー処理ルーチンが無いため、sub_procedureの処理が中断され、呼び出し元であるmain_procedureに処理が戻ります。

main_procedure内にはエラー処理ルーチンがあるため、そちらの中でErrを参照すると「元のエラー情報」を取得することができます。

仮にmain_procedure内にもエラー処理ルーチンが無い場合、呼び出し履歴をどんどん上って行って、最後までエラー処理ルーチンが無いとき初めてVBAのエラーダイアログが表示されます。

上記のコードではエラーが発生したら即処理を抜けますが、処理を抜ける前に後始末をしたい場合は「hatena19」さんの回答のような処理になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

解決策は他の方々から出ているようですので、用途に合わせた実装の仕方についてアドバイスさせていただきます。

OnErrorの基本動作

On Error GoTo ラベル名の記述をすると、その関数を抜けるまでに発生するエラーをキャッチし、ラベル名以降のコード(=例外処理)に処理をスキップします。
なお、関数の途中でもOn Error GoTo 0を記述することでOnErrorを終了できます。

また、OnErrorがエラーをキャッチすると例外処理にスキップしますが、この時点でその関数内でのOnErrorは終了しています。
このため例外処理の中でエラーが発生したとしても、同じOnErrorがキャッチしなおすということはありません。

OnErrorのネスト

親関数でのOnErrorが有効な状態でサブ関数を呼び出した場合、サブ関数内で発生したエラーも親関数のOnErrorでキャッチできます。
しかし、サブ関数内でもOnErrorが記述されていた場合は、サブ関数のOnErrorがエラーをキャッチし、親関数のOnErrorではエラーはキャッチされません。

このようにOnErrorが多段で組まれた場合、直近のOnErrorだけがエラーをキャッチし例外処理を行います。

エラーはRaise命令で任意に発生させることもできるので、サブ関数でエラーキャッチ後に例外処理の中で同じエラーをRaiseすれば、親関数のOnErrorがキャッチすることになります。(VB.NETでいうThrowのような動き)

親関数ではサブ関数のエラーをどう処理したいか?

実際の実装にあたっては、サブ関数でのエラー発生を親関数でどのように処理したいかによって作り方が変わってきます。

①親関数としてもエラーをキャッチし、例外処理に飛ばしたい場合
この場合は、サブ関数側にはOnErrrを記述しないか、もしくはエラーをキャッチした後に同じエラーをRaiseします。
これにより自動的に親関数の例外処理に飛ぶことになります。

動きとしてはどちらも親関数でエラーをキャッチとなりますが、サブ関数内でエラー発生の可能性があるのならサブ関数にもOnErrorを書いておく方が自然だと思います。
⇒サンプルコード(後述)のサブ関数1

②親関数ではサブ関数でのエラー有無を把握し、場合によっては処理を継続したい場合
この場合、サブ関数にOnErrorを記述し、エラーが発生した場合はサブ関数の例外処理で対応します。
また、サブ関数の戻り値としてエラー情報を返すようにします。

例えばサブ関数で発生したエラーに対し、親関数でもエラー番号を調べて対応する必要があるのなら、戻り値はエラー番号とした方がいいでしょう。
⇒サンプルコード(後述)のサブ関数2

もし親関数ではサブ関数内でエラーが発生したことがわかればいいだけなら、戻り値は正常終了/異常終了のTrue/Falseだけ返せば十分です。
⇒サンプルコード(後述)のサブ関数3

サンプル

以下はOnErrorの動きを確認するためのサンプルコードです。

メイン関数から以下3つのサブ関数を呼んでいます。
サブ関数1:親関数でもエラーキャッチできるように同じエラーをRaiseしているサブ関数
サブ関数2:親関数にはエラー番号だけ返すサブ関数
サブ関数3:親関数にはエラー有無だけ返すサブ関数

このうち、サブ関数1でエラーが発生すると、以降の処理をスキップして親関数の例外処理に飛んでしまいます。
全ての動きをみるため、サンプルコードはサブ関数2⇒3⇒1の順に実行しています。

Sub Main()
    On Error GoTo Ex:

    'サブ関数呼び出し2
    Dim iRet As Integer
    iRet = Shori2()
    If iRet = 0 Then
        MsgBox "親関数でのサブ2判定:正常終了"
    Else
        MsgBox "親関数でのサブ2判定:異常終了(" & iRet & ")"
    End If

    'サブ関数呼び出し3
    If Shori3() = True Then
        MsgBox "親関数でのサブ3判定:正常終了"
    Else
        MsgBox "親関数でのサブ3判定:異常終了"
    End If

    'サブ関数呼び出し1
    Call Shori1

    '親関数でキャッチするエラーがない場合、正常終了
    MsgBox "親・終了"   'Shori1のエラーをキャッチするため、この処理は通りません。
    Exit Sub

Ex:
    '■親関数の例外処理■
    '親関数でキャッチするエラーがあった場合、異常終了
    MsgBox "親がキャッチしたエラー:" & Err.Number
End Sub

'サブ関数1(異常があった際、同じエラーをRaiseして親関数でもエラーをキャッチする)
Sub Shori1()
    On Error GoTo EX_1:

    Err.Raise 11  'ここではデバッグ用に0除算エラーを強制的に発生させています。

    'エラーがなければ正常終了
    MsgBox "サブ1・終了"
    Exit Sub

EX_1:
    '■サブ関数1の例外処理■
    'エラーがあれば異常終了
    MsgBox "サブ関数1がキャッチしたエラー:" & Err.Number
    '親関数でキャッチさせるためのエラーを用意
    Err.Raise Err.Number
End Sub

'サブ関数2(異常があった際、エラー番号を返す)
Function Shori2() As Integer
    On Error GoTo EX_2:
    Shori2 = 0

    Err.Raise 11  'ここではデバッグ用に0除算エラーを強制的に発生させています。

    'エラーがなければ正常終了(戻り値:0)
    MsgBox "サブ2・終了"
    Exit Function

EX_2:
    '■サブ関数2の例外処理■
    'エラーがあれば異常終了(戻り値:エラー番号)
    MsgBox "サブ関数2がキャッチしたエラー:" & Err.Number
    Shori2 = Err.Number
End Function

'サブ関数3(異常があったことのみ返す)
Function Shori3() As Boolean
    On Error GoTo EX_3:
    Shori3 = True

    Err.Raise 11  'ここではデバッグ用に0除算エラーを強制的に発生させています。

    'エラーがなければ正常終了(戻り値:True)
    MsgBox "サブ3・終了"
    Exit Function

EX_3:
    '■サブ関数3の例外処理■
    'エラーがあれば異常終了(戻り値:False)
    MsgBox "サブ関数3がキャッチしたエラー:" & Err.Number
    Shori3 = False
End Function

参考になれば幸いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

何となくですが、こういう感じにしたいのでしょうか。

Private Sub main_procedure()

    ' 戻り値を取得する変数
    Dim intRet As Integer

    ' プロシージャを呼び出し、結果を受け取る
    intRet = sub_procedure

    ' 戻り値に応じて処理をする
    Select Case intRet
        Case 1
        MsgBox "○○○"
        Case 2
        MsgBox "△△△"
    End Select

End Sub


Function sub_procedure()

    ' エラーコードを返す
    sub_procedure = 2

End Function

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • VBA

    1415questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1218questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。