| title | keywords | f1_keywords | ms.prod | ms.assetid | ms.date | ms.localizationpriority |
|---|---|---|---|---|---|---|
|
Elements of run-time error handling |
vbaac10.chm5186924 |
vbaac10.chm5186924 |
access |
a0e06a1e-2709-aa51-92d0-340788a31a8a |
09/21/2018 |
medium |
Errors and error handling
When you are programming an application, you need to consider what happens when an error occurs. An error can occur in your application for one of two of reasons. First, some condition at the time the application is running makes otherwise valid code fail. For example, if your code attempts to open a table that the user has deleted, an error occurs. Second, your code may contain improper logic that prevents it from doing what you intended. For example, an error occurs if your code attempts to divide a value by zero.
If you’ve implemented no error handling, then Visual Basic halts execution and displays an error message when an error occurs in your code. The user of your application is likely to be confused and frustrated when this happens. You can forestall many problems by including thorough error-handling routines in your code to handle any error that may occur.
When adding error handling to a procedure, you should consider how the procedure will route execution when an error occurs. The first step in routing execution to an error handler is to enable an error handler by including some form of the On Error statement within the procedure. The On Error statement directs execution in event of an error. If there’s no On Error statement, Visual Basic simply halts execution and displays an error message when an error occurs.
When an error occurs in a procedure with an enabled error handler, Visual Basic doesn’t display the normal error message. Instead it routes execution to an error handler, if one exists. When execution passes to an enabled error handler, that error handler becomes active. Within the active error handler, you can determine the type of error that occurred and address it in the manner that you choose. Access provides three objects that contain information about errors that have occurred, the ADO Error object, the Visual Basic Err object, and the DAO Error object.
Routing execution when an error occurs
An error handler specifies what happens within a procedure when an error occurs. For example, you may want the procedure to end if a certain error occurs, or you may want to correct the condition that caused the error and resume execution. The On Error and Resume statements determine how execution proceeds in the event of an error.
On Error statement
The On Error statement enables or disables an error-handling routine. If an error-handling routine is enabled, execution passes to the error-handling routine when an error occurs.
There are three forms of the On Error statement: On Error GoTo label, On Error GoTo 0, and On Error Resume Next. The On Error GoTo label statement enables an error-handling routine, beginning with the line on which the statement is found. You should enable the error-handling routine before the first line at which an error could occur. When the error handler is active and an error occurs, execution passes to the line specified by the label argument.
The line specified by the label argument should be the beginning of the error-handling routine. For example, the following procedure specifies that if an error occurs, execution passes to the line labeled:
Function MayCauseAnError() ' Enable error handler. On Error GoTo Error_MayCauseAnError . ' Include code here that may generate error. . . Error_MayCauseAnError: . ' Include code here to handle error. . . End Function
The On Error GoTo 0 statement disables error handling within a procedure. It doesn’t specify line 0 as the start of the error-handling code, even if the procedure contains a line numbered 0. If there’s no On Error GoTo 0 statement in your code, the error handler is automatically disabled when the procedure has run completely. The On Error GoTo 0 statement resets the properties of the Err object, having the same effect as the Clear method of the Err object.
The On Error Resume Next statement ignores the line that causes an error and routes execution to the line following the line that caused the error. Execution isn’t interrupted. Use the On Error Resume Next statement if you want to check the properties of the Err object immediately after a line at which you anticipate an error will occur, and handle the error within the procedure rather than in an error handler.
Resume statement
The Resume statement directs execution back to the body of the procedure from within an error-handling routine. You can include a Resume statement within an error-handling routine if you want execution to continue at a particular point in a procedure. However, a Resume statement isn’t necessary; you can also end the procedure after the error-handling routine.
There are three forms of the Resume statement. The Resume or Resume 0 statement returns execution to the line at which the error occurred. The Resume Next statement returns execution to the line immediately following the line at which the error occurred. The Resume label statement returns execution to the line specified by the label argument. The label argument must indicate either a line label or a line number.
You typically use the Resume or Resume 0 statement when the user must make a correction. For example, if you prompt the user for the name of a table to open, and the user enters the name of a table that doesn’t exist, you can prompt the user again and resume execution with the statement that caused the error.
You use the Resume Next statement when your code corrects for the error within an error handler, and you want to continue execution without rerunning the line that caused the error. You use the Resume label statement when you want to continue execution at another point in the procedure, specified by the label argument. For example, you might want to resume execution at an exit routine, as described in the following section.
Exiting a procedure
When you include an error-handling routine in a procedure, you should also include an exit routine, so that the error-handling routine will run only if an error occurs. You can specify an exit routine with a line label in the same way that you specify an error-handling routine.
For example, you can add an exit routine to the example in the previous section. If an error doesn’t occur, the exit routine runs after the body of the procedure. If an error occurs, then execution passes to the exit routine after the code in the error-handling routine has run. The exit routine contains an Exit statement.
Function MayCauseAnError() ' Enable error handler. On Error GoTo Error_MayCauseAnError . ' Include code here that may generate error. . . Exit_MayCauseAnError: Exit Function Error_MayCauseAnError: . ' Include code to handle error. . . ' Resume execution with exit routine to exit function. Resume Exit_MayCauseAnError End Function
Handling errors in nested procedures
When an error occurs in a nested procedure that doesn’t have an enabled error handler, Visual Basic searches backward through the calls list for an enabled error handler in another procedure, rather than simply halting execution. This provides your code with an opportunity to correct the error within another procedure. For example, suppose Procedure A calls Procedure B, and Procedure B calls Procedure C. If an error occurs in Procedure C and there’s no enabled error handler, Visual Basic checks Procedure B, then Procedure A, for an enabled error handler. If one exists, execution passes to that error handler. If not, execution halts and an error message is displayed.
Visual Basic also searches backward through the calls list for an enabled error handler when an error occurs within an active error handler. You can force Visual Basic to search backward through the calls list by raising an error within an active error handler with the Raise method of the Err object. This is useful for handling errors that you don’t anticipate within an error handler. If an unanticipated error occurs, and you regenerate that error within the error handler, then execution passes back up the calls list to find another error handler, which may be set up to handle the error.
For example, suppose Procedure C has an enabled error handler, but the error handler doesn’t correct for the error that has occurred. Once the error handler has checked for all the errors that you’ve anticipated, it can regenerate the original error. Execution then passes back up the calls list to the error handler in Procedure B, if one exists, providing an opportunity for this error handler to correct the error. If no error handler exists in Procedure B, or if it fails to correct for the error and regenerates it again, then execution passes to the error handler in Procedure A, assuming one exists.
To illustrate this concept in another way, suppose that you have a nested procedure that includes error handling for a type mismatch error, an error which you’ve anticipated. At some point, a division-by-zero error, which you haven’t anticipated, occurs within Procedure C. If you’ve included a statement to regenerate the original error, then execution passes back up the calls list to another enabled error handler, if one exists. If you’ve corrected for a division-by-zero error in another procedure in the calls list, then the error will be corrected. If your code doesn’t regenerate the error, then the procedure continues to run without correcting the division-by-zero error. This in turn may cause other errors within the set of nested procedures.
In summary, Visual Basic searches back up the calls list for an enabled error handler if:
-
An error occurs in a procedure that doesn’t include an enabled error handler.
-
An error occurs within an active error handler. If you use the Raise method of the Err object to raise an error, you can force Visual Basic to search backward through the calls list for an enabled error handler.
Getting information about an error
After execution has passed to the error-handling routine, your code must determine which error has occurred and address it. Visual Basic and Access provide several language elements that you can use to get information about a specific error. Each is suited to different types of errors. Since errors can occur in different parts of your application, you need to determine which to use in your code based on what errors you expect.
The language elements available for error handling include:
-
Err object
-
ADO Error object and Errors collection
-
DAO Error object and Errors collection
-
AccessError method
-
Error event
Err object
The Err object is provided by Visual Basic. When a Visual Basic error occurs, information about that error is stored in the Err object. The Err object maintains information about only one error at a time. When a new error occurs, the Err object is updated to include information about that error instead.
To get information about a particular error, you can use the properties and methods of the Err object:
- The Number property is the default property of the Err object; it returns the identifying number of the error that occurred.
- The Err object’s Description property returns the descriptive string associated with a Visual Basic error.
- The Clear method clears the current error information from the Err object.
- The Raise method generates a specific error and populates the properties of the Err object with information about that error.
The following example shows how to use the Err object in a procedure that may cause a type mismatch error:
Function MayCauseAnError() ' Declare constant to represent likely error. Const conTypeMismatch As Integer = 13 On Error GoTo Error_MayCauseAnError . ' Include code here that may generate error. . . Exit_MayCauseAnError: Exit Function Error_MayCauseAnError: ' Check Err object properties. If Err = conTypeMismatch Then . ' Include code to handle error. . . Else ' Regenerate original error. Dim intErrNum As Integer intErrNum = Err Err.Clear Err.Raise intErrNum End If ' Resume execution with exit routine to exit function. Resume Exit_MayCauseAnError End Function
Note that in the preceding example, the Raise method is used to regenerate the original error. If an error other than a type mismatch error occurs, execution will be passed back up the calls list to another enabled error handler, if one exists.
The Err object provides you with all the information you need about Visual Basic errors. However, it doesn’t give you complete information about Access errors or Access database engine errors. Access and Data Access Objects (DAO)) provide additional language elements to assist you with those errors.
Error object and Errors collection
The Error object and Errors collection are provided by ADO and DAO. The Error object represents an ADO or DAO error. A single ADO or DAO operation may cause several errors, especially if you are performing DAO ODBC operations. Each error that occurs during a particular data access operation has an associated Error object. All the Error objects associated with a particular ADO or DAO operation are stored in the Errors collection, the lowest-level error being the first object in the collection and the highest-level error being the last object in the collection.
When a ADO or DAO error occurs, the Visual Basic Err object contains the error number for the first object in the Errors collection. To determine whether additional ADO or DAO errors have occurred, check the Errors collection. The values of the ADO Number or DAO Number properties and the ADO Description or DAO Description properties of the first Error object in the Errors collection should match the values of the Number and Description properties of the Visual Basic Err object.
AccessError method
Use the Raise method of the Err object to generate a Visual Basic error that hasn’t actually occurred and determine the descriptive string associated with that error. However, you can’t use the Raise method to generate a Access error, an ADO error, or a DAO error. To determine the descriptive string associated with an Access error, an ADO error, or a DAO error that hasn’t actually occurred, use the AccessError method.
Error event
Use the Error event to trap errors that occur on an Access form or report. For example, if a user tries to enter text in a field whose data type is Date/Time, the Error event occurs. If you add an Error event procedure to an Employees form, then try to enter a text value in the HireDate field, the Error event procedure runs.
The Error event procedure takes an integer argument, DataErr. When an Error event procedure runs, the DataErr argument contains the number of the Access error that occurred. Checking the value of the DataErr argument within the event procedure is the only way to determine the number of the error that occurred. The Err object isn’t populated with error information after the Error event occurs. Use the value of the DataErr argument together with the AccessError method to determine the number of the error and its descriptive string.
[!NOTE]
The Error statement and Error function are provided for backward compatibility only. When writing new code, use the Err and Error objects, the AccessError function, and the Error event for getting information about an error.
About the contributors
Link provided by 
- Handling Access Errors with VBA
UtterAccess is the premier Microsoft Access wiki and help forum.
See also
- Access for developers forum
- Access help on support.office.com
- Access forums on UtterAccess
- Access developer and VBA programming help center (FMS)
- Access posts on StackOverflow
[!includeSupport and feedback]
Активизирует подпрограмму обработки ошибок и указывает положение подпрограммы в процедуре; используется также для отключения подпрограммы обработки ошибок.
- On Error GoTo строка — Активизирует подпрограмму обработки ошибок, начало которой определяется обязательным аргументом строка, значением которого может быть любая метка строки или номер строки. Если возвращается ошибка выполнения, управление передается на указанную строку и запускается обработчик ошибок. Аргумент строка должен определять строку в той же процедуре, в которой находится инструкция On Error; в противном случае возникает ошибка компиляции.
- On Error Resume Next — Указывает, что возникновение ошибки выполнения приводит к передаче управления на инструкцию, непосредственно следующую за инструкцией, при выполнении которой возникла ошибка. Рекомендуется при доступе к объектам использовать эту форму инструкции, а не On Error GoTo.
- On Error GoTo 0 — Отключает любой активизированный обработчик ошибок в текущей процедуре.
Замечания
Если не выполнена инструкция On Error, то любая ошибка выполнения является фатальной; это означает, что выводится сообщение об ошибке и выполнение программы прекращается.
«Включенным» обработчиком ошибок называют подпрограмму, которая указана в инструкции On Error; «активным» обработчиком ошибок является включенный обработчик ошибок, который обрабатывает текущую ошибку. Если ошибка возникает в самом обработчике ошибок (в промежутке между возникновением ошибки и выполнением инструкции Resume, Exit Sub, Exit Function или Exit Property), то обработчик ошибок, определенный в текущей процедуре, не может обработать ошибку. Управление в этом случае возвращается в вызывающую процедуру; если в вызывающей процедуре включен обработчик ошибок, то обработка ошибки передается ему. Если этот обработчик ошибок является в данный момент активным, т.е. уже обрабатывает ошибку, то управление снова передается назад в вызывающую процедуру и т.д. до тех пор, пока не будет найден включенный, но не активный обработчик ошибок. Если включенный, но неактивный обработчик ошибок найден не будет, ошибка становится фатальной в том месте программы, в котором она впервые возникла. При каждой передаче управления обработчиком ошибок в вызывающую процедуру эта процедура становится текущей. После завершения обработки ошибки обработчиком в любой процедуре возобновляется выполнение текущей процедуры с той ее части, которая указана в инструкции Resume.
Подпрограмма обработки ошибок не может быть процедурой Sub или Function. Эта подпрограмма должна быть частью программы, которая отмечается с помощью метки строки или номера строки.
Для определения причины ошибки в подпрограммах обработки ошибок используют значение свойства Number объекта Err. Необходимо обеспечить в подпрограммах обработки ошибок проверку или сохранение существенных значений свойств объекта Err перед тем, как может возникнуть новая ошибка или перед вызовом процедуры, в которой может возникнуть новая ошибка. Значения свойств объекта Err описывают последнюю ошибку. Текст сообщения об ошибке, соответствующего коду ошибки Err.Number содержится в свойстве Err.Description.
Конструкция On Error Resume Next задает продолжение выполнения с инструкции, непосредственно следующей за инструкцией, которая привела к ошибке выполнения, или с инструкции, непосредственно следующей за вызывающей инструкцией в процедуре, содержащей конструкцию On Error Resume Next. Это позволяет продолжить исполнение программы несмотря на ошибку выполнения. Это позволяет также встроить подпрограмму обработки ошибок в процедуру, а не передавать управление в другую часть процедуры. Конструкция On Error Resume Next становится неактивной при вызове новой процедуры, поэтому для внутренней обработки ошибок необходимо выполнять инструкцию On Error Resume Next в каждой вызываемой процедуре.
При обработке ошибок, возникающих при доступе к другим объектам, рекомендуется использовать конструкцию On Error Resume Next, а не конструкцию On Error GoTo. Проверка объекта Err после каждого взаимодействия с другим объектом позволяет устранить неопределенность в том, при доступе к какому объекту возникла ошибка. Это позволяет всегда точно знать, какой объект поместил значение кода ошибки в свойство Err.Number, а также в каком объекте возникла ошибка (эта информация содержится в свойстве Err.Source).
Конструкция On Error GoTo 0 отключает обработку ошибок в текущей процедуре. Эта конструкция не задает переход на строку 0 для обработки ошибок, даже если в процедуре имеется строка с номером 0. Если инструкция On Error GoTo 0 не выполнялась, то обработчик автоматически отключается при выходе из процедуры.
Для того, чтобы предотвратить выполнение программы обработки ошибок в тех случаях, когда ошибка не возникла, следует помещать соответствующую инструкцию Exit Sub, Exit Function или Exit Property сразу после подпрограммы обработки ошибки, как в следующем примере:
Sub InitializeMatrix(Var1, Var2, Var3, Var4) On Error GoTo ОбработкаОшибок . . . Exit Sub ОбработкаОшибок: . . . Resume Next End Sub
В этом примере программа обработки ошибок помещена между инструкциями Exit Sub и End Sub, что позволяет отделить ее от части программы, соответствующей нормальному выполнению процедуры. Программу обработки ошибок можно разместить в любом месте процедуры.
Ошибки, которые не были перехвачены, возвращаются в управляющее приложение, если объект был запущен как исполняемый файл. В среде разработчика такие ошибки возвращаются в управляющее приложение только при указании соответствующих параметров. За описанием необходимых значений этих параметров и способов их задания следует обращаться к документации главного приложения. Там же следует проверить, позволяет ли главное приложение создавать классы.
Err.Number = vbObjectError + 1052
Системные ошибки при вызовах библиотек динамической компоновки (DLL) не приводят к возникновению исключений и не перехватываются средствами Visual Basic. При вызове функций из библиотек DLL необходимо проверять, успешно ли возвращается каждое значение (согласно спецификациям API), и в случае неудачи проверять значение свойства LastDLLError объекта Err.
Пример
В начале этой программы инструкция On Error GoTo определяет положение подпрограммы обработки ошибок в процедуре. В данном примере попытка удалить открытый файл приводит к возникновению ошибки с кодом 55. Ошибка обрабатывается в подпрограмме, после чего управление возвращается инструкции, которая привела к возникновению ошибки. Инструкция On Error GoTo 0 отключает перехват ошибок. После этого инструкция On Error Resume Next задает отложенный перехват ошибок, что позволяет точно определить, в каком контексте возникла ошибка, генерируемая в следующей инструкции. Следует отметить, что после обработки ошибки вызывается метод Err.Clear для сброса значений свойств объекта Err.
Sub OnErrorStatementDemo()
On Error GoTo ErrorHandler ' Включаем программу обработки
' ошибок.
Open "TESTFILE" For Output As #1 ' Открываем файл.
Kill "TESTFILE" ' Попытка удалить открытый
' файл.
On Error Goto 0 ' Отключаем перехват ошибок.
On Error Resume Next ' Откладываем перехват ошибок.
ObjectRef = GetObject("MyWord.Basic") ' Запускаем несуществующий
' объект, а затем проверяем
' ошибку механизма управления
' программируемыми объектами.
If Err.Number = 440 Or Err.Number = 432 Then
' Выводим сообщение для пользователя и очищаем объект Err.
Msg = "Ошибка при попытке открыть программируемый объект!"
MsgBox Msg, , "Проверка отложенной ошибки"
Err.Clear ' Очищаем поля объекта Err.
End If
Exit Sub ' Выходим из процедуры, чтобы
' не попасть в обработчик.
ErrorHandler: ' Обработчик ошибок.
Select Case Err.Number ' Определяем код ошибки.
Case 55 ' "Ошибка "Файл уже открыт".
Close #1 ' Закрываем открытый файл.
Case Else
' Здесь размещаются инструкции для обработки других ошибок...
End Select
Resume ' Возобновляем выполнение
' со строки, вызвавшей ошибку.
End Sub
I have a simple excel function that connects to a db and retrieves some data and populates a worksheet. The function calls another function to make the db connection and return the query results. How do I exit the calling function if there is an error connecting to the database? This is what my function looks like that connects to the DB. If there is an error connecting to the DB, the messagebox is displayed but then processing resumes in the calling function and then I get an ugly «END or DEBUG» message box…which I am trying to avoid.
Public Function QueryDB(sQuery As String)
On Error GoTo ErrorHandler
... Connect to database and get data
ErrorHandler:
... Display a messagebox telling the user there is an error
'Resume Next
Exit Function
End Function
asked May 8, 2014 at 19:05
3
Public Function QueryDB(sQuery As String)
On Error GoTo ErrorHandler
'... Connect to database and get data
' Exit function before the error handler so
' it doesn't get processed every run
Exit Function
ErrorHandler:
' ... Display a messagebox telling the user there is an error
MsgBox "Oops! An error occurred."
End Function
You may want to handle your errors in the calling sub though since errors «bubble up» to the caller. This will cause your macro to debug even though you have an error handler in QueryDB.
Here is an example of how you can handle errors in called functions
Sub Main()
On Error GoTo DBERROR
QueryDB ("Query String")
On Error GoTo 0
Exit Sub
DBERROR:
MsgBox "Oops! Error " & Err.Number & " occurred in " & Err.Source & ".", _
Title:="Error " & Err.Number
End Sub
Public Function QueryDB(sQuery As String)
Err.Raise 5000, "QueryDB", "Error connecting to DB"
End Function
answered May 8, 2014 at 19:16
RipsterRipster
3,5352 gold badges18 silver badges28 bronze badges
It can be done using Global level variable as below:
Public dbError as Integer
Function ConnectToDb as Integer
On Error GoTo err_Connection
'Asume connection to DB failure
err_Connection:
MsgBox "Connection failed to database !! ", vbOKOnly + vbExclamation
dbError = -500 'Any number
Exit Function
End Function
Sub MainSub
'Call function
ConnectToDb
If dbError = -500 Then
Exit Sub
End If
End Sub
answered Nov 28, 2016 at 13:22
Use «exit sub» command wherever necessary. as you did n’t shared your subroutine/function, I cannot point out where it needs to be given. add «exit sub» according to your logic.
Regards,
Dominic
answered May 8, 2014 at 19:15
Обработка ошибок
Если вы когда-нибудь учились водить автомобиль, то наверняка вспомните, что при первой посадке на водительское сиденье все внимание было приковано к трем деталям: рулю, педалям и рычагу переключения передач. Происходящее вне автомобиля уходило на второй план, так как вначале нужно было стронуться с места. По мере практики навыки вождения улучшались и эти три детали постепенно уходили на задний план. Как ни странно, но руль и рычаг переключения передач всегда оказывались там, куда вы не смотря протягивали руки, а ноги сами находили педали. Теперь все внимание стало занимать происходящее на дороге. Иными словами, вы стали опытным водителем.
В программировании все абсолютно также. Начинающие программисты больше обращают внимание на первые попавшиеся на глаза операторы, функции и другие элементы языка, а сам алгоритм уходит на задний план. Если программа скомпилировалась без ошибок, то это уже большое счастье, хотя это еще не означает, что программа работает правильно. По мере практики мышление программиста меняется, он начинает обращать внимание на мелочи, на форматирование программы, использует более эффективные алгоритмы и в результате всего этого допускает меньше ошибок. Подводя итоги, можно сказать, что начинающий программист просто пишет программу, а опытный программист пытается найти оптимальный алгоритм и предусмотреть поведение программы в различных ситациях. Однако, от ошибок никто не застрахован, поэтому очень важно знать как быстро найти ошибку.
Типы ошибок
Существуют три типа ошибок в программе:
- синтаксические — это ошибки в имени оператора или подпрограммы, отсутствие закрывающей или открывающей кавычек и т. д., то есть ошибки в синтаксисе языка. Как правило, компилятор предупредит о наличии ошибки, а программа не будет выполняться совсем;
- логические — это ошибки в логике работы программы, которые можно выявить только по результатам работы программы. Как правило, компилятор не предупреждает о наличии ошибки, а программа будет выполняться, так как не содержит синтаксических ошибок. Такие ошибки достаточно трудно выявить;
- ошибки времени выполнения — это ошибки, которые возникают во время работы программы. В одних случаях ошибки времени выполнения являются следствием логических ошибок, а в других случаях причиной являются внешние события, например, нехватка оперативной памяти, отсутствие прав для записи в файл и др.
Инструкция On Error
Ошибки времени выполнения можно перехватывать внутри подпрограммы. Для этого используется инструкция On Error, которая имеет три формата:
On Error GoTo <Метка>— при возникновении ошибки управление передается инструкции, помеченной меткой<Метка>. Метка должна быть допустимым идентификатором, к которому предъявляются такие же требования как и к переменным. Внутри подпрограммы метка указывается в самом начале помечаемой строки и после метки ставится двоеточие. В качестве примера создадим функцию для деления двух целых чисел. Внутри функции предусмотрим обработку ошибки деления на0:
Function Деление(x As Integer, y As Integer) As Double
On Error GoTo ПриОшибке
Деление = x / y
Exit Function
ПриОшибке:
Деление = 0
End Function
Если при вызове функции во втором параметре передать значение 0, то управление будет передано в строку, помеченную с помощью метки ПриОшибке. Обратите внимание на то, что метка расположена после инструкции Exit Function. В этом случае код после инструкции Exit Function будет выполнен только в том случае, если возникнет ошибка;
On Error Resume Next— при возникновении ошибки управление передается следующей инструкции;On Error GoTo 0— отключает перехват ошибок.
Если внутри подпрограммы не предусмотрен перехват ошибки, то при возникновении ошибки работа программы прерывается и выводится стандартное окно с описанием и несколькими кнопками: Continue (продолжить), End (завершить выполнение программы), Debug (перейти в режим отладки) и Help (вывод справки).
Инструкция Resume
Инструкция Resume позволяет указать куда следует переходить после обработки ошибки. Инструкция имеет несколько форматов:
Resume [0]— управление передается инструкции, вызвавшей ошибку;Resume Next— управление передается инструкции, следующей за инструкцией, вызвавшей ошибку;Resume <Метка>— управление передается инструкции, помеченной меткой<Метка>.
Если инструкция Resume не указана, то выполняется только код внутри обработчика ошибки и производится выход из подпрограммы.
Получение информации об ошибке и генерация ошибки
Вся информация о последней ошибке доступна через объект Err. Объект содержит следующие свойства:
Number— код ошибки, например, код11для ошибки деления на0. Если ошибки не произошло, то свойство содержит значение0;Description— описание ошибки, например, строка"Division by zero"для ошибки деления на0. Пример вывода кода и описания ошибки:
Debug.Print Err.Number; Err.Description
Source— название текущего проекта;HelpFile— путь к файлу справки;HelpContext— идентификатор раздела в справочном файле;LastDLLError— системный код ошибки при работе с DLL.
Объект Err содержит следующие методы:
Clear()— очищает всю информацию о последней ошибке. Этот метод следует вызвать после успешной обработки ошибки. Информация об ошибке автоматически очищается при выходе из подпрограммы и ряде других случаев;Raise()— позволяет сгенерировать ошибку в программе. Формат метода:
Raise Number[, Source][, Description][, HelpFile][, HelpContext]
В параметре Number указывается код генерируемой ошибки (целое число от 0 до 65 535). Коды от 0 до 512 зарезервированы под системные ошибки, а остальные коды можно использовать под пользовательские ошибки. Чтобы сгенерировать ошибку с пользовательским кодом необходимо сложить код с константой vbObjectError. Остальные параметры являются необязательными и полностью аналогичны одноименным свойствам объекта Err. Пример генерации и обработки пользовательской ошибки:
Sub ГенерацияОшибки()
On Error GoTo ПриОшибке
Err.Raise vbObjectError + 513
Exit Sub
ПриОшибке:
Debug.Print Err.Number; Err.Description
' -2147220991 Automation error
End Sub
Способы поиска ошибок в программе
В предыдущих разделах мы научились обрабатывать ошибки времени выполнения. Однако, наибольшее количество времени программист затрачивает на другой тип ошибок — логические ошибки. В этом случае программа компилируется без ошибок, но результат выполнения программы не соответствует ожидаемому результату. Ситуация еще более осложняется, когда неверный результат проявляется лишь периодически, а не постоянно. Инсценировать такую же ситуацию, чтобы получить этот же неверный результат, бывает крайне сложно и занимает очень много времени. В этом разделе мы рассмотрим лишь «дедовские» (но по прежнему актуальные) способы поиска ошибок, а современные способы отладки приложений, доступные в VBA, изучим в следующем разделе.
Первое, на что следует обратить внимание, — на объявления переменных. Например, рассмотрим простой пример:
Как вы думаете, какое значение отобразится в окне Immediate после выполнения этого кода? Думаете, что число 10? Не факт! Вот тут-то и кроется проблема не видная на первый взгляд. В первой инструкции присваивается значение переменной x, имя которой набрано на английской раскладке клавиатуры, а вот во второй инструкции выводится значение переменной x, имя которой набрано на русской раскладке клавиатуры. В результате значение присваивается одной переменной, а выводится значение другой переменной. Такие ситуации очень часто встречаются в программах на языке VBA, так как объявлять переменную не обязательно. Чтобы избежать такой ситуации следует обязательно объявлять переменные явным образом. Контроль за соблюдением этого правила можно возложить на компилятор, добавив в начале модуля следующую инструкцию:
При наличии инструкции компилятор производит проверку объявления всех переменных. Если переменная не была объявлена явным образом, то компилятор выведет сообщение об ошибке и выполнение программы будет остановлено. Таким образом, код должен выглядеть следующим образом:
Option Explicit
...
Dim x As Integer
x = 10
Debug.Print x ' 10
Далее следует обратить внимание на форматирование кода. Начинающие программисты обычно не обращают на это никакого внимания, считая этот процесс лишним. А на самом деле зря! Компилятору абсолютно все равно, разместите вы все инструкции на одной строке или выполните форматирование кода. Однако, при поиске ошибок форматирование кода позволит найти ошибку гораздо быстрее.
Перед всеми инструкциями внутри блока должно быть расположено одинаковое количество пробелов. Обычно используют три или четыре пробела. От применения символов табуляции лучше отказаться. Если все же используете, то не следует в одном файле совмещать и пробелы и табуляцию. Для вложенных блоков количество пробелов умножают на уровень вложенности. Если для блока первого уровня вложенности использовалось три пробела, то для блока второго уровня вложенности должно использоваться шесть пробелов, для третьего уровня — девять пробелов и т. д. Пример форматирования вложенных блоков приведен в листинге 11.1.
Dim Массив As Variant, i As Integer, j As Integer
Массив = Array(Array(0, 1), Array(2, 3), Array(4, 5))
For i = 0 To 2
For j = 0 To 1
Debug.Print Массив(i)(j)
Next
Next
Длина одной строки не должна содержать более 80 символов. Если количество символов больше, то следует выполнить переход на новую строку. При этом продолжение смещается относительно основной инструкции на величину отступа или выравнивается по какому-либо элементу. Иначе приходится пользоваться горизонтальной полосой прокрутки, а это очень неудобно при поиске ошибок.
Если программа слишком большая, то следует задуматься о разделении программы на отдельные подпрограммы или классы, которые выполняют логически законченные действия. Помните, что отлаживать отдельную подпрограмму гораздо легче, чем «спагетти»-код. Причем прежде чем вставить подпрограмму (или класс) в основную программу ее следует протестировать в отдельном проекте, передавая подпрограмме различные значения и проверяя результат ее выполнения.
Обратите внимание на то, что форматирование кода должно выполняться при написании кода, а не во время поиска ошибок. Этим вы сократите время поиска ошибки и скорее всего заметите ошибку еще на этапе написания. Если все же ошибка возникла, то вначале следует инсценировать ситуацию, при которой ошибка проявляется. После этого можно начать поиск ошибки.
Причиной периодических ошибок чаще всего являются внешние данные. Например, если числа получаются от пользователя, а затем производится деление чисел, то вполне возможна ситуация, при которой пользователь введет число 0. Деление на ноль приведет к ошибке. Следовательно, все данные, которые поступают от пользователей, должны проверяться на соответствие допустимым значениям. Если данные не соответствуют, то нужно вывести сообщение об ошибке, а затем повторно запросить новое число или прервать выполнение всей программы. Кроме того, нужно обработать возможность того, что пользователь может ввести вовсе не число, а строку.
Метод Print() объекта Debug удобно использовать для вывода промежуточных значений. В этом случае значения переменных вначале выводятся в самом начале программы и производится проверка соответствия значений. Если значения соответствуют, то инструкция с методом Print() перемещается на следующую строку программы и опять производится проверка и т. д. Если значения не совпали, то ошибка возникает в инструкции, расположенной перед инструкцией с методом Print(). Если это пользовательская подпрограмма, то проверку значений производят внутри подпрограммы, каждый раз перемещая инструкцию с выводом значений. На одном из этих многочисленных этапов ошибка обычно обнаруживается. В больших программах можно логически догадаться о примерном расположении инструкции с ошибкой и начать поиск ошибки оттуда, а не с самого начала программы.
Инструкции для вывода промежуточных значений можно расставить уже при написании программы, не дожидаясь возникновения ошибки. В этом случае в начале программы объявляется константа с помощью инструкции #Const, а внутри программы производится проверка значения константы:
Проверить значение константы позволяет следующая конструкция:
#If MY_DEBUG Then
' Здесь размещаем инструкции вывода значений
#End If
Таким образом, меняя значение константы MY_DEBUG с 1 на 0, можно отлючать вывод всех промежуточных значений.
Сделать поиск ошибок более эффективным позволяет отладчик, встроенный в редактор VBA. С его помощью можно выполнять программу по шагам, при этом контролируя значения переменных на каждом шагу. Отладчик позволяет также проверить, соответствует ли порядок выполнения инструкций разработанному ранее алгоритму.
Прежде чем начать отладку необходимо пометить строки внутри программы с помощью точек останова. Для добавления точки останова делаем строку активной, а затем из меню Debug выбираем пункт Toggle Breakpoint. Слева от строки появится кружок, обозначающий точку останова. Добавить точку останова можно еще быстрее. Для этого достаточно щелкнуть слева от строки левой кнопкой мыши. Повторный щелчок позволяет удалить точку останова. Кроме того, для добавления или удаления точки отстанова можно воспользоваться клавишей <F9>. Чтобы удалить все точки останова следует из меню View выбрать пункт Clear All Breakpoints.
Когда точки останова расставлены можно начать отладку. Для этого запускаем программу на выполнение обычным способом. При достижении точки останова выполнение программы прерывается и отладчик ожидает дальнейших действий программиста. Инструкция, которая будет выполняться на следующем шаге, помечается желтой стрелкой слева от строки.
В режиме прерывания можно посмотреть значения различных переменных в окне Locals. Если окно не отображается, то отобразить его можно выбрав в меню View пункт Locals Window. Посмотреть значение переменной можно также если навести указатель мыши на переменную. Значение переменной отобразится во всплывающей подсказке.
При отладке можно контролировать значения отдельных переменных, а не всех сразу. Для этого следует выделить название переменной и из меню Debug выбрать пункт Add Watch. Можно также выделить название переменной и из контектного меню выбрать пункт Add Watch. В открывшемся окне устанавливаем флажок Watch Expression и нажимаем кнопку OK. Значение переменной будет отображаться в окне Watches. Чтобы отобразить окно Watches из меню View выбираем пункт Watch Window. Чтобы отменить отслеживание нужно выделить строку в окне Watches и нажать клавишу <Delete>.
Для пошагового выполнения программы предназначены следующие пункты в меню Debug или соответствующие кнопки на панели инструментов Debug (View | Toolbars | Debug):
- Step Into (клавиша <F8>) — выполняет переход к следующей инструкции;
- Step Over — выполняет одну инструкцию. Если в этой инструкции производится вызов подпрограммы, то подпрограмма выполняется за один шаг и отладчик переходит в режим ожидания после выхода из подпрограммы;
- Step Out — при заходе в подпрограмму этот пункт позволяет выполнить подпрограмму за один шаг и выйти из нее. Отладчик переходит в режим прерывания после выхода из подпрограммы;
- Run To Cursor — выполняет переход к инструкции, в которой расположен курсор.
Если необходимо посмотреть последовательность вызова подпрограмм, то следует открыть окно Call Stack, выбрав в меню View пункт Call Stack.
Подача звукового сигнала
При возникновении ошибки или при неправильном вводе данных имеет смысл привлечь внимание пользователя звуковым сигналом. Сгенерировать звуковой сигнал позволяет инструкция Beep. Пример:
Dim Результат
Beep
Результат = InputBox("Необходимо ввести значение")
Статьи по Visual Basic for Applications (VBA)
Excel VBA Errors & Error Handling, On Error & Resume Satements, Exit Statement, Err Object
————————————————————————————————-
Contents:
VBA Erros & Error Handling
Error Handling Setting, in VBE
Error Handler
On Error Statements
Using an Exit Statement
Error Handling in Nested Procedures & The Resume Statement
Get Information from the Error Object
Raise Method of the Err Object: Generate a Run-time error
————————————————————————————————-
Error Handling determines what is to be done next on the occurrence of an error. On encountering a run-time error, an On Error statement enables or disables an error-handling routine within a procedure. A Resume statement can only be used in an error-handling routine — it resumes execution at a sepcified point after the error-handline routine finishes. You can get information on the error from the properties of the Error object — this object is the Err Object. In this section, we cover:
VBA Erros & Error Handling
In vba programming you can have Syntax Errors or Run-time Errors. An error handler determines what action is to be taken within a procedure, on the occurrence of a run-time error.
A syntax error occurs when you enter a line of code which is not allowed or recognized by Visual Basic. You will encounter a syntax error on misspelling a keyword or a named argument, for incorrect punctuation (ex. not specifying a comma as a placeholder for the omitted argument), use an undefined procedure, and so on. These errors are easier to locate as the Code Editor points them out at the time you are writing your code.
A run-time error occurs at the time during which your code is running, that is after you have created your macro. There could be an error in your programming due to incorrect logic used in your code that prevents it from doing what you intended and may stop code execution, for example, if your code attempts to divide a value by zero. Another reason for an error which may cause even a valid code to crash could be a condition not being met, say, a reference to a worksheet in your code which has been deleted by the user. Other examples when a run-time error can occur are: on using incorrect variable names or variable types; if your code goes into an infinite loop; using a value or reference outside the allowable range; and so on. If you dont implement error handling in your macro, on encountering a run-time error your code will stop execution and go into Break Mode and display an error message, thereby confusing and frustrating the user.
Using Error Handling in VBA is an important tool for developers to trap & handle run-time errors in a vba procedure for seamless execution. It is important to set error handling in every procedure else your macro might just crash or stop executing on encountering a run-time error and vba will display a default error message and go into Break Mode allowing the user to debug your code.
Basic Error Handling hides the fault in the macro when it crashes and exits gracefully, and informs the users accordingly. Advanced Error Handling techniques involve saving information on the error cause and the point of the error, and attempt to resolve the error and provide information to the user on the next step.
Error Handling determines what is to be done next on the occurrence of an error. At a basic level, Error Handling involves two parts — (i) enables an error-handling routine with an On Error Statement on encountering an error, and (ii) an error-handling routine which is the section where the procedure flow is directed to on encountering an error. It is to be noted that an error-handling routine is not a procedure (Sub or Function) but a section of code marked by a line label or a line number. An On Error statement enables or disables an error-handling routine within a procedure.
Error Handling Setting, in VBE
You can determine how errors are handled in VBE, by selecting the appropriate option. In VBE, click Options on the Tools Menu, select the General tab in the dialog box. In the Error Trapping Section, you can select from 3 options.
Break on All Errors: Selecting this will stop your code execution and enter Break Mode on every error, even if you are using an error handler (including the On Error Resume Next statement), hence it is not advised to select this option.
Break on Unhandled Errors: This works well in that an error is trapped when an error handler is active else the error causes the macro to go into Break Mode, except for debugging class modules wherein on encountering an error the debugger stops on the line which calls the class and not on the actual error line in the class, thus making it difficult to spot the error and fixing it.
Break in Class Module: Selecting this option will cause an unhandled error in a class module to stop code execution and go into Break Mode at the actual error causing line of code in that class module, but does not work if you use raise errors in your classes via the Err.Raise command which will actually cause an “error”.
Error Handler
An error handler determines what action is to be taken within a procedure, on the occurrence of an error. An ‘enabled’ error handler is the one which is enabled by the On Error Statement; an ‘active’ error handler is the ‘enabled’ error handler which is in the process of handling an error. On encountering an error you may decide to exit the procedure, or else you may want to rectify the error and resume execution. For this you will use On Error statements or Resume statements. A Resume statement can only be used in an error-handling routine — it resumes execution after the error-handline routine finishes.
On Error Statements
On encountering a run-time error, an On Error statement enables or disables an error-handling routine within a procedure. If an error-handling routine is enabled, procedure flow is directed to the error-handling routine which handles the error.
On Error GoTo line
The On Error GoTo line Statement enables the error-handling routine, which is the section starting at the line specified in the line argument. The line argument is required to be specified, and it can be any line label or line number in the same procedure as the On Error statement. A compile-time error will occur if the specified line argument is not in the same procedure as as the On Error statement. The On Error GoTo statement traps all errors, without exceptions.
On Error Resume Next
This Statement specifies that on the occurrence of a run-time error, the procedure flow is directed to the next statement which follows the statement where the error occurred. This effectively skips the error and continues with the macro execution.
An On Error Resume Next statement becomes inactive on calling another procedure is called, hence it needs to be specified in every procedure that is called to use this error handling therein. Note that the properties of the Error object (Err Object) get cleared automatically when Resume Next is used in an error-handling routine, but not on using the Resume Next statement otherwise. Using the On Error Resume Next statement only defers error trapping & handling, whereas an error-handling routine handles the error and using the Resume Next statement therein resumes execution at same line that caused the error.
On Error GoTo 0
On Error GoTo 0 statement Disables any enabled error handler in the current procedure — it means as having no error handler in the code. This statement does not specify 0 as the start of the error-handling routine even though a line numbered 0 may be present in the procedure. An error handler is automatically disabled when a procedure is exited or if it has has run completely, if the procedure does not have an On Error GoTo 0 statement.
Using an Exit Statement
Placing an Exit Sub, Exit Function or Exit Property statement
For a procedure containing an error-handling routine, you will also need to include an exit routine within the procedure to ensure that the error-handling routine runs only if an error is encountered. This can be done by placing an Exit Sub, Exit Function or Exit Property statement immediately above the error-handling routine, if you don’t want it to execute when there is no error.
Single Exit Point
It may be preferable, not necessary, to have a single exit point in your procedure, so that after the Error Handler has handled the error, the procedure flow is directed to a point within the procedure so that the procedure exit is the same under all circumstances. This can be done by placing a Resume statement — Resume <Label> — the Label determines the point at which procedure flow is resumed after the Error Handler has handled the error. This Label has no effect on code execution if no error has occurred. It is preferable to have a single exit point because usually some type of clean up is required before the procedure exits, ex. you often enter Application.EnableEvents = False at the beginning of the code for a worksheet_change event and because EnableEvents is not automatically changed back to True you add Application.EnableEvents = True at the end of the code before exit. A single exit point will obviate the need to duplicate this clean up code in the error-handling routine.
Error Handling in Nested Procedures & The Resume Statement
Using a Resume Statement
A Resume statement can only be used in an error-handling routine — it resumes execution at a sepcified point after the error-handline routine finishes. You can aslo exit or end the procedure after the error-handling routine finishes and not necessarily use the Resume statement. We discuss below three types of syntax used for the Resume statement, and how the control transfers (ie. code execution resumes) by these Resume statements. You should always use a Resume statement instead of a GoTo statement within an error-handling routine, because using a «GoTo line» statement apparantly deactivates subsequent Error Handling — even though both Resume & GoTo statements direct procedure flow out of the error-handling routine.
Resume or Resume 0: Where the error occurrs in the same procedure as the error handler, control is returned to the statement that caused the error and execution resumes at this line. Where the error occurrs in a called procedure, control is returned to the last calling statement in the procedure containing the error handler.
Resume Next: Where the error occurrs in the same procedure as the error handler, control is returned to the next statement which follows the statement that caused the error and execution resumes at this line. Where the error occurrs in a called procedure, control is returned to the next statement which follows the last calling statement in the procedure containing the error handler.
Resume line: When an error occurrs in a procedure, control transfers to the line specified in the line argument. The line argument is a line label or line number and should be in the same procedure as the error handler.
Which Resume Statement to use:
The Resume or Resume 0 statement is used when it is necessary for the macro to correct the error and re-execute the corrected code — say when the user enters an invalid value and you want to prompt the user to enter a valid value and resume at the same line and re-excecute. The Resume Next statement is used when the error handler corrects the error and it is not required to re-execute the error code but to continue execution at the next line. The Resume line statement is used when you want to continue execution at another point in the procedure, which could also be an exit routine.
Given below are 2 Examples which illustrate using On Error Statements & Error Handler in a Procedure
Example 1:
Sub OnErrorResNxtSt()
‘using an On Error Resume Next Statement in a procedure for handling errors
‘a run-time error 1004 occurs while naming another sheet with the same name
‘execution flows to the next statement which follows the statement that caused the error
On Error Resume Next
Dim strNewName As String, ws As Worksheet, response As Integer
‘add a new worksheet at the end
ActiveWorkbook.Worksheets.Add After:=Worksheets(Sheets.Count)
WsName:
‘enter name for worksheet
strNewName = InputBox(«Enter Worksheet Name»)
‘StrPtr — String Pointer — function used to determine if Cancel button has been pressed.
If StrPtr(strNewName) = 0 Then
MsgBox «You have pressed Cancel, Exiting Procedure without changing Worksheet Name»
Exit Sub
End If
‘rename the new worksheet — if name already exists, a run-time error 1004 will occur
ActiveSheet.Name = strNewName
‘Check Err object Number property if it corresponds to the error no. 1004.
‘Error No. 1004 occurs if worksheet with the same name already exists
If Err = 1004 Then
response = MsgBox(«Name already Exists, do you want to retry?», vbYesNo + vbQuestion)
If response = vbYes Then
‘clear error
Err.Clear
‘if worksheet name already exists, enter a new name
GoTo WsName
Else
MsgBox «Exiting Procedure without changing Worksheet Name»
Exit Sub
End If
End If
‘returns 0 — either no error occurred or error was cleared
MsgBox Err.Number
End Sub
Example 2:
Sub OnErrorGoToSt()
‘using an On Error GoTo Statement in a procedure for handling errors, and a Resume statement within an error-handling routine
‘a run-time error 1004 occurs while naming another sheet with the same name
On Error GoTo ErrHandler
Dim strNewName As String, ws As Worksheet
‘add a new worksheet at the end
ActiveWorkbook.Worksheets.Add After:=Worksheets(Sheets.Count)
WsName:
‘enter name for worksheet
strNewName = InputBox(«Enter Worksheet Name«)
‘StrPtr — String Pointer — function used to determine if Cancel button has been pressed.
If StrPtr(strNewName) = 0 Then
MsgBox «You have pressed Cancel, Exiting Procedure»
GoTo exit_proc
End If
‘rename the new worksheet — if name already exists, a run-time error 1004 will occur
ActiveSheet.Name = strNewName
‘returns 0 — either no error occurred or error was cleared (using Resume statement in an error-handling routine, automatically clears the error)
MsgBox Err.Number
‘exit routine to skip error handler
exit_proc:
Exit Sub
ErrHandler:
‘Error No. 1004 occurs in this case if worksheet with the same name already exists
If Err = 1004 Then
MsgBox «Name already exists»
‘resumes execution at this point (WsName)
Resume WsName
Else
‘resumes execution at exit routine and exits sub
Resume exit_proc
End If
End Sub
Error Handling in a Called Procedure
If the called procedure in which an error has occurred does not have an error handler, VBA searches backward in the calling procedures for an enabled error handler, and if found the control is transferred to that error handler in the calling procedure. If an enabled error handler is not found in the backward search, then execution will stop in the current procedure displaying an error message.
Example 3: Error in Nested Procedures — in the absence of an error handler in the called procedure in which an error has occurred, VBA searches backward in the calling procedures and control is transferred to an enabled error handler, if present, in the calling procedure.
Sub CallMarksGrades()
‘this is the calling procedure, with an error handler and Resume statements — the error handler is capable of correcting Type Mismatch, Overflow & Division by Zero errors.
On Error GoTo ErrHandler
‘Declare constants to indicate likely errors
Dim iMarks As Integer, iTotalMarks As Integer, dPcnt As Double, response As Integer
Const conErrorTypeMismatch As Long = 13
Const conErrorDivZero As Long = 11
Const conErrorOverflow As Long = 6
M:
iMarks = InputBox(«Enter Marks«)
TM:
iTotalMarks = InputBox(«Enter Total Marks«)
‘call the MarksPercent function and the result is assgined to the local variable dPcnt
dPcnt = MarksPercent(iMarks, iTotalMarks)
MsgBox «Percentage is » & dPcnt & «%»
‘exit routine to skip error handler
exit_proc:
Exit Sub
ErrHandler:
MsgBox Err
‘Check Err object Number property if it corresponds to the Type Mismatch error
‘a Type Mismatch error will occur if you have entered a non-numerical or pressed Cancel in the Input Box
If Err = conErrorTypeMismatch Then
response = MsgBox(«You may have entered a non-numerical value or pressed Cancel, do you want to Exit procedure?», vbYesNo + vbQuestion)
If response = vbYes Then
Resume exit_proc
Else
‘after correcting the error, resume execution at the same line which caused the error ie. Input Box is re-generated for making a valid entry
Resume
End If
‘Check Err object Number property if it corresponds to the Overflow error (where values exceed limitations or allowable range)
ElseIf Err = conErrorOverflow Then
MsgBox «Overflow error — also possible if both Marks & Total Marks are zero»
‘after correcting an Overflow error, resume execution at the specified line ie. M, which generates the Input Boxes afresh
Resume M
‘Check Err object Number property if it corresponds to the Division by Zero error
ElseIf Err = conErrorDivZero Then
MsgBox «Division by Zero error — Total Marks cannot be zero»
‘after correcting a division by zero error, resume execution at the specified line ie. TM, which generates the Input Box for iTotalMarks
Resume TM
Else
‘control is returned to the next statement which follows the statement that caused the error
Resume Next
End If
End Sub
Function MarksPercent(Marks As Integer, TotalMarks As Integer) As Double
‘this is the called procedure — in case of an error in this procedure, say a division by zero run-time error no. 11, VBA searches backward in the calling procedures for an enabled error handler, and if found the control is transferred to that error handler in the calling procedure.
MarksPercent = Marks / TotalMarks * 100
MarksPercent = Round(MarksPercent, 2)
End Function
If an error occurs in a called procedure within an active error handler which does not correct for that error, using the Raise method to regenerate the original error will force Visual Basic to search backward through the calling procedures hierarchy for an enabled error handler. The Err object’s Raise method is useful to regenerate an original error in a vba procedure — refer the section on Error Object for details on the Raise Method. This is useful in cases where the called procedure’s error handler is not equipped to correct the error either because this type of error was not expected to occur in the called procedure or for any other reason. In this scenario the sequence will be that an error occurrs in a called procedure — the called procedure has an enabled error handler which does not correct the error, and the original error is regenerated using the Raise Method — Visual Basic is forced to do a backward search and execution flows to the error handler (if present) of the immediately preceding calling procedure, which may or may not correct the error — if the immediately preceding calling procedure does not have an error handler or its error handler is not capable of correcting the error and the error is regenerated then the backward search continues. If you do not regenerate the error in the called procedure whose enabled error handler is incapable of handling the error, the error may cause the macro to stop or continue with the error causing other errors.
Example 4: Error in Nested Procedures — for an error in a called procedure with an active error handler which does not correct for that error, on Regenerating the error with the Raise Method, VBA searches backward in the calling procedures and control is transferred to an enabled error handler, if present, in the calling procedure.
Sub Calling_Proc()
‘calling procedure — this handles any error, and corrects in case it is a File Not Found error no. 53
Const conFileNotFound As Integer = 53
On Error GoTo ErrHandler
‘call another procedure
Call Called_Proc
‘exit routine to skip error handler
exit_routine:
Exit Sub
‘error handling routine of the calling procedure
ErrHandler:
‘error is corrected if it is a File Not Found error no. 53
If Err = conFileNotFound Then
MsgBox «Error No 53 — File Not Found, will create a New File to Copy»
Dim strFileToCopy As String, strFileCopied As String
strFileToCopy = «Book11.xlsx«
strFileCopied = «Book22.xlsx«
‘create a new workbook:
Workbooks.Add
‘save as .xlsx file, the default Excel 2007 file format, using the FileFormat Enumeration xlOpenXMLWorkbook (value 51):
ActiveWorkbook.SaveAs fileName:=strFileToCopy, FileFormat:=xlOpenXMLWorkbook
‘close workbook after saving changes:
ActiveWorkbook.Close SaveChanges:=True
‘this will copy the file
FileCopy strFileToCopy, strFileCopied
MsgBox «File Created & Copied»
‘if error is other than a File Not Found error no. 53
Else
MsgBox «Unresolved Error, Exiting Procedure»
End If
‘resumes execution at exit routine and exits sub
Resume exit_routine
End Sub
Sub Called_Proc()
‘this is a called procedure with an error handler that will correct only a Path not found error no. 76
‘for any other error in this procedure, say if the file is not found in the path/directory, the Raise method is used to regenerate the original error and execution flows to an enabled error handler (if present) in the calling procedure
‘Declare constant to indicate anticipated error
Const conPathNotFound As Integer = 76
Dim strFilePath As String, intOrigErrNum As Integer
Dim strFileToCopy As String, strFileCopied As String
strFileToCopy = «Book11.xlsx«
strFileCopied = «Book22.xlsx«
On Error GoTo ErrHandler76
‘specify file path: PATH NOT FOUND ERROR OCCURS HERE
‘not finding the specified path will give a run-time error ’76’ — Path not found
strFilePath = «C:ExcelFiles«
ChDir strFilePath
‘OTHER ERROR OCCURS HERE
‘attempting to Copy a file which does not exist will give a run-time error ’53’ — File not found
FileCopy strFileToCopy, strFileCopied
MsgBox «File Copied»
‘exit routine to skip error handler
exit_proc:
Exit Sub
ErrHandler76:
‘Check Err object Number property if it corresponds to the Path not found error.
If Err = conPathNotFound Then
‘correcting the Path in the Error Handler
strFilePath = ThisWorkbook.Path
MsgBox «Correcting Error No 76 — Path changed to ThisWorkbook path»
‘after correcting the Path, resume execution at the same line which caused the error
Resume
Else
‘for an error other than error no. 76, determine error number.
intOrigErrNum = Err.Number
‘clear error
Err.Clear
MsgBox «Error is other than error no. 76 — will Search Backward in Calling Procedures for an Error Handler to correct this error»
‘Regenerate original error — this will search backward in the calling procedures for an Error Handler if its exists
Err.Raise intOrigErrNum
‘resumes execution at exit routine and exits sub — execution flows to an enabled error handler in the calling procedure if it exists
Resume exit_proc
End If
End Sub
Get Information from the Error Object
Err Object & Properties: On the occurrence of a run-time error, you can get information on the error from the properties of the Error object (this object is the Err Object), which will help you in managing the error and to determine what is to be done next. The Number Property (Err.Number) returns a numeric value specifying the error with a value of zero meaning no error — this is the error’s number. The Number Property is the default property of the Err object. The Description Property (Err.Description) returns a short description of the error but this may not exist at times — if no Visual Basic error corresponds to the Number property, the «Application-defined or object-defined error» message is used. The Description property returns a zero-length string («») if no run-time error has occurred or ErrorNumber is 0. The property settings of the Err object relate to the most recent run-time error, so it is important that your error-handling routine saves these values before the occurrence of another error.
Use the Clear Method (Err.Clear) to to explicitly clear all property settings of the Err object. Using an Exit Sub, Exit Function or Exit Property statement, or using Resume Next statement in an error-handling routine, automatically calls the Clear Method and resets the numeric properties (viz. Number property) of the Err object to zero and the string properties (viz. Description property) to zero-length strings («»). However, the properties of the Err object are not reset when you use any Resume statement outside of an error-handling routine. Err.Clear is used to clear the properties of the Err object properties after the error is handled — using the On Error Resume Next statement defers error handling, whereas an error-handling routine handles the error and using the Resume Next statement therein resumes execution at same line that caused the error. Note that setting the error number to zero (Err.Number = 0) is not the same as using the Clear method because this does not reset the description property.
Using the Source property (Err.Source) lets you know what generated the error — Source returns the name of the object or application that generated the error. Source contains the project name for an error in a standard module. Source is the programmatic ID of your application if an error is generated by your application from code. Source contains a name with the project.class form, for an error in a class module. Source can be specifically defined by the user while using the Raise Method to generate an error. This property may not be very useful in providing information on vba run-time erros as it basically returns the name of the project in which the error occurred.
For Error Handling within a procedure it is usual to programmatically use only the Number property of the Err object, while other properties of the Err object are useful to provide additional information to the user on the cause of the error. Many times in your code it may be preferable to use the On Error Resume Next statement over On Error GoTo statement, because by checking the Err object’s properties after each interaction with an object (line of code) you can determine which object or statement originally generated what error — refer Example 1.
Example 5: Illustrating some common run-time errors in vba, with their respective Error.Number & Error.Description
Sub RunTimeErrorsInVba()
‘Illustrating some common run-time errors in vba, with their respective Error.Number & Error.Description
‘Err.Source in all cases below is «VBAProject», except in 2 instances of Run-time error ‘1004’ wherein the Source is «Microsoft Office Excel»
‘Run-time error ’11’: Division by zero (dividing a number by zero will give this error)
MsgBox 2 / 0
‘Run-time error ‘9’: Subscript out of range (This error occurs if you attempt to access array elements & members of collections beyond their defined ranges. In this case Sheet does not exist — active Workbook contains only 3 sheets)
MsgBox Sheets(7).Name
‘Run-time error ‘1004’: Application-defined or object-defined error (invalid reference). Err.Source returns ‘VBAProject’
Cells(1, 1).Offset(-1, 0) = 5
‘Run-time error ‘1004’: Select method of Range class failed (Sheet1 is not the active sheet whereas Select Method is valid for active sheet only). Err.Source returns ‘Microsoft Office Excel’
Sheets(«Sheet1»).Cells(1, 1).Select
‘Run-time error ‘1004’: Cannot rename a sheet to the same name as another sheet, a referenced object library or a workbook referenced by Visual Basic (renaming the active sheet wherein sheet with the same name already exists).
Err.Source returns ‘Microsoft Office Excel’
ActiveSheet.Name = «Sheet1«
‘Run-time error ’76’: Path not found (the specified path is not found)
ChDir «C:ExcelClients»
‘Run-time error ’68’: Device unavailable (drive does not exist)
ChDrive «H»
‘run-time error ’53’ — File not found (copy or delete a file which does not exist viz. Book1.xlsx)
FileCopy ActiveWorkbook.Path & «» & «Book1.xlsx», ActiveWorkbook.Path & «» & «Book2.xlsx»
Kill ActiveWorkbook.Path & «» & «Book1.xlsx»
‘Run-time error ’91’: Object variable or With block variable not set (using an object variable that does not yet reference a valid object: an error is generated on the reference to ws because the Set statement is omitted viz. Set ws =
ActiveSheet)
Dim ws As Worksheet
ws = ActiveSheet
MsgBox ws.Name
‘Run-time error ‘424’: Object required (sheet name is not a valid object)
Dim ws As Worksheet
Set ws = ActiveSheet.Name
‘Run-time error ’13’: Type mismatch (variable is of incorrect type — reference is to a range object & not worksheet — variable should be declared as — Dim ws As Range)
Dim ws As Worksheet
Set ws = ActiveSheet.Cells(1, 1)
‘entering a string value in the input box below will give a Run-time error ’13’: Type mismatch
Dim result As Single
result = InputBox(«Enter a number»)
‘Run-time error ‘6’: Overflow (this error occurs if you attempt to assign values exceeding the assigned target’s limit — in the present case the value of i is larger than an integer because an integer can hold whole numbers in the range -32,768
to 32,767)
Dim i As Integer
i = 100 * 20000
MsgBox i
End Sub
Raise Method of the Err Object: Generate a Run-time error
Raise Method is used to generate a run-time error. You can raise either a pre-defined error using its corresponding error number, or generate a custom (user-defined) error. Though Raise can be used in place of the Error statement, but because errors generated by using the Error statement give richer information in the Err object, Raise is useful to generate run-time errors for system errors and class modules. Syntax: Err.Raise(Number, Source, Description, HelpFile, HelpContext). The Raise method generates a specific error and the Err object properties are populated with information on that error. Only the Number argument is necessary to specify in the Raise Method, and all other arguments are optional. If optional arguments are omitted and the Err object properties contain uncleared values, those values are assumed for your error values. The Err object’s Raise method is useful to regenerate an original error in a vba procedure — if an error occurs within an active error handler which does not correct for that error, using the Raise method to regenerate the original error will force Visual Basic to search backward through the calling procedures for an enabled error handler. This has been explained & illustrated in Example 4 above.
Arguments of Raise Method: The Number argument is the error’s number. The Source argument represents the source of the error. The Description argument describes the error providing additional information about it. The HelpFile and HelpContext arguments represent the help file and help context ID used to link help to the error message box.
Raise Custom Errors (user-defined errors) using the Err Object’s Raise Method:
You can deliberately generate custom (run-time) errors in vba code, using the Raise Method of the Err Object. You may want to generate a custom error when your code does something you don’t want, for example, to prevent a user from inputting data which may be outside an acceptable range, you can stop the macro by raising an error, complete with an error code and the source of occurrence. To enable this, use the Err object’s Raise method.
The arguments of the Raise Method correspond to the properties of the Err object, and all arguments except the Number argument are optional. While raising a custom error you can set your own custom arguments in the Raise Method. You can raise pre-defined errors using their respective error numbers, but for a custom error you cannot use an error number which is in conflict with any Office built-in error number. To set Err.Number for your custom error, add the number you select as an error code to the vbObjectError constant (-2147221504) to ensure your custom error number is not in conflict with any built-in error numbers, for ex. to return the number -2147220504 as an error code, assign vbObjectError + 1000 to the Err.Number property — Err.Raise vbObjectError + 1000. One option is to set the Source argument as the name of the procedure in which the error occurs.
Example 6: Raise a custom error using Raise Method of the Err object, if length of name is less than 4 characters
Sub RaiseCustomError_1()
‘raise a custom error using Raise Method of the Err object, if length of name is less than 4 characters
On Error GoTo CustomError_Err
Dim strName As String
strName = «Jo«
If Len(strName) < 4 Then
‘an error occurs if name length < 4 characters — raise a custom error
Err.Raise Number:=vbObjectError + 1000, Description:=»Minimum Length of Name is 4 characters«
Else
‘macro executes if no error
MsgBox «Name: » & strName
End If
‘if no error, display message is «Program Executed»
MsgBox «Program Executed»
CustomError_End:
Exit Sub
CustomError_Err:
‘Display error number and description in message box: «Error Number: -2147220504, Description: Minimum Length of Name is 4 characters»
MsgBox «Error Number: » & Err.Number & «, Description: » & Err.Description
‘display message is «Exit Program without Executing»
MsgBox «Exit Program without Executing»
‘resume execution at this point after error handler has handled an error
Resume CustomError_End
End Sub

