If I am using MS Access for a frontend, to link to some databases in the backend, how do I prevent people from browsing to the relevant folders and copying/deleting the databases themselves?
There are several options. Please refer to this link:
http://www.techrepublic.com/blog/10-things/10-tips-for-securing-a-microsoft-access-database/552/
The best options are hiding the db browsing options, and password-protecting the database.
You can't secure the backends in MS Access against people who have permission to use them. You can only hide them. Windows does have support for secure authorisation only for signed applications, but Access has never implemented those methods.
You prevent users from browsing to the relevant folders by
(1) (As discussed in other answers) Hiding the name of the folders, so that people don't know where they are.
(2) Hiding the folders, so that people can't see them unless they have permission to see hidden folders.
(3) Removing "List Folder Contents" permission from a top-level folder, so that people don't have permission to browse to the relevent folder.
You can also prevent people from accidently deleting a database by removing the delete permission from the file.
This is what I do. Code is not mine, I just put it toghether based on two months of research I did. Don't get a false sense of security, however, because passwords are in the connection string, so they can be easily hacked, and you have to find the way to control who links to the db from another db, or else they can still dig into the data:
Disable Object menu
Disable Ribbon. Use AutoExec to run: HideTheRibbon()
Function HideTheRibbon()
DoCmd.ShowToolbar "Ribbon", acToolbarNo
End Function
Disable Shift Key Entering, by putting code in an OnClick even of a form "frmByPassOption" for example. Make sure to change the pasword to something you can remember because once this is in place, no one, including Jesus, will be able to get in ther and change the code.
Disallow F11 key whith the KeyPreview options
'***************** Code Start ***************
'Assign this to the OnClick event of a command button (or double-click event
'of a label or graphic) named "bDisableBypassKey"
'Change the "TypeYourBypassPasswordHere" default password to your password
Private Sub bDisableBypassKey_Click()
On Error GoTo Err_bDisableBypassKey_Click
'This ensures the user is the programmer needing to disable the Bypass Key
Dim strInput As String
Dim strMsg As String
Beep
strMsg = "Do you want to enable the Bypass Key?" & vbCrLf & vbLf & "Key password to enable Bypass Key."
strInput = InputBox(Prompt:=strMsg, title:="Disable Bypass Key Password")
If strInput = "carlo12a" Then
SetProperties "AllowBypassKey", dbBoolean, True
Beep
MsgBox "Bypass Key has been enabled." & vbCrLf & vbLf & "Shift key will allow users to bypass startup" & _
"options next time database is opened.", _
vbInformation, "Set Startup Properties"
Else
Beep
SetProperties "AllowBypassKey", dbBoolean, False
MsgBox "Incorrect ''AllowBypassKey'' Password!" & vbCrLf & vbLf & "The Bypass Key was disabled." & vbCrLf & vbLf & _
"The Shift key will NOT allow the users to bypass the startup options the next time the database is opened.", _
vbCritical, "Invalid Password"
Exit Sub
End If
Exit_bDisableBypassKey_Click:
Exit Sub
Err_bDisableBypassKey_Click:
MsgBox "bDisableBypassKey_Click", Err.Number, Err.Description
Resume Exit_bDisableBypassKey_Click
End Sub
'***************** Code End ***************
Put this code under public module:
'***************** Code Start ***************
'Copy this function into a new public module.
Option Compare Database
Option Explicit
Public Function SetProperties(strPropName As String, varPropType As Variant, varPropValue As Variant) As Integer
On Error GoTo Error_Handler
Dim db As DAO.Database, prp As DAO.Property
Set db = CurrentDb
db.Properties(strPropName) = varPropValue
SetProperties = True
Set db = Nothing
Exit_SetProperties:
Exit Function
Error_Handler:
If Err.Number = 3270 Then 'Property not found
Set prp = db.CreateProperty(strPropName, varPropType, varPropValue)
db.Properties.Append prp
Resume Next
Else
SetProperties = False
MsgBox "SetProperties", Err.Number, Err.Description
Resume Exit_SetProperties
End If
End Function
'***************** Code End ***************
Related
I have a button on a Continuous subform with the below VBA attached -
Private Sub del_Click()
On Error GoTo del_Click_Err
Dim LResponse As Integer
On Error Resume Next
DoCmd.GoToControl Screen.PreviousControl.Name
Err.Clear
If (Not Form.NewRecord) Then
LResponse = Eval("MsgBox('You are about to delete a record.'" & _
"'#If you click yes, you won't be able to undo this delete operation.' & Chr(13) & Chr(10) & " & _
"'Are you sure you want to delete this record?##', 276, 'Are you sure?')")
If LResponse = vbYes Then
DoCmd.SetWarnings False
DoCmd.OpenQuery "qry_DeleteSpecific"
DoCmd.RunCommand acCmdDeleteRecord
DoCmd.SetWarnings True
Else
End If
End If
If (Form.NewRecord And Not Form.Dirty) Then
Beep
End If
If (Form.NewRecord And Form.Dirty) Then
DoCmd.RunCommand acCmdUndo
End If
If (MacroError <> 0) Then
Beep
MsgBox MacroError.Description, vbOKOnly, ""
End If
del_Click_Exit:
DoCmd.SetWarnings True
Exit Sub
del_Click_Err:
MsgBox Error$
Resume del_Click_Exit
End Sub
The button was originally the auto-generated 'Delete Record' button and I have since modified it to include the query activation as well as my own msgBox.
The 'delete' button obviously worked fine before modification. The query also works as intended and I tested a button on a seperate form that just included the MsgBox code, which also worked.
But bringing it all together has failed somehow. When I click the button I don't get the MsgBox and it doesn't delete a record or run the query.
DoCmd.GoToControl Screen.PreviousControl.Name
This line appears to have fired correctly though.
Could anybody explain what may be going wrong with this?
---Edit---
Replaced
Error Clear
With
On Error GoTo del_Click_Err
I now get the error message -
The expression you entered contains invalid syntax
So it turns out it was all in the Quotes. The quotation issue is still a bit of a mystery to me, but I managed to get my code working.
Here's the change -
LResponse = Eval("MsgBox(""You are about to delete a record."" & " & _
"""#If you click yes, you won't be able to undo this delete operation."" & Chr(13) & Chr(10) & " & _
"""Are you sure you want to delete this record?##"", 276, ""Are you sure?"")")
Single quotes seemed to work when it was just the msgBox code by itself but not in the extended code. Anyway, I'll know to look out for this again.
#Andre your comment helped me debug this. I initially left 'Error Clear' as that was what the wizard put in for the delete button.
Others have had issues with the MSACCESS.EXE process not closing (from Task Manager) when exiting their databases. Each of the posts I've read have had something to do with not properly closing recordset variables.
When I exit the database I'm working on, I notice the MSACCESS.EXE process moves from the "Apps" section to "Background Processes" in Win 10 Task Manager. This hung process continues to utilize RAM. I'm certain that I'm closing all recordset variables properly.
Through a lot of debugging, I figured out a simple way to replicate the problem:
Create two forms in a new Access database. Set the PopUp property to True for one of them and False for the other. Save the forms "PopUp" and "NoPopUp" and close the database.
Open Task Manager to view the processes running on your screen.
Open your Access database and open the NoPopUp form. Note the MSACCESS.EXE process under Apps.
Close your database. Note that MSACCESS.EXE is removed from your list of Processes (both under "Apps" and "Background Processes").
Now reopen your Access database and open form PopUp. Then close the database.
Note that the MSACCESS.EXE process moves from the "Apps" section to "Background Processes" and is still utilizing system memory.
Additional MSACCESS.EXE processes hang in Task Manager each time the database is closed after opening a form with its Pop-up property set to True.
My database uses a ton of Pop-up forms. How should I be closing my database so that these hung processes aren't stacking up? (I'm using Access 2013 in Windows 10.)
Thanks,
Sam
How are you closing your database now?
Can you change the command to call a function.
Then in that function call a routine that closes all open forms
You may have to add parameter to close without saving - depending on your results.
Function CloseAllOpenFrms()
On Error GoTo Error_Handler
Dim DbF As Access.Form
Dim DbO As Object
Set DbO = Application.Forms 'Collection of all the open forms
For Each DbF In DbO 'Loop all the forms
DoCmd.Close acForm, DbF.Name, acSaveNo
Next DbF
Error_Handler_Exit:
On Error Resume Next
Set DbF = Nothing
Set DbO = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occured." & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: CloseAllOpenFrms" & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
From http://www.devhut.net/2015/02/17/ms-access-vba-close-all-open-forms/
Try this very basic example in a new sample database.
EDIT: Add a Sleep and DoEvents after every close form in case of caching/fast cpu getting ahead of code? Last attempt to fix weird issue.
In Module 1
Option Compare Database
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Function CloseAllOpenFrms()
On Error GoTo Error_Handler
Dim DbF As Access.Form
Dim DbO As Object
Set DbO = Application.Forms 'Collection of all the open forms
' Close all popups first
For Each DbF In DbO 'Loop all the forms
If DbF.PopUp Then
DoCmd.Close acForm, DbF.Name, acSaveNo
DoEvents
Sleep 1000
End If
Next DbF
' Close remaining forms
For Each DbF In DbO 'Loop all the forms
DoCmd.Close acForm, DbF.Name, acSaveNo
DoEvents
Sleep 1000
Next DbF
Application.Quit acQuitSaveNone
Error_Handler_Exit:
On Error Resume Next
Set DbF = Nothing
Set DbO = Nothing
Exit Function
Error_Handler:
MsgBox "Error closing : " & DbF.Name & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "Error closing form"
Resume Error_Handler_Exit
End Function
Create basic Form1 with two command buttons:
Command button Command1 (Caption= Open Popup Form)
Command button Command0 (Caption = Exit DB)
In Form1's form module paste text
'------------------------------------------------------------
' Command1_Click
'
'------------------------------------------------------------
Private Sub Command1_Click()
On Error GoTo Command1_Click_Err
CloseAllOpenFrms
Command1_Click_Exit:
Exit Sub
Command1_Click_Err:
MsgBox Error$
Resume Command1_Click_Exit
End Sub
'------------------------------------------------------------
' Command0_Click
'
'------------------------------------------------------------
Private Sub Command0_Click()
On Error GoTo Command0_Click_Err
DoCmd.OpenForm "Form2-popup", acNormal, "", "", , acWindowNormal
Command0_Click_Exit:
Exit Sub
Command0_Click_Err:
MsgBox Error$
Resume Command0_Click_Exit
End Sub
Create another form Form2-popup and set Popup property to true
Add command button Command1 with caption "Exit Form"
'------------------------------------------------------------
' Command1_Click
'
'------------------------------------------------------------
Private Sub Command1_Click()
On Error GoTo Command1_Click_Err
DoCmd.Close , ""
Command1_Click_Exit:
Exit Sub
Command1_Click_Err:
MsgBox Error$
Resume Command1_Click_Exit
End Sub
Recently started learning Access and I'm a bit stuck on deleting records within a form. I have a list with the following code:
Private Sub lstPickList_AfterUpdate()
Dim rst As DAO.Recordset
Set rst = Me.RecordsetClone
rst.FindFirst "OrderID=" & lstPickList.Column(0) & ""
If rst.NoMatch Then
MsgBox "The selected record can not be displayed." _
& "To display this record, you must first turn off record filtering.", _
vbInformation
Else
Me.Bookmark = rst.Bookmark
End If
Set rst = Nothing
End Sub
And a button that I would like to use to delete whatever Order is currently selected on the list. The "DeleteRecord" macro just gives me a "The command or action 'DeleteRecord' isn't available now." error. Searching has given me a bunch of code that hasn't worked for me at all.
You can delete directly from the clone:
If rst.NoMatch Then
MsgBox "The selected record can not be displayed." _
& "To display this record, you must first turn off record filtering.", _
vbInformation
Else
rst.Delete
End If
I am creating a user interface based off of one internal and two linked (external) Access datasheets in Access 2013.
Two of the fields on my UI are combo boxes that read from the linked datasheets and display the options. This is so that the entries for suppliers and material types are called-out consistently and typos are avoided. However, I would like to add the following functionality:
-If a new value is entered into the combo box the user will be prompted to fill out the necessary information on the new value. This information will subsequently be saved to the appropriate linked datasheet.
How would I go about setting up the prompt from the combo boxes themselves? It would require Access to open a form or sub-form that will, in turn, save to the linked datasheet.
I'd prefer it to be automatic, instead of end-user prompted so that it isn't skipped. It's been years since I played around with VB, so I would like to avoid that if possible and use Access' built-in functions (even if it requires a little more time). Thank you in advance!
Alright, so I was able to do it after researching the "OnNotInList" function and a little VB code.
In the OnNotInList section of the 'Event' properties sheet, I chose 'Code Builder' and entered the following:
Private Sub Supplier_NotInList(NewData As String, Response As Integer)
Dim ctl As Control
Dim dbsCustomerDatabase As Database
On Error GoTo Supplier_NotInList_Err
Dim intAnswer As Integer
Dim strSQL As String
intAnswer = MsgBox("The supplier " & Chr(34) & NewData & _
Chr(34) & " is not currently listed." & vbCrLf & _
"Would you like to add it to the list now?" _
, vbQuestion + vbYesNo, "Spire Manufacturing Solutions")
' Adding the new entry to the list:
If intAnswer = vbYes Then
strSQL = "INSERT INTO CustomerList([CustomerName]) " & _
"VALUES ('" & NewData & "');"
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
MsgBox "The new supplier has been added to the list." _
, vbInformation, "Spire Manufacturing Solutions"
Response = acDataErrAdded
' Opening the Supplier datasheet to add details
' to the new entry:
MsgBox "Opening Supplier database for new entry..."
DoCmd.OpenTable "CustomerList", acViewNormal, acEdit
End If
Supplier_NotInList_Exit:
Exit Sub
Supplier_NotInList_Err:
MsgBox Err.Description, vbCritical, "Error"
Resume Supplier_NotInList_Exit
End Sub
This allowed me to automatically prompt the user to add the details for a new supplier if they enter a new supplier name. Or, cancel the entry if they simply misspelled it. I'd quite forgotten how versatile VB was. Thank you all for your assistance in getting me headed in the right direction!
I have a function that has been in use for a number of months that checks to see if the form that is going to be opened will actually have records to be viewed before opening it. Recently I decided to change from ACCDB to ACCDE for security purposes. After making the change over the function started throwing error 2450 "Microsoft Access cannot find the referenced form..." I can't seem to find anything of use online that could tell me what the cause of this error is and why it only happens with ACCDE.
On a side note I realize the inefficiency of the logic in this function, it's on my list.
Public Function ValidateFormToOpen(strFormName As String, strFilter As String, strFieldName As String) As Boolean
On Error GoTo Err_Handler
Dim intNumberOfRecords As Integer
'If the form is currently open count how many results will be shown
If CheckFormState(strFormName) Then
intNumberOfRecords = DCount(strFieldName, Access.Forms(strFormName).RecordSource, strFilter)
'If it is closed open it in a hidden state and then count how many records would be shown
Else
DoCmd.OpenForm strFormName, acDesign, "", strFilter, , acHidden
intNumberOfRecords = DCount(strFieldName, Access.Forms(strFormName).RecordSource, strFilter)
DoCmd.Close acForm, strFormName
End If
'If there were records that will be shown return true
If intNumberOfRecords > 0 Then
ValidateFormToOpen = True
Else
ValidateFormToOpen = False
End If
Exit_Handler:
Exit Function
Err_Handler:
Call LogError(Err.Number, Err.Description, strMODULE_NAME & ".ValidateFormToOpen on " & strFormName)
Resume Exit_Handler
End Function
This is the CheckFormState Code
Public Function CheckFormState(sFormName As String) As Boolean
On Error GoTo Err_Handler
If Access.Forms(sFormName).Visible = True Then
CheckFormState = True
End If
Exit_Handler:
Exit Function
Err_Handler:
CheckFormState = False
Resume Exit_Handler
End Function
An ACCDE format database restricts design capabilities in general. I think that may be why you get an error with this line:
DoCmd.OpenForm strFormName, acDesign, "", strFilter, , acHidden
However I'm not positive that is the complete explanation because when I attempt to open a form in Design View (DoCmd.OpenForm "Form1", acDesign) in my ACCDE database, Access gives me a different error message:
"The command you specified is not available in an .mde, .accde, or .ade database."
So I don't know what the solution is for your goal, but I believe it can not be based on opening a form in Design View.