Learn Microsoft Access Advanced Programming Techniques, Tips and Tricks.

Working with Chart Object in VBA

Introduction.

Working with the Microsoft Access Chart Object in VBA can be quite complex — but it’s also a fascinating and rewarding process. Once the code is properly developed, it can be reused across different Access databases to create charts with a consistent look and feel in just a few minutes.

There are numerous chart types, chart areas, and object groups available, each with a wide range of configurable properties. Some of these properties, such as Auto Scaling, are specific to certain chart types — for example, 3D charts.

Note: Before proceeding, ensure that the following essential reference libraries are attached to your database. This will prevent VBA runtime errors when working with chart-related code.

Attaching System Reference Libraries

  1. Open the Visual Basic Editor by selecting Tools → Visual Basic Editor or choosing Code from the View menu.

  2. From the Tools menu, select References.

  3. In the Available References dialog box, check the following libraries:

    • Microsoft Office 12.0 Object Library

    • Microsoft Excel 12.0 Object Library

These libraries are also required to run the demo database provided for download at the end of this page.

After some research and experimentation, I developed a VBA routine that can dynamically modify and format Microsoft Access charts with a clean, professional appearance. I hope you’ll enjoy working with it as much as I did. A sample result is shown in the image below.

Formatting Chart Elements

The resizing of the chart and formatting of its Report various elements — including the Chart Title, Axis Titles, Chart Area, Plot Area, Chart Bars with Gradient Colors, Legends, Grid Lines, Data Labels, and the alignment of Data Labels — are all controlled through VBA code. Placing a chart object on a report with minimal property settings is done manually as a starting point.

When the program is run, it presents three options for the chart type:

  • Bar Chart

  • Line Chart

  • Pie Chart

The same chart object is dynamically transformed into the selected type, using sample values from a table for demonstration purposes. The Pie Chart only uses the first record from the table, and its data handling differs from the Bar and Line Charts. In this example, the Pie Chart is included for demonstration only and is not treated as a separate, fully detailed case.

Color Numbers

The following Color index numbers can be used in different combinations in the Program to get different shades of gradients.

Preparing for Trial Run

