MSAccess VBA code not working on second run - ms-access

The below code is bound to a button. For some reason the below code executes correctly the first time. On the second time, for some users, it does not populate the fields on the website. What could the issue be?
Me!WebBrowser0.Navigate "http://bk00app0001/PMD Image Upload/"
While Me.WebBrowser0.Busy
DoEvents
Wend
Me!WebBrowser0.Document.getElementById("MainContent_Year").Value = Forms![Main Menu]![SeasonList].Value
Me!WebBrowser0.Document.getElementById("MainContent_ItemNumber").Value = Me.OpenArgs
Me!WebBrowser0.Document.getElementById("MainContent_btnLock").Click
I believe I need to set Me!WebBrowser0 = Nothing on the Close event.
However, Me!WebBrowser0 = Nothing throws an error. Any ideas as to how to do this?
UPDATE
On the second time this code is called MS Access throws the following error when it hits this line:
Me!WebBrowser0.Document.getElementById("MainContent_Year").Value = Forms![Main Menu]![SeasonList].Value
'Object variable or With block variable not set'
Looks like it was a timing issue. I was able to solve it by adding the following code before I set any of the values on the webpage:
While Me!WebBrowser0.Document.getElementsByTagName("p").Length < 10
DoEvents
Wend
I am now getting the error: "Runtime error '430' class does not support Automation or does not support expected interface"
This error refers to the following line of code:
Set Cnxn = New ADODB.Connection
Here is a screenshot for the line of code above:
http://postimage.org/image/2v7p8diis/
The above code is called when I close the form that has the button that calls the browser code.

While Me!WebBrowser0.Document.getElementsByTagName("p").Length < 10
DoEvents
Wend
Solved the first issue.
The second issue was due to referencing a non-existent DLL on the user's machine.

Related

.OldValue property in Undo button handler of form gives run-time error 2448

This is my first question, so I hope I get it right.
I am working on a project to review Employee information. I am using two forms, the first one is "ReadOnly," the second is "EditOnly."
The "ReadOnly" form is bound to a query, which defines criteria for specific records to be displayed.
The "EditOnly" form has a subform, bound to 2 tables (which are also part of the query that is the source for the "ReadOnly" form), that have a 1-to-many relation (using info from this answer:
Error 3251 on .oldValue control property).
The "EditOnly" form is opened via a button and is used to edit the data of a specific Employee. In this form I have an Undo button, using this code:
Sub UndoEdits()
If Me.Dirty Then
Me!btnUndo.Enabled = True
Else
Me!btnUndo.Enabled = False
End If
End Sub
Sub btnUndo Click()
Dim ctlC As Control
For Each ctlC in Me.Controls
If ctlC.ControlType = acTextBox Then
ctlC.Value = ctlC.OldValue
End If
Next ctlC
End Sub
which reverts unwanted changes. But when testing the function, after changing some data I get run-time error 2448. Using Debug highlights this row:
ctlC.Value = ctlC.OldValue
Is there a way to make the Undo button work?
Error 2448 is "Can't assign a value to this object".
You will get this error if you try to assign a value to any text boxes on the form that are read only/locked or disabled.
Modify your code to check ctlc for Enabled and Locked and skip any controls that aren't assignable, like this:
Dim ctlC As Control
For Each ctlC in Me.Controls
If ctlC.ControlType = acTextBox Then
If ctlC.Enabled And Not ctlC.Locked Then
ctlC.Value = ctlC.OldValue
End If
End If
Next ctlC
Debugging Tip:
You can check the value of ctlc.Name either by stepping or by writing to the immediate window (Debug.Print ctlc.Name) to see which text box is the source of the problem.

How to fix “Could not update; currently locked” caused by using DAO.Recordset2.Edit while a form is being edited

