Can I do this in VBA

ryetee

Registered User.
Local time
Today, 03:18
Joined
Jul 30, 2013
Messages
952
1. I'm pretty sure I can issue a command to compact the database from within the code, but what should I be aware of, such as
a) How do can I tell if the backend is in use by someone else. Presumably I should not run compact database if it is.
b) by running the compact from VBA will the front end remain open. will the back end remain open. I basically want the code to compact the backend when the user closes the front end, but only if the backend is not in use.

2. Can I close a frnt end, and indeed do the above, if there has been a period of inactivity. If so Can I close the front end and leave a message telling the user that his front end has been closed and he may have lost any updates so should check what he was doing last.
 
Hi,


Unless you're using Access version 2003 or earlier, I am not sure you can execute a C&R from within the same database file. However, you can use VBA to do a C&R on an external db file, like the BE for example, using VBA.
 
The ability to compact the current database using code was removed with, I believe, Access 2010.
You can however compact an external database using code.
The backend will of course be in use even if only you are using it.

You could check for the existence of and read the BE lock file or, if users login/logout, check that information.

It is indeed possible to close another FE after a specified period of inactivity. I have my own code to do this but it is quite complex. You should be able to find examples online

NOTE: You do have to watch out for possible data corruption if you forcibly shut down an external FE.
 
1. I'm pretty sure I can issue a command to compact the database from within the code, but what should I be aware of, such as
a) How do can I tell if the backend is in use by someone else. Presumably I should not run compact database if it is.
b) by running the compact from VBA will the front end remain open. will the back end remain open. I basically want the code to compact the backend when the user closes the front end, but only if the backend is not in use.

2. Can I close a frnt end, and indeed do the above, if there has been a period of inactivity. If so Can I close the front end and leave a message telling the user that his front end has been closed and he may have lost any updates so should check what he was doing last.

Hi, ryetee

You don't need to close anything. With VBA, simply copy the database and do the the compacting on the copy. Then rename the compacted copy when you are satisfied everything is ok. I do this for both the front- and the back- end. Works like a charm on 2007, 2010, 2013. Here is the core routine:

Code:
Private Sub Compact_and_Repair()
    Dim oFSO As Object
    
    CRFlag = True
    On Error GoTo Cr_Error
    'Flush the cache of the current database
    DBEngine.Idle
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    
    If ChkFE Then                          ' check box for front end compacting
         destpath = txtFECDBPath
         'overwrite old file
         If Dir(destpath) <> "" Then
             Kill destpath
         End If
        'Create a file scripting objects that will backup front end db
         oFSO.CopyFile SourceFEpath, destpath
        
         'Compact the new file, ...
          Name destpath As destpath & ".cpk"
          DBEngine.CompactDatabase destpath & ".cpk", destpath
          Kill destpath & ".cpk"
     End If
     
     If ChkBE Then                       ' check box for back end compacting
         destpath = txtBECDBPath
         If Dir(destpath) <> "" Then
             Kill destpath
         End If
        'Create a file scripting objects that will backup back end db
         oFSO.CopyFile SourceBEpath, destpath
        
         'Compact the new file, ...
          Name destpath As destpath & ".cpk"
          DBEngine.CompactDatabase destpath & ".cpk", destpath
          Kill destpath & ".cpk"
     End If
     
     Set oFSO = Nothing
     
     Exit Sub
Cr_Error:
    ToErrLog True, "frmCRDB - Compact_and_Repair()"
    ToErrLog False, Err.Number & "-" & Err.Description
    MsgBox " Operation failed ! -> " & Err.Number & "-" & Err.Description & vbCrLf & _
                   " See Error Log for details ! ", vbExclamation, "Compact & Repair failed !"
    CRFlag = False
End Sub

Best,
Jiri
 
i don't believe you can compact the BE on the FE because you need Exclusive use of the database before you can c&r it.

