MS Access: "Cannot open any more databases." - vba

The Access error, "Cannot open any more databases.", has been discussed several times on StackOverflow[1, 2, 3, 4]. There's also an interesting discussion of the error on Bytes.com, in which Allen Brown and David Fenton weigh in on what can cause the error and argue about whether the limit behind it is about connections or table handles. None of the causes or solutions in those places apply to my situation, as far as I can tell.
I've got a complex database that was working well, but then started throwing this error. I've boiled down the VBA code and data structure to the following bare bones:
Option Explicit
Public Function TestFunction(ID_test_1 As Integer, nID_test_2 As Integer) As Variant
Dim oCurDb_Ftn As DAO.Database, oTestData As DAO.Recordset, sSQL As String, vTestCode As Variant
Set oCurDb_Ftn = CurrentDb()
sSQL = "SELECT * FROM t_test_2 WHERE ID_test_2 = " & nID_test_2 & ";"
Set oTestData = oCurDb_Ftn.OpenRecordset(sSQL)
vTestCode = oTestData![bValue]
oTestData.Close
Set oTestData = Nothing
Set oCurDb_Ftn = Nothing
TestFunction = vTestCode
End Function ' TestFunction
The numbers in the tables are arbitrary. The fields ID_test_n are primary keys. The code above is the entire contents of TestModule. The query TestQuery is:
SELECT t_test_1.ID_test_1, TestFunction(ID_test_1,3) AS [Test code]
FROM t_test_1;
When the query is opened, it at first appears to be okay. But if I scroll down through it, it throws the "cannot open any more" error:
I've discovered one way that I can get rid of the error. If I remove the first parameter of the function TestFunction(), so that it's definition becomes:
Public Function TestFunction(nID_test_2 As Integer) As Variant
...
and the call to it in the query becomes just:
TestFunction(3)
then I can scroll down and up through the query sheet multiple times without error. Those changes are possible because in the bare-bones code of the function, there is no reference to ID_test_1. But in the actual database, that parameter is passed for a reason and omitting it is not an option. Still, it is mysterious to me that whatever is causing the error does not happen if that parameter is not passed.
Can anyone see what's going on here, why I'm getting that error, and how to fix it without excluding parameters from the function?
Environment: Windows 10 Pro 64-bit, Access 2019.

This may be due to a bug in an Office update, about Jan 26, 2022. See Reddit post
Try system restore to roll back the update; or...
Go into Access, File Options, Trust center and add the local front end directory and then check the box to then add the backend data location as a trusted location.

Related

Object with special character "/" produces Automation Error in GetObject

