Obtain Form, Control and Property Data from a Different Database - ms-access

I'm trying to figure out how to get form, control and property data from an Access form that is not in the Access database from where I start the code. I have figured out how to get the data from within the database but I cant figure out how to get the data from a form outside of the database.
I thought that if I were to set the foreign database to the current database, my code would work. However, after executing "For Each frm In appAccess.Forms," the cursor goes to "End Sub."
I tried to work with containers and I was able to return the form name but I wasn't able to figure out how to loop through the controls and properties collections.
Below is the code associated with my first thought. My end objective is to be able to save form data in a different database. Is there a small error with my code or is there a different method I should use to get the data?
Sub GetControlForm()
Dim strPath As String
Dim frm As Form
Dim ctrl As Control
Dim prop As Property
Dim appAccess As New Access.Application
Dim dbs As DAO.Database
strPath = "C:\Users\Tyrone\Desktop\Test14.accdb"
Set appAccess = CreateObject("Access.Application")
appAccess.OpenCurrentDatabase (strPath)
'MsgBox appAccess.CurrentDb.Name
For Each frm In appAccess.Forms
MsgBox frm.Name
For Each ctrl In frm.Controls
MsgBox ctrl.Name
MsgBox ctrl.ControlType.TypeName
MsgBox TypeName(ctrl)
For Each prop In ctrl.Properties
If prop.Name = "RowSource" Then
MsgBox "stop it"
End If
If (TypeName(ctrl) = "ComboBox" Or TypeName(ctrl) = "TextBox") And (prop.Name = "RowSource" Or prop.Name = "ControlSource") Then
MsgBox prop.Value
End If
Next prop
Next ctrl
Next frm
End Sub

The reason your For Each has nothing to loop through is that the forms in the remote database are not open. Per the documentation:
"The properties of the Forms collection in Visual Basic refer to forms
that are currently open."
Try this:
Sub GetControlForm()
Dim strPath As String
Dim obj As AccessObject
Dim frm As Form
Dim ctrl As Control
Dim prop As Property
Dim appAccess As New Access.Application
Dim dbs As DAO.Database
strPath = "C:\Users\Tyrone\Desktop\Test14.accdb"
Set appAccess = CreateObject("Access.Application")
appAccess.OpenCurrentDatabase (strPath)
'MsgBox appAccess.CurrentDb.Name
For Each obj In appAccess.CurrentProject.AllForms
appAccess.DoCmd.OpenForm obj.Name
Set frm = appAccess.Forms(obj.Name)
MsgBox frm.Name
For Each ctrl In frm.Controls
MsgBox ctrl.Name
'MsgBox ctrl.ControlType.TypeName
MsgBox TypeName(ctrl)
For Each prop In ctrl.Properties
If prop.Name = "RowSource" Then
MsgBox "stop it"
End If
If (TypeName(ctrl) = "ComboBox" Or TypeName(ctrl) = "TextBox") And (prop.Name = "RowSource" Or prop.Name = "ControlSource") Then
MsgBox prop.Value
End If
Next prop
Next ctrl
appAccess.DoCmd.Close acForm, frm.Name
Next obj
Set frm = Nothing
appAccess.CloseCurrentDatabase
Set appAccess = Nothing
End Sub

Related

Parsing hyperlinks from Access VBA to Word template

