[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『皆様のVBA例外処理の方法を教えて下さい』(隠居Z)
いまさらで、汗顔の至りですが^^;
1.複数のモジュール[ThisWorkbook、標準[複数]]にわたり
コード書いてます。
2.呼び出し元のみですとどのモジュールのどの関数か
解らないので全ての関数で処理の後、ログを作成し
同じエラー番号で例外を作成、呼び出し元で拾うように
しようとは思うのですが。。。ここで問題が^^;
3.結構呼び出し関数が多いもので横着をして
CallBynameでApplication.Runをセット、メソッドを
指定後関数名を配列に格納したものをループで回して
関数呼び出しをしています。
4.3.では呼び出し元の例外処理の有効スコープが切れ
エラーでコードが中断いたします。
5.ログとれりゃ別に呼び出し元で拾わなくても何も困りは
しないかなぁ。。。と思っているのですが
他に、こうすればぁ〜、とか、あほなことして、こうするんだよ!
みたいなご意見がございましたら是非にもお願いいたします。
聞くは一時の恥、聞かざるは末代までの。。。云云(*^^*)
で、よろしくお願いいたします。
例外処理とはOn Error Goto 〜 を指しておりますです。
m(__)m
Module1
Option Explicit Private Sub main() Dim x, v(), eApp, i&, fps$, fNm$, eFlg As Boolean, xx() On Error GoTo errstp fps = ThisWorkbook.Path & "\" fNm = "errorlog.txt" Open fps & fNm For Output As #1 Close #1 Open fps & fNm For Append As #1 Set eApp = Application v = Array("Module1.p1", "Module1.p2", "Module2.p3", "Module2.p4", "Module2.p5") ReDim xx(UBound(v)) For i = LBound(xx) To UBound(xx) xx(i) = 0 Next For i = LBound(v) To UBound(v) eFlg = CallByName(eApp, "Run", VbMethod, v(i)) If eFlg Then xx(i) = 1 Next Rem Err.Raise 13 If Application.Sum(xx) <> 0 Then MsgBox "エラー発生ログを確認してください" Else MsgBox "正常終了" End If GoTo final: errstp: MyErrSub Err.Number, Err.Description, "errm01", "Main" MsgBox "エラー発生ログを確認してください" final: Erase v, xx Close #1 End Sub Function p1(ParamArray dum()) Dim x On Error GoTo errstp Err.Raise 1 Exit Function errstp: MyErrSub Err.Number, Err.Description, "errm01", "P1" p1 = True End Function Function p2(ParamArray Dummy()) Dim x On Error GoTo errstp Err.Raise 2 Exit Function errstp: MyErrSub Err.Number, Err.Description, "errm01", "P2" p2 = True End Function Sub MyErrSub(num&, etx$, mtx$, ptx$) Dim ltx$ On Error GoTo errstp ltx = "[" & Format(Now, " yyyy/mm/dd : hh:nn:ss ") & "]" ltx = ltx & Chr(32) & num & Chr(32) & etx & Chr(32) ltx = ltx & mtx & Chr(32) & ptx Print #1, ltx Rem Err.Raise 9 Exit Sub errstp: MsgBox "MyErrSub エラーですシステム担当に連絡してください" & Chr(13) & _ Err.Number & Chr(32) & Err.Description End End Sub
Module2
Option Explicit Function p3(ParamArray dum()) Dim x On Error GoTo errstp Err.Raise 3 Exit Function errstp: MyErrSub Err.Number, Err.Description, "errm02", "P3" p3 = True End Function Function p4(ParamArray dum()) On Error GoTo errstp Err.Raise 4 Exit Function errstp: MyErrSub Err.Number, Err.Description, "errm02", "P4" p4 = True End Function Function p5(ParamArray dum()) On Error GoTo errstp Err.Raise 5 Exit Function errstp: MyErrSub Err.Number, Err.Description, "errm02", "P5" p5 = True End Function
たたき台として↑みたいな感じかなぁと思っています。^^;
<< _ _ >>
< 使用 Excel:Excel2016、使用 OS:Windows10 >
>呼び出し元のみですとどのモジュールのどの関数か >解らないので全ての関数で処理の後、ログを作成し >同じエラー番号で例外を作成、呼び出し元で拾う
それって、実際に発生するエラーの話じゃなくて、 どのモジュールの関数か知りたくて、 わざとエラーを発生させて、情報を集める と言う仕掛けの話なんですね?
ロクに考えている訳じゃないのですが、 本当にエラーが発生した時とは何も競合しないのですね?
(半平太) 2024/03/24(日) 16:27:59
>>本当にエラーが発生した時とは何も競合しないのですね?
競合するかもしれません^^;↑コード作成時実際のエラーもありましたので
どちらか解りませんでした( ̄▽ ̄;)
実際は印刷処理が中心なので二回廻して、一回目で全ての関数でエラーが無ければ
二回目で印刷。とか考えております。
m(__)m
(隠居Z) 2024/03/24(日) 17:06:51
・・と言うことは、実際のエラーの捕捉(トラブる箇所の特定)が目的なんですね。
今は何も考えておりません。 取り敢えず、隠居Zさんの意図が確認できただけで十分です。 m(__)m
(半平太) 2024/03/24(日) 17:22:34
> MyErrSub Err.Number, Err.Description, "errm01", "P1"
この部分て「個別」に書くと面倒くさい気がします。
「P1」は呼んだ側の引数から割り出せるし、 "errm01" は "Module1"でも差し支えないですから、 同じく呼んだ側の引数から割り出せるので、「一律」に書ける気がしました。
(半平太) 2024/03/24(日) 20:59:05
えっ、そんな大したことじゃないんですが・・
Module1 Option Explicit
Private Sub main() Dim x, v(), eApp, i&, fps$, fNm$, eFlg As Boolean, xx() On Error GoTo errstp fps = ThisWorkbook.Path & "\" fNm = "errorlog.txt" Open fps & fNm For Output As #1 Close #1 Open fps & fNm For Append As #1 Set eApp = Application v = Array("Module1.p1", "Module1.p2", "Module2.p3", "Module2.p4", "Module2.p5") ReDim xx(UBound(v)) For i = LBound(xx) To UBound(xx) xx(i) = 0 Next For i = LBound(v) To UBound(v) eFlg = CallByName(eApp, "Run", VbMethod, v(i), Split(v(i), ".")) If eFlg Then xx(i) = 1 Next Rem Err.Raise 13 If Application.Sum(xx) <> 0 Then MsgBox "エラー発生ログを確認してください" Else MsgBox "正常終了" End If GoTo final: errstp: MyErrSub Err.Number, Err.Description, "errm01", "Main" MsgBox "エラー発生ログを確認してください" final: Erase v, xx Close #1 End Sub Function p1(s, ParamArray dum()) Dim x On Error GoTo errstp Err.Raise 1 Exit Function errstp: MyErrSub Err.Number, Err.Description, s(0), s(1) p1 = True End Function Function p2(s, ParamArray dum()) Dim x On Error GoTo errstp Err.Raise 2 Exit Function errstp: MyErrSub Err.Number, Err.Description, s(0), s(1) p2 = True End Function Sub MyErrSub(num&, etx$, mtx, ptx) Dim ltx$ On Error GoTo errstp ltx = "[" & Format(Now, " yyyy/mm/dd : hh:nn:ss ") & "]" ltx = ltx & Chr(32) & num & Chr(32) & etx & Chr(32) ltx = ltx & mtx & Chr(32) & ptx Print #1, ltx Rem Err.Raise 9 Exit Sub errstp: MsgBox "MyErrSub エラーですシステム担当に連絡してください" & Chr(13) & _ Err.Number & Chr(32) & Err.Description End End Sub
Module2 Option Explicit
Function p3(s, ParamArray dum()) Dim x On Error GoTo errstp Err.Raise 3 Exit Function errstp: MyErrSub Err.Number, Err.Description, s(0), s(1) p3 = True End Function Function p4(s, ParamArray dum()) On Error GoTo errstp Err.Raise 4 Exit Function errstp: MyErrSub Err.Number, Err.Description, s(0), s(1) p4 = True End Function Function p5(s, ParamArray dum()) On Error GoTo errstp Err.Raise 5 Exit Function errstp: MyErrSub Err.Number, Err.Description, s(0), s(1) p5 = True End Function
(半平太) 2024/03/24(日) 23:47:21
とても興味深い議論、有難うございます。
CallByNameの使い方は参考になりました。 ただこれを使うと、 ・Functionプロシージャの実行時における引数の型チェックは、通常はコールした時点で行われますが、 提案の方式だと、呼び出された側で発生することになるんですね。 ・それと返り値がある場合には、エラーフラッグも併せて配列で返すことになりますか。 少し手間がかかりますかね。
ところで、 一般ユーザーには無理ですが、ご自身であれば、 エラートラップの3つのうち、「エラー発生時に中断」を一時的に選択すれば、 On Error xx などのエラートラップは無効となって、エラーになった箇所で確実に止まります。 これでどこでエラーが発生しているかは分かりますが、これではまずいですか? (xyz) 2024/03/25(月) 07:48:17
なるほど。確かに呼んだ側に情報ありましたですね。
一度書いたものは、使い回そぉ。。。ですね(*^^*)
これだと、キーボードバヒャバチャしなくてもコピペでポイポイで済みますね
使わせて戴きます。有難う御座いました。
m(__)m
xyz さん へ
>>・Functionプロシージャの実行時における引数の型チェックは、通常はコールした時点で行われますが、
>> 提案の方式だと、呼び出された側で発生することになるんですね。
気が付いておりません。勉強になります。じっくり動作確認してみます。
>>・それと返り値がある場合には、エラーフラッグも併せて配列で返すことになりますか。
>> 少し手間がかかりますかね。
Application.Run使用時、引数の参照渡し不可の件でしょうか?
Applicationをバリアント型、若しくはオブジェクト型[Application禁止^^;]
でSetして CallByNameでラップすれば可能になるようです。
でもEXCELバージョンによって動作が変わるとか変わらないとか。。。( ̄▽ ̄)
で
私の今回の場合、値渡しばかりですので使ってみました。
配列引数は引数が無い場合パブリックモード関数ですと開発タブのマクロダイアログに
表示されてしまうので、防止策のダミー引数です。
プライベートにしとけよ。ってしかられそおですが。。通常のcallも試したくて。。。^^;
ご配慮とご案内、ありがとう御座います。私が使用する分は仰せの通りかと
存じます。
使用者は。。。大奥の御台様がお使いになるとかならないとか
停止などするとテレビ見てても呼びつけられますので。。。^^;
それはもうこわぁ〜いですよぉm(__)mm(__)mm(__)m
(*^^*)v
(隠居Z) 2024/03/25(月) 08:29:17
(隠居Z) 2024/03/25(月) 09:42:34
>それと返り値がある場合には、エラーフラッグも併せて配列で返すことになりますか。 提案いただいた参考コードはエラーフラグを返す例ですが、 なんらかの数値なりを返すfunction procedureの場合は、 フラッグとその数値なりを配列にして返すか、数値は参照渡しで受け取るということになるんですかね、 という本題と離れた些末なことでした。
>一般ユーザーには無理ですが、ご自身であれば、 と書きましたが、 そうですね、そういう高貴なかたから呼び出されたくはありませんね。 ありがとうございました。
(xyz) 2024/03/25(月) 11:36:02
隠居Zさん
一つ教えてください。
今回、CallByNameメソッドが使われているのですが、 Application.Run メソッドを直接使っても、 使い勝手は大差ない様な気がするんですが、 何か、重要な違いがあるのでしょうか?
(半平太) 2024/03/25(月) 12:56:19
新しいもの好きで。。。試して見ようかなとか。。。思っただけです。
まだ、詳しい調査はしておりませんです。( ̄▽ ̄:)現在進行形^^
わたしの誤解、理解間違い等ありましたらご指摘賜れば幸甚です。でわ
<< _ _ >>
(隠居Z) 2024/03/25(月) 13:51:54
Option Explicit Sub apptest_main() Dim mx, eApp mx = 10 Set eApp = Application Application.Run "Module1.app1", mx MsgBox mx CallByName eApp, "Run", VbMethod, "Module1.app2", mx MsgBox mx End Sub Private Sub app1(ByRef x) x = 1 End Sub Private Sub app2(ByRef x) x = 2 End Sub
結果 10 と 2 でした
(隠居Z) 2024/03/25(月) 14:41:48
隠居Zさん
貴重な情報をありがとうございました。 なんか、深遠な闇があるんですね。
同氏の話だと、型.Run は 型 結果 Application 不可 1 xlApp_App 不可 2 xlApp_Obj 成功 3 xlApp_Var 成功 4
CallByName経由なら 型 結果 Application 成功 5 xlApp_App 成功 6 xlApp_Obj 成功 7 xlApp_Var 成功 8
とのことなので、隠居Zさんは上記「6」を採用したと言うことですね。
まぁ今回は、渡す引数については、簡単なサンプルを使っているので余り深入りできないです。
私としては、もう少し簡単にならないかなぁと思っていまして。 「呼び出される方のErr.Number」を呼び出し元に返させる、と言う方法が使えないかな、と。 その為、呼び出される方は、エラー処理を行わず、 On Error Resume Nextだけで終わりにする。
具体的アイデア Module1
Private Sub main() Dim x, v(), eApp, i&, fps$, fNm$, eFlg As Boolean, xx()
On Error GoTo errstp fps = ThisWorkbook.Path & "\" fNm = "errorlog.txt" Open fps & fNm For Output As #1 Close #1 Open fps & fNm For Append As #1 Set eApp = Application v = Array("Module1.p1", "Module1.p2", "Module2.p3", "Module2.p4", "Module2.p5") ReDim xx(UBound(v)) For i = LBound(xx) To UBound(xx) xx(i) = 0 Next
Err.Raise 1 Dim ret, errorOccured
For i = LBound(v) To UBound(v) ret = CallByName(eApp, "Run", VbMethod, v(i), v(i)) If ret(0) <> 0 Then Err.Raise ret(0) End If
ret = Empty '戻り値の初期化 Next
Err.Raise 13 If Application.Sum(xx) <> 0 Then MsgBox "エラー発生ログを確認してください" Else MsgBox "正常終了" End If
Erase v, xx Close #1 Exit Sub
errstp: If IsArray(ret) Then errorOccured = ret(1) xx(i) = 1 Else errorOccured = "Module1.Main" xx(1) = 1 End If
MyErrSub Err.Number, Err.Description, errorOccured Resume Next End Sub
Function p1(s) Dim x
On Error Resume Next Err.Raise 1 p1 = Array(Err.Number, s) End Function
Function p2(s, ParamArray dum()) Dim x
On Error Resume Next Err.Raise 2 p2 = Array(Err.Number, s) End Function
Sub MyErrSub(num&, etx$, errDetail) Dim ltx$ On Error GoTo errstp ltx = "[" & Format(Now, " yyyy/mm/dd : hh:nn:ss ") & "]" ltx = ltx & Chr(32) & num & Chr(32) & etx & Chr(32) ltx = ltx & errDetail Print #1, ltx Rem Err.Raise 9 Exit Sub errstp: MsgBox "MyErrSub エラーですシステム担当に連絡してください" & Chr(13) & _ Err.Number & Chr(32) & Err.Description End End Sub
Module2
Function p3(s, ParamArray dum()) Dim x
On Error Resume Next Err.Raise 3 p3 = Array(Err.Number, s) End Function
Function p4(s, ParamArray dum()) Dim x
On Error Resume Next ' Err.Raise 4 p4 = Array(Err.Number, s) End Function
Function p5(s, ParamArray dum()) Dim x
On Error Resume Next Err.Raise 5 p5 = Array(Err.Number, s) End Function
(半平太) 2024/03/25(月) 15:48:15
>On Error Resume Nextだけで終わりにする。
これはマズかったです。m(__)m 現実のプロシージャは色んなことやっているはずなので、 無益な処理を続けさせるべきではなかったです。
あと、プロシージャ名を引数に渡す必要はなかったです。 今呼び出したばかりの関数名に決まっていますので、 呼出元で容易に割り出せます
なので、pnプロシージャはこう言う形の方が良かったです。
Function pn(ParamArray dum()) On Error GoTo final
Err.Raise n final: pn = Err.Number End Function
これで返り値も単純なLong値となり、 呼出元での疑似エラー発動処理もシンプルになります。
それにしても、そこらじゅうでエラーしまくりそうなプロジェクトなんですね。 地雷原を歩く様で怖すぎ。私はこれ以上近寄らないことにします。
(半平太) 2024/03/26(火) 13:46:54
(*^^;*)。プロジェクト作成者の性格がちゃらんぽらんなもので。つい。。。m(__)m
今、おさらいを兼ねて、お示し戴いたコードに書き換えておりました。
更なるご提案も取り込んでまいります。
本当に、ありがとうございました。m(__)m
(隠居Z) 2024/03/26(火) 14:47:04
以下のように呼び出し元でエラーを取得するものを作ったことがあります。 ErrObjectのSourceプロパティを利用して、各モジュール名.プロシージャ名を どのルートでエラーになったか追えるようにしていました。 参考になれば。
'Module1 Option Explicit Const MODULE_NAME$ = "Module1" Public Sub Main()'呼び出し元 On Error GoTo OnErr Call CatchErrProc Exit Sub OnErr: 'エラー処理 MsgBox Err.Number & vbCrLf & _ Err.Description & vbCrLf & _ Err.Source End Sub Public Sub MyErrRaise(ByRef srcErr As ErrObject, ByVal moduleName$, ByVal procName$) Dim track$ track = moduleName & "." & procName & ";" If srcErr.Source <> "VBAProject" Then track = srcErr.Source & track Err.Source = track Err.Raise srcErr.Number, track, srcErr.Description End Sub Private Sub CatchErrProc() Const PROC_NAME$ = "CatchErrProc" On Error GoTo OnErr '適時コメントアウトしてください Fnc1 Fnc2 Fnc4 Exit Sub OnErr: MyErrRaise Err, MODULE_NAME, PROC_NAME End Sub Public Function Fnc1() Const PROC_NAME$ = "Fnc1" On Error GoTo OnErr Err.Raise 1004 Exit Function OnErr: MyErrRaise Err, MODULE_NAME, PROC_NAME End Function Public Function Fnc2() Const PROC_NAME$ = "Fnc2" On Error GoTo OnErr Fnc3 Exit Function OnErr: MyErrRaise Err, MODULE_NAME, PROC_NAME End Function Public Function Fnc3() Const PROC_NAME$ = "Fnc3" On Error GoTo OnErr Err.Raise 5 Exit Function OnErr: MyErrRaise Err, MODULE_NAME, PROC_NAME End Function
'Module2 Option Explicit Const MODULE_NAME$ = "Module2" Public Function Fnc4() Const PROC_NAME$ = "Fnc4" On Error GoTo OnErr Err.Raise 9 Exit Function OnErr: MyErrRaise Err, MODULE_NAME, PROC_NAME End Function
(tkit) 2024/03/26(火) 16:01:07
お陰様で、例外処理の理解が深まりました。
ついでに「元の例外処理の有効スコープが切れない場合(※)」はどうなるか、 ちょっと考えてみました。 ※つまり、普通にCallできて、CallByName や Application.Run を使わないで済む場合
この場合は、Call元に制御が戻るので、Call先にはエラートラップを設定する必要がないようです。
Module1
Private Sub main() Dim x, v(), eApp, i&, fps$, fNm$, eFlg As Boolean, xx() Dim ret As Long
On Error GoTo errstp i = -1 '初期化
fps = ThisWorkbook.Path & "\" fNm = "errorlog.txt" Open fps & fNm For Output As #1 Close #1 Open fps & fNm For Append As #1 Set eApp = Application v = Array("Module1.p1", "Module1.p2", "Module2.p3", "Module2.p4", "Module2.p5")
ReDim xx(UBound(v))
Err.Raise 11
i = i + 1: Debug.Print p1 i = i + 1: Debug.Print p2 i = i + 1: Debug.Print p3 i = i + 1: Debug.Print p4 i = i + 1: Debug.Print p5 i = -1 '初期化
Err.Raise 12 If Application.Sum(xx) <> 0 Then MsgBox "エラー発生ログを確認してください" Else MsgBox "正常終了" End If
Erase v, xx Close #1 Exit Sub
errstp: If i = -1 Then 'Mainで発生 xx(0) = xx(0) + 1 MyErrSub Err.Number, Err.Description, "Module1.Main" Else xx(i) = 1 MyErrSub Err.Number, Err.Description, v(i) End If
Resume Next End Sub
Function p1(ParamArray dum()) Dim x Err.Raise 1 p1 = "p1成功" End Function
Function p2(ParamArray dum()) Dim x ' Err.Raise 2 p2 = "p2成功" End Function
Sub MyErrSub(num&, etx$, errDetail) Dim ltx$ On Error GoTo errstp
ltx = "[" & Format(Now, " yyyy/mm/dd : hh:nn:ss ") & "]" ltx = ltx & Chr(32) & num & Chr(32) & etx & Chr(32) ltx = ltx & errDetail Print #1, ltx ' Err.Raise 9 Exit Sub errstp: MsgBox "MyErrSub エラーですシステム担当に連絡してください" & Chr(13) & _ Err.Number & Chr(32) & Err.Description End End Sub
Module2 Function p3(ParamArray dum()) Dim x Err.Raise 3 p3 = "p3成功" End Function
Function p4(ParamArray dum()) Dim x ' Err.Raise 4 p4 = "p4成功" End Function
Function p5(ParamArray dum()) Dim x Err.Raise 5 p5 = "p5成功" End Function
(半平太) 2024/03/27(水) 11:54:54
(隠居Z) 2024/03/27(水) 13:56:28
Option Explicit Sub Program_Main() Dim i As Long Dim Pr() As Variant Dim pRoc As Variant Dim rEv As Long Dim ErPlace As String Dim ErrFlg As Boolean On Error GoTo ErrStp i = -1 Pr = Array("Module1.LogFile_Open", "Module1.MyErrSub", _ "Module1.P1", "Module1.P2", "Module2.P3", "Module2.P4", "Module2.P5") Module1.LogFile_Open i Module1.MyErrSub "Test", "Test", "Test", i i = -1 Rem *********************************************************************** Err.Raise 11 i = i + 3: Module1.p1 i = i + 1: Module1.p2 i = i + 1: Module2.p3 i = i + 1: Module2.p4 i = i + 1: Module2.p5 Rem *********************************************************************** i = -1 Err.Raise 12 GoTo Finally ErrStp: ErrFlg = True If i = 0 Or i = 1 Then GoSub Finally End If If i = -1 Then ErPlace = "Module1.Program_Main" & " i = " & i Else ErPlace = Pr(i) End If MyErrSub Err.Number, Err.Description, ErPlace Resume Next Finally: Close Stop If ErrFlg And i = -1 Then MsgBox "異常終了です。エラーログを参照してください" ElseIf ErrFlg And (i = 0 Or i = 1) Then MsgBox "エラーログを出力出来ません" & Chr(13) & Pr(i) & Chr(13) & Err.Number & Err.Description Else MsgBox "正常に終了致しました。" End If Erase Pr End Sub Sub LogFile_Open(ByRef i As Long) Dim fps As String Dim fNm As String i = 0 fps = ThisWorkbook.Path & "\" fNm = "ErrorLog.txt" If Dir(fps & fNm) <> "" Then Kill fps & fNm End If Open fps & fNm For Append As #1 Exit Sub End Sub Sub MyErrSub(num, etx$, mPtx, Optional ByRef i As Long) Dim ltx As String i = 1 ltx = "[" & Format(Now, " yyyy/mm/dd : hh:nn:ss ") & "]" ltx = ltx & Chr(32) & num & Chr(32) & etx & Chr(32) ltx = ltx & mPtx Rem Err.Raise 9 Print #1, ltx Exit Sub End Sub Private Sub p1() Rem Err.Raise 1 Debug.Print "p1" End Sub Private Sub p2() Err.Raise 2 Debug.Print "p2" End Sub
Module2
Option Explicit Sub p3(ParamArray Dummy()) Rem Err.Raise 13 Debug.Print "p3" End Sub Sub p4(ParamArray Dummy()) Rem Err.Raise 14 Debug.Print "p4" End Sub Sub p5(ParamArray Dummy()) Rem Err.Raise 15 Debug.Print "p5" End Sub
(隠居Z) 2024/03/29(金) 13:13:44
済みません。CallByName って使わなくなったのですか? (そっちがメインの話と思っていたのですが)。
(半平太) 2024/03/29(金) 14:30:58
それと同時にマイクロソフト様の例外処理のHP、確かVB。NETだったかも。←に
try、catch、finally、若しくはUsing とon error の ご説明がありまして
勿論今回はvbaのお話でtry、catch、finally、若しくはUsinは有りません。
結論は通常コール、CallByNameどちらも一長一短で。
本音はお勉強を兼ねて双方で組み立ててみようと思っております。[暇ですし(*^^*)]
更に余裕があれば
ケースバイケースで両方混在 ← 他ブックのマクロから呼び出し?
エラー処理のクラス化 ← これは出来るかどうかあまり自信は御座いません。
毛躓きましたら、質問させて戴くかもしれません。又
引き続き、これはどぉだぁ〜。。。、これだけは覚えておいて損はないよ。等々御座いましたら
お教えいただければ幸甚です。m(__)m
何せ今まではマクロ組んでも殆ど自分用なもので、真面にエラー処理してませんので
やり方をお聞きしたくてご質問させて戴いた次第です。
(隠居Z) 2024/03/29(金) 16:51:13
>通常の方をお勧め戴いたのかと。。。思っていました。 いや、CallByNameって面白い発想だなと思っていました。 やりたいのはこっちに違いないと早合点してしまったようです。 (実行中のマクロ名が取得できるツールがVBAにもあれば、問題も小さくなるんでしょうが・・)
>呼び出し先で、何もせずとも呼び出し元にエラーをキックバックしてくださいますので >手間いらずかなとか。 私もそうは思ったのですが、言うほど簡単でもなかったです。
例えば、テキストファイルのOPEN段階でトラブるかも知れないとしたら 書込み工程なんてそもそも無理ですから、処理の場合分けが錯綜せざるを得ないです。
> お陰様で、例外処理の理解が深まりました。 とか言ってしまいましたが、時期尚早でした。 調べを進めると、 On Error GoTo -1 てな文があり、 いままで見たことなかった(か、もしくは、スルーしていたか)ですが、 エラー処理では普通の知識らしいので、まだまだ道遠しの感があります。
コードを目だけで追って、ここでエラーになると最終的に何が起きるか、 なんて分かる人っているんでしょうかね。 結果を見てから後講釈なら幾らでもいるんでしょうが。
まっ、私自身はエラー処理はほどんど書かないで済ませている側なので 人様にアドバイスできるレベルにないです。 他の回答者のアドバイスをご期待ください。
(半平太) 2024/03/29(金) 17:41:43
>>コードを目だけで追って、ここでエラーになると最終的に何が起きるか、
>> なんて分かる人っているんでしょうかね。
絶対とは申しませんが、あまり、居られないのでは。。。で、
エラー処理が有るのではと思いますです。
On Error GoTo -1
初耳です^^;早速調べてみます。。(*^^*)
また、お気づきの点等々御座いましたら、宜しくお願い致します。
ありがとう御座いました。m(__)m
(隠居Z) 2024/03/29(金) 21:01:01
自己流の軽〜い実験^^;
Option Explicit Sub OneInstanceMain() Dim i As Long Dim v On Error GoTo ErrStp On Error Resume Next Err.Raise 13 On Error GoTo -1 Debug.Print Err.Number On Error Resume Next Err.Raise 9 On Error GoTo 0 Debug.Print Err.Number ErrStp: On Error GoTo -1 With Worksheets("Sheet1") End With End Sub 同じってことはないですよね。0 と -1 ^^; (隠居Z) 2024/03/30(土) 09:59:32
>エラー処理が有るのではと思いますです。 いえ、あのー、そのエラー処理が分かり難いと言う趣旨なのですが・・
一般論として、Goto文は流れがスパゲッティ状になるので出来るだけ書くな、と言われますよね。 でも、Goto文なんてかわいいものです。何故って、これから何処へ飛ぶよって目で追う事が出来ます。
しかし、エラー処理文だと 何処から→そんなの分かりません。エラーが発生した時に判明するのだから。 何処へ →それは、そこに書いてないです、ずーっと前に書いてあったでしょう? 忘れたんですか? と言う調子です。悪質度はこっちの方が高いです。 それでいて、必要悪として使わざるを得ない場面がある。。 困った奴です。
普通は、問題が発生する直前でトラップ入れて、そこを抜ければ元に戻すのだろうなぁと思っています。 ※冒頭にトラップを入れて、後は処理プロシージャに任せるのは荒っぽ過ぎると言う認識です。
地雷原を走破するなんて特殊事情がある時、そんな丁寧なことはやってられない、と言うことなんですかね。
以前、ここでプロの意見を拝聴したことがあります。 [[20150906185643]] 『On Error ?ステートメントについて』(ichinose)
(半平太) 2024/03/30(土) 10:53:47
(隠居Z) 2024/03/30(土) 11:49:22
>on error goto -1 使い方教えて
あくまで、私が理解した範囲です。m(__)m
軽〜い実験コードをどう使えばいいのか分からなかったので、 もっと軽〜いのでやります。
※OneInstanceMain2は、ステップ実行のみにしてください(無限ループに陥りますので)
Sub OneInstanceMain1() On Error GoTo ErrStp Err.Raise 1
Debug.Print "終了" Exit Sub ErrStp: Debug.Print Err.Number On Error GoTo 0 Debug.Print Err.Number Err.Raise 11 ' エラー処理中なので実行時エラーとなる End Sub
Sub OneInstanceMain2() On Error GoTo ErrStp Err.Raise 2
Debug.Print "終了" Exit Sub ErrStp: Debug.Print Err.Number On Error GoTo -1 ’エラー処理中であることがキャンセルされ、普通にCallされたことになる Debug.Print Err.Number Err.Raise 12 ’再度ErrStpへジャンプ→無限ループになる End Sub
※On Error GoTo -1 は エラー処理中フラグ(?)もキャンセルしますので、 エラー処理内でエラーが発生しても、実行時エラーにならず、 エラー発生の直前のエラートラップが適用されます。例の場合、再度ErrStpに飛びます。
エラー処理コード内でのエラー発生がそもそもトラブルの元で、 前提がおかしい気がします。(テストではいざ知らず)。 なので、普通はこんな形なんですかねぇ・・
Sub OneInstanceMain3() Dim i On Error GoTo ErrStp i = 1 Err.Raise 3 i = 2 Err.Raise 13
Debug.Print "終了" Exit Sub ErrStp: Debug.Print Err.Number Debug.Print "エラー発生後の処理" & i Resume Next End Sub
(半平太) 2024/03/30(土) 14:02:58
> On Error GoTo 0 > Debug.Print Err.Number > Err.Raise 11 ' エラー処理中なので実行時エラーとなる エラー処理中であろうがなかろうが、On Error GoTo 0 でDefaultにしているので、 実行時エラーになるのは当然でした。 m(__)m
(半平太) 2024/03/30(土) 14:11:11
一関数のステップが増えれば増えるほど必要な例外処理も増えると
思いますので、内容によっては変更も有るとは思いますが基本は
一処理一関数一例外処理
に刻めばコードの可読性は少しはましかも、とか考えています。
あ!、Erl関数も勉強になりました、ログに追加しようと思います(*^^*)
m(__)m
(隠居Z) 2024/03/30(土) 20:29:04
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.