Follow the simple steps, explained below, and get prepared for the trial run.

  1. Create a Table with the following Structure and save it with the name Table1.

  2. Add the sample records with the values shown above.

  3. Open a new Report in Design View.
  4. Select Object from the Insert Menu and select Microsoft Graph 2000 Chart (or Microsoft Graph Chart in MS-Access 2003) from the Object Type List.

    The inserted chart object with default values will be in an activated state, displaying the default values in the Data Grid.

  5. Click outside the chart on the Detail Section of the Report to deactivate and deselect the Chart.

  6. Click on the Chart again to select it and display the Property Sheet (View ->Properties)

  7. Change the following Property Values as given below:

    • Name: Chart1

    • Row Source Type: Table/Query

    • Row Source: Table1

    • Column Heads: Yes

    Even though the following properties can be changed manually, these are changed through the Code:

    • SizeMode : 3 (Zoom)
    • Column Count: Number of Columns in the Source Data

    • Left: 0.2917?

    • Top: 0.2708?

    • Width: 5.5729?

    • Height: 4.3854?

    2D Chart Area Zones

    An MS Access 2D Chart Object has 3 different areas:

    1. the outer Frame
    2. Chart Area where Chart Title, Axis Titles, and Legend Values appear.

    3. Plot Area where the chart Data Series Values, Data Labels, Gridlines, Scale, and Category Values appear in the Bar or Line Charts.

    If the Size Mode property is set to Clip (value 0), resizing the chart using the last four properties (Left, Top, Width, Height) will only adjust the outer frame, leaving the inner sections — the Chart Area and Plot Area — unchanged. If the property is set to Stretch or Zoom (values 1 or 3, respectively), the inner chart sections will resize to fit within the outer frame. Zoom is the preferred setting, as it maintains the correct aspect ratio of the chart during resizing, preventing distortion.

    The Column Count property is determined from the Row Source table or query.

    The program also validates the Row Source Type property. If it is not set to Table/Query, it will be corrected. However, if the Row Source property does not contain a valid table name or SQL string, the program will terminate and display an error message.

  8. Save the Report with the Name myReport1.
  9. The VBA Code.

  10. Copy and Paste the following VBA Code into the Global Module and save the Module.
    Public Function ChartObject(ByVal ReportName As String, ByVal ChartObjectName As String)
    '------------------------------------------------
    'Author : a.p.r. pillai
    'Date   : June-2008/Revision on 12/2019
    'Source Code : from Microsoft Access Help
    'and modified certain parameters
    '------------------------------------------------
    Dim Rpt As Report, grphChart As Object
    Dim msg As String, lngType As Long, cr As String
    Dim ctype As String, typ As Integer, j As Integer
    Dim db As Database, rst As Recordset, recSource As String
    Dim colmCount As Integer
    Const twips As Long = 1440
    
    'On Error GoTo ChartObject_Err
    
    cr = vbCr & vbCr
    
    msg = "1. Bar Chart" & cr
    msg = msg & "2. Line Chart" & cr
    msg = msg & "3. Pie Chart" & cr
    msg = msg & "4. Quit" & cr
    msg = msg & "Select Type 1,2 or 3"
    
    ctype = "": typ = 0
    Do While typ < 1 Or typ > 4
     ctype = InputBox(msg, "Select Chart Type")
     If Len(ctype) = 0 Then
        typ = 0
     Else
     typ = Val(ctype)
     End If
    Loop
    
    Select Case typ
        Case 4
            Exit Function
        Case 1
           lngType = xlColumnClustered
        Case 2
           lngType = xlLine
        Case 3
           lngType = xl3DPie
    End Select
    
    DoCmd.OpenReport ReportName, acViewDesign
    Set Rpt = Reports(ReportName)
    
    Set grphChart = Rpt(ChartObjectName)
    
    grphChart.RowSourceType = "Table/Query"
    
    recSource = grphChart.RowSource
    
    If Len(recSource) = 0 Then
       MsgBox "RowSource value not set."
       Exit Function
    End If
    
    'get number of columns in chart table/Query
    Set db = CurrentDb
    Set rst = db.OpenRecordset(recSource)
    colmCount = rst.Fields.Count
    rst.Close
    
    With grphChart
        .ColumnCount = colmCount
        .SizeMode = 3
        .Left = 0.2917 * twips
        .Top = 0.2708 * twips
        .Width = 5.5729 * twips
        .Height = 4.3854 * twips
    End With
    
    grphChart.Activate
    
    'Chart type, Title, Legend, Datalabels,Data Table
    With grphChart
         .chartType = lngType
        ' .chartType = xlColumnClustered
        '.AutoScaling = True
        ' only for 3D type
        .HasLegend = True
        .HasTitle = True
        .ChartTitle.Font.Name = "Verdana"
        .ChartTitle.Font.Size = 14
        .ChartTitle.Text = "Revenue Performance - Year 2007"
        .HasDataTable = False
        .ApplyDataLabels xlDataLabelsShowValue
    End With
    
    'apply gradient color to Chart Series
    If typ = 1 Or typ = 2 Then
        For j = 1 To grphChart.SeriesCollection.Count
          With grphChart.SeriesCollection(j)
            '.Interior.Color = RGB(Int(Rnd(j) * 200), Int(Rnd(j) * 150), Int(Rnd(j) * 175))
            .Fill.OneColorGradient msoGradientVertical, 4, 0.231372549019608
            .Fill.Visible = True
            .Fill.ForeColor.SchemeColor = Int(Rnd(1) * 54) + 2
            If typ = 1 Then
               .Interior.Color = msoGradientVertical
            End If
            .DataLabels.Font.Size = 10
            .DataLabels.Font.Color = 3
            If typ = 1 Then
                .DataLabels.Orientation = xlUpward
           Else
                .DataLabels.Orientation = xlHorizontal
            End If
         End With
        Next j
    End If
    
    If ctype = 3 Then
     GoTo nextstep 'skip axes for pie chart
    End If
    
    'Y-Axis Title
    With grphChart.Axes(xlValue)
        .HasTitle = True
        .HasMajorGridlines = True
        With .AxisTitle
            .Caption = "Values in '000s"
            .Font.Name = "Verdana"
            .Font.Size = 12
            .Orientation = xlUpward
        End With
    End With
    
    'X-Axis Title
    With grphChart.Axes(xlCategory)
        .HasTitle = True
        .HasMajorGridlines = True
        .MajorGridlines.Border.Color = RGB(0, 0, 255)
        .MajorGridlines.Border.LineStyle = xlDash
        With .AxisTitle
            .Caption = "Quarterly"
            .Font.Name = "Verdana"
            .Font.Size = 10
            .Font.Bold = True
            .Orientation = xlHorizontal
        End With
    End With
    
    With grphChart.Axes(xlValue, xlPrimary)
         .TickLabels.Font.Size = 10
    End With
    With grphChart.Axes(xlCategory)
         .TickLabels.Font.Size = 10
    End With
    
    nextstep:
    
    With grphChart
        .ChartArea.Border.LineStyle = xlDash
        .PlotArea.Border.LineStyle = xlDot
        .Legend.Font.Size = 10
    End With
    
    'Chart Area Fill with Gradient Color
    With grphChart.ChartArea.Fill
        .Visible = True
        .ForeColor.SchemeColor = 2
        .BackColor.SchemeColor = 19
        .TwoColorGradient msoGradientHorizontal, 2
    End With
    
    'Plot Area fill with Gradient Color
    With grphChart.PlotArea.Fill
        .Visible = True
        .ForeColor.SchemeColor = 2
        .BackColor.SchemeColor = 10
        .TwoColorGradient msoGradientHorizontal, 1
    End With
    
    grphChart.Deselect
    
    DoCmd.Close acReport, ReportName, acSaveYes
    DoCmd.OpenReport ReportName, acViewPreview
    
    ChartObject_Exit:
    Exit Function
    
    ChartObject_Err:
    MsgBox Err.Description, , "ChartObject()"
    Resume ChartObject_Exit
    End Function
    

    Running the Code

  11. Open the VBA Module that you have pasted the code into if you have closed it.

  12. Run the code from the Debug Window (press Ctrl+G to display the Debug Window) using the following syntax:

    ChartObject "myReport1", "Chart1"

    Or call the function from the On_Click() Event Procedure of a Command Button on a Form.

  13. Select Chart Type 1, 2, or 3 for Bar Chart, Line Chart, or Pie, respectively.

The Program will open the Report myReport1 in Design View, modify the Graph Chart for the selected Type, save it, and then reopen it in Print Preview. You may minimize the VBA Window (Alt+F11) to view the Chart. Since the Report is saved after the changes, you may open it manually in the design view or Print Preview.

When you run the Code for Bar Chart or Line Chart, the Gradient Scheme Color Codes are selected randomly, which will apply different shades of Gradient Colors every time.

NB: Any suggestions for improvement are welcome.

Download the Demo Database.

Download Demo Database

  1. MS-Access and Graph Charts
  2. MS-Access and Graph Charts-2
  3. Working With Chart Object in VBA
  4. Column Chart and VBA
  5. Pie Chart Object and VBA
  6. Missing Lines in Line-Chart
  7. Pie Chart and Live Data on Form
  8. Scaling Chart Object
  9. Cross-Tab Union Queries for Chart
