9

Rob Bovey 著の "Professional Excel Development" という本を手に入れましたが、それは私の目を開いています。

エラー処理を使用してコードを再調整しています。ただし、わからないことが多いです。特に、関数で正しく使用する方法を知る必要があります。Bovey のエラー ハンドラの再スロー バージョンを使用します (一番下)。私が始めたとき、私は基本的なブール (非再スロー) メソッドを使用していて、サブルーチンをブール関数に変えました。(PS私は答えに基づいてブール法に戻っています。)

関数をこのスキームに適合させる方法についてのガイダンスが必要です。エラー処理ブール値を返すだけでなく、他の関数でそれらをネストできるように、実際の値 (文字列または double、たとえば、失敗した場合は -1) を返すようにします。

これは、bDrawCellBorders(myWS) への典型的なサブルーチン呼び出しがエントリ ポイント内でどのように見えるかです。サブコールはうまく機能しているようです。(つまり、エラー処理スキームにブール値を返すことができるようにするためだけに関数に変換されたサブルーチンです。)

Sub UpdateMe()  ' Entry Point

    Const sSOURCE As String = "UpdateMe()"

    On Error GoTo ErrorHandler

    Set myWS = ActiveCell.Worksheet
    Set myRange = ActiveCell
    myWS.Unprotect

' lots of code

    If Not bDrawCellBorders(myWS) Then ERR.Raise glHANDLED_ERROR    ' Call subroutine

' lots of code

ErrorExit:
    On Error Resume Next
    Application.EnableEvents = True
    myWS.Protect AllowFormattingColumns:=True
    Exit Sub

ErrorHandler:
    If bCentralErrorHandler(msMODULE, sSOURCE,,True) Then  ' Call as Entry Point
        Stop
        Resume
    Else
        Resume ErrorExit
    End If
End Sub

ただし、これを実際の関数に拡張する方法がわかりません。これは、サブルーチン用に作成された本の例に基づいており、関数に切り替えただけです。質問: * どのように呼びますか? 単純に x = sngDoSomeMath(17) * のようなものですか? エラー処理は適切に機能しますか? * bReThrow=true でエラー処理ルーチンを呼び出す適切な場所はどこですか?

Public Function sngDoSomeMath(ByVal iNum As Integer) As Single

Dim sngResult As Single

Const sSOURCE As String = "sngDoSomeMath()"

On Error GoTo ErrorHandler

' example 1, input did not pass validation. don't want to 
' go up the error stack but just inform the
' calling program that they didn't get a good result from this 
' function call so they can do something else
If iNum <> 42 Then
    sngResult = -1    'function failed because I only like the number 42
    GoTo ExitHere
End If

' example 2, true error generated
sngResult = iNum / 0

sngDoSomeMath = lResult

ExitHere:
    Exit Function
ErrorHandler:

' Run cleanup code
'  ... here if any

' Then do error handling

If bCentralErrorHandler(msMODULE, sSOURCE, , , True) Then ' The true is for RETHROW
    Stop
    Resume
End If

End Function

エラー処理ルーチン:

'
' Description:  This module contains the central error
'               handler and related constant declarations.
'
' Authors:      Rob Bovey, www.appspro.com
'               Stephen Bullen, www.oaltd.co.uk
'
' Chapter Change Overview
' Ch#   Comment
' --------------------------------------------------------------
' 15    Initial version
'
Option Explicit
Option Private Module

' **************************************************************
' Global Constant Declarations Follow
' **************************************************************
Public Const gbDEBUG_MODE As Boolean = False    ' True enables debug mode, False disables it.
Public Const glHANDLED_ERROR As Long = 9999     ' Run-time error number for our custom errors.
Public Const glUSER_CANCEL As Long = 18         ' The error number generated when the user cancels program execution.


