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

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

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

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

Q&A

解決済

4回答

32529閲覧

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

x-ryo

総合スコア14

VBA

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

0グッド

2クリップ

投稿2018/01/23 13:20

###前提・実現したいこと
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ページで確認できます。

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

imihito

2018/01/23 14:43

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

回答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

jawa

総合スコア3013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

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

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

hatena19

総合スコア33715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

x-ryo

2018/01/24 12:26

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

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

crowmt

総合スコア402

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問