Launch password protected database and close existing one - ms-access

I am trying to set up a "Launcher" database which contains VBA code that will open a second database which is password protected. I can then convert the launcher db to accde so the VBA containing the password cannot be read.
I have the following code so far.
Private Sub Form_Load()
Dim acc As Access.Application
Dim db As DAO.Database
Dim strDbName As String
strDbName = "C:\database Folder\secureDB.accdb"
Set acc = New Access.Application
acc.Visible = True
Set db = acc.DBEngine.OpenDatabase(strDbName, False, False, ";PWD=swordfish")
acc.OpenCurrentDatabase (strDbName)
Application.Quit
End Sub
When the launcher db is opened a form loads which subsequently fires the above code. It works but the problem is the last line which is intended to close the launcher db only but closes both databases. I have also tried opening the main database using Shell but am unable to pass the password this way.
How can I close the first database while keeping the second open?

You can use the following:
Private Sub Form_Load()
Dim acc As Access.Application
Dim db As DAO.Database
Dim strDbName As String
strDbName = "C:\database Folder\secureDB.accdb"
Set acc = New Access.Application
acc.Visible = True
acc.OpenCurrentDatabase strDbName, False, "swordfish"
Set db = acc.CurrentDb() 'Don't know why you want a reference to the db
acc.UserControl = True
Application.Quit
End Sub
The relevant part is acc.UserControl = True, that forces the DB to stay visible and stops it from closing as soon as the reference to the Application object gets destroyed.
A sample database that stores the main database password encrypted with a salted user password can be found in this answer

I was having trouble getting the accepted answer to work properly. I was able to make work with:
Public Function OpenAccessDb(strVerPath, strFileName, sRecordset, strPwd)
'You may also need to have the following References Added:
'Microsoft Access 16.0 Object Library & Microsoft Office 16.0 Access Database Engine Object
'Visual Basic for Applications// Microsoft Excel 16.0 Object Library// OLE Automation//
'Microsoft Forms 2.0 Object Library// Microsoft Outlook 16.0 Object Library// Microsoft Office 16.0 Object Library
Dim oDAO As DAO.DBEngine, oDB As DAO.Database, oRS As DAO.Recordset
Dim sPath As String
'sPath = GetProperDirectory(strVerPath, strFileName) ' you can bypass this function by setting the path manually below and commenting this out.
sPath = "C:\database Folder\secureDB.accdb"'manually set the path here and comment out line above
Set oDAO = New DAO.DBEngine
Set oDB = oDAO.OpenDatabase(sPath, False, True, "MS Access;PWD=" & strPwd)
Set oRS = oDB.OpenRecordset(sRecordset)
''paste to call this function
''note this function utilizes the GetProperDirectory function.
''The GetProperDirectory function uses xxxxx as the location source
''therefore the strVerPath should start after \xxxxx\yyyyyy\yyyyy\DB.accdb
'strVerPath = "\yyyyyy\yyyyy\"
'strFileName= "DB.accdb"
'sRecordSet= "table in access DB" 'the table you are sending the data to
'strPwd = "password' 'this is the password that allows access to the database
'booOpenSend= OpenAccessDb(strVerPath, strFileName, sRecordSet, strPwd)
''end paste
End Function

Related

it is possible to call ms-Access function from outside