there are steps to take.
open an External db that will do the compacting.
from within this db, again check if you can Exclusively open the db to be c&r.
you can use OpenDatabase method of a workspace and passed True as it second parameter to open it exclusively.
if successfully opened, closed it again then c&r.
 
Hi,


Unless you're using Access version 2003 or earlier, I am not sure you can execute a C&R from within the same database file. However, you can use VBA to do a C&R on an external db file, like the BE for example, using VBA.

I want to do it on the back end. Front end isn't a problem and it always gets copied on start up so will always be C and R.
WHat I want to know is I quit he front end I want to compact the back end. How do I know if it's in use? Effectively when the last user quits I want to compact the BE.
 
THanks to all. Everything taken on board!!
 
See my comment in post #3 starting 'you could check...'
 
I want to do it on the back end. Front end isn't a problem and it always gets copied on start up so will always be C and R.
WHat I want to know is I quit he front end I want to compact the back end. How do I know if it's in use? Effectively when the last user quits I want to compact the BE.
Hi,

My website is currently down or I would have posted a link to a similar code that isladogs already posted above. However, maybe this blog article might give you another possible approach as well.


Good luck!
 
Hi dbGuy/ryeTee,
I might be wrong but I don't think setting the Compact On Close in the back-end would work if the BE is "closed" from the front-end (meaning the last user exits). You need to actually open the BE file and close it to get it to compact.
I have a free utility (http://forestbyte.com/ms-access-utilities/fba-ms-access-back-end-compacter/) that can be scheduled to run using the Windows scheduler or in this case could be called from the front-end on exiting. Right now there are some messages that might make it not that user friendly (it checks for the ldb/laccdb files so you would be left with a message box if found) but I could change those messages with timed messages and add a text log.

Cheers,
Vlad
 
Hi all, I have updated the utility so it uses timed messages (set to 5 seconds) and writes to text log in the same folder as itself (Application.Curentproject.path).

I have tested it and seems to work OK - I added a call to open the utility (FBA_BAK.accde) from the Unload event of a switchboard form in one of my front-ends. Ideally it should be deployed in the same location with the local front-end for each user in a split db deployment (very small file 1.7 kb).

Cheers,
Vlad
 
I use the following procedure to compact the BE database from the FE. These do not need to be in the same folder.
It can be done even when other users are logged in as a copy is used.
The routine does the following:
a) copy the BE to a temp file
b) compact the temp file
c) save the compacted file to a backups folder
d) delete the temp file

Modify file names as appropriate

Code:
Public Function BackupBEDatabase()

On Error GoTo Err_Handler

'creates a copy of the backend database UKAddressFinderBE.accdb to the backups folder with date/time suffix

    Dim fso As Object
    Dim strOldPath As String, strNewPath As String, strTempPath As String, strFileSize As String
    Dim newlength As Long
    Dim STR_PASSWORD As String
    
    STR_PASSWORD = ucp(Nz(DLookup("ItemValue", "tblProgramSettings", "ItemName='Pwd'"), ""))
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    strFilename = "UKAddressFinderBE.accdb"
    strFileType = Mid(strFilename, InStr(strFilename, ".")) 'e.g. .accdb
            
    strOldPath = GetLinkedDBFolder & "\" & strFilename
    
    strNewPath = GetBackupsFolder & "\BE\" & _
         Left(strFilename, InStr(strFilename, ".") - 1) & "_" & Format(Now, "yyyymmddhhnnss") & strFileType
         
    strTempPath = GetBackupsFolder & "\" & _
         Left(strFilename, InStr(strFilename, ".") - 1) & "_TEMP" & strFileType
         
   ' Debug.Print strOldPath
   ' Debug.Print strTempPath
   ' Debug.Print strNewPath
    
    If SilentFlag = True Then GoTo StartBackup:
        If FormattedMsgBox("This procedure is used to make a backup copy of the Access back end database, UKAddressFinderBE.accdb.           " & _
            "@The backup will be saved to the Backups folder with date/time suffix                   " & vbCrLf & _
                vbTab & "e.g. " & strNewPath & "                            " & vbCrLf & vbCrLf & _
            "This can be used for recovery in case of problems    " & vbCrLf & vbCrLf & _
            "Create a backup now?         @", _
                vbExclamation + vbYesNo, "Copy the Access BE database?") = vbNo Then
                    Exit Function
        Else
            DoEvents
                   
