views:

173

answers:

3

I'm generating a query and report through VBA. I have an option of asking the user if they want to output the report as a snapshot. I first ask them if they want to make a snap shot. If they say no, nothing happens. If they say yes, they get a prompt asking where they want to save it.

Everything works great except if they say yes and then click Cancel on the prompt, it raises a runtime error 2501 saying the report action was cancelled. Here is the code.

DoCmd.OpenReport "CONCERNS", acViewPreview, lstFee.Value & " DETAILS"
If MsgBox("Do you wish to create a snapshot of this report?", vbQuestion + vbYesNo) = vbYes Then
    DoCmd.OutputTo acReport, "CONCERNS", "SnapshotFormat(*.snp)", ""
End If

This is also the end of my procedure so I don't really care if an error happens here since all the important stuff happened already. I just know some monkey somewhere will flip if they ever see it. Is there a way to handle this error? On Error Resume Next is not an option because that would make debugging a nightmare in the future. It sounds like I'm looking for something like a Try/Catch but I don't think VBA supports that.

A: 

There are (at least) two ways to handle this.

1> get the filename and handle possible cancellation in a step before sending the report snapshot. I haven't done this recently but there's another way to generate the snapshot report than the DoCmd.OutputTo command, or some variation that doesn't require the command itself to use a file dialog. I generated report snapshots in an old application and didn't have to ask the user for a filename. I'll try to find the code and show an example.

2> use On Error Resume Next, but only right before the DoCmd.OutputTo routine, then see if there's an error, then turn it back off:

If MsgBox("Do you wish to create a snapshot of this report?", _
    vbQuestion + vbYesNo) = vbYes Then

    On Error Resume Next
    DoCmd.OutputTo acReport, "CONCERNS", "SnapshotFormat(*.snp)", ""
    if Err.Number = 2501 Then
        '' log or ignore error
    Else
        '' log or warn other unexpected errors
    End If
    On Error Goto 0

End If
Todd
Had to look up what On Error GoTo 0 does. This is perfect! Thanks!
mandroid
You're very welcome. I think its more practical to use a localized error handling technique rather than goto-based jumping around. Handle the error your expecting at the place that it happens, rather than jumping to the end of the routine to some big case statement, then jumping back to some other place to continue. That's why VB is accused of promoting spaghetti code.
Todd
On Error Resume Next is very dangerous. You should never use it for more than one line of code at a time, and immediately turn it off qith On Error GoTo 0. It's much better to trap for the SPECIFIC error number you know this circumstance triggers, and discard that SPECIFIC error. If an error you didn't anticipate happens, the code above will ignore it, but if you take my advice, it will be reported to the user (or handled appropriately).
David-W-Fenton
True, using On Error Resume Next can lead to uncaught errors if you're not careful, but with the Else clause included above, it will at least capture some unexpected ones. Unfortunately, On Error Goto 0 resets the Err object so it's no use checking it afterwards. You would have to store Err.Number, and probably Err.Description, turn error breaking back on, then check the stored error number to see if there was a problem. In practice, the above construct works well, and it's easier to follow than the jumping back and forth method. The real problem here is that VB just has clumsy error handling.
Todd
+1  A: 
On Error GoTo errHandler
  ....
  Exit Sub

errHandler:
  If (Err.Number = 2501) Then
    Resume Next
  End If

End Sub
Smandoli
I don't seem to be good at posting code blocks here. The point is you get an error handler going, and it uses "resume next" for just that error. No nightmares.
Smandoli
Select your block of lines and hit the "Code" icon (zeros and ones) in the editor to format them correctly. Or put 4 spaces in front of each line, same thing.
Todd
This is a vastly preferable approach to using the On Error Resume Next before the DoCmd.OpenReport.
David-W-Fenton
This solution forgot to handle all the other errors. In other words an Else and Msgbox Err.Description would be strongly suggested.
Tony Toews
+2  A: 

All you need is to handle the error ie:

On Error Goto HandleErr
DoCmd.OpenReport "CONCERNS", acViewPreview, lstFee.Value & " DETAILS"
If MsgBox("Do you    wish to create a snapshot of this report?" _
    , vbQuestion + vbYesNo) = vbYes Then    
    DoCmd.OutputTo acReport, "CONCERNS", "SnapshotFormat(*.snp)", ""
End If

ExitHere:
Exit Sub 'or Function

HandleError:
Select Case Err.Number
Case 2501 'Report Was Cancelled
   If MsgBox ("Did you really want to cancel saving the report?", _
       vbYesNo + vbDefaultButton2 ,"Please Confirm") = vbNo then
       Resume
    Else
       Resume ExitHere
    End if
Case Else
    Msgbox "An Unexpected error Occurred " & Err.Description, _
        vbExclamation,"Error"
    Resume ExitHere
End Select

This will give the user the option to undo the cancel and let them know what they did.

Mark3308