' **************************************************************
' Module Constant Declarations Follow
' **************************************************************
Private Const msSILENT_ERROR As String = "UserCancel"   ' Used by the central error handler to bail out silently on user cancel.
Private Const msFILE_ERROR_LOG As String = "Error.log"  ' The name of the file where error messages will be logged to.


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Comments: This is the central error handling procedure for the
'           program. It logs and displays any run-time errors
'           that occur during program execution.
'
' Arguments:    sModule         The module in which the error occured.
'               sProc           The procedure in which the error occured.
'               sFile           (Optional) For multiple-workbook
'                               projects this is the name of the
'                               workbook in which the error occured.
'               bEntryPoint     (Optional) True if this call is
'                               being made from an entry point
'                               procedure. If so, an error message
'                               will be displayed to the user.
'
' Returns:      Boolean         True if the program is in debug
'                               mode, False if it is not.
'
' Date          Developer       Chap    Action
' --------------------------------------------------------------
' 03/30/08      Rob Bovey       Ch15    Initial version
'
Public Function bCentralErrorHandler( _
       ByVal sModule As String, _
       ByVal sProc As String, _
       Optional ByVal sFile As String, _
       Optional ByVal bEntryPoint As Boolean, _
       Optional ByVal bReThrow As Boolean = True) As Boolean

    Static sErrMsg As String

    Dim iFile As Integer
    Dim lErrNum As Long
    Dim sFullSource As String
    Dim sPath As String
    Dim sLogText As String

    ' Grab the error info before it's cleared by
    ' On Error Resume Next below.
    lErrNum = ERR.Number
    ' If this is a user cancel, set the silent error flag
    ' message. This will cause the error to be ignored.
    If lErrNum = glUSER_CANCEL Then sErrMsg = msSILENT_ERROR
    ' If this is the originating error, the static error
    ' message variable will be empty. In that case, store
    ' the originating error message in the static variable.
    If Len(sErrMsg) = 0 Then sErrMsg = ERR.Description

    ' We cannot allow errors in the central error handler.
    On Error Resume Next

    ' Load the default filename if required.
    If Len(sFile) = 0 Then sFile = ThisWorkbook.Name

    ' Get the application directory.
    sPath = ThisWorkbook.Path
    If Right$(sPath, 1) <> "\" Then sPath = sPath & "\"

    ' Construct the fully-qualified error source name.
    sFullSource = "[" & sFile & "]" & sModule & "." & sProc

    ' Create the error text to be logged.
    sLogText = "  " & sFullSource & ", Error " & _
               CStr(lErrNum) & ": " & sErrMsg

    ' Open the log file, write out the error information and
    ' close the log file.
    iFile = FreeFile()
    Open sPath & msFILE_ERROR_LOG For Append As #iFile
    Print #iFile, Format$(Now(), "mm/dd/yy hh:mm:ss"); sLogText
    If bEntryPoint Or Not bReThrow Then Print #iFile,
    Close #iFile

    ' Do not display or debug silent errors.
    If sErrMsg <> msSILENT_ERROR Then

        ' Show the error message when we reach the entry point
        ' procedure or immediately if we are in debug mode.
        If bEntryPoint Or gbDEBUG_MODE Then
            Application.ScreenUpdating = True
            MsgBox sErrMsg, vbCritical, gsAPP_NAME
            ' Clear the static error message variable once
            ' we've reached the entry point so that we're ready
            ' to handle the next error.
            sErrMsg = vbNullString
        End If

        ' The return vale is the debug mode status.
        bCentralErrorHandler = gbDEBUG_MODE

    Else
        ' If this is a silent error, clear the static error
        ' message variable when we reach the entry point.
        If bEntryPoint Then sErrMsg = vbNullString
        bCentralErrorHandler = False
    End If

    'If we're using re-throw error handling,
    'this is not the entry point and we're not debugging,
    're-raise the error, to be caught in the next procedure
    'up the call stack.
    'Procedures that handle their own errors can call the
    'central error handler with bReThrow = False to log the
    'error, but not re-raise it.
    If bReThrow Then
        If Not bEntryPoint And Not gbDEBUG_MODE Then
            On Error GoTo 0
            ERR.Raise lErrNum, sFullSource, sErrMsg
        End If
    Else
        'Error is being logged and handled,
        'so clear the static error message variable
        sErrMsg = vbNullString
    End If

End Function
4

3 に答える 3

15

それはロブによる素晴らしい本です。

