I used DoCmd.RunCommand acCmdPrint to print a report. If I print the report, ok. But if I cancel, Access show a error and stop run the button code.
I used DoCmd.SetWarnings (False) but don't suppress this error.
How can I do?
You need to check the error code in your error handler, and if it's "Operation cancelled", ignore it.
Option Explicit
Sub Something()
On Error GoTo Trap
'DoCmd...
Leave:
On Error GoTo 0
Exit Sub
Trap:
If Err.Number <> 2501 Then MsgBox Err.Description, vbCritical
Resume Leave
End Sub
Related
I have just upgraded from MS Access 2013 to 2019 and my duplicate record buttons have stopped working. I get the error "The command or action Paste is not available now". Have looked through the Trust Center for anything that might be upsetting it but I cannot see anything. I created a new button using the Duplicate Record wizard, and that has the same problem. So it's not my code.
Private Sub Command115_Click()
On Error GoTo Err_Command115_Click
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdCopy
DoCmd.RunCommand acCmdRecordsGoToNew
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdPaste
Exit_Command115_Click:
Exit Sub
Err_Command115_Click:
MsgBox Err.Description
Resume Exit_Command115_Click
End Sub
After several hours of hairpulling. I have arrived at a work around. Just putting a pause of point one second before the paste avoids the error message. So it seems there is some kind of timing issue. Might be some kind of record locking problem that only occurs on slower computers.
Private Sub Copy_Record_Click()
On Error GoTo Err_Copy_Record_Click
DoCmd.RunCommand acCmdSelectRecord
DoCmd.RunCommand acCmdCopy
DoCmd.RunCommand acCmdRecordsGoToNew
DoCmd.RunCommand acCmdSelectRecord
Pause (0.1)
DoCmd.RunCommand acCmdPaste
Exit_Copy_Record_Click:
Exit Sub
Err_Copy_Record_Click:
MsgBox Err.Description
Resume Exit_Copy_Record_Click
End Sub
I am attempting to have my end sub when I click cancel. However, I am getting a Run-Time Error when I do so.
I am just trying to close the dialog box which I did with an Else: Exit Sub statement. However, it still shows the Run-Time Error, while it should just exit sub.
This was a simple fix of just adding an ErrorHandler like so:
Public Sub Run_Split()
On Error GoTo ErrHandler
'Call Private Subs
Exit Sub
ErrHandler:
MsgBox "User Cancelled Program", vbCritical
End Sub
Thank you to everyone that has helped me on this site in the past, your help as allowed me to be somewhat self taught in VBA and I was able to solve this without asking for assistance.
Some background:
Precursor: I have looked around SO at the other Error Handling questions, but I haven't been able to fully apply the answers to my situation. I feel like Err.Raise is how I would accomplish what I'll describe below. But, I'm not sure how to implement it in the way I need. If I were to use Err.Raise how would I exit the Sub1-15 first before raising the error code in the main sub?
That being said,
I have a large Excel VBA project that performs a plethora of different routines. I chose to call all routines from one main routine for means of later maintenance on the individual routines. I have an On Error handler in my main sub that I would like to have triggered if an error is thrown in any of the routines called from that main routine.
Is there a way to:
Record the
Error type that occurred
Error message
Sub that raises the error
On Error exit that sub to return to the main sub, then
Raise the error that just occurred in the other sub so that the NotifyandRepair Error Handler is called?
I have the following situation
Sub MainSub()
On Error GoTo NotifyandCorrect
Call Sub1
Call Sub2
...
Call Sub15
Exit Sub
NotifyandCorrect:
'Send copy of faulty file, the error code and Sub that caused it
'Then stop macro execution completely
End Sub
Sub Sub1()
On Error Exit Sub1 and raise current Error in MainSub(?)
'Perform data checks
End Sub
Sub Sub2()
On Error Exit Sub2 and raise current Error in MainSub(?
'Modify data groups
End Sub
Sub Sub15()
On Error Exit Sub15 and raise current Error in MainSub(?
'Clean up work
End Sub
Is there anyway I can avoid having to do something like below for each of Sub1-Sub15?
Sub MainSub()
On Error GoTo NotifyandCorrect
Call Sub1
Call Sub2
...
Call Sub15
Exit Sub
NotifyandCorrect:
'Send copy of faulty file, the error code and Sub that caused it
'Then stop macro execution completely
End Sub
...
...
Sub Sub15()
On Error Goto HaltExecution
'Clean up work
Exit Sub
HaltExecution:
'Note Error message & type
'Note that Sub15 is where error occurred
End Sub
Closing Questions
Is this at all possible?
If this isn't possible, how should I handle this to do something like what I described? What would you suggest (please provide an example if you can)
You need to handle errors in your "child" methods, and have them "re-throw" the error (using Err.Raise in the error handler subroutine) so the caller gets to see it - when re-throwing, specify the method's name as the "source". The following code produces this output:
5 Invalid procedure call or argument DoSomething1
9 Subscript out of range DoSomething2
Public Sub MainSub()
On Error GoTo ErrHandler
DoSomething1
DoSomething2
Exit Sub
ErrHandler:
Debug.Print Err.Number, Err.Description, Err.Source
Resume Next
End Sub
Private Sub DoSomething1()
On Error GoTo ErrHandler
Err.Raise 5
Exit Sub
ErrHandler:
Err.Raise Err.Number, "DoSomething1", Err.Description
End Sub
Private Sub DoSomething2()
On Error GoTo ErrHandler
Err.Raise 9
Exit Sub
ErrHandler:
Err.Raise Err.Number, "DoSomething2", Err.Description
End Sub
Is there anyway I can avoid having to do something like below for each of Sub1-Sub15?
No. Each procedure must handle runtime errors, there's no way around it.
Specifying method names in hard-coded strings is annoying. By encapsulating each procedure into its own object (say, some ICommand implementation), you can achieve the same result by leveraging the TypeName function:
Module1
Option Explicit
Public Sub MainSub()
On Error GoTo ErrHandler
RunCommand New DoSomething1
RunCommand New DoSomething2
Exit Sub
ErrHandler:
Debug.Print Err.Number, Err.Description, Err.Source
Resume Next
End Sub
Private Sub RunCommand(ByVal command As ICommand)
command.Execute
End Sub
ICommand (class module)
Public Sub Execute()
End Sub
DoSomething1 (class module)
Option Explicit
Implements ICommand
Private Sub ICommand_Execute()
On Error GoTo ErrHandler
Err.Raise 5
ErrHandler:
Err.Raise Err.Number, TypeName(Me), Err.Description
End Sub
DoSomething2 (class module)
Option Explicit
Implements ICommand
Private Sub ICommand_Execute()
On Error GoTo ErrHandler
Err.Raise 9
ErrHandler:
Err.Raise Err.Number, TypeName(Me), Err.Description
End Sub
The ICommand interface isn't really needed, but formalizes the way each DoSomething command is to be called. The idea is to have an object to implement each procedure - that way you can have TypeName(Me) as your error source, and never need to hard-code a string. You'll have 15 methods in 15 dedicated class modules, instead of 15 procedures in a single standard module.
You can use Err.Number and Err.Description to get info about the error.
Next, I would suggest creating a temp string and updating it whenever a new sub is entered. such as:
Sub Sub1()
temp= "sub1"
...
End Sub
Sub Sub2()
temp= "sub2"
...
End Sub
So whenever an error is handled, the string temp holds the value of the sub it occurred in.
I have never worked with VBA, therefore this could by an easy task, but I can't get it working :-) Simply I need to catch a run time error in following code :
Private Sub CheckBox1_Click()
ActiveWorkbook.Sheets("(X)").Unprotect
ActiveWorkbook.Sheets("(X)").Select
ActiveSheet.Range("F18").Select
'here comes the error
ActiveSheet.Range("$A$2:$X$310").AutoFilter Field:=1, Criteria1:="1"
Sheets("(40 UKÁŽKA)").Protect DrawingObjects:=True, Contents:=True, Scenarios:=True
End Sub
Welcome to old school error handling.
What you are looking for is either
Sub MySub()
On Error Resume Next
DoMyStuff()
End Sub
if you want to swallow this issue, e.g equivalent of Try Catch End
or
Sub MySub()
On Error Goto ErrorHandler
DoMyStuff()
KeepGoing :
DoSomeMoreStuffAnyway()
Exit Sub
ErrorHandler:
HandleTheError()
Exit Sub
You can get the Error number from the variable Err
You can also fix and call Resume to go to the next line of code after the error happened
You can also do Resume To a lable e.g. Resume KeepGoing in the above.
More info here MSDN VBA Error Handling
Use On Error. See this for a good discussion of the topic.
On Error GoTo ErrHandler
<do things>
On Error GoTo 0 'Turn default error handling back on
Exit Sub
ErrHandler:
If Error.Number = xxxx Then
<error processing>
End If
(then Resume )(or Resume Next) (or do nothing & let sub end)
End Sub
Why would I want to get out of an Error Handler (after handling) with an Exit Sub instead of just letting it go to the End Sub?
I'm sure it's simple. I just don't understand. Thanks for any help.
Example:
Public Sub SubA()
On Error Goto ProcError
''# other code
MsgBox FuncA()
ProcExit:
Exit Sub
ProcError:
MsgBox Err.Description
Resume ProcExit
End Sub
Your ProcExit label is your place where you release all the resources whether an error happened or not. For instance:
Public Sub SubA()
On Error Goto ProcError
Connection.Open
Open File for Writing
SomePreciousResource.GrabIt
ProcExit:
Connection.Close
Connection = Nothing
Close File
SomePreciousResource.Release
Exit Sub
ProcError:
MsgBox Err.Description
Resume ProcExit
End Sub
Typically if you have database connections or other objects declared that, whether used safely or created prior to your exception, will need to be cleaned up (disposed of), then returning your error handling code back to the ProcExit entry point will allow you to do your garbage collection in both cases.
If you drop out of your procedure by falling to Exit Sub, you may risk having a yucky build-up of instantiated objects that are just sitting around in your program's memory.