I created a public function in an existing Access form and I`m trying to call it from outside the application.Very simple function just created for testing this.
Public Function test1(ByVal test1 As String)
Dim xlApp As New Excel.Application
xlApp.Visible = False
Dim wb As Excel.Workbook
Set wb = xlApp.Workbooks.Add
Dim ws As Excel.Worksheet
Set ws = wb.Worksheets(1)
End Function
I created the connection to it, on Automation Anywhere and I´m trying to call the function created.
Connection String im using:
Provider=Microsoft.ACE.OLEDB.16.0;Data Source="$connection$";Jet OLEDB:Database Password="$pass$"
Tried doing this, without suceed
Select test1("test")
EXEC test1("test1")
EXECUTE test1("test1")
Also with simple '
No way to do this on background so as suggested below I created a sub and called it from an VB Script
Set appAccess = CreateObject("Access.Application")
appAccess.OpenCurrentDatabase "RUTA ACCESS",,"CONTRASEÑA"
appAccess.UserControl = True
appAccess.Run "generarEtiqueta","numPropuesta","numExp","fileSavePath"
appAccess.CloseCurrentDatabase
appAccess.Quit
generarEtiqueta is the sub, all the other are arguments
You can create a module in access vba to use it in any form, or independent of form. The function can be called from outside as such:
Dim appAccess As New Access.Application
appAccess.OpenCurrentDatabase ("C:\My Documents\myDatabase.mdb")
appAccess.Run "myDatabase.test1", "Pass your argument here"
Running code behind a form requires the form to be open.
Example of a VBScript running a Sub and Function procedures in Access general module as well as a macro.
Dim ObjAccess
Set ObjAccess = CreateObject("Access.application")
ObjAccess.visible = false
ObjAccess.OpenCurrentDatabase("filepath\filename.accdb")
ObjAccess.Run("FunctionName") 'not finding a way to pass argument to Function
ObjAccess.Run "SubName", "argument" 'if Sub does not require argument then eliminate
ObjAccess.DoCmd.RunMacro "MacroName"
ObjAccess.Quit
Set ObjAccess = Nothing
I tested calling a Sub that issued a MsgBox and a Debug.Print. MsgBox works, Debug.Print does not.

MS Access VBA File Dialog Crashing

From MS Access I am generating several MS Access Workbooks. Via the following code I am getting the desired save location for all of the workbooks. The following code was working without issues a few days ago. Now it abruptly fails with no error number. MS Access crashes and I get a prompt to restart MS Access and a backup file is automatically created of the MS Access project I am working on.
Strangely the code works fine if I step through it with the debugger. It simply is not working at full speed.
UPDATE 1:
If I do the falling the save_location call works.
Private Sub make_report()
' TODO#: Change to late binding when working
Dim strSaveLocation as string
Dim xl as Excel.Application
dim wb as Excel.Workbook
strSaveLocation = save_location("G:\Group2\Dev\z_report")
Set xl=New Excel.Application
' do workbook stuff
With xl
strSaveLocation = strSaveLocation & "\report_name.xlsx"
wb.SaveAs strSavelLocation, xlOpenXMLWorkbook
End With ' xl
Set xl=nothing
End Sub
If I call the save_location function like this it abruptly crashes MS Access. It doesn't throw an error or anything. It just crashes.
Private Sub make_report()
' TODO#: Change to late binding when working
Dim strSaveLocation as string
Dim xl as Excel.Application
dim wb as Excel.Workbook
Set xl=New Excel.Application
' do workbook stuff
With xl
' the call to save_location is inside of the xl procedure
strSaveLocation = save_location("G:\Group2\Dev\z_report")
strSaveLocation = strSaveLocation & "\report_name.xlsx"
wb.SaveAs strSavelLocation, xlOpenXMLWorkbook
End With ' xl
Set xl=nothing
End Sub
By moving the save_location call inside the Excel.Application work string it fails. I don't understand why.
Private Function save_location(Optional ByVal initialDir As String) As String
On Error GoTo err_trap
Dim fDialog As Object
Dim blMatchIniDir As Boolean
Set fDialog = Application.FileDialog(4) ' msoFileDialogFolderPicker
With fDialog
.Title = "Select Save Location"
If NOT (initialDir=vbnullstring) then
.InitialFileName = initialDir
End If
If .Show = -1 Then
' item selected
save_location = .SelectedItems(1)
End If
End With
Set fDialog = Nothing
exit_function:
Exit Function
err_trap:
Select Case Err.Number
Case Else
Debug.Print Err.Number, Err.Description
Stop
Resume
End Select
End Function
Actions tried:
Decompile project and recompile
Create new MS Access project and import all objects
Compact and repair
Reset all reference
Notes:
I am using the client's system and
I don't know of any system updates
Client's system is a virtual desktop via VMWare
Office 2013
Windows 7 Pro
while i am not sure if this is the specific problem - but if it is the case, it messes with anything VBA. Check the folder names and file names for any apostrophes. While windows allows this, an apostrophe will be seen in VBA as a comment, and will crash it. Have the client walk you through the exact file that he selects to confirm there is no apostrophe character in the filename or folder name.

VBA - Upload data from Excel to Access without Access installed

I am fairly new to VBA but am trying to upload data from an Excel Workbook to an Access database table from a computer that does not have Access installed. I have searched for a solution online but haven't found anything yet that I can get to work with my code.
The error code I am getting is...429 cannot create activex component
I have some VBA code set up in the Excel workbook which calls a Sub in Access [which works on a machine which has Access installed] but I don't know what the correct code should be if the machine doesn't have Access installed.
Sub Upload_SiteObsData_Excel_To_Access(Database_Path)
Database_Path = "\\Path\db1.mdb"
Dim acApp As Object
Dim db As Object
Set acApp = CreateObject("Access.Application")
acApp.OpenCurrentDatabase ("\\Path\db1.mdb")
Set db = acApp
acApp.Run "Upload_SiteObsData_to_Access"
acApp.Quit
Set acApp = Nothing
End Sub
The procedure in Access is as follows:
Option Compare Database
Option Explicit
Dim Excel_Path As String
Dim Excel_Range As String
Dim UserNameOffice As String
Dim Excel_File_TechForm As String
Sub SetUp_Variables()
UserNameOffice = CreateObject("wscript.network").UserName
Excel_Path = "C:\Documents and Settings\" & UserNameOffice & "\Desktop\"
Excel_Range = "MyData"
Excel_File_TechForm = "SiteObsForm_v0.2.xls"
End Sub
Sub Upload_SiteObsData_to_Access()
SetUp_Variables
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel9, "TBL_SiteObsData", Excel_Path & Excel_File_TechForm, True
End Sub
I would be extremely grateful for any help. Thanks in advance
I was just fooling around with some Excel VBA code and the following seemed to work:
Option Explicit
Sub Upload_Excel_to_Access()
Dim con As Object '' ADODB.Connection
Set con = CreateObject("ADODB.Connection") '' New ADODB.Connection
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data source=C:\Users\Public\Database1.accdb;"
con.Execute _
"INSERT INTO TBL_SiteObsData " & _
"SELECT * FROM [Excel 12.0 Xml;HDR=YES;IMEX=2;ACCDB=YES;DATABASE=C:\Users\Public\Book1.xlsm].[Sheet1$]"
con.Close
Set con = Nothing
End Sub
I think you'l have to find another way round this issue, without access installed, Excel cannot create the "Access.Application" object, it just flat-out doesn't know what access is.
Can you pull the data from Access instead?
I've done this the first time I connected Excel to Access via VBA, and I know for sure it works using the code that Gord Thomson provided. Establishing an ADODB connection and executing an append query.

How to see who is using my Access database over the network?

I actually have 2 questions:
1. How might I see who is using my Access database?
E.g: There is someone with an Access database opened and it created the .ldb file, I would like to see a list of who opened that database (it could be more than one person).
2. How might I see who is using a linked table?
E.g: I have 10 different Access databases, and all of them are using a same linked table. I would like to see who is using that linked table.
I don't even know if it's really possible, but I really appreciate your help!
For you information: The main problem is that lots of people use the same Access in the same network drive, so when I need to change it I have to kick them all out, but I never know who is actually using it.
Update: Rather than reading and parsing the .ldb/.lacdb file, a better approach would be to use the "User Roster" feature of the Access OLEDB provider as described in the Knowledge Base article
https://support.microsoft.com/en-us/kb/285822
and in the other SO question
Get contents of laccdb file through VBA
Original answer:
I put together the following a while ago. It looked promising but then I discovered that computers are not immediately removed from the lock file when they disconnect. Instead, Jet/ACE seems to (internally) mark them as inactive: If ComputerA disconnects and then ComputerB connects, ComputerB overwrites ComputerA's entry in the lock file.
Still, it does provide a list of sorts. I'm posting it here in case somebody can offer some suggestions for refinement.
I created two tables in my back-end database:
Table: [CurrentConnections]
computerName Text(255), Primary Key
Table: [ConnectionLog]
computerName Text(255), Primary Key
userName Text(255)
A VBA Module in my back-end database contained the following code to read (a copy of) the lock file and update the [CurrentConnections] table:
Public Sub GetCurrentlyConnectedMachines()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim fso As Object '' FileSystemObject
Dim lck As Object '' ADODB.Stream
Dim lockFileSpec As String, lockFileExt As String, tempFileSpec As String
Dim buffer() As Byte
Set cdb = CurrentDb
cdb.Execute "DELETE FROM CurrentConnections", dbFailOnError
Set rst = cdb.OpenRecordset("SELECT computerName FROM CurrentConnections", dbOpenDynaset)
lockFileSpec = Application.CurrentDb.Name
If Right(lockFileSpec, 6) = ".accdb" Then
lockFileExt = ".laccdb"
Else
lockFileExt = ".ldb"
End If
lockFileSpec = Left(lockFileSpec, InStrRev(lockFileSpec, ".", -1, vbBinaryCompare) - 1) & lockFileExt
'' ADODB.Stream cannot open the lock file in-place, so copy it to %TEMP%
Set fso = CreateObject("Scripting.FileSystemObject") '' New FileSystemObject
tempFileSpec = fso.GetSpecialFolder(2) & "\" & fso.GetTempName
fso.CopyFile lockFileSpec, tempFileSpec, True
Set lck = CreateObject("ADODB.Stream") '' New ADODB.Stream
lck.Type = 1 '' adTypeBinary
lck.Open
lck.LoadFromFile tempFileSpec
Do While Not lck.EOS
buffer = lck.Read(32)
rst.AddNew
rst!computerName = DecodeSZ(buffer)
rst.Update
buffer = lck.Read(32) '' skip accessUserId, (almost) always "Admin"
Loop
lck.Close
Set lck = Nothing
rst.Close
Set rst = Nothing
Set cdb = Nothing
fso.DeleteFile tempFileSpec
Set fso = Nothing
End Sub
Private Function DecodeSZ(buf() As Byte) As String
Dim b As Variant, rt As String
rt = ""
For Each b In buf
If b = 0 Then
Exit For '' null terminates the string
End If
rt = rt & Chr(b)
Next
DecodeSZ = rt
End Function
The following code in the Main_Menu form of the front-end database updated the [ConnectionLog] table
Private Sub Form_Load()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim wshNet As Object '' WshNetwork
Set wshNet = CreateObject("Wscript.Network")
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("SELECT * FROM ConnectionLog", dbOpenDynaset)
rst.FindFirst "ComputerName=""" & wshNet.computerName & """"
If rst.NoMatch Then
rst.AddNew
rst!computerName = wshNet.computerName
Else
rst.Edit
End If
rst!userName = wshNet.userName
rst.Update
Set wshNet = Nothing
End Sub
Finally, the following form in the back-end database listed [its best guess at] the current connections
It is a "continuous forms" form whose Record Source is
SELECT CurrentConnections.computerName, ConnectionLog.userName
FROM CurrentConnections LEFT JOIN ConnectionLog
ON CurrentConnections.computerName = ConnectionLog.computerName
ORDER BY ConnectionLog.userName;
and the code-behind is simply
Private Sub Form_Load()
UpdateFormData
End Sub
Private Sub cmdRefresh_Click()
UpdateFormData
End Sub
Private Sub UpdateFormData()
GetCurrentlyConnectedMachines
Me.Requery
End Sub
Easy. Open the .ldb file in notepad (or any text editor) and you can see the machine names.
RE: How might I see who is using my Access database?
•E.g: There is someone with an Access database opened and it created the .ldb file, I would like to see a list of who opened that database (it could be more than one person).
Just happened across this while looking for something else, and I thought I might share what I do for this. Note that this assumes that the host computer (the computer on which the database file resides) uses file sharing to provide access to the file.
You will need to be on the host computer, or have authority to connect to that machine.
click Start
right-click My Computer and select Manage
if you're not on the host computer, right-click 'Computer Management' and enter the host's name
Expand 'Shared Folders' and click on 'Open Files'
At the right is the list of currently open files with the username for each current user
I agree with Gord's Original answer. I used this code on my database, it seems that there is a way around computers not being taken out of CurrentConnections upon exit of the DB.
I placed this on my main menu form because it is always open until the user exits. I used the unload event on my form to get this to work, and it works awesome! Here is my code
p.s. Ignore SetWarnings I just have that on so the user doesn't have to click through prompts.
Private Sub Form_Unload(Cancel As Integer)
Dim wshNet As Object
Dim deleteSQL As String
Set wshNet = CreateObject("WScript.Network")
DoCmd.SetWarnings False
deleteSQL = "DELETE tblCurrentConnections.* " & _
"FROM tblCurrentConnections WHERE[computerName] = '" & wshNet.computerName & "';"
DoCmd.RunSQL deleteSQL
DoCmd.SetWarnings True
End Sub

Updating MS Access Linked Table from VBS file

I am currently working on moving 100s of access databases from a variety of folders to another set of folders and need to update any references to linked tables that will be broken during the move. I have identified how to update the location of the linked database table by adding a macro to the access database itself by doing something like the following:
Dim tdf As TableDef, db As Database
Set db = CurrentDb
db.TableDefs.Refresh
For Each tdf In db.TableDefs
' My Logic for checking to see if it is is a linked
' table and then updating it appropriately
Next
Set collTables = Nothing
Set tdf = Nothing
Set db = Nothing
However, I do not want to have to add the code to each of the access databases so I was wondering if there was a way to create a VBS file which would execute the same type of logic. I tried the following code, but I am getting the following error when the line with the for each logic is executed: "Arguments are of the wrong type, are out of acceptable range or are in conflict with one another"
Set MyConn = CreateObject("ADODB.Connection")
MyConn.Open "Provider = Microsoft.Jet.OLEDB.4.0; Data Source = MyFile.mdb"
for each tblLoop in db.TableDefs
' business logic
next
set tblLoop = nothing
MyConn.close
set MyConn = nothing
I'm hoping that someone more familiar with doing this type of coding will be able to point me in the right direction. Is there a way to utilize the TableDefs table from outside of Access through a VBS file and if so, what would that code look like.
Thanks,
Jeremy
You cannot use tabledefs with ADO, but you can open the database in VBScript:
Dim db ''As DAO.Database
Dim ac ''As Access Application
''As noted by wmajors81, OpenDatabase is not a method of the application object
''OpenDatabase works with DBEngine: http://support.microsoft.com/kb/152400
Set ac = CreateObject("Access.Application")
ac.OpenCurrentDatabase("c:\test.mdb")
Set db = ac.CurrentDatabase
For Each tdf In db.TableDefs
Etc.
If you have start up code or forms, or database passwords, you will run into some problems, but these can be overcome, for the most part, by simulating the shift key press. This would be easier, I think, in VBA than VBScript, but AFAIK it is possible in VBScript. database passwords can be supplied in the OpenDatabase action.
I was able to expand upon the answer by #Remou to come up with some code that worked. Part of his answer included the following statement which threw an error "Set db = ac.OpenDatabase". As far as I can tell "OpenDatabase" is not a valid method, but OPenCurrentDatabase is. Also, I was getting an error when trying to set db equal to the value returned by OpenCurrentDatabase so I'm assuming that it is a sub and not a function. However, I was able to get access to the Current Database by utilizing ac.CurrentDB once I had established the connection to the the database utilizing OpenCurrentDatabase
Dim db ''As DAO.Database
Dim ac ''As Access Application
Set ac = CreateObject("Access.Application")
ac.OpenCurrentDatabase("D:\delete\UpdatingLinkedTableInAccess\GrpLfRsvs201108.mdb")
set db = ac.CurrentDB
For Each tdf In db.TableDefs
With tdf
If Len(.Connect) > 0 Then
If Left(.Connect, 4) = "ODBC" Then
' ignore these are connected via ODBC and are out of scope
Else
' biz logic
End If
End If
End With
next
set db = nothing
ac.Quit
set ac = nothing
Thanks again #Remou for your assistance.
You don't need to create an Access application instance. Use DBEngine and DAO.Workspace instead.
Option Explicit
Dim db
Dim dbe
Dim strDbPath
Dim tdf
Dim wrkJet
strDbPath = "C:\Access\webforums\whiteboard2003.mdb"
Set dbe = CreateObject("DAO.DBEngine.36")
Set wrkJet = dbe.CreateWorkspace("", "admin", "", 2) ' dbUseJet = 2
' exclusive = True and read-only = False '
Set db = wrkJet.OpenDatabase(strDbPath, True, False)
For Each tdf In db.TableDefs
If Left(tdf.Connect, 10) = ";DATABASE=" Then
WScript.Echo tdf.Connect
End If
Next
db.Close
Set db = Nothing
Set wrkJet = Nothing
Set dbe = Nothing
You would need "DAO.DBEngine.120" for ACCDB format database.
If you're using a database password, include it in OpenDatabase.
Set db = wrkJet.OpenDatabase(strDbPath, True, False, ";pwd=password")