私の2セントのエラー処理(プロシージャまたは関数のいずれか)は、 KISSに基づいています(シンプルにしてください

エラー ハンドラに何を求めているか理解できましたか?

これは通常、エラーハンドラーに必要/期待するものです...

  1. エラーが発生した行
  2. エラー番号
  3. エラーメッセージ
  4. 該当する場合はイベントをリセット

上記を破りましょう。エラー ハンドラーがどのように見えるかはもうおわかりでしょうが、次の例を考えてみましょう。

Sub Sample()
    Dim i As Integer, j As Integer

    On Error GoTo Whoa

    Application.ScreenUpdating = False

    i = 1111111111

    For j = 1 To i
        Debug.Print ThisWorkbook.Sheets(1).Cells(i, 1).Value
    Next i

LetsContinue:
    Exit Sub
Whoa:
    MsgBox Err.Description
    Resume LetsContinue
End Sub

これは非常に基本的なエラー ハンドラですが、私にとってはあまり役に立ちません。それでは、より使いやすいように微調整してみましょう。上記のコードを実行すると、下のスクリーンショットに示すようなエラー メッセージが表示されます。気付いたとしても、あまり役に立ちません。

ここに画像の説明を入力

Logic上記で述べたすべてのポイントに取り組みましょう

  1. エラーが発生した行

ERLと呼ばれる、ほとんどの人が知らないプロパティがあります。実際にこれを使用して、エラーが発生したコードの行番号を取得できます。そのためには、コードに番号を付ける必要があります。この例を参照してください。

Sub Sample()
    Dim i As Integer, j As Integer

10      On Error GoTo Whoa

20      Application.ScreenUpdating = False

30      i = 1111111111

40      For j = 1 To i
50          Debug.Print ThisWorkbook.Sheets(1).Cells(i, 1).Value
60      Next j

LetsContinue:
70      Exit Sub
Whoa:
80      MsgBox Erl
90      Resume LetsContinue
End Sub

上記のコードを実行すると、これが得られます

ここに画像の説明を入力

これで、30 行目でエラーが発生したことがわかりました。i = 1111111111

次に進む

  1. エラー番号
  2. エラーメッセージ

Err.Numberエラー番号とエラー メッセージは、それぞれ とから取得できますErr.DescriptionErlそれでは、Err.Numberと を組み合わせましょうErr.Description

この例を確認してください

Sub Sample()
    Dim i As Integer, j As Integer

10      On Error GoTo Whoa

20      Application.ScreenUpdating = False

30      i = 1111111111

40      For j = 1 To i
50          Debug.Print ThisWorkbook.Sheets(1).Cells(i, 1).Value
60      Next j

LetsContinue:
70      Exit Sub
Whoa:
80      MsgBox "The Error Happened on Line : " & Erl & vbNewLine & _
           "Error Message : " & Err.Description & vbNewLine & _
           "Error Number : " & Err.Number
90      Resume LetsContinue
End Sub

このコードを実行すると、このような結果が得られます。

ここに画像の説明を入力

エラー メッセージをさらにカスタマイズして、より使いやすいものにすることができます。例えば

'~~> Message you want to deliver to the user in case the error happens
Const sMsg As String = "Please take a screenshot of this message and contact the developer for a resolution"
'~~> Title of your message box
Const sTitle As String = "Oopsie Daisies"

'~~> Change the above as applicable

Sub Sample()
    Dim i As Integer, j As Integer

10      On Error GoTo Whoa

20      Application.ScreenUpdating = False

30      i = 1111111111

40      For j = 1 To i
50          Debug.Print ThisWorkbook.Sheets(1).Cells(i, 1).Value
60      Next j

LetsContinue:
70      Exit Sub
Whoa:
80      MsgBox "The Error Happened on Line : " & Erl & vbNewLine & _
           "Error Message : " & Err.Description & vbNewLine & _
           "Error Number : " & Err.Number & vbNewLine & vbNewLine & _
           sMsg, vbCritical, sTitle
90      Resume LetsContinue
End Sub

ここに画像の説明を入力

次のものへ :)

該当する場合はイベントをリセット

イベントを操作しているときにエラーが発生した場合、エラー処理がないとコードが壊れます。残念ながら、それはイベントをリセットしません。エラー ハンドラでイベントをリセットすることは非常に重要です。

上記のコードで気付いた場合は、Application.ScreenUpdating = False. コードが壊れると、そのイベントはリセットされません。LetsContinueこの場合、エラー ハンドラでそれを処理する必要があります。この例を参照してください。

'~~> Message you want to deliver to the user in case the error happens
Const sMsg As String = "Please take a screenshot of this message and contact the developer for a resolution"
'~~> Title of your message box
Const sTitle As String = "Oopsie Daisies"

'~~> Change the above as applicable

Sub Sample()
    Dim i As Integer, j As Integer

10      On Error GoTo Whoa

20      Application.ScreenUpdating = False

30      i = 1111111111

40      For j = 1 To i
50          Debug.Print ThisWorkbook.Sheets(1).Cells(i, 1).Value
60      Next j

LetsContinue:
70      Application.ScreenUpdating = True
80      Exit Sub
Whoa:
90      MsgBox "The Error Happened on Line : " & Erl & vbNewLine & _
           "Error Message : " & Err.Description & vbNewLine & _
           "Error Number : " & Err.Number & vbNewLine & vbNewLine & _
           sMsg, vbCritical, sTitle
100     Resume LetsContinue
End Sub

Philippe と同様に、VBA には MZ-Tools を使用することを強くお勧めします。私はロバの年のために今それを使用しています...

お役に立てれば。

于 2013-09-27T09:28:37.513 に答える
2

VBA でのエラー処理管理の提案は、ここにあります。

まったく同じツール (MZ-Tools) とメソッド (自動化されたエラー報告システムを構築するために使用できる標準/汎用エラー ハンドラー) が Excel でも機能します。

于 2013-09-27T04:31:31.447 に答える