Getting a more useful/accurate error message - ms-access

We have an issue with an Access front-end that seemingly randomly but constantly times out users with no explanation. This has been a long-standing issue, each time the disconnect happens we're provided with the sub that's causing the issue and a generic error message.
I'm starting to think the error message is misleading, it gives a generic "Connection Failure" with an Error Code of 0. After Googling the code that apparently means no error occurred?
I use C# not VBA so I'm not familiar with it but the error handling is as follows:
Private Sub Form_Timer()
Dim blnSystemMaintenance As Boolean
On Error GoTo ErrHand
' Check for System Maintenance.
blnSystemMaintenance = DLookup("SystemMaintenance", "ConfigItems")
If blnSystemMaintenance Then
//Do stuff
Else
//Do stuff
End If
//Do stuff
End If
ErrExit:
Exit Sub
Resume
ErrHand:
' If Err.Number = 1 Then
' Else
MsgBox "Error number: " & Err.Number & vbCrLf & _
"Error description: " & Err.Description, vbCritical, _
"Unexpected Error Occurred in Sub: Form_Timer"
Resume ErrExit
' End If
End Sub
Is there a way to get a more helpful error message?

Domain aggregates often don't give descriptive error messages. I'm assuming your database runs into problems connecting to the backend when running the domain aggregate.
You can easily replace your domain aggregate with a recordset call:
blnSystemMaintenance = CurrentDb.OpenRecordset("SELECT SystemMaintenance FROM ConfigItems")(0).Value
Often, those give a bit more descriptive errors, if the error occurs at all when using a recordset.

Sometimes error messages may be misleading for some type of functions like DLookup, this is a system problem, but sometimes error messages are misleading because not all procedures have correct error handlers and it's difficult to localize the problem especially if the developer has no direct access to the application. So, correct error handlers may significantly simplify troubleshooting.
Normally I use two types of error handlers, which give me quite clear diagnostic messages. Most common - usual error handler for procedures, which may interact with the user and normally called by the system - events handlers:
Private Sub Frame2_Click()
On Error GoTo ErrorHandler
'code here
ExitHere:
On Error Resume Next
Exit Sub
Resume '>> remove in release
ErrorHandler:
MsgBox "Error " & err.Number & " (" & err.Description & "), Line " & Erl & " in procedure Frame2_Click of Form_Form1", vbExclamation + vbMsgBoxHelpButton, "Error " & Now()
Resume ExitHere
End Sub
The second type of handlers - for procedures, which may be called only by other VBA procedures, "bubble" handler, which adds information about the error to error description and passes the error up to caller procedure:
Sub MySub()
On Error GoTo ErrorHandler
'code here
ExitHere:
Exit Sub
Resume '>> remove in release
ErrorHandler:
Debug.Assert Not (STOP_AT_ERROR And IS_DEV) '>> remove in release
err.Raise err.Number, "MySub of Form_Form1", err.Description & vbCrLf & "in MySub of Form_Form1 at " & Erl
End Sub
It allows to show full call stack with error lines and procedure names. Line numbers should be added to each line of code though.
For debug simplifying I use two constants: if STOP_AT_ERROR is True and IS_DEV is True, code execution stops right after the error without bubbling and allows to inspect variables. For inspecting, I move the code execution pointer to the line Resume using Ctrl-F9, then press F8 and code pointer moves to the row, which caused the error.
In the production or QA versions just change IS_DEV to False and code won't stop at Debug.Assert line.
For automatic generating error handlers and adding line numbers, I use third party software, for instance, MZ-Tools. It can be done manually, but it's quite a time consuming

Related

Currentdb.Execute with dbFailonError not throwing an error