Share:

Linking with IBM AS400 Tables

Introduction.

IBM iSeries (AS400) DB2 tables can be converted into dBase format, downloaded, and then linked or imported into MS Access databases. The downloading process is typically initiated and run from the AS400 menus. If multiple steps are required before transferring the output file to the local drive, this process can be automated using macro scripts. Keystrokes can be recorded and modified so that the target file is saved to a specific location on the local machine with a predefined name, allowing it to remain linked to the Microsoft Access database.

You need the necessary Access privileges to the iSeries (AS400) mainframe tables, and you can link the table directly into your MS-Access database using an ODBC-based procedure.  We will explore this aspect shortly.

Typically, Reports are generated on the AS400 and delivered to users as hard copies or exported as text-based spool files if a soft copy is required. These files can be downloaded in text file format or imported into Microsoft Excel—though Excel may not always parse numbers, dates, or other formats correctly. AS400 tables can also be downloaded directly into Excel. If the number of rows exceeds 65,535 (the limit for an Excel worksheet), multiple worksheets will be created automatically to accommodate all the data.

Linking to IBM iSeries DB2 Tables.

Let us review the steps for linking IBM iSeries DB2 Tables in MS-Access Database. The example images are created from the Windows 2000 Workstation.

Creating ODBC System DSN.

  1. Select Start Menu -> Settings -> Control Panel -> Administrative Tools -> double-click on Data Sources (ODBC).

    The ODBC Data Source Administrator Settings will be displayed. See the Image given below. The Following Steps will walk you through the procedure:

  2. Select the System DSN Tab on the ODBC Data Source Administrator.

  3. Click Add ... Button to display a list of Data Source Drivers.

  4. Select Client Access ODBC Driver (32-bit) from the displayed list in the Create New Data Source Control and click Finish.

  5. Type a name in the Data Source name Control. I have inserted the name myData as the Data Source Name. We have to look for this name when we attempt to link the Table to MS-Access.

  6. Click on the Server Tab.

  7. Type the specific iSeries Folder Name where your data table resides in the Library List Control. If more than one Library File, separate them with Commas.

  8. Select the Read-Only (Select statements only) option under Connection Type to ensure that we have no intention to modify the data in the iSeries Table.
  9. Click the Apply button followed by the OK Button. The System Data Source Name myData appears in the System DSN Tab. See the image below.

  10. Click OK to close the ODBC Configuration Main Control (the Apply button remains disabled in this case).

Linking to MS-Access Database.

  1. Open your MS-Access Database.

  2. Select File -> Get External Data -> Link Table or Import Option.

  3. Select ODBC Databases in the Files of Type control in the Common Dialog Control and click the Link (or Import) Button, as the case may be.

  4. Select the Machine Data Source Tab on the ODBC Control and find the Data Source Name myData that you have created, select it, and click OK.

    You will be prompted for AS400 User ID and password. Key in your User ID, Password, and click OK.

    The Tables list will open up, showing all the Table Names available in the AS400 iSeries Machine, prefixed with the Library Name followed by a period.

  5. Select the Table(s) to Link and Click OK.

    The Fields of the selected Table will be displayed, suggesting highlighting one or more fields for indexing if needed.

  6. Highlight the field(s) if you would like to create a Unique Index for the Table; otherwise, click OK without selecting any.

The selected Table will be linked (or imported as the case may be) into your Database.

The AS400 Login Issue

If the table remains linked, whenever you attempt to use the table after opening your MS-Access Database, it will prompt for the AS400 iSeries UserID and Password.  The login is valid for the current Session of the Access Database only.

If you don't want this to happen in the middle of some process, it is better to invoke the login immediately after opening the Database. To do this, create a Query, Form, or Report that uses the linked iSeries Table, and opens it with an Autoexec Macro or the Form in Startup. Even better, create a VBA routine to open the linked table that invokes the login procedure, and the User Logon at the beginning of the current session. This will take care of the rest of the Session time.

Share:

REPAIRING COMPACTING DATABASE WITH VBA

Introduction.

Repairing and compacting the database is an essential maintenance task in Microsoft Access to keep the database size optimized and prevent performance issues. During regular use, MS Access creates temporary work objects within the database, causing the file size to grow over time.

If the database is used by a single user, this is not a major concern. You can simply enable the Compact on Close option in Access settings to automate this process:

  • Go to Tools → Options → General Tab

  • Check the box labeled Compact on Close

With this enabled, Access will automatically compact and repair the database each time it is closed.

However, if the database is shared on a network, enabling this feature can cause problems. Compacting requires exclusive access to the database, which means no other users can be connected while the process runs. If multiple users attempt to close the shared database, Access will attempt to compact it and fail, potentially leading to instability or corruption over time.

Granting Exclusive Access through Tools → Security → User and Group Permissions → Permissions Tab prevents multiple users from accessing the database concurrently, but that defeats the purpose of a shared system.

Access requires exclusive access during compacting because the process actually deletes the original database file and re-creates it. The compacting operation involves the following internal steps:

Database Compacting Steps.

  1. Select Tools -> Database Utilities -> Compact and Repair Database. Closes the Current Database.

  2. Creates a temporary Database named db1.mdb in the current folder.

  3. Transfers all the Objects (Tables, Forms, Reports, etc.), except the work objects, into db1.mdb.

  4. Deletes the original Database.

  5. Renames the db1.mdb file to the original name.

  6. Opens the newly created Database.

When No Database is active.

