自分用のメモなので、形は整ってないです。
エラー処理における、On Error の有効範囲とその動作について
Sub sample1()
On Error GoTo Label01
Call sample2
Call sample3
Exit Sub
Label01:
MsgBox "Label01"
End Sub
Sub sample2()
On Error GoTo Label02
Dim i As Long
i = "abc"
On Error GoTo 0
Exit Sub
Label02:
MsgBox "Label02"
End Sub
Sub sample3()
Dim i As Long
i = "abc"
Exit Sub
Label03:
MsgBox "Label03"
End Sub
'On Errorの有効範囲は、On Error GoTo 0まで、もしくはそのプロシージャを抜ける前
'sample1を実行すると、sample2で発生したエラーはLabel02:でトラップされるが、
'sample3で発生したエラーはsample1まで伝播し、Label01:でトラップされる
'呼び出し元の呼び出し元へも、エラーは伝播する
'※On Error がないプロシージャーでのエラー時の動作
'・呼び出し元が無い場合はエラー停止
'・呼び出し元にOn Error が無い場合はエラー停止
'・呼び出し元にOn Error がある場合はその時点でプロシージャーを抜ける
'以下の例では、sample6で発生したエラーがsample4まで伝播している
Sub sample4()
On Error GoTo Label04
Call sample5
Exit Sub
Label04:
MsgBox "Label04"
End Sub
Sub sample5()
Call sample6
End Sub
Sub sample6()
Dim i As Long
i = "ttt"
Exit Sub
End Sub
エラー処理の、On Error Resume Next On Error GoTo 0と、プロシージャの呼び出し元のエラートラップの関係
On Error GoTo 0としても、呼び出し元のエラートラップが無効になるわけではないらしい
Sub aaa()
On Error GoTo EH1
Call bbb
Exit Sub
EH1:
MsgBox "EH1"
End Sub
Sub bbb()
Dim long1 As Long
On Error Resume Next
long1 = 100 / 0 'このエラーは無視される
If Err.Number <> 0 Then MsgBox "エラー番号" & Err.Number
'エラー番号は取得できる
On Error GoTo 0
' これはOn Error Resume Nextの宣言を無効にするだけらしい。aaa()のエラートラップを無効にするわけではない
long1 = 100 / 0 ' このエラーはaaa()まで伝播する
End Sub
エラー番号一覧 Err.Number で取得できる
3 Return に対応する GoSub がありません。
5 プロシージャの呼び出し、または引数が不正です。
6 オーバーフローしました。
7 メモリが不足しています。
9 インデックスが有効範囲にありません。
10 この配列は固定されているか、または一時的にロックされています。
11 0 で除算しました。
13 型が一致しません。
14 文字列領域が不足しています。
16 式が複雑すぎます。
17 要求された操作は実行できません。
18 ユーザーによる割り込みが発生しました。
20 エラーが発生していないときに Resume を実行することはできません。
28 スタック領域が不足しています。
35 Sub または Function が定義されていません。
47 DLL のクライアント アプリケーションの数が多すぎます。
48 DLL 読み込み時のエラーです。
49 DLL が正しく呼び出せません。
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 の使い方が不正です。
97 オブジェクトが定義クラスのインスタンスではない場合、このオブジェクトに関するフレンド関数は呼び出せません。
98 プロパティまたはメソッドの呼び出しの場合には、引数または戻り値としてプライベート オブジェクトへの参照を含めることはできません。
298 システムリソースまたは DLL をロードできません。
320 キャラクタ デバイスは使えません。
321 不正なファイル形式です。
322 必要な一時ファイルを作成できません。
325 リソース ファイルの形式が不正です。
327 データ値が見つかりません。
328 不正なパラメータです。配列に書き込めません。
335 システム レジストリにアクセスできません。
336 コンポーネントが正しく登録されていません。
337 コンポーネントが見つかりません。
338 コンポーネントが正常に実行されませんでした。
360 このオブジェクトは既にロードされています。
361 このオブジェクトは、ロードまたはアンロードすることはできません。
363 指定されたコントロールが見つかりません。
364 既にアンロードされています。
365 現在アンロードできません。
368 ファイルは古い形式で作成されています。このプログラムには新しい形式のファイルが必要です。
371 指定されたオブジェクトは、Show メソッドのオーナー フォームとして使用できません。
380 プロパティの値が不正です。
381 不正なプロパティ配列インデックスです。
382 実行時には値を設定できません。
383 値を設定できません。値の取得のみ可能なプロパティです。
385 プロパティ配列インデックスが必要です。
387 値を設定できません。
393 実行時には値を取得できません。
394 値を取得できません。値の設定のみ可能なプロパティです。
400 既にフォームは表示されています。モーダルにできません。
402 一番手前 (前面) のモーダル フォームを先に閉じてください。
419 オブジェクトを利用できません。
422 プロパティが見つかりません。
423 プロパティまたはメソッドが見つかりません。
424 オブジェクトが必要です。
425 オブジェクトの使い方が不正です
429 ActiveX コンポーネントはオブジェクトを作成できません。
430 クラスはオートメーションまたは予測したインターフェースをサポートしていません。
432 オートメーションの操作中にファイル名またはクラス名を見つけられませんでした。
438 オブジェクトは、このプロパティまたはメソッドをサポートしていません。
440 オートメーション エラーです。
442 リモート プロセス用のタイプ ライブラリまたはオブジェクト ライブラリへの参照は失われました。参照設定を解除して [OK] を押してください。
443 オートメーション オブジェクトには既定値がありません。
445 オブジェクトはこの動作をサポートしていません。
446 オブジェクトは名前付き引数をサポートしていません。
447 オブジェクトは現在の国別情報の設定をサポートしていません。
448 名前付き引数が見つかりません。
449 引数は省略できません。
450 引数の数が一致していません。または不正なプロパティを指定しています。
451 Property Let プロシージャが定義されておらず、Property Get プロシージャからオブジェクトが返されませんでした。
452 序数が不正です。
453 関数は指定された DLL には定義されていません。
454 コード リソースが見つかりません。
455 コード リソースのロック エラーです。
457 このキーは既にこのコレクションの要素に割り当てられています。
458 Visual Basic でサポートされていないオートメーションが変数で使用されています。
459 オブジェクトまたはクラスがこのイベント セットをサポートしていません。
460 クリップボードのデータ形式が不正です。
461 メソッドまたはデータ メンバーが見つかりません。
462 リモート サーバーがないか、使用できる状態ではありません。
463 ローカル マシンにクラスが登録されていません。
480 AutoRedraw イメージを作成できません。
481 ピクチャが不正です。
482 プリンター エラーです。
483 プリンタ ドライバは指定されたプロパティをサポートしていません。
484 システムからプリンタ情報を受けるときに問題が発生しました。プリンタが正しく設定されているかを確かめてください。
485 ピクチャの形式が不正です。
486 フォームのイメージをこのプリンターで印刷することはできません。
520 クリップボードを空にできません。
521 クリップボードを開けません。
735 一時ファイルに保存できません。
744 検索文字列が見つかりませんでした。
746 置換後の文字列が長すぎます。
1004 アプリケーション定義またはオブジェクト定義のエラーです。
31001 メモリが不足しています。
31004 オブジェクトがありません。
31018 クラスが設定されていません。
31027 オブジェクトをアクティブにできません。
31032 埋め込みオブジェクトが作成できません。
31036 ファイルへの書き込み中にエラーが発生しました。
31037 ファイルの読み込み中にエラーが発生しました。
-2147221080 オートメーション エラーです。
上記以外 アプリケーション定義またはオブジェクト定義のエラーです。
エラーを発生させる Err.Raise
エラーを補足した後に、再度スローできるので、エラー処理には有効
Sub ttt()
'エラーを発生させる。以下の構文
' Err.Raise number, source, description, helpfile, helpcontext
' number: エラー番号 0~512まではシステムで使われている。513~65535まではユーザが使える
'実際には、513以降にも使われている番号はあるらしい。513~519か、600番台を使うのがいい
On Error Resume Next
Err.Raise 11 '0で除算のエラーを発生させる
Call ShowErrorInfo ' エラー情報を取得
Err.Clear '一旦エラーをクリア
Err.Raise 513, "独自エラー513"
' ユーザ定義のエラー、513番を発生させる
' "独自エラー513" はsourceになる
Call ShowErrorInfo
Err.Clear
Err.Raise 514, "独自エラー514", "ABCDE"
' ユーザ定義のエラー、513番を発生させる
' "ABCDE" はdescriptionになる
Call ShowErrorInfo
Err.Clear
Err.Raise vbObjectError + 513, "ユーザ定義エラー513"
' vbObjectError + 513 で、クラス モジュール内で独自のエラーコードに設定するらしいが、よくわからない
Call ShowErrorInfo
On Error GoTo 0
End Sub
Sub ShowErrorInfo()
Debug.Print "*******************"
Debug.Print Err.Number
Debug.Print "---------------"
Debug.Print Err.Description
Debug.Print "---------------"
Debug.Print Err.Source
Debug.Print "*******************"
Debug.Print ""
End Sub
'ttt()の実行結果は以下
'*******************
'11
'---------------
'0 で除算しました。
'---------------
'VBAProject
'*******************
'
'*******************
'513
'---------------
'アプリケーション定義またはオブジェクト定義のエラーです。
'---------------
'独自エラー513
'*******************
'
'*******************
'514
'---------------
'ABCDE
'---------------
'独自エラー514
'*******************
'
'*******************
'-2147220991
'---------------
'オートメーション エラーです。
'イベントはどのサブスクライバーも呼び出すことができませんでした
'---------------
'ユーザ定義エラー513
'*******************
'Err.Raise 513, "独自エラー513" の形でスローして、Err.NumberとErr.sourceで情報を取得すればいいのかな
親・子・孫プロシージャの関係で、どのレベルでエラーが発生したかを、親で判断する例
各レベルでエラー番号の範囲を決めて、Err.Raiseで再スローしている これがいいのかは自信無いが
Sub Parent() '親
Dim arrErrors() As String
Dim lng1 As Long
Dim i As Long
On Error GoTo ParentEH
ReDim arrErrors(0)
lng1 = -250 'この数値を変えて、エラーの発生するレベルを調整
If lng1 < -200 Then
Err.Raise 13 '13番は適当
End If
lng1 = 0
Call Child(arrErrors, lng1)
lng1 = -150
Call Child(arrErrors, lng1)
If arrErrors(0) <> "" Then
i = 0
Do While arrErrors(i) <> ""
Debug.Print arrErrors(i)
i = i + 1
Loop
End If
On Error GoTo 0
Exit Sub
ParentEH:
If Err.Number >= 650 And Err.Number <= 699 Then
'GrandChildのレベルで発生したエラーの場合
MsgBox "GarandChildレベルでエラー発生"
ElseIf Err.Number >= 630 And Err.Number <= 649 Then
'Childのレベルで発生したエラーの場合
MsgBox "Childレベルでエラー発生"
Else
arrErrors(UBound(arrErrors)) = "Parentでエラー発生。エラー番号: " & Err.Number
ReDim Preserve arrErrors(UBound(arrErrors) + 1)
MsgBox "Parentでエラー発生"
End If
Resume Next 'エラーが発生した次のステップまで戻る
End Sub
Sub Child(ByRef arrErrors() As String, ByVal lng1 As Long) ' 子
On Error GoTo ChildEH
If lng1 < -100 Then
Err.Raise 6 '6番は適当
End If
Call GrandChild(arrErrors, lng1)
On Error GoTo 0
Exit Sub
ChildEH:
If Err.Number >= 650 And Err.Number <= 699 Then
Err.Raise Err.Number
'GrandChildのレベルで発生したエラーは、そのままの番号でスロー
Else
arrErrors(UBound(arrErrors)) = "Childでエラー発生。エラー番号: " & Err.Number
ReDim Preserve arrErrors(UBound(arrErrors) + 1)
Err.Raise 630
'Childのレベルでは、630~649のエラーをスローすることにする
End If
End Sub
Sub GrandChild(ByRef arrErrors() As String, ByVal lng1 As Long) ' 孫
On Error GoTo GrandChildEH
lng1 = 100 / lng1
On Error GoTo 0
Exit Sub
GrandChildEH:
arrErrors(UBound(arrErrors)) = "GrandChildでエラー発生。エラー番号: " & Err.Number
ReDim Preserve arrErrors(UBound(arrErrors) + 1)
Err.Raise 650
'GrandChildのレベルでは、650~699のエラーをスローすることにする
End Sub
On Error GoTo~、On Error Resume Nextは、その後にOn Error GoTo~、On Error Resume Nextを記述すれば上書きされるらしい
On Error GoTo 0を毎回記述する必要は無いか
Sub aaa()
On Error GoTo EH1
On Error Resume Next
'この時点で、On Error GoTo EH1 は無効になり、エラーは無視して進むようになるらしい
'On Error GoTo 0 を記述する必要は無い
Err.Raise 514
On Error GoTo EH1
'この時点で、On Error Resume Next は無効になり、エラーはトラップされるようになる
Err.Raise 515
On Error GoTo 0
Exit Sub
EH1:
MsgBox "エラー発生。エラー番号: " & Err.Number
End Sub
エラー処理 基本
Sub aaa()
' 単純なエラー処理の例
On Error GoTo ErrorHandler ' エラーが発生した場合は、"ErrorHandler"へ移動
ThisWorkbook.Charts(1).Activate
MsgBox ActiveSheet.Name
On Error GoTo 0 ' エラーのトラップを無効にする
Exit Sub
' 必須。これが無いとプロシージャを抜けないので、ErrorHandlerの処理に移動してしまう
ErrorHandler: ' エラー発生時の移動先
MsgBox "グラフシートがありません"
' このままプロシージャを抜ける
End Sub
Sub bbb()
' エラー時の処理実行後、本処理に復帰する例
On Error GoTo ErrorHandler1
Dim long1 As Long
long1 = 0
MsgBox 100 / long1
On Error GoTo 0
ReturnPoint: ' エラー処理からの復帰ポイント
On Error GoTo ErrorHandler2
Worksheets("存在しないシート").Activate
On Error GoTo 0
Exit Sub
ErrorHandler1:
MsgBox "0で除算した可能性があります"
Resume ReturnPoint ' ReturnPoint:に戻る
ErrorHandler2:
MsgBox "存在しないシート名が指定されました"
Resume Next ' エラーの発生した処理の、次の処理に戻る
' ※ Resume を指定すると、エラーの発生した処理に戻るが、またそこでエラーが発生して永久ループの可能性あり
End Sub
エラーが発生しても無視して処理を続行する
On Error Resume Next ' エラーが発生した場合でも、無視して処理を続行する
MsgBox 100 / 0
Cells(-100, 2.5).Select
If Err.number <> 0 Then
' エラーが発生していなければ、Err.numberは0になる
MsgBox "何らかのエラーが発生しています"
End If
On Error GoTo 0 ' このステートメントでErr.numberはクリア(0)になってしまうので注意
エラーの情報を取得する
Sub sss()
On Error GoTo ErrorHandler
Cells(-1, -200).Select
On Error GoTo 0
Exit Sub
ErrorHandler:
Debug.Print Err.Number ' エラー番号。エラーがない場合は0
Debug.Print Err.Description ' エラーの説明文
Debug.Print Err.Source ' エラーの発生元のオブジェクト名、またはアプリケーションの名前
Debug.Print Err.HelpContext ' ヘルプファイルのトピックに対応するコンテキスト番号
Debug.Print Err.HelpFile ' ヘルプファイルへの絶対パス
Debug.Print Err.LastDllError ' 最後にダイナミックリンクライブラリ(DLL)を呼び出したときのエラーコード
Err.Clear ' エラー内容のクリア
Err.Raise 11 ' 0で除算したエラーを発生させる
End Sub
エラーの内容をクリアする
Sub aaa()
On Error Resume Next
MsgBox 100 / 0
If Err.number <> 0 Then
MsgBox "エラークリア前のエラー番号: " & Err.number & vbCrLf & "エラークリア前のエラー説明: " & Err.Description
Err.Clear ' エラー内容のクリア
MsgBox "エラークリア後のエラー番号: " & Err.number & vbCrLf & "エラークリア後のエラー説明: " & Err.Description
End If
On Error GoTo 0 ' このステートメントでもエラーの内容はクリアされる
End Sub
エラーハンドラーの部分では、On Error Resume Nextを指定してもエラーが無視されない? 多分これは仕様
「ツール」→「オプション」→「全般」で、エラートラップに関する設定有りだが、「エラー処理対象外~」が本来のはず
Sub aaa()
On Error GoTo ErrHandler
Err.Raise 514
MsgBox "完了"
Exit Sub
ErrHandler:
On Error Resume Next
Err.Raise 514 'エラーは無視するはずだが、ここで止まってしまう
MsgBox "エラー処理完了"
'「ツール」→「オプション」→「全般」で、エラートラップに関する設定有り
'「エラー処理対象外~」にしないと、そもそもエラー処理がまともに実行されない
End Sub