vba: passing a variable into error handles - vba

i have a statement:
on error go to label
however i would like to pass into the label the variable which caused the error
is this possible?

You can use Err to get the error No and Description
Sub|Function SomeName()
On Error GoTo Err_SomeName ' Initialize error handling.
' Code to do something here.
Exit_SomeName: ' Label to resume after error.
Exit Sub|Function ' Exit before error handler.
Err_SomeName: ' Label to jump to on error.
MsgBox Err.Number & Err.Description ' Place error handling here.
Resume Exit_SomeName ' Pick up again and quit.
End Sub|Function

First, I think you mean:
on error goto label
And no, you can't pass variables using a goto command. However, you can check the Err.Description for details, and if you are raising your own errors, you can do this:
' Raise a custom error.
Err.Raise Number:=vbObjectError + 1000, _
Source:="TestRaiseCustomError", _
Description:="My custom error description."
So if you are raising your own error, you could set Source to the field that caused the problem.
Refer to the Use the Err Object's Raise Method to Raise Custom Errors section at this link for more info.

I can't think of a clever way to do it. I normally have an error handeling class/function that way I can use "on error goto" to pass the error to the bottom block then call the error handeling function. The advantage of this is it's nice to have a centralised error handler but also you can customise it so in my case I pass the name of the procedure thats crashed. It's not pretty but you could if you really wanted to pass either a collection of variables (dependant on how many you have) or set up something to identify the variable based on the line number (which you'd have to add manauly...)
on error goto err
'Code
err:
ErrorHandeler err, "String with Procedure name"

Declare global variables and use them in the code and in your error code.
Public global_variable1 As Integer
Public global_variable2 As String
Private Sub Btn1234_Click()
....
end sub
Err_abcd:
....
End Sub

Related

Error "application-defined or object-defined"

I have a form contains two subforms (BuyList_Q subform) and (ProductStore_Q subform)
I use a button to transfer data from ProductStore to BuyList
Private Sub Command69_Click()
On Error GoTo Err_AddtoOrder_Click
Me.BuyList_Q_subform.Form.BL_PCode.Value = Me.ProductStore_Q_subform.Form.BuyCode.Value
Me.BuyList_Q_subform.Form.BL_PName.Value = Me.ProductStore_Q_subform.Form.P_Name.Value
Me.BuyList_Q_subform.Form.BL_PPrice.Value = Me.ProductStore_Q_subform.Form.P_Price(S).Value
Me.BuyList_Q_subform.Form.BL_PCount.Value = Me.CountNum_txt.Value
Exit_AddtoOrder_Click:
Exit Sub
Err_AddtoOrder_Click:
MsgBox Err.Description
Resume Exit_AddtoOrder_Click
End Sub
all of this working good but this line
Me.BuyList_Q_subform.Form.BL_PPrice.Value = Me.ProductStore_Q_subform.Form.P_Price(S).Value
get the error in the title !!
Could you help me to solve this issue?
Issue is with ( ) characters in object name. Advise not to use space nor punctuation/special characters (underscore is exception) in naming convention. If you do, then must enclose in [ ] characters to define name.
Also, not necessary to use .Value because this is default property for data input controls.
Me.BuyList_Q_subform.Form.BL_PPrice = Me.ProductStore_Q_subform.Form.[P_Price(S)]
Don't do this naming and preserve your sanity.

How to stop Excel Macro Which Still Runs After Application.Quit Method

I have found similar questions, but for other issues, seems that Excel is called from another application and process is left after Excel application closes.
In my case, I have a macro in my Excel file, and I try to close the application when an error occurs.
I have my error handling set this way:
'Code code code
CleanExit:
Logger.LogData LOG_DEBUG, MODULE_NAME, "Initialize", "Some module initialized!"
Exit Function
ErrorExit:
Logger.LogData LOG_ERROR, MODULE_NAME, "Initialize", "Error found! Description: " & err.description
Main.HandleError err, MODULE_NAME, "Initialize"
GoTo CleanExit
End function
I want my macro to stop running when error occurs in some module and not to stop if it's in another module (hence the GoTo CleanExit).
Error handler is set-up in this way:
Public Function HandleError(ByRef err As ErrObject, ByVal moduleOrgin As String, ByVal methodOrgin As String)
Dim wbk As Workbook
'Do something if module origin meets my parameters and exit function right here if my conditions are met
MsgBox "Some message to the user about the problem"
If GetSetting(SETTING_HIDE_APPLICATION, False) = True Then
For Each wbk In addinWorkbook.Application.Workbooks
wbk.Saved = True
Next wbk
addinWorkbook.Application.Quit
End If
End Function
After this code runs I assume that all further code running stops, as my Excel workbook, which hosts my macro code is closed with the application.
In reality I get a cascade of errors, where the error message is shown 3 times until it closes for good. How can I avoid code any code running after Application.Quit method?
Code workflow when error occurs and what runs after Application.Quit:
Main method to initialize my form
Call to loader method which throws error (Application should quit here)
Main method continues after loader method is finished
Subsequent method is called from main method which also throws an error (because first loader failed)
Lastly my main method throws an error
In total I receive 3 msgboxes with error descriptions.
I must note, that I use the same error handling procedure in all methods, but I would like the code to stop executing, so further code does not trigger any errors.
How can I avoid code any code running after Application.Quit method?
If you want to stop everything, write End after Application.Quit. It stops every piece of VBA and kills all variables you have assigned. This is not considered a good practice (At all!), but it will work exactly as you want.