StartBackup:
            If CurrentProject.AllForms("frmAdmin").IsLoaded Then
                Forms!frmAdmin.lblInfo.visible = True
                Forms!frmAdmin.lblInfo.Caption = "Creating a backup copy of the back end database . . ."
                DoEvents
            End If
            
            'copy database to a temp file
            fso.CopyFile strOldPath, strTempPath
            Set fso = Nothing
                      
            'compact the temp file (with password)
            DBEngine.CompactDatabase strTempPath, strNewPath, ";PWD=" & STR_PASSWORD & "", , ";PWD=" & STR_PASSWORD & ""
            
            'delete the tempfile
            Kill strTempPath
                
            DoEvents
            
            'get size of backup
            newlength = FileLen(strNewPath) 'in bytes
             
            'setup string to display file size
            If FileLen(strNewPath) < 1024 Then  'less than 1KB
               strFileSize = newlength & " bytes"
            ElseIf FileLen(strNewPath) < 1024 ^ 2 Then  'less than 1MB
               strFileSize = Round((newlength / 1024), 0) & " KB"
            ElseIf newlength < 1024 ^ 3 Then 'less than 1GB
               strFileSize = Round((newlength / 1024), 0) & " KB   (" & Round((newlength / 1024 ^ 2), 1) & " MB)"
            Else 'more than 1GB
                strFileSize = Round((newlength / 1024), 0) & " KB   (" & Round((newlength / 1024 ^ 3), 2) & " GB)"
            End If
            
            DoEvents
            
    End If
            
    FormattedMsgBox "The Access backend database has been successfully backed up.                " & _
        "@The backup file is called " & vbCrLf & _
            vbTab & strNewPath & "                       " & vbCrLf & vbCrLf & _
            "The file size is " & strFileSize & "              @", vbInformation, "Access BE Backup completed"
            
    If CurrentProject.AllForms("frmAdmin").IsLoaded Then
        Forms!frmAdmin.lblInfo.visible = False
        Forms!frmAdmin.lblInfo.Caption = ""
    End If
    
Exit_Handler:
    Exit Function
    
Err_Handler:
    Set fso = Nothing
    If Err <> 0 Then
      FormattedMsgBox "Error " & Err.Number & " in BackupBEDatabase procedure : " & _
          "@" & Err.description & "      @", vbCritical, "Error copying database"
    End If
    Resume Exit_Handler
    
End Function

Whilst i'm at it, the following code does much the same for the FE
a) copy the FE to a temp file
b) compact the temp file
c) save the compacted file to a backups folder
d) delete the temp file

Code:
Public Function BackupFEDatabase()

On Error GoTo Err_Handler

