MailMerge из Excel — ошибочное поведение макроса

Добрый день,

Я настроил макрос для создания отдельных сертификатов на основе этого потока (Автоматизация слияния с помощью Excel VBA). Но макрос всегда вел себя хаотично, работал один день, а на следующий выдавал мне ошибки.

Наиболее частая ошибка, которую я получаю, заключается в том, что Excel ожидает другого приложения (Word) для выполнения действия OLE. Но иногда возникают ошибки времени выполнения, когда он не хочет знать объекты.

Я переработал макрос, надеясь решить проблемы раз и навсегда, но текущая ошибка не любит «Конец с», прежде чем я закрою Word. У меня 3 "С", так почему бы не 3 "Конца с". - Я не просто хочу убрать «Конец с», потому что мне кажется, что нельзя открывать Word для каждого сертификата и снова закрывать его. Это напрашивается на проблемы.

Макрос настроен на просмотр листа Excel, оценку столбца K (r, 11) и, если он пуст (это означает, что сертификат еще не создан), выполнить слияние и сохранить документ в формате pdf в указанную папку.

Это код. Кто-нибудь может понять, почему у VBA с этим проблемы? Спасибо!

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

person Christine Rieger    schedule 11.05.2017    source источник
comment
У вас есть три оператора End With в цикле For r, но только два оператора With. Если вы сделаете отступ в своем коде, вы увидите проблему. (Возможно, мне следует добавить сюда ссылку на Rubber Duck, в разработке которой принимали участие несколько экспертов по VBA. .)   -  person YowE3K    schedule 11.05.2017
comment
Просто для ясности, With/End With — это управляющая структура, такая же, как For/Next, If/Then/Else, Do/Loop и т. д. Как и все управляющие структуры, они не могут охватывать другие управляющие структуры.   -  person Rich Holton    schedule 11.05.2017
comment
Кроме того, если вы еще этого не сделали, я настоятельно рекомендую вам поместить Option Explicit в первую строку каждого из ваших модулей кода. Это вызовет ошибку компиляции для любых необъявленных переменных и очень полезно для предотвращения некоторых типов странного поведения макроса.   -  person Rich Holton    schedule 11.05.2017


Ответы (1)


Если вы сделаете отступ в своем коде и избавитесь от «неважных» вещей, вы получите следующее:

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

Если вы посмотрите на это, вы вскоре увидите, что у вас есть несоответствие With/End With блоков и For/Next циклов.

Поскольку у вас есть только два оператора With в цикле For, но у вас есть три оператора End With, компилятор «запутается» и будет настаивать на том, чтобы вы исправили ошибку.

person YowE3K    schedule 11.05.2017
comment
Хорошо, выше сработало, но возникла новая ошибка. Я много работаю с этими выражениями (большинство моих макросов отправляют электронные письма из Excel, поэтому я не уверен, почему у него вдруг возникла проблема. У меня была ошибка 424, объявлена ​​ошибка 1004, удалил набор. Теперь я получаю ошибку компиляции , недопустимый квалификатор Dim sh1 As String sh1 = ActiveWorkbook.Sheets(Ultrasound) FirstName = sh1.Cells(r, 1).Value - person Christine Rieger; 11.05.2017
comment
Вам нужно Set объектов, поэтому Set sh1 = ActiveWorkbook.Sheets("Ultrasound") - person YowE3K; 11.05.2017
comment
Ошибка для этого: Ошибка компиляции, требуется объект. Поскольку он объявлен, я не уверен, чего он хочет. - person Christine Rieger; 12.05.2017
comment
@ChristineRieger К сожалению, извините, я не заметил, что вы также объявили это неправильно (код в комментариях трудно прочитать) - правильное объявление - Dim sh1 As Worksheet - вы объявляли его как String. - person YowE3K; 12.05.2017
comment
Назад к ошибке выполнения 1004, определяемой приложением или определяемой объектом ошибке. Я хожу кругами. (Это проблема, циклическая ссылка :-)?) - person Christine Rieger; 12.05.2017
comment
@ChristineRieger Dim sh1 As Worksheet Set sh1 = ActiveWorkbook.Sheets("Ultrasound") FirstName = sh1.Cells(r, 1).Value должно работать (при условии, что в активной рабочей книге есть лист под названием «Ультразвук» и что ваша переменная r находится в диапазоне от 1 до 1048576) - person YowE3K; 12.05.2017
comment
Спасибо @YowE3K. Я слишком сильно опустил букву r. Но теперь я вернулся к этому, ожидая, пока Word выполнит (это ошибка, которую я пытался устранить для начала). Код открывает Word. У меня больше ничего не открывается в Ворде. Но он не открывает шаблон Set objMMMD = objWord.Documents.Open(cDir + WTempName). И для настоящего удовольствия, когда я пытаюсь снова, он выдает ошибку времени выполнения 462. Теперь это новая ошибка. - person Christine Rieger; 12.05.2017
comment
@ChristineRieger Помимо того факта, что вы используете + вместо & для конкатенации, я не вижу ничего особенно плохого в этой строке. (И VBA обычно справляется с +, поэтому я не думаю, что это вызывает проблему.) Я предлагаю вам задать новый вопрос, чтобы вы могли показать свой текущий код - не видя, как код был изменен, это немного сложно комментировать, что может быть не так. (И я не эксперт по MS Word, поэтому новый вопрос может привлечь внимание кого-то, кто увидит проблему быстрее, чем я.) - person YowE3K; 12.05.2017
comment
Я знал об ограничении с комментариями. спасибо @YowE3K. поднимет новое дело. Спасибо за вашу помощь. (Мне было интересно узнать о +, но они были в коде, поэтому не трогали) - person Christine Rieger; 12.05.2017