###前提・実現したいこと
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/ツール等のバージョンなど)
より詳細な情報で
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答4件
0
解決策は他の方々から出ているようですので、用途に合わせた実装の仕方についてアドバイスさせていただきます。
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
参考になれば幸いです。
投稿2018/01/24 05:38
総合スコア3020
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ごくシンプルに書けば以下のようになります。
vba
1Sub main_procedure() 2 3On Error GoTo エラー処理 4 5 Call sub_procedure 6 7Exit Sub 8 9エラー処理: 10 Select Case Err.Number 11 Case 5 12 MsgBox Err.Number & " : " & Err.Description 13 'Case "○"... 14 '... 15 Case Else 16 MsgBox Err.Number & " : " & Err.Description 17 End Select 18End Sub 19 20Sub sub_procedure() 21 Dim a 22 a = 1 / 0 '0除算エラー 23End Sub
sub_procedure
で実行時エラーが発生した場合、まずはsub_procedure
内でエラー処理ルーチン(On Error~)が探索されます。
上記コードではsub_procedure
内にエラー処理ルーチンが無いため、sub_procedure
の処理が中断され、呼び出し元であるmain_procedure
に処理が戻ります。
main_procedure
内にはエラー処理ルーチンがあるため、そちらの中でErr
を参照すると「元のエラー情報」を取得することができます。
仮にmain_procedure
内にもエラー処理ルーチンが無い場合、呼び出し履歴をどんどん上って行って、最後までエラー処理ルーチンが無いとき初めてVBAのエラーダイアログが表示されます。
上記のコードではエラーが発生したら即処理を抜けますが、処理を抜ける前に後始末をしたい場合は「hatena19」さんの回答のような処理になります。
投稿2018/01/23 22:20
総合スコア2166
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
Raise メソッドで実行時エラーを再送できます。
コード例
vba
1Sub main_procedure() 2 3 On Error GoTo エラー処理 4 5 Call sub_procedure 6 7 Exit Sub 8 9エラー処理: 10 Select Case Err.Number 11 Case 11 12 MsgBox Err.Source & "内で 実行時エラー:" & Err.Number & vbCrLf & Err.Description 13 Case Else 14 MsgBox Err.Source & "内で 実行時エラー:" & Err.Number & vbCrLf & Err.Description 15 End Select 16End Sub 17 18Sub sub_procedure() 19Dim x As Long, y As Long 20 21 On Error GoTo エラー処理 22 23 x = 0 24 y = 100 / x 25 26 Exit Sub 27 28エラー処理: 29 Err.Raise Err.Number, "sub_procedure", Err.Description 30End Sub 31
上記で、main_procedure を実行すると下記のメッセージがでます。
sub_procedure内で 実行時エラー:11
0 で除算しました。
投稿2018/01/23 21:16
総合スコア34345
0
何となくですが、こういう感じにしたいのでしょうか。
VBA
1Private Sub main_procedure() 2 3 ' 戻り値を取得する変数 4 Dim intRet As Integer 5 6 ' プロシージャを呼び出し、結果を受け取る 7 intRet = sub_procedure 8 9 ' 戻り値に応じて処理をする 10 Select Case intRet 11 Case 1 12 MsgBox "○○○" 13 Case 2 14 MsgBox "△△△" 15 End Select 16 17End Sub 18 19 20Function sub_procedure() 21 22 ' エラーコードを返す 23 sub_procedure = 2 24 25End Function
投稿2018/01/23 15:50
総合スコア402
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。