'creates a copy of the current db (frontend) to the backups folder with date/time suffix

    Dim fso As Object
    Dim strOldPath As String, strNewPath As String, strTempPath As String, strFileSize As String
    Dim newlength As Long
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    strFileType = Mid(CurrentDb.Name, InStr(CurrentDb.Name, ".")) 'e.g. .accdb
    strFilename = Mid(CurrentDb.Name, InStrRev(CurrentDb.Name, "\") + 1)
    strFilename = Left(strFilename, Len(strFilename) - Len(strFileType)) 'e.g. JSONTest
    
    strOldPath = CurrentDb.Name
    strTempPath = Left(CurrentDb.Name, InStr(CurrentDb.Name, ".") - 1) & _
        "_TEMP" & Mid(CurrentDb.Name, InStr(CurrentDb.Name, "."))
            
         
    strNewPath = GetBackupsFolder & "\FE\" & _
         strFilename & "_v" & GetVersion & "_" & Format(Now, "yyyymmddhhnnss") & strFileType
    
    If SilentFlag = True Then GoTo StartBackup:
        If FormattedMsgBox("This procedure is used to make a backup copy of the Access front end (FE) database.           " & _
            "@The backup will be saved to the Backups folder with version info and date/time suffix                   " & vbCrLf & _
                vbTab & "e.g. " & strNewPath & "                            " & vbCrLf & vbCrLf & _
            "This can be used for recovery in case of problems    " & vbCrLf & vbCrLf & _
            "Create a backup now?         @", _
                vbExclamation + vbYesNo, "Copy the Access FE database?") = vbNo Then
                    Exit Function
        Else
            DoEvents
                   
StartBackup:
            If CurrentProject.AllForms("frmAdmin").IsLoaded Then
                Forms!frmAdmin.lblInfo.visible = True
                Forms!frmAdmin.lblInfo.Caption = "Creating a backup copy of the front end database . . ."
                DoEvents
            End If
            
            'copy database to a temp file
            fso.CopyFile strOldPath, strTempPath
            Set fso = Nothing
            
            strNewPath = GetBackupsFolder & "\FE\" & _
                strFilename & "_v" & GetVersion() & "_" & Format(Now, "yyyymmddhhnnss") & strFileType
                
            'Debug.Print strTempPath
            'Debug.Print strNewPath
            
            'compact the temp file
            DBEngine.CompactDatabase strTempPath, strNewPath
            
            'delete the tempfile
            Kill strTempPath
                
            DoEvents
            
            'get size of backup
            newlength = FileLen(strNewPath) 'in bytes
             
            'setup string to display file size
            If FileLen(strNewPath) < 1024 Then  'less than 1KB
               strFileSize = newlength & " bytes"
            ElseIf FileLen(strNewPath) < 1024 ^ 2 Then  'less than 1MB
               strFileSize = Round((newlength / 1024), 0) & " KB"
            ElseIf newlength < 1024 ^ 3 Then 'less than 1GB
               strFileSize = Round((newlength / 1024), 0) & " KB   (" & Round((newlength / 1024 ^ 2), 1) & " MB)"
            Else 'more than 1GB
                strFileSize = Round((newlength / 1024), 0) & " KB   (" & Round((newlength / 1024 ^ 3), 2) & " GB)"
            End If
            
            DoEvents
            
    End If
            
    FormattedMsgBox "The Access FE database has been successfully backed up.                " & _
        "@The backup file is called " & vbCrLf & _
            vbTab & strNewPath & "                       " & vbCrLf & vbCrLf & _
            "The file size is " & strFileSize & "              @", vbInformation, "Access FE Backup completed"
            
    If CurrentProject.AllForms("frmAdmin").IsLoaded Then
        Forms!frmAdmin.lblInfo.visible = False
        Forms!frmAdmin.lblInfo.Caption = ""
    End If
    
Exit_Handler:
    Exit Function
    
Err_Handler:
    Set fso = Nothing
    If Err <> 0 Then
      FormattedMsgBox "Error " & Err.Number & " in BackupFEDatabase procedure : " & _
          "@" & Err.description & "      @", vbCritical, "Error copying database"
    End If
    Resume Exit_Handler
    
End Function
 
Thanks Colin! But I don't think that after running your code the "actual" (production) back-end will be compacted and ready to go as the OP requested. Mine would check to see if the lock file is present and for the last user out it will copy the back-end to a local (C) folder to minimize the chances of corruption, compact it, make back-up copies (pre and post compact) as required and copy the compacted file back to the original location.

Cheers,
Vlad
 
Absolutely true.
To do that would require the main file(s) to be replaced with the backup copy.
Just thought it might be useful to someone.
 

Users who are viewing this thread

Back
Top Bottom