In Access 2003-2016, I am using CurrentDb.Execute with dbFailonError to run an INSERT statement. The INSERT statement should fail (and it does) because one field has an incorrect value based on a related table with "Enforced Referential Integrity". However, it does not throw an error. I have tried recreating this issue in a new database, and the error works correctly. There is something wrong in the settings with my current database, and I don't want to recreate it from scratch. I have taken everything out of my database except for the problematic piece, and my minimal reproducible example database is at this link.
Here is my code, but the problem is that this code works fine and does throw errors when I create a new database from scratch. It just doesn't work in my current database.
Private Sub Command34_Click()
Dim testsql As String
testsql = "INSERT INTO tblObservations (Site,TotalDepth) VALUES ('SUD-096',5)"
With CurrentDb
On Error GoTo Err_Execute
.Execute testsql, dbFailOnError
On Error GoTo 0
MsgBox ("Upload completed. " & .RecordsAffected & " records added.")
End With
Exit Sub
Finish:
Exit Sub
Err_Execute:
If DBEngine.Errors.Count > 0 Then
For Each errLoop In DBEngine.Errors
MsgBox ("Error number: " & errLoop.Number & vbCr & errLoop.Description)
Next errLoop
End If
Resume Finish
End Sub
Use Option Explicit, like Hans said. Always use Option Explicit!
You're missing a reference to the Microsoft Office ##.# Access Database Engine object. This is where dbFailOnError is defined. Because you don't have that reference, dbFailOnError is not defined. This reference is added to all Access databases by default, and I strongly recommend adding it.
And because you're not using Option Explicit, VBA doesn't mind that it's undefined and just casts that undefined variable to a zero.
If, for some reason, you don't want to add the reference, use the corresponding value for dbFailOnError:
.Execute testsql, 128

Access Run-time Error 2475 *occasionally* occuring

I have an error log that logs in the access table whenever a runtime error occurs for a user in the error trapper, and a particular error seems to occur for 10 random users, every hour at least.
This error appears to occur completely at random, on a random module with the Set ActiveForm code, with random users at random intervals. As far as I can see, there is no pattern between the users.
2475 - "You entered an expression that requires a form to be the active window".
This appears to occur in any of the modules that contain any of the setting of a form. I am using the following lines:
Dim af as Object
Set af = Screen.ActiveForm
I have tried using alternatives, such as declaring it as Form, and also tried the below:
Dim sstatus as String
Dim ps as String
If DLookup("[TM_UserType]", "[SD_Teams]", "[TM_username]= '" & usernm & "'") = "adj" Then
sstatus = "adj"
Else
sstatus = "tm"
End If
ps = "frmProdSubmit_" & sstatus
Then referencing the form this way:
Forms(ps).cmbTeam.Value = ""
But this still causes the same issue, even removing the ActiveForm part.
The last thing to mention (as I believe they could be factors) is that the front end is accessed through a shortcut, which minimises the Access window. Not sure if this could be the culprit, or if the user clicking another application can remove the focus.
The back-end of the database is also accessed by up to around 700 users each day.
As it stands, the error trapper pops up with the message, but the front end continues working correctly. It's just an annoying issue to resolve, but am slowly running out of ideas now, and any help would be hugely appreciated!
Error 2475 is thrown when a non-form object is the active screen object such as a table datasheet. I've encountered this error in an application that uses multiple instances of a form and needs to track whether the multiple form module is active or one of the other application module functions in which case all instances of the multiple forms (popups) need to have .visible set to false. I use the Screen.ActiveForm.Name call in the Form_Deactivate event.
You can trap the error in the procedure's error handler and take action knowing the screen's active object is not a form.
Example:
Private Sub Form_Deactivate()
On Error GoTo errHandler
If Screen.ActiveForm.Name <> "AnApplicationForm" Then 'throws 2475 if not a form object
sstatus = "status message"
End If
ExitSub:
Exit Sub
errHandler:
If Err.Number = 2475 Then Resume Next 'screen active object is not a form i.e. datasheet
MsgBox "Error in " & Me.Name & ".Form_Deactivate: " & Err.Number & " - " & Err.Description
Resume ExitSub
End Sub 'Form_Deactivate

Check if Connection is OK in Classic ASP