If no database is currently open when you select the Compact and Repair option, Access will prompt you to choose the source database from your disk. You will then be asked to specify a target name and location for saving the compacted copy. Access will not automatically overwrite the original database; instead, it creates a new compacted version. It is up to you to decide whether to retain or replace the old database file—renaming them appropriately is recommended for clarity and version control.

When performing compacting operations on a server, disk quota allocation can become a limiting factor. The user running the process must have at least twice the size of the database (or more) available in their allocated disk quota to allow Access to create the compacted copy before deleting the original.

In multi-user environments where several databases are shared across network folders, maintaining each one manually can be cumbersome. In such cases, a dedicated Compacting Utility Program is invaluable. This program, built in VBA, can automatically compact one or more databases sequentially. It follows the same logical steps outlined earlier (Steps 1 to 7), with minor adjustments in handling multiple databases efficiently.

The Compacting Utility that we create has the following advantages:

  • Uses Local Disk Space for the work file, instead of Network disk space, and runs the compacting process faster.

  • Can select more than one Database for compacting.

  • Takes a safe Backup on the Local Drive.

  • No failures due to the non-availability of enough Disk Space under the User's Disk Quota.

We will create a small Database with a Table to hold a list of Database Path Names, a Form, and two VBA Programs on the Form Module.

