1

Good Afternoon,

I have set up a macro to generate individual certificates based on this thread (Automating Mail Merge using Excel VBA). But the macro has always behaved erratically, working one day, throwing errors at me the next.

The most frequent error I get is that Excel is waiting for another application (Word) to perform an OLE action. But at times there are runtime errors where it doesn't want to know the objects.

I have reworked the macro, hoping to sort the issues once and for all but the current error doesn't like the "End With" before I close the Word. I have 3 "Withs", so why doesn't it like 3 "End Withs". - I don't just want to take out the "End With" because I it makes sense to me that one doesn't open Word for each certificate and close it again. That is asking for problems.

The macro is set to go through the Excel sheet, evaluate column K (r, 11) and if it's empty (meaning the certificate hasn't been generated yet), perform the mailmerge and save the document as a pdf into the defined folder.

This is the code. Can anybody see why VBA has a problem with it? Thanks!

Public Sub MailMergeCert()

Dim bCreatedWordInstance As Boolean
Dim objWord As Word.Application
Dim objMMMD As Word.Document

Dim FirstName As String
Dim LastName As String
Dim Training As String
Dim SeminarDate As String
Dim HoursComp As String
Dim Location As String
Dim Objectives As String
Dim Trainer As String

Dim cDir As String
Dim r As Long
Dim ThisFileName As String

FirstName = sh1.Cells(r, 1).Value
LastName = sh1.Cells(r, 2).Value
Training = sh1.Cells(r, 3).Value
SeminarDate = Format(sh1.Cells(r, 4).Value, "d mmmm YYYY")
HoursComp = sh1.Cells(r, 5).Value
Location = sh1.Cells(r, 6).Value
Objectives = sh1.Cells(r, 7).Value
Trainer = sh1.Cells(r, 8).Value

'Your Sheet names need to be correct in here
Set sh1 = ActiveWorkbook.Sheets("Ultrasound")


'Setup filenames
Const WTempName = "Certificate_Ultrasound_2017.docx" 'Template name

'Data Source Location
cDir = ActiveWorkbook.Path + "\" 'Change if required
ThisFileName = ThisWorkbook.Name

On Error Resume Next

'Create Word instance
bCreatedWordInstance = False
Set objWord = CreateObject("Word.Application")

If objWord Is Nothing Then
  Err.Clear
  Set objWord = CreateObject("Word.Application")
  bCreatedWordInstance = True
  End If

If objWord Is Nothing Then
    MsgBox "Could not start Word"
    Err.Clear
    On Error GoTo 0
    Exit Sub
End If

' Let Word trap the errors
On Error GoTo 0

' Set to True if you want to see the Word Doc flash past during construction
objWord.Visible = False

'Open Word Template
Set objMMMD = objWord.Documents.Open(cDir + WTempName)
objMMMD.Activate

'Merge the data
With objMMMD
.MailMerge.OpenDataSource Name:=cDir + ThisFileName, _
    sqlstatement:="SELECT *  FROM `Ultrasound$`"   ' Set this as required

lastrow = Sheets("Ultrasound").Range("A" & Rows.Count).End(xlUp).Row
r = 2

For r = 2 To lastrow
    If IsEmpty(Cells(r, 11).Value) = False Then GoTo nextrow

With objMMMD.MailMerge  'With ActiveDocument.MailMerge
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
  .FirstRecord = r - 1
  .LastRecord = r - 1
  .ActiveRecord = r - 1
End With
.Execute Pause:=False
End With

'Save new file PDF
Dim UltrasoundCertPath As String
UltrasoundCertPath = "C:\Users\305015724\Documents\ApplicationsTraining\2016\Ultrasound\"
Dim YYMM As String
YYMM = Format(sh1.Cells(r, 16).Value, "YYMM")
Dim NewFileNamePDF As String
NewFileNamePDF = YYMM & "_" & sh1.Cells(r, 3).Value & "_" & sh1.Cells(r, 7).Value '& ".pdf" 'Change File Name as req'd"
objWord.ActiveDocument.ExportAsFixedFormat UltrasoundCertPath & NewFileNamePDF, ExportFormat:=wdExportFormatPDF

End With


' Close the Mail Merge Main Document
objMMMD.Close savechanges:=wdDoNotSaveChanges
Set objMMMD = Nothing
If bCreatedWordInstance Then
objWord.Quit
End If

