In this example, I use a Visual Basic 5 front end to interrogate a user-selected Microsoft Access database for all the reports it contains. A user can then select a report by name and filter it according to the criteria selected on screen. (See Figure 3-8.) The result is viewable on screen in Print Preview mode or is printable to paper.
Folder: | CHAP03\ReportInAccess |
Dependencies: | Company Stock.mdb Microsoft Common Dialog Control 5.0 Microsoft Windows Common Controls 5.0 Microsoft DAO 3.5 Object Library |
Project Name: | ReportsInAccess.vbp |
Instructions: | Load Visual Basic 5, and open the ReportsInAccess.vbp file. Press Ctrl+F5 to run. |
The starting point for this example is in the Company Stock.mdb database, where a query is designed to support the example’s report requirement. The qryUniverseOfCompanies query is created with all possible fields available for report use. No filtering is performed within the query because we will use the WHERE clause option of OpenReport. (This ensures that the user has total flexibility over what data will be returned in the report.) Two macros are also created: OpenReport, which supports the alternative method of opening Access 2 MDB files where no Access VBA object model is available for communication with Access; and CloseReport, which exits the Access application when the user closes the report.
Figure 3-8 Report selection utilizing the Microsoft Access report writer
The OpenReport and CloseReport macros contain the following functions and commands:
The rptCompanyUniverse report is then designed with two key properties set: Record Source set to qryUniverseOfCompanies, and On Close set to the macro CloseReport. These settings ensure that the right data is being used with the report and that the Access application will terminate when the user quits the report. This feature is important if you consider the problems that can occur if the user has free rein over the database window, which in this example is hidden behind the report.
Now we are left with the task of providing the user with the tools to gain access to this report. Two components are included in ReportsInAccess.vbp: the module modReportsInAccess, which loads the main form on start-up; and the main form frmReportsInAccess, which provides the user with an interface for reporting. Within frmReportsInAccess, a private variable is defined to hold the database filename in which the report resides:
Private fm_sDatabaseFileName As String
In the cmdOpenDatabase_Click procedure, we determine what reports are available in the Access database. Two points are critical:
Because of these two points, it is impossible to determine what reports are available to access the system MSysObjects table held within the Access database. This table provides details of all objects within an Access database, from tables to reports. Reports are identified by the Type data column having the value -32764. (To view systems tables with Access, you need to select Options from the Tools menu and enable the View System Objects option. Here is the code in the cmdOpenDatabase_Click routine to retrieve the report names into a list box:
' Define the variables required to access the database.
Dim ws As Workspace
Dim db As Database
Dim rs As Recordset
' Find the database the user wants.
dlg.Filter = "Database (*.mdb)|*.mdb"
dlg.InitDir = App.Path
dlg.ShowOpen
If dlg.filename & "" <> "" Then
fm_sDatabaseFileName = dlg.filename
End If
txtDatabase = fm_sDatabaseFileName
Me.MousePointer = vbHourglass
' Make sure that we have a filename to work with.
If txtDatabase <> "" Then
lstReports.Clear
' Open a Jet workspace, and get the database.
Set ws = CreateWorkspace("", "Admin", "", dbUseJet)
Set db = ws.OpenDatabase(fm_sDatabaseFileName)
' Read the system table to find all reports.
Set rs = _
db.OpenRecordset _
("Select Name From MSysObjects " & _
"Where Type = -32764 Order By Name", _
dbOpenSnapshot, dbReadOnly)
' Load any reports into the list box.
If rs.RecordCount > 0 Then
rs.MoveFirst
Do Until rs.EOF
lstReports.AddItem rs!Name
rs.MoveNext
Loop
lstReports.ListIndex = 0
End If
' Close all objects.
rs.Close
Set rs = Nothing
db.Close
Set db = Nothing
ws.Close
Set ws = Nothing
End If
Me.MousePointer = vbDefault
The code used to activate the report is split into two different methods: the Access 2 method, which fires a Shell command to load Access and execute the OpenReport macro created earlier to display the report; and the Access VBA method, which uses the DoCmd.OpenReport method to display the report. The code to place a report into Print Preview follows:
Private Sub cmdPreview_Click()
' Create an Access object.
Dim objAccess As Object
Me.MousePointer = vbHourglass
' Make sure a report is selected.
If lstReports.ListIndex <> -1 Then
' Which Access method has been selected?
Select Case optAccessVersion(0).Value
Case True 'Access 2.0
' Provide the parameters in string format
' delimited by |.
' /X executes an Access macro.
' /Cmd provides additional string data on the
' command line.
Shell "Msaccess.exe " & fm_sDatabaseFileName _
& " /X OpenReport /Cmd " & lstReports & _
"|2|" & sBuildWhereClause, vbMaximizedFocus
Case False ' Access 7/97
' Get the Access database application object.
Set objAccess = _
GetObject(fm_sDatabaseFileName)
' With the application object, open the report
' and maximize it within Access's MDI parent
' window.
With objAccess.Application
.DoCmd.OpenReport lstReports, acPreview, _
, sBuildWhereClause
.DoCmd.Maximize
End With
' Close the object.
Set objAccess = Nothing
End Select
End If
Me.MousePointer = vbDefault
This example provides a simple solution for accessing Access reports from within other component applications. Given the drawbacks mentioned earlier, though, I don’t recommend that you attempt to provide too much reporting to your users via the Access report writer.