#excel #vba #ms-word #copy-paste #onerror
#excel #vba #ms-word #копировать-вставить #onerror
Вопрос:
Приведенный ниже код предназначен для последовательного копирования строки из ячеек в столбце Excel (i = 3-61), поиска папки каталога, содержащей множество копий одного и того же файла .doc, и вставки каждой строки во вторую строку, первый столбец первой таблицы в каждом файле .doc.
Проблема: программа намеренно продолжает цикл и завершает выполнение остальной части кода после первого выполнения следующей строки:
wddoc.Tables(1).Cell(2, 1).Range.Paste
Это происходит даже при том, что я перехожу в каждую строку кода, используя F8, чтобы добраться до этой строки кода. Код завершает выполнение, ничего не вставив в оставшиеся файлы в каталоге. (Строка в строке 3 документа Excel была успешно вставлена в plan template — Copy (10).docx, но остальные строки не были вставлены в остальные файлы)
Код:
Option Explicit
Sub CopyExcelToWord(path As String)
'variables----------------------------------------------------------------
'Decare Object variables for the Word application and file or documentl
Dim wdapp As Object, wddoc As Object, i As Integer
'Declare a String variable for the directory root and current file in that directory
Dim currentPath As String
'main process----------------------------------------------------------
'error handling is extremely important in making Excel work with Word
On Error Resume Next
'GetObject needs two parameters. The first is optional
Set wdapp = GetObject(, "Word.Application")
If Err.Number = 429 Then
Err.Clear
'we create a new instance of MS Word
Set wdapp = CreateObject("Word.Application")
End If
'Our application is made visible
wdapp.Visible = True
currentPath = Dir(path, vbDirectory)
For i = 3 To 61
Do Until currentPath = vbNullString
Debug.Print currentPath
If Left(currentPath, 1) <> "." And Left(currentPath, 1) <> "" Then
Debug.Print path amp; currentPath
Sheet1.Range(Cells(i, 2), Cells(i, 2)).Copy
'we activate our MS Word instance
wdapp.Activate
Set wddoc = wdapp.Documents(path amp; currentPath)
If wddoc Is Nothing Then Set wddoc = wdapp.Documents.Open(path amp; currentPath)
wddoc.Activate
wddoc.Tables(1).Cell(2, 1).Range.Paste
'Free alocated memory and close
wdapp.Quit
Set wddoc = Nothing
Set wdapp = Nothing
'The following line of code removes the cell selection in Excel
Application.CutCopyMode = False
currentPath = Dir()
Else
currentPath = Dir()
End If
Loop
Next
End Sub
Печать (я поместил «…«, где я пропустил часть пути):
. . . . plan template — Copy (10).docx L C:**…** plan template — Copy (10).docx
Программа непреднамеренно выполняет остальную часть кода. Строка в строке 3 документа Excel была успешно вставлена в шаблон плана — Копировать (10).docx, а остальные строки не были вставлены в остальные файлы)
копия шаблона плана (11).docx L C: *…**шаблон плана — Копировать (11).docx Шаблон плана урока — Копировать (12).docx L C: * … шаблон плана -копировать (12).docx шаблон плана — копировать (13).docx LC: ** … plan template — L … C: *…** plan template — Копировать (9).план урока docx template.docx L C:*…**план template.docx
Комментарии:
1. Согласно комментарию ниже, а также после первого завершения, если поместить строку в ошибку GoTo 0 , а затем заменить Лист1. Диапазон (ячейки (i, 2), ячейки (i, 2)). Скопируйте с помощью ws.Range(ws.Cells(i, 2), ws.Cells(i, 2)). Скопируйте и убедитесь, что вы поместили лист для копирования в переменную с именем ws в начале кода, т.е. Dim ws Как Worksheet: Set ws = ThisWorkbook . Рабочие листы («Лист1») (или соответствующее имя листа)
2. Я сталкивался с несколькими случаями, когда вызов приведет к продолжению кода вместо пошагового выполнения. Я бы назвал это ошибкой в отладчике VBA. О, ирония судьбы.
3. @QHarr — Спасибо за ваше предложение. Я следовал вашим инструкциям, но получаю ошибку времени выполнения 9 «ошибка нижнего индекса вне диапазона». Приведенный выше код взят из модуля с именем ‘Module1’. Я вызываю модуль из листа 1 в рабочей книге. Что я сделал не так?
4. @HackSlash. Хах, да, вполне возможно, что этот отладчик ржавый… В этом экземпляре.. Я искренне надеюсь, что нет.
5. @QHarr. Я решаю имя ошибки во время выполнения, изменив ‘sheet1’ на пользовательское имя листа. Однако теперь программа достигает только строки: Set wddoc = wdapp . Документы (path amp; currentPath), прежде чем я получу ошибку времени выполнения 4160 — «ошибка, определенная приложением или объектом»
Ответ №1:
Я не уверен, что исправление этого решит вашу проблему, но у вас есть
wddoc.Tables(1).Cell(2, 1).Range.Paste
'Free alocated memory and close
wdapp.Quit
Set wddoc = Nothing
Set wdapp = Nothing
После того, как вы выполнили wdapp.Quit, у вас больше нет wdapp, поэтому на следующей итерации вашего цикла «For i» ничего не будет работать.
Но если вы хотите сохранить свой wddoc, вы не можете полагаться на Set wddoc = Nothing
это. Вам нужно выполнить явное закрытие или сохранить и закрыть
Так, например
wddoc.Tables(1).Cell(2, 1).Range.Paste
wddoc.Close -1 ' SaveChanges:=Word.wdSaveOptions.wdSaveChanges
' Only do this outside your "For i =" loop
'Free alocated memory and close
'wdapp.Quit
Set wddoc = Nothing
' Only do this outside your "For i =" loop
' Set wdapp = Nothing
Комментарии:
1. Спасибо за ваше предложение. У меня такая же проблема после установки ‘wddoc’ и ‘wdapp’ на ‘nothing’ вне ‘For-loop’. Я думаю, мне нужно, чтобы ‘wdoc.save’ и ‘wdoc.close’ находились в i-цикле, потому что я хочу сохранить и закрыть документ перед открытием нового документа. ‘wddoc’ также инициализируется в цикле for. У меня есть код для «При возобновлении следующей ошибки», поэтому может возникнуть ошибка, вызывающая это для следующих итераций. Однако, когда я удаляю эту обработку ошибок, я получаю сообщение об ошибке в строке ‘Set wdapp = GetObject(, «Word. «).
2. Обновление: я закомментировал строки: Set wdapp = GetObject(, «Word. «). и «При возобновлении следующей ошибки», а также для остальной обработки ошибок. Я остаюсь с той же проблемой.
3. Вы не должны были этого делать. Верните свой код обратно, но добавьте
On Error GoTo 0
непосредственно передwdapp.Visible = True
этим, чтобы вернуть обработку ошибок в состояние по умолчанию.4. @EmptyStack — я согласен с @slightlysnarky — вам нужно закрыть документ и сохранить изменения в цикле, но выйти из приложения вне цикла. Но вы должны выйти из Word только в случае
Set wdapp = GetObject(, "Word.Application")
сбоя. Я бы добавил логическое значение в этот момент и протестировал его позже, напримерIf quitWord then wdapp.Quit
5. @EmptyStack «Я думаю, мне нужно, чтобы ‘wdoc.save’ и ‘wdoc.close’ находились в цикле ввода-вывода, потому что я хочу сохранить и закрыть документ, прежде чем открывать новый документ» Ну, это то, что сказал мой пост. Что произошло, когда вы это сделали?
Ответ №2:
Ваша «проблема» не имеет ничего общего с командой paste .
Ваш код устанавливает, что все ошибки должны игнорироваться, создает объект приложения Word, затем входит в цикл, где:
- значение ячейки копируется
- открывается документ Word
- содержимое буфера обмена вставляется в ячейку таблицы в документе Word
- Word закрывается, а объект приложения уничтожается
Первая итерация цикла будет выполнена успешно, но последующие итерации приведут к ошибке в каждой строке, которая включает Word, поскольку объект больше не существует. Эти ошибки игнорируются из-за On Error Resume Next
.
Что вам нужно сделать:
- Сброс обработки ошибок после получения объекта Word
- Добавьте флаг, если Word не был открыт, чтобы его можно было закрыть по завершении операций
- Закройте документ и сохраните изменения после его завершения внутри цикла
- Перемещение
wdapp.quit
за пределы цикла
Поскольку Word сохраняет историю буфера обмена, и вы копируете только значение одной ячейки, я бы не стал использовать copy paste для этого. Вместо этого запишите значение непосредственно в ячейку таблицы.
Вот как я бы написал ваш код:
Option Explicit
Sub CopyExcelToWord(path As String)
'variables----------------------------------------------------------------
'Decare Object variables for the Word application and file or document
Dim wdapp As Object, wddoc As Object, i As Integer
'Declare a String variable for the directory root and current file in that directory
Dim currentPath As String
'declare flag to show if Word needs to be quit
Dim quitWord As Boolean
'main process----------------------------------------------------------
'error handling is extremely important in making Excel work with Word
On Error Resume Next
'GetObject needs two parameters. The first is optional
Set wdapp = GetObject(, "Word.Application")
If Err.Number = 429 Then
Err.Clear
'we create a new instance of MS Word
Set wdapp = CreateObject("Word.Application")
'as Word wasn't already open make application visible
wdapp.Visible = True
'set flag to show Word needs to be shut down
quitWord = True
End If
'reset error handling so that any subsequent errors aren't ignored
On Error GoTo 0
currentPath = Dir(path, vbDirectory)
For i = 3 To 61
Do Until currentPath = vbNullString
Debug.Print currentPath
If Left(currentPath, 1) <> "." And Left(currentPath, 1) <> "" Then
Debug.Print path amp; currentPath
Set wddoc = wdapp.Documents.Open(path amp; currentPath)
wddoc.Tables(1).Cell(2, 1).Range.Text = Sheet1.Range(Cells(i, 2), Cells(i, 2)).Value
'document no longer required so close and save changes
wddoc.Close -1 ' SaveChanges:=Word.wdSaveOptions.wdSaveChanges
Set wddoc = Nothing
currentPath = Dir()
Else
currentPath = Dir()
End If
Loop
Next
'Now that operations involving Word are complete quit Word if necessary and destroy objects
If quitWord Then wdapp.Quit
Set wdapp = Nothing
End Sub
Комментарии:
1. Спасибо. Я сделал так, как посоветовали вы и немного придирчивый. Строка кода: wddoc. Таблицы (1).Ячейка (2, 1).Диапазон. Текст = Лист1. Диапазон (ячейки (i, 2), ячейки (i, 2)). Значение и добавление флага quitWord, похоже, остановили нежелательное продолжение кода в режиме отладки. Однако теперь я получаю ошибку времени выполнения 5 (недопустимый вызов процедуры или аргумент) в строке: ‘currentPath = Dir ()’ (над оператором ‘else’).
2. @EmptyStack — вы уверены, что у вас 59 файлов в этой папке?
3. Короткий ответ Нет. вопрос: требуется ли это для работы кода? У меня 59 ячеек, в которых 59 уникальных строк. Предполагается, что каждый документ будет иметь одну из 59 уникальных строк. Если строка currentPath= Null выполняется до того, как я скопировал последнюю строку, цикл прервется, что просто означает, что мне нужно добавить больше шаблонов документов в файл каталога. Пожалуйста, поправьте меня, если я ошибаюсь. Еще раз спасибо
4. @EmptyStack — если вы намерены добавить каждую из строк в документ, то да, вам нужно 59 документов. Это слабое место вашего решения. Если вы удалите внешний цикл и у вас будет более 59 документов, ваш код сломается. Если вы оставите внешний цикл включенным, но у вас будет меньше 59 документов, ваш код сломается. Для этого есть решение, но вам нужно задать отдельный вопрос.
5. Я удалил строку кода, которая изменяла имя документа после того, как я вставил в него строку: If Dir(currentPath) <> «» Затем назовите currentPath как newFileName, потому что его строка currentPath = Dir() выдавала ошибку времени выполнения. Код выполняется по назначению. Спасибо