Sha*_*i W 9 error-handling excel vba excel-vba
我得到了Rob Bovey的"专业Excel开发"一书,它开启了我的视野.
我正在使用错误处理重新编写代码.但是,有很多我不明白.我特别需要知道如何在函数中正确使用它.我使用Bovey的错误处理程序的重新抛出版本(在底部).当我开始时,我使用基本的布尔(非重新抛出)方法并将我的子例程转换为布尔函数.(PS我根据答案切换回布尔方法.)
我需要有关如何将功能纳入此方案的指导.我希望它们返回它们的实际值(一个字符串或双精度值,例如,如果它们在某些情况下失败则返回-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
Run Code Online (Sandbox Code Playgroud)
但是,我不知道如何将其扩展到实际功能.这是基于为子程序编写的书中的一个例子,我只是将其切换为一个函数.问题:*我该怎么称呼它?它只是像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
Run Code Online (Sandbox Code Playgroud)
错误处理程序例程:
'
' 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
Run Code Online (Sandbox Code Playgroud)
Sid*_*out 14
这是Rob的一本很棒的书.
我的两分钱错误处理(程序或功能)基于KISS(保持简单傻)
从错误处理程序中了解您的需求?
这通常是我想要/期望从错误处理程序...
让我们打破上述.由于您现在已经知道您的错误处理程序是什么样的,请考虑此示例.
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
Run Code Online (Sandbox Code Playgroud)
这是一个非常基本的错误处理程序,但它对我的帮助很小.所以我们现在调整它以使其更有用.如果您运行上面的代码,您会收到一条错误消息,如下面的屏幕截图所示,如果您注意到,它没有多大帮助.

我们现在解决Logic上面提到的所有问题
- 发生错误的行
有一个叫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
Run Code Online (Sandbox Code Playgroud)
当你运行上面的代码时,你会得到这个

所以现在我知道错误发生在30号线上了 i = 1111111111
继续下一步
- 错误号码
- 错误信息
的错误数量和错误消息可以从被检索Err.Number和Err.Description分别.现在让我们结合起来Erl,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
Run Code Online (Sandbox Code Playgroud)
当您运行此代码时,您将得到类似的内容.

您可以选择进一步自定义错误消息,使其更加用户友好.例如
'~~> 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
Run Code Online (Sandbox Code Playgroud)

到下一个:)
如果适用,重置事件
当您处理事件并发生错误时,如果没有错误处理,代码会中断.不幸的是,这并没有重置事件.在错误处理程序中重置事件非常重要.
如果您在上面的代码中注意到我们正在设置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
Run Code Online (Sandbox Code Playgroud)
和Philippe一样,我也强烈建议您使用MZ-Tools进行VBA.我现在一直用它来做驴年......
希望这可以帮助.
我需要更多关于这项特定技术的帮助,所以我直接找到了消息来源,Bovey 先生很客气地回复了。他允许我将他的回复发布到 StackOverflow 社区。
下面的说明指的是他首选的函数错误处理方法“布尔错误处理”技术,而不是替代的“重新抛出方法”,这两种方法都在他的“专业 Excel 开发”第二版一书中有所描述。
嗨,莎莉,
在回答有关函数中错误处理的问题时,您可以在 VBA 中使用函数进行三种错误处理方案:
1) 该函数非常简单,不需要错误处理程序。在不太可能的情况下,在这样的函数中发生错误,它将溢出到调用过程的错误处理程序中。
2) 一个非平凡的函数需要一个错误处理程序,并使用书中描述的布尔返回值系统。函数需要返回的任何其他值都通过 ByRef 参数返回。这个案例涵盖了我编写的绝大多数函数。有些事情你不能用这样的函数做,直接将它们输入另一个函数的参数就是一个例子,但我认为这是一个很好的权衡,以实现防弹错误处理。
3) 一个非平凡的函数需要一个错误处理程序并且必须返回一个与其错误状态无关的值。这是一种罕见的情况,因为我可以通过重构我的代码将其中的 99% 以上转换为案例 2。如果你不能这样做,你唯一的选择就是选择一个超出正常返回值范围的任意返回值,并用它来指示发生了错误。如果这个函数的调用者看到这个任意的错误标志值,它就知道它不能继续了。
Rob Bovey 应用专家 http://www.appspro.com/
代码示例 (Shari W)
' Show how to call a function using this error handling method.
Const giBAD_RESULT As Integer = -1
Function TestMath() ' An Entry Point
Dim sngResult As Single
Dim iNum As Integer
' Call the function, actual result goes in sngResult but it returns the error handling boolean.
' A true error like Div 0 will go to error handler.
' Set Up Error Handling for Entry Point
Application.EnableCancelKey = xlErrorHandler
Dim bUserCancel As Boolean
Const sSOURCE As String = "TestMath()"
On Error GoTo ErrorHandler
' End Error Set Up
iNum = 0 ' Try 0 to create error
If Not bDoSomeMath(iNum, sngResult) Then ERR.Raise glHANDLED_ERROR
' If function does parameter checking and wants to return a bad input code, check for that.
If sngResult = giBAD_RESULT Then
MsgBox ("Bad input to bDoSomeMath " & iNum)
Else
MsgBox ("I believe the answer is " & sngResult)
End If
ErrorExit:
On Error Resume Next
Exit Function
ErrorHandler:
If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then
Stop
Resume
Else
Resume ErrorExit
End If
End Function
Function bDoSomeMath(ByVal iNum As Integer, ByRef sngResult As Single) As Boolean
' Error handling Set Up
Dim bReturn As Boolean
Const sSOURCE As String = "bDoSomeMath()"
On Error GoTo ErrorHandler
bReturn = True
' End Error Set Up
If iNum < 0 Or iNum > 1000 Then
sngResult = giBAD_RESULT 'function failed because I only like the numbers 0 to 1000
GoTo ErrorExit
Else
sngResult = 100 / iNum ' generate a true error by iNum = 0
End If
ErrorExit:
On Error Resume Next
bDoSomeMath = bReturn
Exit Function
ErrorHandler:
bReturn = False
If bCentralErrorHandler(msMODULE, sSOURCE, , , True) Then
Stop
Resume
Else
Resume ErrorExit
End If
End Function
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
35305 次 |
| 最近记录: |