I'm using VBA in Access 2010 form to populate a Word template with data from my tables.
What I can't achieve so far is inserting a hyperlink in the text.
To make things easier for me I'm inserting all the data into table in the template like this:
Private Sub button_Click()
On Error GoTo myError
Dim objWRD As Object 'Word.Application
Dim objDoc As Object 'Word.Document
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strRecords As String
'open a query and prepare the data'
Set db = CurrentDb()
Set qfd = db.QueryDefs("my_query")
Set rs = qfd.OpenRecordset()
'open a Word template'
Set objWRD = CreateObject("Word.Application")
objWRD.Visible = True
Set objDoc = objWRD.Documents.Add("path_to_my_document_template", , , True)
objWRD.ScreenUpdating = False
'insert records into template'
Dim i As Integer
i = 1
While Not rs.EOF
objDoc.Tables(i).Cell(2, 1).Range.Text = "" & rs("hyperlink")
objDoc.Tables(i).Cell(2, 2).Range.Text = "" & rs("description")
rs.MoveNext
i = i + 1
Wend
rs.Close
Set rs = Nothing
leave:
Exit Sub
myError:
MsgBox Error$
Resume Next
End Sub
Can anyone please help me to insert a working hyperlink to the template into rs("hyperlink") place?
Where you reference the table cell to hold the hyperlink, try this:
objDoc.Hyperlinks.add Anchor:=objDoc.tables(i).Cell(2, 1).Range, _
Address:=rs("hyperlink")
And to add additional text to the same cell (In this case I'm inserting "Text to Insert" prior to the hyperlink.
With objDoc.Tables(i).Cell(2, 1).Range
.Collapse Direction:=wdCollapseStart
.Text = "Text to Insert" & Chr(11)
End With
so your While Loop would look something like this:
Dim i As Integer
i = 1
While Not rs.EOF
objDoc.Hyperlinks.add Anchor:=objDoc.Tables(i).Cell(2, 1).Range, _
Address:=rs("hyperlink")
With objDoc.Tables(i).Cell(2, 1).Range
.Collapse Direction:=wdCollapseStart
.Text = "Text to Insert" & Chr(11)
End With
objDoc.Tables(i).Cell(2, 2).Range.Text = "" & rs("description")
rs.MoveNext
i = i + 1
Wend

How can I create button to search database column names in MS Access?

I am trying to create a button in MS Access 2013 that allows a user to search a database for a column containing input text. I was able to find the search code in this post ( Find a table when you know the name of a column? ) but I can't figure out how to bind it to a button. Also when I run the search function from main it doesn't give any output. The only way I can get the search function to work is to hard code the search string into the function.
Sub Main()
Dim inStr As String
ListTablesWithColumnNamesContaining (InputBox("Name contains", "Search"))
End Sub
Public Sub ListTablesWithColumnNamesContaining(ByVal pText As String)
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Set db = CurrentDb
For Each tdf In db.TableDefs
For Each fld In tdf.Fields
If InStr(1, fld.Name, "pText", vbTextCompare) > 0 Then
Debug.Print tdf.Name & ":", fld.Name
End If
Next fld
Next tdf
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
End Sub
You should create a form, put a button inside it choosing button from the Design menu tab.
Then you need to double click the button, and you will open the properties window. Inside this window in the event tab, you need to double click the "on click" row and then press the ".." button on the side.
Now you should see the VBA Editor with the cursor inside this function:
Private function button1_onClick (....)
End Function
You can copy and paste your code here inside and obtain this:
Private function button1_onClick (....)
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Dim pText As String
pText = InputBox("Name contains", "Search")
Set db = CurrentDb
For Each tdf In db.TableDefs
For Each fld In tdf.Fields
If InStr(1, fld.Name, pText, vbTextCompare) > 0 Then
Msgbox tdf.Name & ":" & fld.Name
End If
Next fld
Next tdf
Set fld = Nothing
Set tdf = Nothing
Set db = Nothing
End Function
Note that, as HansUp commented, you need to remove the quotes surrounding pText. I've also put the InputBox command directly inside this function and substituted the debug.print with a Message Box.

Passing Functions through Sub Procedure

I am trying to call a function when running a sub proecudere, however, I keep getting an error message saying "Argument not optional", can someone help?
Code as follows:
Public Sub ret()
Dim FSO As New Scripting.FileSystemObject
Const cstrFolderF = "\\tblSCFLAGCHECKER.txt"
If FSO.FileExists(cstrFolderF) Then
DoCmd.RunSQL "DELETE * FROM [tblSCFLAG_CHECKER]"
DoCmd.TransferText acImportDelim, "tblSCFLAG_CHECKER", "tblSCFLAG_CHECKER", cstrFolderF, True
changefieldnames
Else
'SCAnswer = MsgBox("SC Flags does not exist, do you wish to continue?", vbYesNo Or vbQuestion Or vbDefaultButton2)
'If SCAnswer = vbNo Then Exit Sub
End If
End Sub
Private Sub changefieldnames()
Dim db As Database
Dim tdf As TableDef
Dim n As Object
Set db = CurrentDb
Set tdf = db.TableDefs("tblSCFLAG_CHECKER")
For Each n In tdf.Fields
If n.Name = "?Person ID" Then n.Name = "Person ID"
Next n
Set tdf = Nothing
Set db = Nothing
End Sub
Your changefieldnames function requires two arguments but you give none in the call after
DoCmd.TransferText acImportDelim, "tblSCFLAG_CHECKER", "tblSCFLAG_CHECKER", cstrFolderF, True
changefieldnames
As a remark: you should try to debug your code instead of just posting an error without even stating where exactly the error occurs.

VBA ActiveDocument Concerns / Alternatives?

I'm using VBA in access to open up a protected word template, fill in the data, and then re-protect it.... this way, if the database system goes down, the word template can still be used manually in its protected state.
I have just started using VBA and in this line:
If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect Password:=""
End If
I'm concerned that whilst running the code in access, that if the user opens up another word document and makes it the focus, that it will occidentally get protected instead of the other. How do I keep active focus on the document I'm writing to... or do I need to reference my document somehow using WordApp.protect (or something similar that works)
Private Sub Command0_Click()
Dim WordApp As Word.Application
Dim strDatabasePath As String
Dim strTemplatePath As String
Dim strTemplate As String
Dim strJobTitle As String
Dim strFile As String
strFile1 = "testcoc.dotx"
strFile2 = "testcoc-private.dotx"
strDatabasePath = CurrentProject.Path & "\"
strTemplatePath = "\templates\"
strTemplate = strDatabasePath & strTemplatePath & strFile2
On Error Resume Next
Set WordApp = GetObject(, "Word.Application")
If Err.Number <> 0 Then
Set WordApp = CreateObject("Word.Application")
End If
On Error GoTo ErrHandler
WordApp.Visible = True
WordApp.WindowState = wdWindowStateMaximize
WordApp.Documents.Add Template:=strTemplate, NewTemplate:=True
'strJobTitle = DLookup("JobTitle", "Job", "JobNum = " & [JobType])
strJobTitle = DLookup("JobTitle", "Job", "JobNum = 'J0456'")
With WordApp.Selection
'Unprotect the file
If ActiveDocument.ProtectionType <> wdNoProtection Then
ActiveDocument.Unprotect Password:=""
End If
.Goto what:=wdGoToBookmark, Name:="bm_0_4"
.TypeText strJobTitle
End With
'Reprotect the document.
'If ActiveDocument.ProtectionType = wdNoProtection Then
'ActiveDocument.Protect _
'Type:=wdAllowOnlyFormFields, NoReset:=True, Password:=""
'End If
DoEvents
WordApp.Activate
Set WordApp = Nothing
Exit Sub
ErrHandler:
Set WordApp = Nothing
End Sub
Thank You
I haven't tried this but WordApp.Documents.Add Template:=strTemplate, NewTemplate:=True does return the new document. So I would do something like
Dim doc as Word.Document
Set doc = WordApp.Documents.Add(Template:=strTemplate, NewTemplate:=True)
and reference doc throughout my code instead of ActiveDocument. It seems like doing that should get help you avoid the particular situation you're concerned about.

Determine if Subform/Subreport Has a Form or a Report Loaded in MS Access

I have a Subform/Subreport control displayed on a Form in an Access 2010 database, and I use it to display both Forms and Reports. I have a few event handlers in which I need to know whether a Report is currently loaded into the Subform/Subreport control, or if it's a Form that's loaded. I have tried all of the following to no avail.
Any of the following conditions
If IsEmpty(NavigationSubform.Form) Then '...
If IsNull(NavigationSubform.Form) Then '...
If IsOject(NavigationSubform.Form) Then '...
If NavigationSubform.Form Is Nothing Then '...
If NavigationSubform.Form Is Null Then '...
If Nz(NavigationSubform.Form) Then '...
If (Not NavigationSubform.Form) = -1 Then '... This is a trick I use to check for uninitialized arrays
Results in
Run-time error '2467':
The expression you entered refers to an object that is closed or doesn't exist.
Is there some way that I can check whether a Subform/Subreport control currently has a Form or Report loaded without intentionally causing an error?
I don't believe that there is a way to reliably perform the check without error trapping, so you may want to wrap the code in a Public Function and put it into a regular VBA Module:
Public Function CheckSubformControlContents(ctl As SubForm) As String
Dim obj As Object, rtn As String
rtn = "None"
On Error Resume Next
Set obj = ctl.Form
If Err.Number = 0 Then
rtn = "Form"
Else
On Error Resume Next
Set obj = ctl.Report
If Err.Number = 0 Then
rtn = "Report"
End If
End If
Set obj = Nothing
On Error GoTo 0
CheckSubformControlContents = rtn
End Function
Then your form code can simply call CheckSubformControlContents(Me.NavigationSubform).
Here are two functions that work in Access 2013 for determining if a name is a Report or a Form.
Once that is determined the IsLoaded function of AllForms or AllReports can be used. Note that dbs is an object and rpt or frm are AccessObjects not forms or reports
Public Function IsForm(FormName As String) As Boolean
Dim dbs As Object
Dim frm As AccessObject
Set dbs = Application.CurrentProject
IsForm = False
For Each frm In Application.CurrentProject.AllForms
If frm.Name = FormName Then
IsForm = True
Exit For
End If
Next frm
Set frm = Nothing
Set dbs = Nothing
End Function
Public Function IsReport(ReportName As String) As Boolean
Dim dbs As Object
Dim rpt As AccessObject
Set dbs = Application.CurrentProject
IsReport = False
For Each rpt In Application.CurrentProject.AllReports
If rpt.Name = ReportName Then
IsReport = True
Exit For
End If
Next rpt
Set rpt = Nothing
Set dbs = Nothing
End Function
Here is a program that uses the above functions:
Public Sub EnumerateTaggedControls(ReportName As String, MyTag As String)
Dim dbs As Object
Dim rpt As Report
Dim frm As Form
Dim col As Controls
Dim ctl As Control
Dim left As Integer
Dim top As Integer
Dim width As Integer
Dim height As Integer
Dim tag As String
Dim i As Integer
Const format1 As String = "0000 "
Set dbs = Application.CurrentProject
If IsForm(ReportName) Then
If dbs.AllForms(ReportName).IsLoaded Then
DoCmd.OpenForm ReportName, acViewDesign
Set frm = Forms(ReportName)
Set col = frm.Controls
End If
Else
If dbs.AllReports(ReportName).IsLoaded Then
DoCmd.OpenReport ReportName, acViewDesign
Set rpt = Reports(ReportName)
Set col = rpt.Controls
Else
Debug.Print ReportName & " is not a loaded form or report."
Exit Sub
End If
End If
Set dbs = Nothing
Debug.Print Tab(53); "Left Top Width Height"
For Each ctl In col
With ctl
left = .Properties("Left")
top = .Properties("Top")
width = .Properties("Width")
height = .Properties("Height")
tag = Nz(.Properties("Tag"), vbNullString)
If MyTag = "" Then
i = 1
Else
i = InStr(1, tag, MyTag)
End If
If i > 0 Then
Debug.Print .Name & ">"; Tab(33); tag; Tab(53); Format(left, format1) & Format(top, format1) & Format(width, format1) & Format(height, format1)
End If
End With
Next ctl
Debug.Print "====================================================="
Set ctl = Nothing
Set rpt = Nothing
Set col = Nothing
Set frm = Nothing
End Sub
I hope this meets your requirements.