The Design Task

  1. Create a new Database with the name CompUtil.mdb.

  2. Create a Table with the following structure.

    Table: FilesList
    Field Name Type Size
    ID AutoNumber  
    dbPath Text 75
  3. Save the Table with the name FilesList and key in the full path names of your Databases running on the Server, and close the table. Do not use the UNC type server addressing method: 

    "\\ ServerName\FolderName\DatabaseName" 
  4. Open a new Form and create a List Box using the FilesList Table. See the design given below. Draw two Label Controls below the List Box and two Command Buttons below that, side by side.

  5. Resize the Controls and position them to match the design given above. The finished design in Normal View is shown below. The Labels below the List Box are kept hidden and will appear only when the Program runs.

    Change the Property Values of the Form and controls, so that your Form and design look exactly like the design given above.

  6. Click on the List Box and display the property sheet (View -> Properties).

  7. Change the List Box's Property Values as given below:

    • Name: dbList
    • Row Source Type: Table/Query
    • Row Source: SELECT [FilesList].[ID], [FilesList].[dbPath] FROM [FilesList]
    • Column Count: 2
    • Column Heads: No
    • Column Widths: 0.2396";1.4271"
    • Bound Column: 2
    • Enabled: Yes
    • Locked: No
    • Multiselect: Simple
    • Tab Index: 0
    • Left: 0.3021"
    • Top: 0.7083"
    • Width: 3.2083"
    • Height: 1.7708"
    • Back Color: 16777215
    • Special Effect: Sunken
  8. Resize the child Label Control, attached to the List Box, to the same size and position it above the List Box. Change the Caption to Database List.

  9. Click on the first Label Control below the List Box, display the Property Sheet, and change the following Properties:

    • Name: lblMsg
    • Visible: No
    • Left: 0.3021"
    • Top: 2.5"
    • Width: 3.2083"
    • Height: 0.5"
    • Back Color: 128
    • Special Effect: Sunken
  10. Display the Property Sheet of the second Label Control and change the following Properties:

    • Name: lblstat
    • Visible: No
    • Left: 0.3021"
    • Top: 3.0417"
    • Width: 3.2083"
    • Height: 0.1667"
    • Back Style: Transparent
    • Back Color: 16777215
    • Special Effect: Flat
    • Border Style: Transparent
  11. Change the following properties of the left-side Command Button:

    • Name: cmdRepair
    • Caption: Repair/Compact
    • Tab Index: 1
    • Left: 0.3021"
    • Top: 3.25"
    • Width: 1.4271"
    • Height: 0.2292"

  12. Change the following properties of the right-side Command Button:

    • Name: cmdClose
    • Caption: Quit
    • Tab Index: 1
    • Left: 2.0833"
    • Top: 3.25"
    • Width: 1.4271"
    • Height: 0.2292"
  13. Change the Properties of the Form. Click on the left top corner of the Form where the left-side and Top design guides (Scales) meet. When you click there, a blue square will appear, indicating that the Form is selected. Display the Property Sheet and click on the All Tab. If that is not the current one, change the following Properties:

    • Caption: External Repair/Compact Utility
    • Default View: Single Form
    • Views Allowed: Form
    • Allow Edits: Yes
    • Allow Deletions: No
    • Allow Additions: No
    • Data Entry: No
    • Scroll Bars: Neither
    • Record Selectors: No
    • Navigation Buttons: No
    • Dividing Lines: No
    • Auto Resize: Yes
    • Auto Center: Yes
    • Pop up: Yes
    • Modal: Yes
    • Border Style: Dialog
    • Control Box: Yes
    • Min, Max Buttons: None
    • Close Button: Yes
    • Width: 3.9063"
  14. Click on the Detail Section of the Form, and change the Height Property:

    • Height: 3.7917"
  15. Create a Header Label at the top with the Caption Compacting Utility, and set the Font Size to 18 Points.

    NB: If you would like to create a Heading with 3D-style characters, as the sample shown above, visit the Page Create 3D Heading on Forms and follow the procedure explained there. You can do it later.

  16. Select the Rectangle Tool from the Toolbox and draw a Rectangle around the Controls as shown on the Design.

    Form Class Module Code.

  17. Display the VBA Module of the Form (View -\> Code), Copy, and Paste the following code into it, and save the Form with the name Compacting.
    Private Sub cmdClose_Click()
    If MsgBox("Shut Down...?", vbYesNo + vbDefaultButton2 + vbQuestion, _"cmdQuit_Click()") = vbYes Then
        DoCmd.Quit
    End If
    End Sub
    
    Private Sub cmdRepair_Click()
    Dim lst As ListBox, lstcount As Integer
    Dim j As Integer, xselcount As Integer
    Dim dbname As String, t As Double, fs, f
    Dim ldbName As String, strtmp As String
    
    'create a temporary folder C:\tmp, if not present
    On Error Resume Next
    Set fs = CreateObject("Scripting.FileSystemObject")
    Set f = fs.GetFolder("c:\tmp")
        If Err = 76 Or Err > 0 Then
           Err.Clear
           fs.createfolder ("c:\tmp")
        End If
    
    On Error GoTo cmdRepair_Click_Err
    
    Me.Refresh
    Set lst = Me.dbList
    lstcount = lst.ListCount - 1
    
    xselcount = 0
    For j = 0 To lstcount
    If lst.Selected(j) Then
        xselcount = xselcount + 1
    End If
    Next
    
    If xselcount = 0 Then
       MsgBox "No Database(s)Selected."
       Exit Sub
    End If
    
    If MsgBox("Ensure that Selected Databases are not in Use. " _
    & vbCrLf & "Proceed...?", vbYesNo + vbDefaultButton2 + vbQuestion, "cmdRepair_Click()") = vbNo Then
       Exit Sub
    End If
    
    For j = 0 To lstcount
        If lst.Selected(j) Then
          dbname = lst.Column(1, j)
           dbname = Trim(dbname)
           ldbName = Left(dbname, Len(dbname) - 3)
           ldbName = ldbName & "ldb" 'for checking the presense of lock file.
           If Len(Dir(ldbName)) > 0 Then 'database is active
              MsgBox "Database: " & dbname v vbCrLf & "is active. Skipping to the Next in list."
              GoTo nextstep
           End If
    
           If MsgBox("Repair/Compact: " & dbname & vbCrLf & "Proceed...?", vbQuestion + vbDefaultButton2 + vbYesNo, "cmdRepair_Click()") = vbYes Then
                Me.lblMsg.Visible = True
                Me.lblStat.Caption = "Working, Please wait..."
                Me.lblStat.Visible = True
                DoEvents
    
                dbCompact dbname 'run compacting
    
                Me.lblStat.Caption = ""
                DoEvents
    
    nextstep:
                t = Timer
                Do While Timer <= t + 7 'delay loop
                   DoEvents 'do nothing
                Loop
            End If
        End If
    Next
    
       Me.lblMsg.Visible = False
       Me.lblStat.Caption = ""
       Me.lblStat.Visible = False
    
    strtmp = "c:\tmp\db1.mdb" 'Delete the temporary file
    If Len(Dir(strtmp)) > 0 Then
      Kill strtmp
    End If
    
    Set fs = Nothing
    Set f = Nothing
    Set lst = Nothing
    
    cmdRepair_Click_Exit:
    Exit Sub
    
    cmdRepair_Click_Err:
    MsgBox Err.Description, , "cmdRepair_Click()"
    Resume cmdRepair_Click_Exit
    End Sub
    

    Private Function dbCompact(ByVal strdb As String)
    Dim t As Long
    Dim xdir As String, strbk As String
    Const tmp As String = "c:\tmp\"
    
    On Error GoTo dbCompact_Err
    
    If Len(Dir(tmp & "db1.mdb")) > 0 Then
        Kill tmp & "db1.mdb"
    End If
    
    t = InStrRev(strdb, "\")
    If t > 0 Then
       strbk = Mid(strdb, t + 1)
    End If
    strbk = tmp & strbk
    
    xdir = Dir(strbk)
    If Len(xdir) > 0 Then
       Kill strbk
    End If
    'Make a Copy in c:\tmp folder as safe backup
    Me.lblMsg.Caption = "Taking Backup of " & strdb & vbCrLf _
    & "to " & tmp
    DoEvents
    
       DBEngine.CompactDatabase strdb, strbk
    
    Me.lblMsg.Caption = "Transferring Objects from " & strdb & vbCrLf _
    & "to " & tmp & "db1"
    DoEvents
    
       DBEngine.CompactDatabase strdb, tmp & "db1.mdb"
    
    ' Delete uncompacted Database and Copy Compacted db1.mdb with
    ' the Original Name
    
    lblMsg.Caption = "Creating " & strdb & " from " & tmp & "db1.mdb"
    DoEvents
    
        If Len(Dir(strdb)) > 0 Then
            Kill strdb
        End If
    
        DBEngine.CompactDatabase tmp & "db1.mdb", strdb
    
    lblMsg.Caption = strdb & " Compacted Successfully." & vbCrLf & "Database backup copy saved at Location: " & tmp
    DoEvents
    
    dbCompact_Err_Exit:
    Exit Function
    
    dbCompact_Err:
    MsgBox Err & " : " & Err.Description, , "dbCompact()"
      Resume dbCompact_Err_Exit
    End Function
    

    You can set the Compacting Form to open at Startup. Select Startup from the Tools Menu. Select Form Compacting in the Display Form/Page Control. To hide the Database Window, remove the check mark from the Display Database Window Option.

    The Trial Run

  18. Open the Compacting Form in Normal view. Select one or more Databases from the List Box for Compacting.

  19. Click the Repair/Compact Command Button.

When you run the program for the first time, it checks for the existence of the folder C:\tmp. If that folder is not found, the program automatically creates it. This directory serves as the working area for the Compacting Utility—regardless of whether the program is executed from the server or a local drive. All backup copies of the compacted databases are stored in this location for safekeeping.

Before initiating the compacting process, the program performs a status check on each selected database to ensure that no users are currently accessing it. If a database is found to be in use, the program will display a notification message. The compacting operation is skipped for that particular database, preventing potential file conflicts or data corruption.

The Label Controls that we have created and kept hidden under the List Box will be made visible. It will be updated with the program's current activity information at different stages of the Compacting Procedure.

Any suggestions for improvement of this Program are welcome.

The Demo Database is now upgraded to MS-Access Version 2016 and can be downloaded from the link below.

Share:

Database Open Close Event Alerts

Introduction.

When your application is installed on a network and shared by multiple users, it’s often useful to monitor database activity, such as which user opens or closes the database, and when these events occur.

In some cases, your database may not be secured (i.e., anyone with access to the shared location can open it). Even if it’s primarily intended for a few trusted users whose Workstation IDs or Network IDs you already know, it’s still possible for unauthorized users to explore it out of curiosity.

To address this, you can implement a monitoring and alert system within the database. When someone opens the database, the system records their workstation or network ID, along with the login time. If an unauthorized user attempts to open it, the system can immediately send a message to that workstation. The intruder will receive a warning message to close the database immediately. This action makes it clear that their activity is being monitored, discouraging future unauthorized access attempts.

You can also use the same mechanism for legitimate administrative purposes. For example:

  • To receive an alert when someone opens the database during maintenance work, so you can prevent data conflicts.

  • To detect when the current active user has closed the database, allowing you to safely make updates.

  • To send a message to an active user directly from your system — for example, requesting them to close the database so you can apply fixes, or notifying them that maintenance tasks are complete,  without needing to contact them by phone or in person.

It’s both interesting and highly practical to automate certain administrative tasks and receive timely feedback from your databases. This allows you to plan and execute maintenance or coordination activities more efficiently,  keeping in constant touch with both your users and databases.

All of these capabilities become possible once your databases can send alert messages directly to your workstation whenever users open or close them. For implementation details, refer to the article titled Sending Alerts to Workstations Based on Process-Related Activities within a Database.” Once you know each user’s workstation ID, you can even send messages back to their PCs directly from your desktop whenever you need to communicate with them.

You can also explore the related article Who Is Online,” where we discuss alternative approaches to these same monitoring concepts.

If you manage multiple applications across the network, you may occasionally receive too many alert messages. That’s not a problem; you can easily turn specific alerts on or off without having to modify any of your databases individually.

At first glance, this might sound like a large or complex project, but it’s actually quite simple to implement. You can set it up in just about ten minutes, and you’ll immediately see it in action. All you need is a Windows network environment in your office, nothing more.

The Alert Message Contents

The Alert Messages must be loaded with the following information when received:

  • User Workstation-ID
  • Date and Time
  • Database PathName
  • Status info (Open/Close)
  • User Network ID
  • MS-Access User ID

Our Network Administrator was kind enough to set my Last Name (PILLAI) as my WorkStation ID. The images of sample Network Messenger Alerts that come to my WorkStation are given below. 

The Database Open Event Alert Message.

Database Close Event Alert Message

All we need for this interesting Trick is a VBA Routine (given below) and 3 text files. The VBA Program must be copied to the Global Module of your Database and called from the Main Switchboard (Control Screen) in the On Open and On Close Event Procedures.

If you have a Library Database already attached to your Databases from a Network Location, then place the main Code in the Library Database only. Then you need to install only two lines of code in the On Open and On Close Event Procedures in the Main Switchboard Form (Control Screen) in your Databases.

Prepare for a Trial Run

But for now, let us try it in one of your Databases installed in a Network Location shared by Users. When you are ready to implement it in other Databases, you can do so following the same procedure. The Names and usage of the three Text files (all of them are Optional), created for your control purposes, are given below:

File-1: AccsCtrl.txt - List of Databases where the Message Alert Programs are running.

File-2: AccLog.txt - Message Alert Log entries for reference purposes.

File-3: Message.BAT - For sending messages and alerts from your PC to your Database Users' Workstation.

  1. Copy and paste the following VBA Code into a Global Module of your Project or Library Database and save it:

    The OpenCloseAlert() Function

    Public Const accmsgtxt As String = "h:\inhsys\comlib\AccsCtrl.txt"
    Public Const acclogtxt As String = "h:\inhsys\comlib\AccsLog.txt"
    
    Public Function OpenCloseAlert(ByVal mstat As String)
    '-----------------------------------------------------------
    'Author: a.p.r. pillai
    'URL   : www.msaccesstips.com
    'Date  : 20/05/2008
    'All Rights Reserved by www.msaccesstips.com
    '-----------------------------------------------------------
    Dim t As Double, WorkStationID As String * 15
    Dim netUserName As String * 15, accUserName As String * 15
    Dim str As String, loc As Integer, AlertMsg As String
    Dim AlertFlag As String,  flag As Boolean
    Dim chk As String, dbpath As String, m_stat As String * 1
    Dim status As String * 8, dttime As String * 22
    
    On Error GoTo OpenCloseAlert_Err
    
    dbpath = CurrentDb.Name
    m_stat = mstat
    str = Dir(accmsgtxt)
    If Len(str) = 0 Then
    'accsctrl.txt File Not Found   
    'ignore ON/OFF flag checking   
    'proceed to Alert Message Section
       GoTo nextstep
    End If
    
    'open the control file and check the Status
    Open accmsgtxt For Input As #1
    AlertFlag = " ": flag = False
    Do While Not EOF(1)
    Input #1, chk
    If flag = False And Left(chk, 5) = "ALERT" Then
       flag = True
       chk = UCase(chk)
       loc = InStr(6, chk, "OFF")
       If loc > 0 Then     'Turn off Alerts from All Databases
         Exit Function
       Else
         GoTo readnext
       End If
    End If
    
    loc = InStr(1, chk, dbpath)
    If loc > 0 Then'database file found, take the flag value
      AlertFlag = Right(Trim(chk), 1)
      Exit Do
    End If
    readnext:
    Loop
    Close #1
    
    If AlertFlag = "0" Or Len(AlertFlag) = 0 Then   'Turn off Alert in this Database
       Exit Function
    End If
    
    nextstep:
    
    WorkStationID = Environ("COMPUTERNAME")
    netUserName = Environ("USERNAME")
    accUserName = CurrentUser
    
    status = IIf(Left(mstat, 1) = "O", "OPEN", "CLOSE")
    dttime = Format(Now(), "mm/dd/yyyy hh:nn:ss")
    
    AlertMsg = LCase(CurrentDb.Name) & " OPEN/CLOSE Status : " & vbCr & vbCr & "STATUS............: " & IIf(Left(mstat, 1) = "O", "OPEN", "CLOSE") & vbCr & "WORKSTATION ID....: " & WorkStationID & vbCr & "NETWORK USERNAME..: " & netUserName & vbCr & "ACCESS USERNAME...: " & accUserName & vbCr 
    
    'insert your Workstation ID replacing the text
     Call Shell("NET SEND  " & AlertMsg, vbHide)
    
    str = Dir(acclogtxt)
    If Len(str) = 0 Then
      GoTo OpenCloseAlert_Exit
    Else
      Open acclogtxt For Append As #1
      Print #1, status; dttime; WorkStationID; netUserName; accUserName; CurrentDb.Name
      Close #1
    End If
    
    OpenCloseAlert_Exit:
    Exit Function
    
    OpenCloseAlert_Err:
    MsgBox Err.Description, , "OpenCloseAlert()"
    Resume OpenCloseAlert_Exit
    End Function
    

    The first two lines in the above code must be placed in the Global Declaration area of the Module, below the Option Declarations, as indicated below.

    Option Compare Database
    Option Explicit
    Public Const accmsgtxt As String = "h:\inhsys\comlib\AccsCtrl.txt"
    Public Const acclogtxt As String = "h:\inhsys\comlib\AccsLog.txt"
    
  2. Copy the following lines in the VBA Module of the Main Switchboard (Control Screen) Form or copy only the middle line into their respective Event Procedures, if they already exist:

    Private Sub Form_Open(Cancel As Integer)
         OpenCloseAlert "Open"
    End Sub
    
    Private Sub Form_Close()
         OpenCloseAlert "Close"
    End Sub
    
  3. We will create the Text Files AccsCtrl.txt and AccsLog.txt in a common location on the Server, where all your Application Users have Access Rights. Change the Server Path h:\inhsys\comlib in the Constant Declaration lines to the common location Path on your Server. Do not use UNC Path specification \\Server\Folder\database.

    Note: The term Path represents the location address of a file without the File Name, but Path Name denotes the location Address including the File Name and File Name Extension.

    Create Text Files

  4. Open Windows Notepad (Start -> Program Files -> Accessories -> Notepad). Copy and paste the following lines into the blank Notepad File:
    ALERT=ON
    H:\FolderName\FolderName\MYDB1.MDB=1
    G:\FolderName\MYDB2.MDB=0
    
  5. Change the second and third lines to point to your Databases on a Server already in use by others. Save the Text File with the name AccsCtrl.txt at the Location on the Server specified in the constant declaration line path given above. Databases can be in any location on the Server.

  6. Select New from Notepad File Menu to open a new text File. Save the empty text file in the same location on the Server with the name AccsLog.txt. The Log details of the Alert Messages that you receive will be saved in this file, too. You can open and view history when needed.

    This file can be created programmatically if it doesn’t already exist. However, I decided to leave that choice to you, depending on whether you want to maintain it or not. If you have multiple applications running with this alert mechanism enabled, the log file may grow rapidly, consuming a significant portion of your disk quota.

    You can experiment with it to observe the frequency of logged events and determine whether ongoing logging is necessary. It’s also a good practice to periodically review and manage the file’s contents — either by deleting older entries or by archiving them to another file on your local drive to keep disk usage under control.

  7. Create Desktop Shortcuts to these Files so that you can open them quickly, and edit or view the contents when needed. Right-click on the Desktop, highlight New, and select Shortcut from the displayed menu. Browse to the location of the AccsCtrl.txt file and select it, click OK, click Next, then click Finish.

    Let us look into the Logic of the Main Program OpenCloseAlert() and how the File AccsCtrl.txt is interpreted, and control the execution of the Program.

    • If you have not created the File AccsCtrl.txt at all (as per the declaration Public Const accmsgtxt As String = "h:\inhsys\comlib\AccsCtrl.txt" In the specified location, you will still receive the Alert Messages, but you cannot control them by switching them off or on at will.

    • If you have created the File AccsCtrl.txt but forgot to add the Database Path Name with flag 1 at the end, then the Alerts will not trigger for that Database.

    • If the first line in this file is ALERT=OFF, then further lines in this file will not be processed and turn off the Alerts from all Databases.

    • Any value after the word ALERT= other than OFF (ON or anything else except space) will be ignored, and will proceed with the individual Database level flag checking. We opted out of checking the ON flag setting because we are doing it at the individual database level to trigger the Alerts. Besides, this line was introduced to switch off all alerts from all databases with one change. If you prefer to control with an individual file-level flag setting (which is explained below), you don't need to put this line at all in this File.

    • If you place the ALERT=OFF statement after a few lines of the Database Path Names (see Step 4) in the Text File, then the program always checks the lines above this statement and executes the program OpenCloseAlert(). This depends on the logic setting (1 or 0) at the Database level. But, Path Names after this line are ignored and never checked.

    • We have added two sample Database Path Names after the first line with Alert status flag =1 and =0 at the end (1= Alerts ON, 0=Alerts OFF). You may add any number of Databases in this way, with flag value 0 or 1 after the equal (=) sign, after installing the Program OpenCloseAlert() in the Database.

    • When the program encounters the Database Path Name, it extracts the last character from that line to check the status. Ensure that you are not adding any other characters after 0 or 1 except white spaces.

    • If the flag is 0, then the Alert Message will be turned off for that Database. Any other value will send it.

    • By adjusting the values in this file, you can control Alerts coming to you without touching any of your Databases.
    • If you have not created the Logfile AccsLog.txt, the program will not generate any error, but the message history will not be maintained. You can delete old records from this file to keep the file size small on the Server.

    • Create copies of these Files periodically as a backup and keep them in a safe place for restoring, if the active one gets corrupted or deleted by mistake.

    The DOS Batch File.

  8. We will create a DOS Batch File on your Desktop for sending messages to your Database Users as and when the need arises. Open Windows Notepad and write the following line:

    NET SEND WorkstationID messagetext
    
  9. Note: The NET SEND Command works under Windows XP only. Later versions of Windows use the MSG Command.   C:\MSG /? - The Command displays the details of different Parameters that can be used with this Command.

    Write the network of a known machine in place of the text 'WorkstationID' and a test message, replacing the text 'message text--.'

  10. Select Save As from the File menu and browse to your Desktop (C:\Documents and Settings\your network ID\Desktop) and save it with the name MESSAGE.BAT. Select All Files in the Save As Type control before saving it. The MESSAGE.BAT name will appear on your Desktop.

  11. Since this file is on your Desktop, you can always right-click on it, select Edit from the displayed menu and open it in Notepad and change the WorkStationID and message text, and close it.

  12. Double-click on the Desktop icon of MESSAGE.BAT File to send the message after making changes. Batch Files are treated as programs, and if you face any security issues, please check with your System Administrator. Alternatively, you can send Network messages directly from the DOS Prompt. Open Run from the Start Menu. Type cmd and click OK. Type the NET SEND command followed by WorkstationID and your Message Text, giving a space between the WorkstationID and the Message, then press Enter Key.

When you implement this method correctly, you can keep track of your Databases, and the log file (AccsLog.txt) will record the history of activities. If you need, you can link this Text File to a Database for analysis purposes and find out the frequency and User-level time spent, and so on.

When you communicate with your Database Users, asking them to open or close the Database, they will also know that you are watching over their activities. You can open and check the AccsLog.txt file contents to find out who is active and for how long, etc.

You must consider securing your Databases for the internal security of Objects and for regulating access rights to different categories of Users if you have not done so already. Read the Pages Microsoft Access Security for details on this very powerful feature. It may take some time to understand all the twists and turns of this feature. But if you start using it, you can learn it over a period of time by experimenting. Believe me, if you are a serious MS-Access Developer, you must learn it. Doesn't matter how long it takes to understand the rules. You can post your doubts over Security issues in the Comments Section. I will extend all possible help that I can give you.

The Trial Run.

Now the stage is all set for trial Runs. Ask one of your Application Users to open the above Database from their Workstation. You must get a similar Pop-up message, like the sample image given above, during both Opening and Closing events. Ask more Users to open the same Database from their PCs, too. You must get Alerts from each instance of the same Database.

You can implement the same Code in other Databases also and add their Path Names in the AccsCtrl.txt file.

Share:

PRESENTATION: ACCESS USER GROUPS (EUROPE)

Translate

PageRank

Post Feed


Search

Popular Posts

Blog Archive

Powered by Blogger.

Labels

Forms Functions How Tos MS-Access Security Reports msaccess forms Animations msaccess animation Utilities msaccess controls Access and Internet MS-Access Scurity MS-Access and Internet Class Module External Links Queries Array msaccess reports Accesstips WithEvents msaccess tips Downloads Objects Menus and Toolbars Collection Object MsaccessLinks Process Controls Art Work Property msaccess How Tos Combo Boxes Dictionary Object ListView Control Query VBA msaccessQuery Calculation Event Graph Charts ImageList Control List Boxes TreeView Control Command Buttons Controls Data Emails and Alerts Form Custom Functions Custom Wizards DOS Commands Data Type Key Object Reference ms-access functions msaccess functions msaccess graphs msaccess reporttricks Command Button Report msaccess menus msaccessprocess security advanced Access Security Add Auto-Number Field Type Form Instances ImageList Item Macros Menus Nodes RaiseEvent Recordset Top Values Variables Wrapper Classes msaccess email progressmeter Access2007 Copy Excel Export Expression Fields Join Methods Microsoft Numbering System Records Security Split SubForm Table Tables Time Difference Utility WScript Workgroup database function msaccess wizards tutorial Access Emails and Alerts Access Fields Access How Tos Access Mail Merge Access2003 Accounting Year Action Animation Attachment Binary Numbers Bookmarks Budgeting ChDir Color Palette Common Controls Conditional Formatting Data Filtering Database Records Defining Pages Desktop Shortcuts Diagram Disk Dynamic Lookup Error Handler External Filter Formatting Groups Hexadecimal Numbers Import Labels List Logo Macro Mail Merge Main Form Memo Message Box Monitoring Octal Numbers Operating System Paste Primary-Key Product Rank Reading Remove Rich Text Sequence SetFocus Summary Tab-Page Union Query User Users Water-Mark Word automatically commands hyperlinks iSeries Date iif ms-access msaccess msaccess alerts pdf files reference restore switch text toolbar updating upload vba code