Run Sub before macro Ends like Finally block

Is there some VBA best practice to use something like 'before end' subroutines?
I am changing Excel's default configs when my macro starts, and before my macro reaches its 'end sub' line I am resetting the configs to its standards.
But what if some error occurs? Am I supposed to define 'On Error' treatment inside all subs to reset the configs to the standard properties?
Just for example, I am changing configs such as:
ScreenUpdating
DisplayStatusBar
Calculation
DisplayAlerts
I'm pretty sure there is no such mechanism that is called unconditionally before exiting a function or a subroutine. You may have though error handlers (but these are executed conditionally; see the comment of ckuhn203 for an example).
However, there is such a mechanism for instances of Class Modules (i.e. for objects). When an object is destroyed (this happens when is not referenced anymore by any variable/storage), its Class_Terminate subroutine is called no-matter-what. If you can wrap your task in such an object that you discard immediately after you create it, you could override overwrite this subroutine to do the cleanup.
If I understand your question correctly, yes, the best way is to define an On Error Goto line, in each method where it's needed, like this:
Public Sub DoSomething()
On Error GoTo Finally ' Try
Application.ScreenUpdating = False
' Do your stuff here
Finally:
Application.ScreenUpdating = True
End Sub
This will ensure the things like ScreenUpdating get done even if there is an error. You can also add a catch block, like this:
Public Sub DoSomething()
On Error GoTo Catch ' Try
Application.ScreenUpdating = False
' Do normal stuff here
GoTo Finally
Catch:
' Do only error stuff here
Finally:
Application.ScreenUpdating = True
End Sub
Generally speaking, GoTo is a hated practice, but for error catching, VBA kind of forces your hand.

VB6 Error Handling in Properties -> Best practise?

