During the design process in a Microsoft Access database, you may need to find where a particular label Caption is being used. Or perhaps you need to compare the Row Source of combo boxes across multiple forms. The VBA functions below provide a way to capture some control property values in table that you can view or query.
FillObjectControls() – Get property values from all controls on all Forms and Reports.
FillObjectControls_Form() – Get property values from all controls on a particular Form.
FillObjectControls_Report() – Get property values from all controls on a particular Report.
You may run the functions from the Immediate window like this:
?FillObjectControls()
Here is the list of property values that the function stores in the ObjectControls table:
• Name
• ControlType
• ControlSource
• RowSource
• Caption
• ControlTipText
• StatusBarText
• Visible
If the control has an associated label:
• Label Name
• Label Caption
If the control is a subform or subreport:
• SourceObject
Create a new code module and paste in the code below. The functions require 2 tables, which are mapped out at the top of the code.
basObjectControls
Option Compare Database
Option Explicit
'
' basObjectControls() Version 1.0.0
' Copyright © 2023 Extra Mile Data, www.extramiledata.com.
' For questions or issues, please contact [email protected].
' Use (at your own risk) and modify freely as long as proper credit is given.
'
' RUN FillObjectControls()
'
' ObjectControls
' Fields:
' ObjectControlID AutoNumber
' ObjectType
' ObjectName
' ParentObjectName
' ObjectCaption
' ControlName
' ControlControlTypeID Long Integer
' ControlControlType
' ControlControlSource
' ControlRowSource Long Text
' ControlSourceObject
' ControlCaption
' ControlControlTipText
' ControlStatusBarText
' ControlVisible
' ControlLabelName
' ControlLabelCaption
' Processed Yes/No
'
' AccessControlTypes
' Fields:
' ControlTypeConstant
' ControlTypeName
' ControlTypeID Long Integer
' Records:
' 1) Copy to Notepad
' 2) Replace spaces between columns with Tab
' 3) Copy results and paste into AccessControlTypes
'
' acAttachment Attachment 126
' acBoundObjectFrame Bound object frame 108
' acCheckBox Check box 106
' acComboBox Combo box 111
' acCommandButton Command button 104
' acCustomControl ActiveX (custom) control 119
' acEmptyCell Empty Cell 127
' acImage Image 103
' acLabel Label 100
' acLine Line 102
' acListBox List box 110
' acNavigationButton Navigation button 130
' acNavigationControl Navigation control 129
' acObjectFrame Unbound object frame or chart 114
' acOptionButton Option button 105
' acOptionGroup Option group 107
' acPage Page 124
' acPageBreak Page break 118
' acRectangle Rectangle 101
' acSubform Subform/subreport 112
' acTabCtl Tab 123
' acTextBox Text box 109
' acToggleButton Toggle button 122
' acWebBrowser Web browser 128
'
Public Function FillObjectControls(Optional ClearTable As Boolean = True) As Boolean
' This procedure fills the ObjectControls table with control info from
' all Forms and Reports.
' If ClearTable is True, then it empties ObjectControls before starting.
On Error GoTo Err_Handler
Dim strSQL As String
Dim aob As AccessObject
Dim lngCount As Long
Dim lngTotalCount As Long
If ClearTable Then
strSQL = "DELETE * FROM ObjectControls"
CurrentDb.Execute strSQL, dbFailOnError
End If
lngTotalCount = CurrentProject.AllForms.Count + CurrentProject.AllReports.Count
lngCount = 0
' Loop through the Forms.
For Each aob In CurrentProject.AllForms
FillObjectControls_Form aob.Name
lngCount = lngCount + 1
If lngCount Mod 10 = 0 Then
Debug.Print lngCount & " of " & lngTotalCount
DoEvents
End If
Next
' Loop through the Reports.
For Each aob In CurrentProject.AllReports
FillObjectControls_Report aob.Name
lngCount = lngCount + 1
If lngCount Mod 10 = 0 Then
Debug.Print lngCount & " of " & lngTotalCount
DoEvents
End If
Next
' Update ControlControlType.
strSQL = "UPDATE ObjectControls INNER JOIN AccessControlTypes " _
& "ON ObjectControls.ControlControlTypeID = AccessControlTypes.ControlTypeID " _
& "SET ObjectControls.ControlControlType = [AccessControlTypes].[ControlTypeName];"
CurrentDb.Execute strSQL, dbFailOnError
FillObjectControls = True
Exit_Proc:
On Error Resume Next
Set aob = Nothing
Exit Function
Err_Handler:
MsgBox Err.Number & " " & Err.Description, vbCritical, "FillObjectControls()"
FillObjectControls = False
Resume Exit_Proc
End Function
'
Public Function FillObjectControls_Form(FormName As String, _
Optional ClearTable As Boolean = False) As Boolean
' This procedure fills the ObjectControls table with control info for
' the FormName form.
' If ClearTable is True, then it empties ObjectControls before starting.
On Error GoTo Err_Handler
Dim strSQL As String
Dim frm As Form
Dim rst As DAO.Recordset
Dim ctl As Control
Dim ctlLabel As Control
Dim strFormName As String
Dim strControlSourceObject As String
Dim strObjectType As String
Dim intPos As Integer
Dim varParentObjectname
Dim strWhere As String
If ClearTable Then
strSQL = "DELETE * FROM ObjectControls"
CurrentDb.Execute strSQL, dbFailOnError
End If
' See if the form already exists in the table. If it does, then exit.
' Otherwise, add it unprocessed to the table.
strWhere = "ObjectType='Form' AND ObjectName='" & FormName & "'"
If DCount("ObjectControlID", "ObjectControls", strWhere) > 0 Then
FillObjectControls_Form = True
GoTo Exit_Proc
Else
strSQL = "INSERT INTO ObjectControls ( " _
& "ObjectType, " _
& "ObjectName, " _
& "Processed ) " _
& "VALUES ( " _
& "'Form', " _
& "'" & FormName & "', " _
& "False )"
CurrentDb.Execute strSQL, dbFailOnError
End If
strWhere = "ObjectType='Form' AND Processed=False"
Do While DCount("ObjectControlID", "ObjectControls", strWhere) > 0
strSQL = "SELECT * FROM ObjectControls WHERE Processed = False"
Set rst = CurrentDb.OpenRecordset(strSQL)
With rst
.MoveFirst
strFormName = Nz(!ObjectName, "")
If Len(strFormName) = 0 Then
.Edit
!Processed = True
.Update
Else
varParentObjectname = !ParentObjectName
DoCmd.OpenForm strFormName, acDesign, , , , acHidden
Set frm = Forms(strFormName)
.Edit
!ObjectCaption = frm.Caption
!Processed = True
.Update
For Each ctl In frm.Controls
On Error Resume Next
.AddNew
!ObjectType = "Form"
!ParentObjectName = varParentObjectname
!ObjectName = strFormName
!ControlName = ctl.Name
!ControlControlTypeID = ctl.ControlType
!ControlControlSource = ctl.ControlSource
!ControlRowSource = ctl.RowSource
!ControlCaption = ctl.Caption
!ControlControlTipText = ctl.ControlTipText
!ControlStatusBarText = ctl.StatusBarText
!ControlVisible = ctl.Visible
If ctl.Controls.Count > 0 Then
Set ctlLabel = ctl.Controls.Item(0)
!ControlLabelName = ctlLabel.Name
!ControlLabelCaption = ctlLabel.Caption
End If
' If this is a subform, add a new Form record.
If ctl.ControlType = 112 Then
strControlSourceObject = ctl.SourceObject
intPos = InStr(1, strControlSourceObject, ".")
If intPos > 0 Then
strObjectType = Left(strControlSourceObject, intPos - 1)
strControlSourceObject = Right(strControlSourceObject, _
Len(strControlSourceObject) - intPos)
Else
strObjectType = "Form"
End If
!ControlSourceObject = strControlSourceObject
strSQL = "INSERT INTO ObjectControls ( " _
& "ObjectType, " _
& "ObjectName, " _
& "ParentObjectName, " _
& "Processed ) " _
& "VALUES ( " _
& "'" & strObjectType & "', " _
& "'" & strControlSourceObject & "', " _
& "'" & strFormName & "', " _
& "False )"
CurrentDb.Execute strSQL, dbFailOnError
End If
!Processed = True
.Update
On Error GoTo Err_Handler
Next ctl
DoCmd.Close acForm, strFormName, acSaveNo
End If
.Close
End With ' rst
Loop
FillObjectControls_Form = True
Exit_Proc:
On Error Resume Next
rst.Close
DoCmd.Close acForm, strFormName, acSaveNo
Set frm = Nothing
Exit Function
Err_Handler:
MsgBox Err.Number & " " & Err.Description, vbCritical, "FillObjectControls_Form()"
FillObjectControls_Form = False
Resume Exit_Proc
Resume
End Function
'
Public Function FillObjectControls_Report(ReportName As String, _
Optional ClearTable As Boolean = False) As Boolean
' This procedure fills the ObjectControls table with control info for
' the ReportName report.
' If ClearTable is True, then it empties ObjectControls before starting.
On Error GoTo Err_Handler
Dim strSQL As String
Dim frm As Report
Dim rst As DAO.Recordset
Dim ctl As Control
Dim ctlLabel As Control
Dim strReportName As String
Dim strControlSourceObject As String
Dim strObjectType As String
Dim intPos As Integer
Dim varParentObjectname
Dim strWhere As String
If ClearTable Then
strSQL = "DELETE * FROM ObjectControls"
CurrentDb.Execute strSQL, dbFailOnError
End If
' See if the Report already exists in the table. If it does, then exit.
' Otherwise, add it unprocessed to the table.
strWhere = "ObjectType='Report' AND ObjectName='" & ReportName & "'"
If DCount("ObjectControlID", "ObjectControls", strWhere) > 0 Then
FillObjectControls_Report = True
GoTo Exit_Proc
Else
strSQL = "INSERT INTO ObjectControls ( " _
& "ObjectType, " _
& "ObjectName, " _
& "Processed ) " _
& "VALUES ( " _
& "'Report', " _
& "'" & ReportName & "', " _
& "False )"
CurrentDb.Execute strSQL, dbFailOnError
End If
strWhere = "ObjectType='Report' AND Processed=False"
Do While DCount("ObjectControlID", "ObjectControls", strWhere) > 0
strSQL = "SELECT * FROM ObjectControls WHERE Processed = False"
Set rst = CurrentDb.OpenRecordset(strSQL)
With rst
.MoveFirst
strReportName = Nz(!ObjectName, "")
If Len(strReportName) = 0 Then
.Edit
!Processed = True
.Update
Else
varParentObjectname = !ParentObjectName
DoCmd.OpenReport strReportName, acDesign, , , acHidden
Set frm = Reports(strReportName)
.Edit
!ObjectCaption = frm.Caption
!Processed = True
.Update
For Each ctl In frm.Controls
On Error Resume Next
.AddNew
!ObjectType = "Report"
!ParentObjectName = varParentObjectname
!ObjectName = strReportName
!ControlName = ctl.Name
!ControlControlTypeID = ctl.ControlType
!ControlControlSource = ctl.ControlSource
!ControlRowSource = ctl.RowSource
!ControlCaption = ctl.Caption
!ControlControlTipText = ctl.ControlTipText
!ControlStatusBarText = ctl.StatusBarText
!ControlVisible = ctl.Visible
If ctl.Controls.Count > 0 Then
Set ctlLabel = ctl.Controls.Item(0)
!ControlLabelName = ctlLabel.Name
!ControlLabelCaption = ctlLabel.Caption
End If
' If this is a subReport, add a new Report record.
If ctl.ControlType = 112 Then
strControlSourceObject = ctl.SourceObject
intPos = InStr(1, strControlSourceObject, ".")
If intPos > 0 Then
strObjectType = Left(strControlSourceObject, intPos - 1)
strControlSourceObject = Right(strControlSourceObject, _
Len(strControlSourceObject) - intPos)
Else
strObjectType = "Report"
End If
!ControlSourceObject = strControlSourceObject
strSQL = "INSERT INTO ObjectControls ( " _
& "ObjectType, " _
& "ObjectName, " _
& "ParentObjectName, " _
& "Processed ) " _
& "VALUES ( " _
& "'" & strObjectType & "', " _
& "'" & strControlSourceObject & "', " _
& "'" & strReportName & "', " _
& "False )"
CurrentDb.Execute strSQL, dbFailOnError
End If
!Processed = True
.Update
On Error GoTo Err_Handler
Next ctl
DoCmd.Close acReport, strReportName, acSaveNo
End If
.Close
End With ' rst
Loop
FillObjectControls_Report = True
Exit_Proc:
On Error Resume Next
rst.Close
DoCmd.Close acReport, strReportName, acSaveNo
Set frm = Nothing
Exit Function
Err_Handler:
MsgBox Err.Number & " " & Err.Description, vbCritical, "FillObjectControls_Report()"
FillObjectControls_Report = False
Resume Exit_Proc
Resume
End Function