Is there a simple way to check if a connection string was successful in connecting to the specified database:
Scenario:
Connection string example:
ConnString="DRIVER={MySQL ODBC 5.1 Driver}; SERVER=###.###.####.##; PORT=3306; DATABASE=DbName; USER=DbUser; PASSWORD=DbUser_Pswrd; OPTION=3;"
If the above fails, to logon for example, as the MySQL server is currently offline or whatever is there a simple way to check that there is an issue rather than the generic error 80004005 being thrown as explained below?
Solution to this is to solve error above being thrown when a page loads where the following line(s) in the code causes error as connection is not able to connect to the database:
rs.ActiveConnection = connString
I want to catch this connection issue before the above line is read so that I can redirect to a page that has no connection string and display a message saying the server is currently offline etc.
I just need the catch error code please.
VBScript Error Handling
The way to catch errors in VBScript is using the On Error Resume Next statement and Err object built into the VBScript Runtime.
What is the Err Object?
The Err object is used to contain information about errors raised at runtime, it always contains the last error raised, constantly overwriting itself as more errors are raised.
When errors are raised the execution is halted, so what is the point of Err?
This is because by default errors halt script execution. However VBScript provides a mechanism to ignore those errors and continue execution by moving to the next executable line and populate the Err object. We do this by placing a On Error Resume Next statement at the point where we want execution to ignore runtime errors.
It is important to remember that On Error Resume Next will only ignore runtime errors. Compilation Errors and Syntax Errors will still halt execution of a script.
So I'm using On Error Resume Next how do I trap an error?
With an If statement, once an error has been raised the Err object will be populated with that error and can be interrogated.
On Error Resume Next
'Line we are checking for error. When an error occurs execution will
'move to the next line, in this case the If Err.Number <> 0 Then.
rs.ActiveConnection = connString
If Err.Number <> 0 Then
'Raise a custom error, output error to screen or perform some action.
'Remember to clear the Err object before continuing.
Err.Clear
End If
'We no longer want to ignore errors
On Error Goto 0
Placing the On Error Resume Next statement resets the Err object as if the Err.Clear method had been called.
Common uses in Classic ASP
Sometimes you might want to detect a specific error and return a more friendly customised response, the simplest way to do this is building the response from the If Err.Number <> 0 Then statement.
If Err.Number <> 0 Then
Response.Write "Error (" & Err.Number & ") occurred: " & Err.Description
End If
A more complex approach is to raise your own error, which can then be captured by others further up the execution tree (depending on the complexity of your web application).
Err.Raise vbObjectError + 1, "My Custom App", "Connection not detected"
You might also want to capture a list of errors which can be done by using an Array or Scripting.Dictionary object instead of outputting the error immediately.
Dim errors(), error_count
Dim err_obj
...
'This block could be repeated throughout the code for various
'error checks.
If Err.Number <> 0 Then
ReDim Preserve errors(error_count)
errors(error_count) = Array(Err.Number, Err.Description)
error_count = error_count + 1
End If
...
'Output errors
If IsArray(errors) Then
Response.Write "<p>" & error_count & " error(s) have been detected</p>"
Response.Write "<ol>"
For Each err_obj In errors
Response.Write "<li>Error: " & err_obj(0) & " - " & err_obj(1) & "</li>"
Next
Response.Write "</ol>"
End If
Detecting various error codes that could be returned using a Select statement instead of using the classic If statement approach, like so;
Select Case Hex(Err.Number)
Case &H800A0006
'Overflow error
Case &H800A000B
'Division by zero error
Case Else
'Anything else
End Select
Useful Links
VBScript — Using error handling
Generating Sensible Error Messages Using Err.Raise
You would use on error resume next here, which basically tells your script to skip a line if it throws an error and continue from the next line, By checking if the err.number is not equal to 0, you can trap the error and do whatever you want from there. I would advise "disabling" on error resume next when you're done by using on error goto 0 as leaving it "enabled" throughout your code could lead to some undesirable results.
Here's a quick example of how your code would look:
err.clear
on error resume next
rs.ActiveConnection = connString
if err.number<>0 then
'## do whatever you want here
end if
on error goto 0

Multi-Page vs Multi-PDF Loop problems