DAO.Recordset2.Edit is causing a “Could not update; currently locked” error.
I want to save the edited form, update the record and refresh the form.
But all attempts to save the form fail to fix the error. They fail to clear the record lock. Closing the form clears the lock, but that is messy, looking for a better way.
Steps:
typed data into a form.
Clicked a button that triggers:
' saves the form but does not clear the record lock
If Me.Dirty Then
Me.Dirty = False
End If
click another button that triggers adding a photo:
Private Sub EndPhotoTaking_Click()
Dim attachmentField As DAO.Field2
Dim photoItemRecordSet As DAO.Recordset2
With [Forms]![Inspection - All sub sections].Form
Set photoItemRecordSet = .Recordset
End With
Set attachmentField = photoItemRecordSet("Photo")
Set photoItemAttachment = attachmentField.Value
'---- error “Could not update; currently locked” on line below
photoItemRecordSet.Edit
Then I get the error “Could not update; currently locked”.
I am using VBA to add a picture into the record, but it is not working. It does not work if the record has been changed in any way.
It is running the Line of code "Me.Dirty = False", so this saves the record. But then I get the error. I only get the error if I enter data into the from.
The form that I enter data into contains a subform, would that have an impact? I suspect it does because I have another form that does not have a subform and it works just fine with the same code. Is there anything that would cause "Me.Dirty = False" to fail to clear the lock.
I have also tried "DoCmd.Save acForm, formName", but that did not help.
The table is sharepoint list style.
Edit
Added extra code to show origin of photoItemRecordSet.Edit
updated title and description. Added details to say saving the form is not clearing the record lock.
Workaround: close the form. Update the record. Reopen the form.
This works but is less than ideal.
Use the RecordsetClone:
Set photoItemRecordSet = .RecordsetClone
photoItemRecordSet.Bookmark = .Bookmark
I was having a similar problem, the record was saved and a requery didn't help. I was finally able to set the form RecordSource to the recordsource that I originally had it set to again, navigate to the record I was on and then the add photo worked.
I put this code in the Error Handler;
If Err.Number = 3218 Then
rstEmployee.Close
Set rstEmployee = Nothing
Me.RecordSource = "qryPersonnelData"
Set rstEmployee = db.OpenRecordset(strSQL)
DoCmd.SearchForRecord , "", acFirst, "[ID] = " & thisID
Resume
I hope this helps someone.

MS Access 2010 VBA: mysterious compile error on custom LostFocus sub

In a data validation form, I have a subroutine checking previously-entered data on a LostFocus event by ensuring that the release time (TimeReleased in table; Me.txtTimeReleased on form) is after the capture time (ObservationTime in table; Me.txtObservationTime on form). I'm using LostFocus rather than BeforeUpdate because the data were bulk-imported into the db and are now being error-checked.
My users keep getting a compile error (Compile Error: method or data member not found) upon tabbing out of the field this sub is attached to but I cannot reproduce the problem locally. The error occurs on this line:
If (Me.txtTimeReleased) <= (Me.ObservationTime) Then
and the part highlighted is '.txtTimeReleased'
Full code block:
Private Sub txtTimeReleased_LostFocus()
Dim badData As Variant
Dim resp As Variant
'Also check that time released is after time captured
If Not IsNull(Me.txtObservationTime) And Not IsNull(Me.txtTimeReleased) Then
If (Me.txtTimeReleased) <= (Me.ObservationTime) Then
resp = MsgBox("Release time must be after capture time." & vbCrLf & "Please double check this field's value: is it correct?", _
vbYesNo + vbExclamation + vbDefaultButton2, "Release Time Before Capture Time")
If resp <> vbYes Then badData = True
End If
End If
If badData = True Then
Me.cmbTaxonId.SetFocus 'set focus away so can set focus back
With Me.txtTimeReleased
.SetFocus
.SelStart = 0
.SelLength = 10
End With
End If
End Sub
Other things to note:
Both the table field and form control are formatted as 'Short Time' (24-hour time)
There is an input mask on that form control for 24-hour time; I use input masks very rarely and thus aren't familiar with them--perhaps the input mask could be causing the problem?
There are similar LostFocus subs on most of the other controls which do not produce this (or any other) error
Things I've tried:
Checking spelling
Fully decompling and recompiling the code: starting with shift, compact and repair with shift, open with /decompile flag while holding shift, compact and repair with shift, re-open with shift, and finally compile (without error)
Replacing the form in their database with one that works fine for me on the same data
Google
Things that seem odd to me:
I can't reproduce the error locally.
The error is triggering on the second instance of
Me.txtTimeReleased rather than the first: it has already passed a Not
IsNull(Me.txtTimeReleased) check.
The fact that it's a compile error: could that be masking something else?
Thanks for your time, and please let me know if there's any additional information that would be useful. Any thoughts are most welcome!
You checked for Null txtObservationTime and txtTimeReleased, but compare then txtTimeReleased and ObservationTime. Maybe solution is:
If Not IsNull(Me.txtObservationTime) And Not IsNull(Me.txtTimeReleased) Then
If (Me.txtTimeReleased) <= (Me.txtObservationTime) Then
Opening the .mdb with the /decompile flag is one of the first things I would have suggested, but you said you already tried that.
Here's another undocumented trick to deal with "hidden" compile problems that get baked in by VBA behind the scenes:
First, make a backup copy of your .mdb just to be safe (this is, after all, an undocumented technique).
Then, save your form to a text file using SaveAsText:
SaveAsText acForm, "MyFormName", "C:\MyFormName.txt"
Finally, re-load your form using the equally undocumented LoadFromText:
LoadFromText acForm, "MyFormName", "C:\MyFormName.txt"
Compile.
Compact.
Repair.
Hope for the best.
Good luck.
I suggest you use variables:
intThat = Me.txtTimeReleased
If intThis <= intThat Then
Try using ! instead of a dot:
intThat = Me!txtTimeReleased
If intThis <= intThat Then
And now, the answer that worked for me last week:
Comment out the offending line.
Run a compile that is successful.
Restore the offending line.
The compile may work now. Don't ask me why.

