I have a Mail Merge Document which is controlled via VBA. After the user selects the records he wants to print, I want these to get a print date set in the database. For that I need a list of the records included in the mail merge.
I tried using the .Included property, setting ThisDocument.MailMerge.DataSource.ActiveRecord = wdFirstRecord
(I later removed the wdFirstRecord
in favour of 1
since it was giving me trouble)
and then checking for ThisDocument.MailMerge.DataSource.Included
to be true but got a 5852 runtime-error "Object not available". EDIT: I used the following code to iterate over the records. When I remove either of the commented .Included statements, I get said error. (The execution does not feel as slow as yesterday anymore, though it is not especially fast.)
Function outputRecords(Optional limitRecords = -1)
With ThisDocument.MailMerge.DataSource
Dim str
For currentFieldNameIndex = 1 To .FieldNames.Count
str = str & .FieldNames(currentFieldNameIndex) & vbTab
Next
Debug.Print str
For currentRecordIndex = 1 To .RecordCount
If currentRecordIndex <= limitRecords Or limitRecords < 0 Then
.ActiveRecord = currentRecordIndex
str = ""
For currentDataFieldIndex = 1 To .DataFields.Count
str = str & .DataFields(currentDataFieldIndex) & vbTab
Next
'Debug.Print str
End If
'.Included = True
'Debug.Print .Included
Next
End With
End Function
Is there a solution to know which records are selected by the user?
About my document: After some general computation, the data source is linked to the document using
Dim sql As String
sql = "SELECT * FROM `Sheet0$` "
sql = sql & "WHERE ((`" & photoPathHeader & "` > '') AND (`" & photoLastEditHeader & "` >= #" & Format(printFromDate, "yyyy-mm-dd") & "#)) "
sql = sql & "ORDER BY `klasse#name` ASC"
ThisDocument.MailMerge.OpenDataSource _
name:=ThisDocument.Path & "\" & ThisDocument.Variables("masterDataFileName"), _
SQLStatement1:=sql, _
ReadOnly:=True, LinkToSource:=True
a dialog where the user can select individual records for printing is shown. I used this code for that:
Application.Dialogs(wdDialogMailMergeRecipients).Display
And finally, the Mail Merge is executed using
ThisDocument.MailMerge.Execute
Many thanks in advance!
Thanks to @yokki's answer, I was able to combine that with what I know and ended up with the following
Sub listIncluded()
Dim LastRecord As Long
With ActiveDocument.MailMerge.DataSource
' Storing the index of the last record for later use
.ActiveRecord = wdLastRecord
LastRecord = .ActiveRecord
.ActiveRecord = wdFirstRecord
Do
Debug.Print .ActiveRecord
DoEvents
If .ActiveRecord = LastRecord Then Exit Do
.ActiveRecord = wdNextRecord
Loop Until .ActiveRecord > LastRecord ' Note this will never be satisfied and the loop will always be exited via the Exit Do statement
End With
End Sub
I find the WdMailMergeActiveRecord enumeration a bit confusing but this works.
The original answer threw a 5853 Invalid parameter
error on the wdNextRecord
if the last included record had already been reached and was not equal to the last record overall (i.e. the last record was not included). I circumvented this issue by storing the index of the last record into a local variable and using that to check if the last included record was reached.
Thank you very much to everyone who helped!
As briefly pointed out in a comment, I already have a list of all the data in the data source as an array since I also use it in other parts of the script. I used the following statement for that
numRows = wks.Range("A1").CurrentRegion.Rows.Count
masterData = wks.Range("A1").CurrentRegion.Offset(RowOffset:=1).Resize(RowSize:=numRows).Value
wks
refers to an Excel worksheet object.