Set objWord = Nothing
Cells(r, 11).Value = Date

0:
Set objWord = Nothing

nextrow:
Next r


End Sub
Community
  • 1
  • 1
  • 2
    You have three `End With` statements within your `For r` loop, but only two `With` statements. If you indent your code, you will see the issue. (Maybe I should put in a plug here for [Rubber Duck](http://rubberduckvba.com) - which a few of the VBA experts here have been involved in developing.) – YowE3K May 11 '17 at 03:01
  • 1
    Just to be explicit, With/End With is a control structure, just like For/Next, If/Then/Else, Do/Loop, etc.. Like all control structures, they cannot straddle other control structures. – Rich Holton May 11 '17 at 03:16
  • 1
    Also, if you don't already, I urge you to put "Option Explicit" as the first line of each of your code modules. This will cause a compile error for any undeclared variables, and is very helpful in preventing some types of odd macro behavior. – Rich Holton May 11 '17 at 03:31

1 Answers1

4

If you indent your code and get rid of the "unimportant" stuff, you end up with this:

Public Sub MailMergeCert()
    '...
    With objMMMD
        '...
        For r = 2 To lastrow
            '...
            With objMMMD.MailMerge
                '...
                With .DataSource
                    '...
                End With
                '...
            End With
            '...
        End With
        '...
    Next r

End Sub

If you look at that, you soon see that you have a mismatch of With/End With blocks and For/Next loops.

Because you only have two With statements within the For loop, but you have three End With statements, the compiler gets "confused" and insists that you correct the error.

YowE3K
  • 23,852
  • 7
  • 26
  • 40
  • Okay, above worked but a new error cropped up. I work with these expressions a lot (most of my macros send emails out of Excel so I'm not sure why it suddenly has a problem. I had error 424, declared, error 1004, removed the Set. Now I get a Compile Error, invalid qualifier. Dim sh1 As String sh1 = ActiveWorkbook.Sheets("Ultrasound") FirstName = sh1.Cells(r, 1).Value – Christine Rieger May 11 '17 at 04:46
  • You have to `Set` objects, so `Set sh1 = ActiveWorkbook.Sheets("Ultrasound")` – YowE3K May 11 '17 at 04:58
  • The error for that is Compile Error, Object required. Since it is declared, I'm not sure what it wants. – Christine Rieger May 12 '17 at 02:13
  • @ChristineRieger Oops - sorry - I didn't notice that you had declared it incorrectly as well (it's hard to read code in comments) - the correct declaration is `Dim sh1 As Worksheet` - you were declaring it as a `String`. – YowE3K May 12 '17 at 02:40
  • Back to runtime error 1004, application-defined or object-defined error. I'm going in circles. (Is that the problem, circular reference :-)?) – Christine Rieger May 12 '17 at 04:24
  • @ChristineRieger `Dim sh1 As Worksheet` `Set sh1 = ActiveWorkbook.Sheets("Ultrasound")` `FirstName = sh1.Cells(r, 1).Value` should work (assuming the active workbook has a sheet called "Ultrasound" and that your variable `r` is between 1 and 1048576) – YowE3K May 12 '17 at 04:27
  • Thanks @YowE3K. I had the r too far down. But now I'm back to it waiting for the Word to perform (which is the error I was trying to clear to start with). The code opens Word. I have nothing else open in Word. But it won't open the template "Set objMMMD = objWord.Documents.Open(cDir + WTempName)". And for some real fun, when I try again, it throws up run time error 462. Now that's a new one. – Christine Rieger May 12 '17 at 06:41
  • @ChristineRieger Apart from the fact that you use a `+` instead of `&` for concatenation, I don't see anything particularly wrong with that line. (And VBA usually copes with the `+`, so I don't think that is causing an issue.) I suggest you raise a new question, so that you can show your current code - without seeing how the code has been changed it is a bit hard to comment on what could be wrong. (And I'm not a MS Word expert, so a new question might draw attention from someone who might see the problem quicker than I will.) – YowE3K May 12 '17 at 07:49
  • I was aware of the limitation with the comments. thanks @YowE3K. will raise a new case. Thanks for your help. (I was wondering about the + but they were in the code so didn't touch) – Christine Rieger May 12 '17 at 08:15