On Error GoTo not working; Code breaks

I am writing a VBA function to import data from one table to another in Access. The table I'm importing into has more strict data constraints (i.e. types, size etc.), so I'm expecting a lot of errors.
Rather than sift through every VBA error that comes up, I want my recordset loop to skip the entire current record and make a note of it in a separate table whenever it runs into an error. So every other line I've inserted On Error GoTo RecordError. But for some reason it's not handling every error. My code just breaks and tells me what the error is. I have the "Break on Unhandled Exceptions" option checked already.
Here's a screenshot that should explain it.
Why would it be breaking on the line immediately following an Error handler?
I think you're not understanding how VB(A) error handling works. Follow these principles:
An On Error... statement only applies to the routine (Sub or Function) in which it appears (though it will also catch errors that "bubble up" from routines that are called from within the routine in which you use it).
On Error sets a state. That is, Once you issue an On Error... it remains in force for the rest of the routine, unless superceded by a new On Error....
There are four forms of On Error...:
On Error GoTo <label>: <label> must be defined in the same routine, by writing the label name immediately followed by a colon (:) on a line by itself.
On Error Resume: immediately retries the error-throwing statement. Hardly ever used, since it's potentially infinite.
On Error Resume Next: ignores the error & continues. Sometimes useful at the end of routines for cleanup (for instance, if you want to Close a Recordset that may or may not be open). Alternatively, this form can also be used if you check the Err object immediately after any potentially error-throwing line (if Err.Number is zero (0), the statement succeeded without throwing an error). This is way too much work for most situations.
On Error GoTo 0: turns off error handling.
Given this, it's usual to place the On Error... statement immediately followng the routine's declaration (the Sub or Function statement), though some people put their Dim statements in between. If you want to temporarily change the manner of error handling within a routine, put the "new" one right before the code to which it is to apply, and (if used), the "revert" (reissuing the original), right after.
Even given all that, I have no idea why it would break on the error-throwing line when "Break on Unhandled Errors" is selected, unless you've managed to confuse it so much that it thinks there's no active error handling (and I'd be surprised if it compiled if that were the case).
Note that David Heffernan gave you the essential part of this in his answer, and it was here before mine....
The reason it is not working is because you cannot use On Error Goto ... within an error handler.
see http://www.cpearson.com/excel/errorhandling.htm
you cannot use On Error to skip a few lines, instead on error should go to a error handler which then resume's to the desired next line (in your example you could probably get away with one error handler which contains a resume next which will take you back to the next field).
thanks to Tim Williams on this question: The second of 2 'On Error goto ' statements gets ignored
and BTW ParseInt on a ZIP will destroy zip codes that begin with a 0, zipcodes should probably be treated as text.
You need to place the On Error line before the code whose errors you wish to handle.
What's more you only need to have one On Error line. The error handler then stays active until the subroutine exits or you execute another On Error statement.
Error handling with VBA is a real PITA. I'd propose you to have a look at this answer to the 'MS-Access, VBA and error handling' question, and have it adapted to your own situation. You can easily write down some code that will store all your error messages in a table, building a de facto error reporting system.
Setting the debug mode to 'break on all errors' will make the program execution stop at the line that causes an error even when the error handler has been correctly written. This can be confusing as it appears that error handling is not working.
Nobody has really answered your question.
Say your code is something like this (a skeletal framework):
Public Sub MySub()
On Error GoTo errHandler
Dim rs As DAO.Recordset
Set rs = CurrentDB.OpenRecords([SQL SELECT])
If rs.RecordCount >0 Then
rs.MoveFirst
Do Until rs.EOF
[do whatever that produces the error]
errSkipToNext:
rs.MoveNext
Loop
End If
exitRoutine:
If Not (rs Is Nothing) Then
rs.Close
Set rs = Nothing
Exit Sub
errHandler:
Select Case Err.Number
Case X, Y, Z ' where these are error numbers you want to ignore
Err.Clear
' do whatever it is you need to do in order to record the offending row
Call RecordError(rs!PK, Err.Number) ' PK is a field that identifies the bad record
GoTo errSkipToNext
Case Else
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error!"
Resume exitRoutine
End Select
End Sub
In this code, you use a SELECT CASE in your error handler to decide which errors you want to ignore. In my code framework above, I listed the error numbers as X, Y, Z, but you'd replace that with the real error numbers you want to ignore, instead.
You don't want to ignore every single error because you might end up ignoring important errors elsewhere in your subroutine. If you don't want to figure out what the limited number of errors you want to ignore happen to be, I would suggest that you set a flag at the beginning of the code block that produces the errors you want to ignore, then use an `If bolErrorInCodeBlockToIgnore Then to decide if you're ignoring all errors or not. Something like this:
Public Sub MySub()
On Error GoTo errHandler
Dim rs As DAO.Recordset
Dim bolErrorInCodeBlockToIgnore As Boolean
Set rs = CurrentDB.OpenRecords([SQL SELECT])
If rs.RecordCount >0 Then
rs.MoveFirst
Do Until rs.EOF
bolErrorInCodeBlockToIgnore = True
[do whatever that produces the error]
errSkipToNext:
rs.MoveNext
Loop
End If
exitRoutine:
If Not (rs Is Nothing) Then
rs.Close
Set rs = Nothing
Exit Sub
errHandler:
If bolErrorInCodeBlockToIgnore Then
Err.Clear
' do whatever it is you need to do in order to record the offending row
Call RecordError(rs!PK, Err.Number) ' PK is a field that identifies the bad record
bolErrorInCodeBlockToIgnore = False
GoTo errSkipToNext
Else
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error!"
Resume exitRoutine
End If
End Sub
I would much prefer the first, as I'm a firm believer in only ignoring known errors, not any old error that happens. But it might be quite difficult to come up with tests that will produce all the possible errors you want to ignore.
I have seen error handling fail too. Here is one example.
Public Function Have(ByVal item As Variant) As Boolean
'Have = Have data. Simplifies handling nulls and empty strings in validation code
On Error GoTo Procerr
If IsNull(item) Then
Have = False
**ElseIf Len(Trim(item)) = 0 Then 'Faster than Item <> ""**
Have = False
ElseIf item = 0 Then
Have = False
Else
Have = True
End If
exitproc:
Exit Function
Procerr:
'Errors sometimes occur if an unbound control is referenced
Have = False
End Function
The code sometimes fails on the line flagged with **. Here is the error message.
Note that the error handler has failed. In this case, the form that called the code returned had its recordsource set on the fly to an empty recordset, hence the fields on the screen are not visible. The form is a continuous form, so records and fields are not visible when the form is loaded with an empty recordset. The have() function is not directly called by my code, but somehow seems to be triggered by the me.requery method. The have() has been called hundreds of millions of times in my code but this is the only instance that causes it to fail and the error handler is not involked.
To Lance Roberts re original question. utf-8 unicode can sometimes play havoc with ms-access as it seems to be allow data to be confused for instruction codes (my guess). utf-8 can get into your data if data was originally loaded from a text file. utf-8 with a byte order mark (BoM) is particularly nasty. When you run some procedure that works with the data, strange errors can occur and it may look like your file has become corrupt. In other cases, text handling functions give wrong answers, e.g. Mid() will see the BOM and if you specify a starting point will start at the BOM, but Len() ignores the BOM. I am speculating that if you have this issue, then ms-access may not handle errors correctly. I have had similar issues importing data and importing utf-8 as ANSI was the cause. Note that utf-8 and ANSI are identical most of the time for plain English data so your errors may not be on every line. My errors were mostly with time-date fields. Try exporting the data first and then forcing it to be ANSI and remove any BoM and and reimporting it.

Started to get a Run-Time error '3159'; Not a Valid bookmark all of a sudden in Access 2007

I am really new to programming access. I converted an old 97 access db to access 2007 and it has been working fine for awhile. Today I go into it and was snooping around in design view and looking at the code. I didn't change anything. Just looked. When I went to run the code I kept getting the "Not a valid bookmark" error. Just to be sure I opened up the old program I converted and all the code is the same the line that is giving me the problem is the
Me.Bookmark = pos
The following is the whole routine.
Thanks in advance.
Private Sub ProductID_AfterUpdate()
Dim pos As Variant
Me![UnitPrice] = Me![ProductID].Column(2)
Me![ProductName] = Me![ProductID].Column(1)
Me![GLAcct] = Me![ProductID].Column(3)
DoCmd.DoMenuItem acFormBar, acRecordsMenu, acSaveRecord, , acMenuVer70
pos = Me.Bookmark
Me.Requery
Me.Bookmark = pos
End Sub
Edit: I already tried compact and repair.
You will need to change this code as it is out of date for quite some time. I am not sure why it worked in the first place, because the bookmarks will have changed after updating, saving and requerying. I have commented the requery line, because it does not seem to serve a useful purpose, if you wish to update the combo, requery that. If you wish to find a record after an action, save the unique ID to a variable and find it. DoMenuItem is deprecated, you can use RunCommand instead, in this case, however, Me.Dirty=false will save.
Private Sub ProductID_AfterUpdate()
Dim pos As Variant
Me![UnitPrice] = Me![ProductID].Column(2)
Me![ProductName] = Me![ProductID].Column(1)
Me![GLAcct] = Me![ProductID].Column(3)
Me.Dirty=False
'pos = Me.Bookmark
'Me.Requery
'Me.Bookmark = pos
End Sub
To requery a form and return to the same record, do this:
Dim lngPKValue As Long
With Me.RecordsetClone
lngPKValue = Me!ID
' Me.Dirty = False is unnecessary, as the Requery saves the data
Me.Requery
.FindFirst "[ID]=" & lngPKValue
If Not .NoMatch Then
Me.Bookmark = .Bookmark
End If
End With
Now, where you put this code depents. I don't quite see in the original code why there's a need to requery, as the updates have been done to the record you're already on, so you're not really accomplishing anything by requerying and returning to the record you started on. But there are circumstances in which you'd want to do that (e.g., in an ordered recordset where you've edited values that will change the place of this particular record in the sorted result), and the above is the way to do it.
If it's necessary, you'd probably want to turn off painting of the form (Me.Painting = False, the Me.Painting = True once you've set the bookmark) or of the application (Application.Echo = False/True) so the screen doesn't flicker and you don't see the requerying and navigating. But be sure you add an error handler, since if an error happens while screen painting is turned off, your user may end up stuck and unable to continue.