I have a form that contains multiple partners that share a "pool". The partners are listed on a subform. After I'm done entering the information, I want a button to run a report for each of the partners with their specific information. But since it's multiple partners and I need one report for each (which I then want to email), I want to use a Loop to go through each of the partners.
EDIT1: Added entire code for review. I do have Option Explicit in and I have compiled it as well.
Private Sub btn_Run_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "Select * FROM Cobind_qryReport WHERE PartPoolName = """ & Me.TopLvlPoolName & """"
Debug.Print "strSQL: " & strSQL
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL)
On Error GoTo Err_PO_Click
If MsgBox("Do you wish to issue the cobind invites?", vbYesNo + vbQuestion, "Confirmation Required") = vbYes Then
rs.MoveFirst
Do While rs.EOF = False
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" _
& rs!CatCode & "_" & rs!PartPoolName "Cobind Invite_" & _
Format(Now(), "mmddyy") & ".pdf"
DoCmd.SendObject acSendReport, "Cobind_rptMain", acFormatPDF, ,_
, , " Cobind Invite", "Please find the cobind invite attached._
Response is needed by " & [RSVP] & ". Thank you.", True
rs.MoveNext
Loop
End If
Exit_PO_Click:
MsgBox ("It didn't work")
rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
Err_PO_Click:
MsgBox Err.Description
Resume Exit_PO_Click
End Sub
This should allow me to create a report for each record in my query, save it to my server, then open an email to send it out. Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression." If I take out the [PartPoolName], it'll create a PDF with four pages (each page showing a partner), where I want to end up with four separate PDFs.
The first thing you should do is add Option Explicit to the Declarations section of your module.
Then, from the Visual Basic editor's main menu, select Debug->Compile [your project name here]
Fix all the problems the compiler complains about. I suspect one of the compiler's first complaints may be triggered by this section of your code:
rs.MoveFirst
Do While Recordset.EOF = False
Do you have two recordset objects open, or one?
After you fix everything the compiler complains about, try your revised code.
If you get runtime errors, show us the exact error message and which code line is highlighted.
If the part of your code you haven't shown us includes an error hander, you can disable that error handler like so:
'On Error GoTo Err_PO_Click
Error handlers are great for production to shield users from errors. However, during development you really need to be able to identify which code line causes the error.
Alternatively, you can leave your error handler active and select Tools->Options from the editor's main menu. In the Options dialog, select the General tab, then select the "Break on All Errors" radio button and click OK. You can switch that option back to "Break on Unhandled Errors" after you finish your testing.
Update: You wrote: Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression."
What is [PartPoolName]? If it's a field in the recordset, you can reference its value as rs!PartPoolName If it's something else, perhaps a global variable, give us more information about it.
Update2: Whenever your current code completes without error, you will hit this:
Exit_PO_Click:
MsgBox ("It didn't work")
Can that be right?
Update3: This OutputTo statement is your issue now, right?
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" & _
"Cobind Invite_" & Format(Now(), "mmddyy") & ".pdf"
Cobind_rptMain is a report. It has a RowSource for its data. You're calling OutputTo with that report 4 times (once for each of the 4 rows in the recordset). Yet you expect 4 different versions of that report ... a separate report for each PartPoolName value?
To finish off the fine work by HansUp visit a page on how to print a report for a single record and how to generate reports to attach to emails. See the Emailing reports as attachments from Microsoft Access page.

disable shift key on startup in ms-access

Problem: In MS Access you can hold the shift key when opening a database in order to bypass Startup options and the AutoExec Script. I want to disable this permanently.
First of all I know this has been answered on numerous other sites, however I could not find a question about it here, but I have a slightly different need.The solutions I found were focused on placing invisible buttons to re-enable the shift-key shortcut with passwords etc.
I want a very simple solution. I want a script I can add to my AutoExec script to disable the shift-key shortcut or something like that.
I DO NOT need a way to re-enable the shift-key shortcut.
The simplest, most secure, and easiest way to do this is preferred.
Thanks!
I have always used this bit of code
Function SetBypass(rbFlag As Boolean, File_name As String) As Integer
DoCmd.Hourglass True
On Error GoTo SetBypass_Error
Dim db As Database
Set db = DBEngine(0).OpenDatabase(File_name)
db.Properties!AllowBypassKey = rbFlag
setByPass_Exit:
MsgBox "Changed the bypass key to " & rbFlag & " for database " & File_name, vbInformation, "Skyline Shared"
db.Close
Set db = Nothing
DoCmd.Hourglass False
Exit Function
SetBypass_Error:
DoCmd.Hourglass False
If Err = 3270 Then
' allowbypasskey property does not exist
db.Properties.Append db.CreateProperty("AllowBypassKey", dbBoolean, rbFlag)
Resume Next
Else
' some other error message
MsgBox "Unexpected error: " & Error$ & " (" & Err & ")"
Resume setByPass_Exit
End If
End Function
You pass it a filename and then say if you want the bypass key to be enabled or not.
The problem is that anyone else with this code can use it to “Unlock” your database and enable the bypass key.
The only way I can think to get around this would be to only give the users the runtime version of access