im using CodeSmart 2013 to analyze my VB6 projects.
The review function says i should add error handling (or at least "on error resume next") to my class-properties.
My properties typically look like this (in 99% cases):
Public Property Let PLZ(ByVal strPlz As String)
myStrPLZ = strPlz
End Property
Public Property Get PLZ() As String
PLZ = myStrPLZ
End Property
When i automatically add error handling it would look like this:
Public Property Let PLZ(ByVal strPlz As String)
'<EhHeader>
On Error GoTo PLZ_Err
'</EhHeader>
myStrPLZ = strPlz
'<EhFooter>
Exit Property
PLZ_Err:
MsgBox Err.Description & vbCrLf & _
"in TNV.frmSucheTeilnehmer.PLZ " & _
"at line " & Erl, _
vbExclamation + vbOKOnly, "Application Error"
Resume Next
'</EhFooter>
End Property
Public Property Get PLZ() As String
'<EhHeader>
On Error GoTo PLZ_Err
'</EhHeader>
PLZ = myStrPLZ
'<EhFooter>
Exit Property
PLZ_Err:
MsgBox Err.Description & vbCrLf & _
"in TNV.frmSucheTeilnehmer.PLZ " & _
"at line " & Erl, _
vbExclamation + vbOKOnly, "Application Error"
Resume Next
'</EhFooter>
End Property
is anyone practically doing error handling in properties? is this best practise? because this would be a lot of additional code to my projects (code overview decreases imho)
Thx for help!
Greetings from germany
SLimke
You should add error handling in just the same way as you would in any method (Sub/Function).
My rule of thumb is that if the method is only a couple of lines long and doesn't do anything exotic then there is no error handling required. The same can be said of a property Get/Set
Yes adding error handling to all your property getters and setters generates a lot of code so one option could be to use centralised error handling. See this post for some discussion of this: Centralized error handling in VB6
Don't take these guidelines (especially from a program written by someone with their own opinion of what "best practice" entails). I've never used it so I can't speak (nor do I doubt) it's quality... just saying.
MarkJ is also right. If you don't need any validation on property setting then just make them public variables. If you later need to add validation, making them into private variables and having the public Property Get/Let/Set instead won't break the interface and no other code changes are needed.
As for adding error handlers in every class property get/let? Why? Personally, I assume if someone is going to use my class they will at least take a moment to make sure they know what the !##$ they are doing and how to use it. If they set a property so incorrectly that it causes a runtime (or compile-time) error then they will know right away.
If the value for setting the property is coming from the user, i.e.
MyClass.SomeProperty = Input("Enter something: ")
Then I personally think the error code should be placed there. i.e.
On Error GoTo StupidUser
MyClass.SomeProperty = Input("Enter something: ")
Exit Sub
ErrorHandler:
MsgBox "You did not supply a correct value!", vbExclamation
Otherwise, what are you going to do when you handle an error in your class? Pass it on to a centralized error handler which will just create more code to follow and end up with the same result? The user being notified/written to a log/etc.?
I (again, personally... programming isn't black & white) prefer to put error handling code in the caller routine... the procedure that's using the class, setting properties, etc.
Any sort of "code optimizer/checker" is written by a person or multiple, and even reputable ones will bring up debate among those who use it on how it should work.
TL;DR: some recommendations can be safely ignored.
Why not use public fields instead of these boilerplate properties?
Public PLZ As String
If you later need to add logic, no problem! You can convert public fields to properties without breaking clients.

What error handling should be used in VB.NET

What error handling should be used in VB.NET?
Should one use the "On Error Goto ErrorHandler ... Exit Sub ErrHandler ... End Sub" pattern or should you use the "try { ... } catch { ... } finally { ... }" pattern?
"try { ... } catch { ... } finally { ...}" pattern by a long shot.
C#
try
{
// Do Something that may go wrong
}
catch (Exception ex)
{
//Do something with the error
}
finally
{
//Cleanup
}
or
VB
Try
// Do Something that may go wrong
Catch ex as Exception
//Do something with the error
Finally
//Cleanup
End Try
The most obvious reasons I can think of off the top of my head to steer clear of On Error GoTo... would have to be:
On Error GoTo does not discriminate between types of exceptions.
On Error GoTo does not provide as much structure as Try/Catch/Finally (e.g., nesting one Try/Catch block within another).
On Error GoTo has no counterpart to Finally (that I know of).
I'm sure in many cases, clever use of On Error GoTo could mimic the behavior that is built in to VB.NET's Try/Catch/Finally feature. But what would be the point?
On Error Goto ErrorHandler ... Exit Sub ErrHandler ... End Sub is from the VB6 days. Definitely go with Try... Catch... Finally...
A little background
'On Error Goto' is the way things were done in VB 6 before the .Net days. The VB compiler still allows this so you can easily port old VB code to VB.Net. VB.Net is probably the only .Net language that supports this.
'Try Catch Finally' is the .Net way to do things and a lot more flexible allowing you to catch, wrap and rethrow exceptions. It allows for easier interoperation between components written in different languages and is a lot more readable when you do more complex error handling because you don't have goto's.
Old post, but here's my two penneth. Debugging with On Error Goto is a lot easier than Try Catch:
On Error Goto ErrHand
do something that goes wrong
do something else
ErrHand:
Resume Next
Place a breakpoint on Resume Next and if it hits, step through your code once and you jump to the statement directly after the one that caused the exception, making it a lot easier to track down the problem.
On Error Goto is also good if you expect errors, like resources that are created by other processes that you are not in control of and aren't yet available, or locked resources when you know other processes will lock a resource and you must wait your turn. With On Error Goto you can wait for a bit and then Resume Retry, where Retry is a label in your code to try the operation again. When you look at code with that structure it's very obvious what's going on:
On Error Goto ErrHand
dim ErrCnt as Integer = 0
do something
RetryFile:
On Error Goto FileErr
download a file
On error Goto ErrHand
do something with the file
On Error Goto 0
Goto Done
FileErr:
ErrCnt += 1
if ErrCnt < 10 then
sleep for a while
Resume RetryFile
else
Throw New Exception("Can't download the file")
end if
ErrHand:
Throw New Exception(Err.Number & ": " & Err.Description)
Done:
tidy up
One last point. I use both structures as I do like the Try Catch nesting, but as can be seen from the above, similar functionality can by achieved with On Error Goto, and in some ways it's neater as it moves the error handling out of the flow of the main code and all into one place.