We have an old Microsoft Access font end that serves as the GUI to our user database. I was never much of a VBA person so as I go through fixing bugs I'm learning as I go.
Our Access DB has a number of commands to sync info to Active Directory. One such command is to add a user to a group. However, whenever the group contains a / the group is never added.
The debug produces this as:
Run-time error -2147463168 (80005000)': Automation Error".
Printing out the targetgroup shows the DN as I expect it. Trying to escape the / before the GetObject doesn't help and causes its own auth error.
Here's the top part of the function -
Function AddGroup(TargetGroup, strUserID, Optional strOptReqBy)
Dim objDL
Set objUser = GetObject("LDAP://" & GetDName(CStr(strUserID)))
Set objDL = GetObject("LDAP://" & TargetGroup)
On Error Resume Next
objDL.Add (objUser.ADsPath)
objDL.SetInfo
On Error GoTo 0
This works fine if the group does not contain a /.
Debug points to Set objDL = GetObject("LDAP://" & TargetGroup)
Looking for some input on why this is happening. Thanks!
In an LDAP path, the / is a separator. Not only is the // used near the beginning, but you can also specify the server you want to connect to, followed by a /, then the DN of the object, like this:
LDAP://example.com/DC=example,DC=com
That's necessary if the computer you're running this from isn't not joined to the same (or trusted) domain than the domain you're connecting to.
So that means that if the DN of the object you want to bind to has a /, it will think that everything before the / is a server to connect to and it explodes.
So you just need to escape it, which, as you've already learned, is done with a \:
LDAP://OU=This\/That,DC=example,DC=com
So yeah, a simple replace will do:
Set objUser = GetObject("LDAP://" & Replace(GetDName(CStr(strUserID)), "/", "\/")
Don't feel bad. Even Microsoft has this bug in their code.

Word automation failing on server, but dev station works great

I am automating a oft-used paper form by querying the user on a web page, then modifying a base Word document and feeding that modified doc file to the user's browser for hand-off to Word.
The code is Visual Basic, and I am using the Microsoft.Office.Interop module to manipulate the document by manipulating Word. Works fine on the development system (Visual Studio 2015) but not on the production server (IIS 8.5).
Both the Documents.Open() call and the doc.SaveAs() call fail with Message="Command failed" Source="Microsoft Word" HResult=0x800A1066
Things I've tried:
Added debugging out the whazoo: Single-stepping is not an option on the production machine, so I pinpointed the problem lines with debug output.
Googled and found that this problem has been reported as early as 2007, but no viable solutions were reported.
A couple sites mentioned timing issues, so I added several pauses and retries -- none helped.
Some mentioned privileging, so I tried changing file permissions & application pool users -- neither helped.
Enhanced my exception handling reports to show more details and include all inner exceptions. That yielded the magic number 800A1066 which led to many more google hits, but no answers.
Added fall-back code: if you can't open the main document, create a simple one. That's when I found the SaveAs() call also failing.
Dropped back to the development system several times to confirm that yes, the code does still work properly in the right environment.
Greatly condensed sample code does not include fallback logic. My Word document has a number of fields whose names match the XML tokens passed as parameters into this function. saveFields() is an array of those names.
Dim oWord As Word.Application
Dim oDoc As Word.Document
oWord = CreateObject("Word.Application")
oWord.Visible = True
oDoc = oWord.Documents.Open(docName)
Dim ev As String
For i = 0 To saveFields.Length - 1
Try
ev = dataXD.Elements(saveFields(i))(0).Value
Catch
ev = Nothing
End Try
If ev IsNot Nothing Then
Try
Dim field = oDoc.FormFields(saveFields(i))
If field IsNot Nothing Then
If field.Type = Word.WdFieldType.wdFieldFormTextInput Then
field.Result = ev
End If
End If
Catch e As Exception
ErrorOut("Caught exception! " & e.Message)
End Try
End If
Next
...
oDoc.SaveAs2(localDir & filename)
oDoc.Close()
oWord.Quit(0, 0, 0)
The code should generate a modified form (fields filled in with data from the parameters); instead it fails to open, and the fallback code fails to save the new document.
On my dev system the document gets modified as it should, and if I break at the right place and change the right variable, the fallback code runs and generates the alternate document successfully -- but on the production server both paths fail with the same error.
Barring any better answers here, my next steps are to examine and use OpenXML and/or DocX, but making a few changes to the existing code is far preferable to picking a new tool and starting over from scratch.
Unfortunately, Lex Li was absolutely correct, and of course, the link to the reason why is posted on a site my company considers off limits, thus never showed up in my google searches prior to coding this out.
None of the tools I tried were able to handle the form I was trying to automate either -- I needed to fill in named fields and check/uncheck checkboxes, abilities which seemed beyond (or terribly convoluted in) the tools I evaluated ...
Eventually I dug into the document.xml format myself; I developed a function to modify the XML to check a named checkbox, and manipulated the raw document.xml to replace text fields with *-delimited token names. This reduced all of the necessary changes to simple string manipulation -- the rest was trivial.
The tool is 100% home-grown, not dependent upon any non-System libraries and works 100% for this particular form. It is not a generic solution by any stretch, and I suspect the document.xml file will need manual changes if and when the document is ever revised.
But for this particular problem -- it is a solution.
This was the closest I got to a complicated part. This function will check (but not uncheck) a named checkbox from a document.xml if the given condition is true.
Private Shared Function markCheckbox(xmlString As String, cbName As String, checkValue As Boolean) As String
markCheckbox = xmlString
If checkValue Then ' Checkbox needs to be checked, proceed
Dim pos As Integer = markCheckbox.IndexOf("<w:ffData><w:name w:val=""" & cbName & """/>")
If pos > -1 Then ' We have a checkbox
Dim endPos As Integer = markCheckbox.IndexOf("</w:ffData>", pos+1)
Dim cbEnd As Integer = markCheckbox.IndexOf("</w:checkBox>", pos+1)
If endPos > cbEnd AndAlso cbEnd > -1 Then ' Have found the appropriate w:ffData element (pos -> endPos) and the included insert point (cbEnd)
markCheckbox = markCheckbox.Substring(0, cbEnd) & "<w:checked/>" & markCheckbox.Substring(cbEnd)
End If
' Any other logic conditions, return the original XML string unmangled.
End If
End If
End Function

Visio: DOS Sharing violation (Error 1532)

So I'm really confused right now. Out of the blue my code gets me the error "DOS Sharing violation".
It's weird because, it says that is trying to save my document, but I just want to open it.
This is my Code:
Public Sub ReadActivity()
Dim vsoDocument As Visio.Document
Dim vsoPage As Visio.Page
Set vsoDocument = Documents.Open("C:\Users\Philip\Dropbox\Test\Aktivität0.vsdx")
Set vsoPage = vsoDocument.Pages(1)
SvgExport (ActiveDocument.path & "\files_and_images\" & Left(ActiveDocument.name, (InStrRev(ActiveDocument.name, ".", -1, vbTextCompare) - 1)) & ".svg")
CreateCodeActivity
vsoDocument.Close
End Sub
So as you might see the code is simple nothing special is going on.
Before calling the method I'm using this for encoding my textfile: VBA : save a file with UTF-8 without BOM
And two things are very weird. First of all, I used this method two days in a row for coding the method "CreateCodeActivity" and I didn't have any problems. And second, if I call the method let's say three times, on the third time everything works perfectly...
Where might be the problem?
Thank you #Shmukko for the tip, it is really the windows defender that gives me the error.
For Windows 10 the solution is: Go to Settings and select Update & security -> Windows Defender. Select Exclude a file extension and enter the file type for Visio.
That's it.

Use DBEngine with Run-time Access

i try to connect my xls with access database. Below code work greate when i have installed full access program on my machine. Problem is when i try tu use it on machine what have only installed Run-time version of access.
I have use this references:
Visual Basic For Applications
Microsoft Excel 14.0 Object Library
OLE Automation
Microsoft Office 14.0 Object Library
Microsoft Forms 2.0 Object Library
When i try to run below code i get error: ActiveX component can't create object or return reference to this object (Error 429)
Sub mcGetPromoFromDB()
Application.ScreenUpdating = False
Dim daoDB As DAO.Database
Dim daoQueryDef As DAO.QueryDef
Dim daoRcd As DAO.Recordset
'Error on line below
Set daoDB = Application.DBEngine.OpenDatabase("K:\DR04\Groups\Functional\DC_Magazyn\Sekcja_Kontroli_Magazynu\Layout\dbDDPiZ.accdb")
Set daoRcd = daoDB.OpenRecordset("kwPromoIDX", dbOpenDynaset)
Dim tempTab() As Variant
For Each Article In collecArticle
daoRcd.FindNext "IDX = " & Article.Index
Article.PromoName = daoRcd.Fields(1).Value
Article.PromoEnd = "T" & Format(daoRcd.Fields(2).Value, "ww", vbMonday, vbUseSystem)
Next
Application.ScreenUpdating = True
End Sub
Is IDX an indexed field?
Is kwPromoIDX optimized for this specific purpose? I mean does it only contain the fields required for this update, or are you pulling extra useless fields? Perhaps something like "SELECT IDX, [Field1Name], [Field2Name] FROM kwPromoIDX" would be more efficient.
Since you are only reading the table records, and don't seem to need to actually edit them instead of dbOpenDynaset, use dbOpenSnapshot.
Just throwing out an idea here, you'd have to test to see if it made any difference, but perhaps you could try to reverse your logic. Loop through the recordset 1 by 1 and locate the IDX within your worksheet.
Another thing I've done in the past is use .CopyFromRecordset and copied the entire recordset into a temporary worksheet and done the juggling back and forth entirely within Excel, to eliminate the back and forth.
Lastly, another approach can be to quickly loop through the entire recordset and populate an array, collection, ... and then work with it instead of Access. This way the data is all virtual and you reduce the back and forth with Access.
You'll need to do some testing to see what works best in your situation.

Intermittent error when attempting to control another database

I have the following code:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.Run "Routine"
obj.CloseCurrentDatabase
Set obj = Nothing
The problem I'm experimenting is a pop-up that tells me Access can't set the focus on the other database. As you can see from the code, I want to run a Subroutine in another mdb. Any other way to achieve this will be appreciated.
I'm working with MS Access 2003.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've tried this in our development database and it works. This doesn't mean anything as the other code also workes fine in development.
I guess this error message is linked to the state of one of your databases. You are using here Jet connections and Access objects, and you might not be able, for multiple reasons (multi-user environment, unability to delete LDB Lock file, etc), to properly close your active database and open another one. So, according to me, the solution is to forget the Jet engine and to use another connexion to update the data in the "other" database.
When you say "The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database", I assume that the role of your "Routine" is to update some data, either via SQL instructions or equivalent recordset updates.
Why don't you try to make the corresponding updates by opening a connexion to your other database and (1) send the corresponding SQL instructions or (2) opening recordset and making requested updates?
One idea would be for example:
Dim cn as ADODB.connexion,
qr as string,
rs as ADODB.recordset
'qr can be "Update Table_Blablabla Set ... Where ...
'rs can be "SELECT * From Table_Blablabla INNER JOIN Table_Blobloblo
set cn = New ADODB.connexion
cn.open
You can here send any SQL instruction (with command object and execute method)
or open and update any recordset linked to your other database, then
cn.close
This can also be done via an ODBC connexion (and DAO.recordsets), so you can choose your favorite objects.
If you would like another means of running the function, try the following:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.DoCmd.RunMacro "MyMacro"
obj.CloseCurrentDatabase
Set obj = Nothing
Where 'MyMacro' has an action of 'RunCode' with the Function name you would prefer to execute in Working.mdb
I've been able to reproduce the error in 'development'.
"This action cannot be completed because the other application is busy. Choose 'Switch To' to activate ...."
I really can't see the rest of the message, as it is blinking very fast. I guess this error is due to 'switching' between the two databases. I hope that, by educating the user, this will stop.
Philippe, your answer is, of course, correct. I'd have chosen that path if I hadn't developed the 'routine' beforehand.
"I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user." As it is impossible to prevent the user to switch application in Windows, I'd like to close the subject.