Как переместить курсор после определенного слова в документе Word с помощью кода 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с внешними приложениями, такими как Microsoft Word, из системы 1С, мы часто сталкиваемся с необходимостью адаптировать существующие решения, написанные на VBA (Visual Basic for Applications), под синтаксис и особенности языка 1С. В данной статье мы подробно разберем, как перевести VBA-код, предназначенный для поиска определенного слова и установки курсора сразу после него, на язык 1С, используя возможности COM-объектов.

Эта задача актуальна для многих разработчиков 1С, которым требуется автоматизировать создание или модификацию документов Word, например, при формировании отчетов, договоров или приказов на основе данных из информационной базы. Мы рассмотрим по шагам, как настроить взаимодействие 1С с Word, использовать объектную модель Word для поиска и позиционирования курсора, а также как корректно обрабатывать константы и параметры методов.

Понимание исходного VBA-кода

Прежде чем переходить к адаптации кода на 1С, нам необходимо тщательно проанализировать оригинальный VBA-макрос. Это поможет нам понять логику работы и определить, какие объекты, свойства и методы Word используются.


Sub макрос()
    With ActiveDocument.Range.find
        .Text = "Слово1"
        If .Execute = True Then
            .Parent.Collapse Direction:=wdCollapseEnd
            .Parent.Select
        End If
    End With
End Sub

Давайте разберем каждую строку этого кода:

  1. With ActiveDocument.Range.find: Эта строка начинает блок With, который позволяет нам многократно обращаться к свойству find объекта Range текущего активного документа (ActiveDocument). Объект Range в Word представляет собой непрерывную область в документе. Получая .find от Range, мы инициализируем объект для поиска текста в этом диапазоне.
  2. .Text = "Слово1": Здесь мы устанавливаем текст, который будем искать. В данном случае это "Слово1".
  3. If .Execute = True Then: Метод Execute() запускает процесс поиска. Если искомый текст найден, метод возвращает True, и код внутри блока If будет выполнен. Если текст не найден, метод возвращает False.
  4. .Parent.Collapse Direction:=wdCollapseEnd: Если слово найдено, .Parent в данном контексте относится к объекту Range, который был найден методом find. Метод Collapse() "сворачивает" диапазон до одной из его границ. Параметр Direction:=wdCollapseEnd указывает, что диапазон должен быть свернут к своему конечному положению. Это означает, что курсор (точка вставки) будет установлен сразу после найденного слова.
  5. .Parent.Select: Метод Select() делает найденный (и свернутый) диапазон текущим выделением, что фактически перемещает курсор в это место.

Таким образом, основная логика заключается в получении объекта поиска, указании искомого текста, выполнении поиска, а затем, в случае успеха, перемещении курсора в конец найденного фрагмента.

Начальная настройка: Получение объектов Word в 1С

Для того чтобы 1С могла взаимодействовать с Microsoft Word, нам необходимо установить связь с приложением Word и получить доступ к конкретному документу. Мы будем использовать COM-объекты для этой цели. Обратимся к коду, который вы предоставили, и рассмотрим его подробнее.


// Получаем макет Word из конфигурации 1С
Макет = ПолучитьМакет("ЮИ_ПриказWord");

// Получаем COM-объект документа Word из макета
// ДокументWord теперь является объектом Word.Document
MSWord = Макет.Получить(); 

Попытка
    // Получаем объект приложения Word из документа
    // В данном случае, Макет уже является объектом Word.Document, 
    // поэтому WordПриложение = MSWord.Application; будет более корректным.
    // Строка Макет = MSWord.Application.Documents(1); перезаписывает ссылку на другой документ,
    // если документ, полученный из макета, не является первым документом в коллекции.
    // Для ясности и корректности, будем работать с MSWord как с документом.
    WordПриложение = MSWord.Application; 
    
    // Если нужно сделать Word видимым, чтобы пользователь видел процесс
    WordПриложение.Visible = Истина;

    // Активируем документ, чтобы он был на переднем плане
    MSWord.Activate(); 
    
    // Получаем объект Range для всего содержимого документа
    // (Content возвращает Range, представляющий основной текст документа)
    ОбластьПоиска = MSWord.Content; 
    
    // Получаем объект Find из Range
    Замена = ОбластьПоиска.Find; // Переименуем переменную для ясности в ПоискОбъект
    
Исключение
    Сообщить(ОписаниеОшибки());
    // Важно: закрывать приложение только если нет других открытых документов
    Если WordПриложение <> Неопределено Тогда
        Если WordПриложение.Documents.Count = 0 Тогда // Проверяем, что документов нет
            WordПриложение.Quit(); // Закрываем приложение Word
        КонецЕсли;
    КонецЕсли;
    Возврат Ложь;
КонецПопытки;

Давайте поясним эти шаги:

  1. Макет = ПолучитьМакет("ЮИ_ПриказWord");: Мы получаем двоичные данные макета, хранящегося в конфигурации 1С. Предполагается, что этот макет представляет собой документ Word.
  2. MSWord = Макет.Получить();: Метод Получить() объекта "Макет" в 1С возвращает COM-объект, который является экземпляром Word.Document. Это наш основной объект для работы с содержимым документа.
  3. WordПриложение = MSWord.Application;: Из объекта документа Word мы получаем ссылку на родительский объект Application, который представляет собой само приложение Microsoft Word. Это позволяет нам управлять глобальными параметрами Word, такими как его видимость или закрытие.
  4. WordПриложение.Visible = Истина;: Если мы хотим, чтобы пользователь видел, как происходит работа с документом Word, мы можем установить свойство Visible приложения в Истина. В противном случае Word будет работать в фоновом режиме.
  5. MSWord.Activate();: Этот метод делает наш документ активным и перемещает окно Word на передний план, если оно было скрыто или находилось в фоновом режиме.
  6. ОбластьПоиска = MSWord.Content;: Для выполнения поиска нам необходим объект Range, который представляет собой область документа, в которой будет происходить поиск. MSWord.Content возвращает Range, охватывающий весь основной текст документа.
  7. ПоискОбъект = ОбластьПоиска.Find;: От полученного объекта Range (ОбластьПоиска) мы получаем объект Find, который предоставляет все методы и свойства для выполнения операции поиска.

Мы видим, что ваш подход к получению объектов Word в целом верен, но важно быть внимательными при работе с переменными, чтобы не перезаписывать ссылки на объекты, как это могло бы произойти со строкой Макет = MSWord.Application.Documents(1);, если MSWord уже был нашим целевым документом.

Реализация логики поиска и позиционирования курсора в 1С

Теперь, когда мы получили необходимые COM-объекты Word, мы можем перенести логику поиска и установки курсора из VBA на язык 1С. Вспомним наш VBA-код:


With ActiveDocument.Range.find
    .Text = "Слово1"
    If .Execute = True Then
        .Parent.Collapse Direction:=wdCollapseEnd
        .Parent.Select
    End If
End With

И адаптируем его для 1С, используя уже полученные нами объекты:


// ... (начальная настройка и получение объектов MSWord, WordПриложение, ПоискОбъект) ...

Попытка
    // Устанавливаем текст для поиска
    ПоискОбъект.Text = "Слово1";
    
    // Выполняем поиск. Если слово найдено, Execute возвращает Истина.
    Если ПоискОбъект.Execute() Тогда
        // ПоискОбъект.Parent возвращает найденный Range.
        // Сворачиваем найденный диапазон к его концу.
        // Константа wdCollapseEnd в VBA имеет числовое значение 0.
        // В 1С при работе с COM-объектами мы передаем это числовое значение напрямую.
        ПоискОбъект.Parent.Collapse(0); 
        
        // Выделяем полученную точку вставки, что фактически устанавливает туда курсор.
        ПоискОбъект.Parent.Select();
        
        Сообщить("Курсор перемещен после слова 'Слово1'.");
    Иначе
        Сообщить("Слово 'Слово1' не найдено в документе.");
    КонецЕсли;

Исключение
    Сообщить("Произошла ошибка при работе с Word: " + ОписаниеОшибки());
    // Корректное закрытие приложения Word в случае ошибки
    Если WordПриложение <> Неопределено Тогда
        Если WordПриложение.Documents.Count = 0 Тогда
            WordПриложение.Quit();
        КонецЕсли;
    КонецЕсли;
КонецПопытки;

// ... (дальнейшая работа с документом или его закрытие) ...

Давайте подробнее остановимся на ключевых моментах этого фрагмента кода на 1С:

Установка и выполнение поиска

ПоискОбъект.Text = "Слово1";
Эта строка аналогична VBA-коду. Мы просто присваиваем строковое значение свойству Text объекта Find, указывая, какой текст необходимо найти.

Если ПоискОбъект.Execute() Тогда
Метод Execute() запускает операцию поиска. Его результат, как и в VBA, является булевым значением: Истина, если текст найден, и Ложь в противном случае. Мы используем его в условном операторе Если...Тогда для принятия решения о дальнейших действиях.

Метод Execute() может принимать множество необязательных параметров, которые позволяют уточнить поиск, например, учитывать регистр (MatchCase), искать только целые слова (MatchWholeWord), искать в прямом или обратном направлении (Forward) и так далее. Если нам нужен более сложный поиск, мы можем установить эти параметры до вызова Execute():


// Пример использования дополнительных параметров поиска
ПоискОбъект.MatchCase = Истина; // Учитывать регистр
ПоискОбъект.MatchWholeWord = Истина; // Искать только целые слова
ПоискОбъект.Forward = Истина; // Искать вперед по документу
ПоискОбъект.Wrap = 1; // wdFindContinue - Продолжать поиск с начала или конца документа при достижении края
// Значения констант: wdFindAsk (0), wdFindStop (1), wdFindContinue (2)
// 1 = wdFindStop, 2 = wdFindContinue
ПоискОбъект.Execute();

В нашем случае, для простой задачи, установка только свойства Text достаточна.

Сворачивание диапазона и позиционирование курсора

ПоискОбъект.Parent.Collapse(0);
Это самый критичный момент при переходе от VBA к 1С. В VBA мы использовали именованный параметр Direction:=wdCollapseEnd. В 1С, при работе с COM-объектами, мы обычно передаем параметры позиционно, а константы Word (такие как wdCollapseEnd) должны быть заменены их числовыми значениями.

Константа wdCollapseEnd имеет числовое значение 0. Поэтому, чтобы свернуть найденный диапазон к его концу, мы вызываем метод Collapse() с параметром 0:

ПоискОбъект.Parent.Collapse(0);

Здесь ПоискОбъект.Parent возвращает тот Range, который был найден методом Find. Вызов Collapse(0) превращает этот диапазон в точку вставки (курсор) в конце найденного текста.

ПоискОбъект.Parent.Select();
После сворачивания диапазона до точки, мы вызываем метод Select() для этого диапазона. Этот метод выделяет диапазон. Поскольку наш диапазон теперь является всего лишь точкой, это эквивалентно установке курсора в данную позицию. Именно это действие и выполняет финальное перемещение курсора после искомого слова.

Полный пример кода на 1С для работы с макетом Word

Теперь давайте объединим все рассмотренные шаги в единый, рабочий код на языке 1С, который вы можете использовать в своих обработках или модулях.


Процедура ПереместитьКурсорПослеСловаВWord()
    
    // 1. Получаем макет Word из конфигурации 1С
    МакетWordИзКонфигурации = ПолучитьМакет("ЮИ_ПриказWord");

    // Объявляем переменные для COM-объектов вне блока Попытка,
    // чтобы они были доступны в блоке Исключение и после него для очистки.
    Перем ДокументWordДляРаботы;
    Перем WordПриложение;
    Перем ОбластьПоиска;
    Перем ПоискОбъект;
    
    Попытка
        // 2. Получаем COM-объект документа Word из макета
        // ДокументWordДляРаботы теперь является объектом Word.Document
        ДокументWordДляРаботы = МакетWordИзКонфигурации.Получить();
        
        // 3. Получаем объект приложения Word из документа
        WordПриложение = ДокументWordДляРаботы.Application;
        
        // 4. Делаем приложение Word видимым, если это необходимо
        // Если Word должен работать в фоне, можно установить в Ложь
        WordПриложение.Visible = Истина;

        // 5. Активируем документ, чтобы он был на переднем плане
        // Это важно, если Word был запущен в скрытом режиме или перекрыт другими окнами
        ДокументWordДляРаботы.Activate();
        
        // 6. Получаем объект Range для всего содержимого документа
        // Content возвращает Range, представляющий основной текст документа.
        // Это диапазон, в котором будет производиться поиск.
        ОбластьПоиска = ДокументWordДляРаботы.Content; 
        
        // 7. Получаем объект Find из объекта Range
        ПоискОбъект = ОбластьПоиска.Find;
        
        // 8. Устанавливаем текст для поиска
        ПоискОбъект.Text = "Слово1";
        
        // 9. Выполняем поиск. Если слово найдено, Execute возвращает Истина.
        Если ПоискОбъект.Execute() Тогда
            // 10. ПоискОбъект.Parent возвращает найденный Range.
            // Сворачиваем найденный диапазон к его концу (wdCollapseEnd = 0).
            // Это перемещает точку вставки (курсор) сразу после найденного слова.
            ПоискОбъект.Parent.Collapse(0); 
            
            // 11. Выделяем полученную точку вставки, что фактически устанавливает туда курсор.
            ПоискОбъект.Parent.Select();
            
            Сообщить("Курсор успешно перемещен после слова 'Слово1'.");
        Иначе
            Сообщить("Слово 'Слово1' не найдено в документе.");
        КонецЕсли;

    Исключение
        Сообщить("Произошла ошибка при работе с Word: " + ОписаниеОшибки(), СтатусСообщения.Важное);
        // В случае ошибки, корректно закрываем приложение Word,
        // если оно было открыто только для нашего документа и других документов нет.
        Если WordПриложение <> Неопределено Тогда
            Попытка
                Если WordПриложение.Documents.Count = 0 Тогда // Проверяем, что нет других открытых документов
                    WordПриложение.Quit();
                КонецЕсли;
            Исключение
                // Игнорируем ошибки при попытке закрыть, так как приложение может быть уже закрыто
            КонецПопытки;
        КонецЕсли;
        // Возврат из процедуры в случае серьезной ошибки
        Возврат;
    КонецПопытки;

    // 12. После завершения работы с документом, рекомендуется его закрыть и освободить COM-объекты.
    // Это предотвращает утечки памяти и зависание процессов Word.
    // Примечание: Если документ должен остаться открытым для пользователя, эти строки можно закомментировать.
    Попытка
        Если ДокументWordДляРаботы <> Неопределено И WordПриложение <> Неопределено Тогда
            // Сохранить документ перед закрытием, если были изменения
            // ДокументWordДляРаботы.Save(); 
            ДокументWordДляРаботы.Close(0); // 0 = wdDoNotSaveChanges (не сохранять изменения)
                                         // 1 = wdSaveChanges (сохранить изменения)
                                         // 2 = wdPromptToSaveChanges (предложить сохранить)
            
            // Если после закрытия нашего документа не осталось других открытых документов,
            // закрываем приложение Word.
            Если WordПриложение.Documents.Count = 0 Тогда
                WordПриложение.Quit();
            КонецЕсли;
        КонецЕсли;
    Исключение
        Сообщить("Ошибка при закрытии документа Word или приложения: " + ОписаниеОшибки(), СтатусСообщения.Внимание);
    КонецПопытки;
    
    // Освобождаем COM-объекты (не всегда обязательно, но хорошая практика)
    ДокументWordДляРаботы = Неопределено;
    WordПриложение = Неопределено;
    ОбластьПоиска = Неопределено;
    ПоискОбъект = Неопределено;

КонецПроцедуры

Важные моменты и лучшие практики при работе с COM-объектами Word

Работа с внешними COM-объектами, такими как Microsoft Word, из 1С требует соблюдения определенных правил и лучших практик, чтобы избежать проблем с производительностью, утечками памяти или "зависанием" процессов:

  1. Освобождение COM-объектов: Крайне важно корректно закрывать документы Word и приложение Word после завершения работы. Если этого не сделать, процессы WINWORD.EXE могут оставаться запущенными в фоновом режиме, потребляя системные ресурсы и блокируя файлы. Используйте методы Document.Close() и Application.Quit(). Всегда проверяйте Application.Documents.Count перед вызовом Application.Quit(), чтобы не закрыть другие документы пользователя, которые не относятся к вашей задаче. После закрытия рекомендуется присваивать переменным Неопределено для явного освобождения ссылок на COM-объекты.
  2. Обработка ошибок: Всегда заключайте код работы с COM-объектами в блоки Попытка...Исключение. Взаимодействие с внешними приложениями может быть непредсказуемым, и ошибки могут возникать по разным причинам (Word не установлен, документ заблокирован, неверный путь к файлу и т.д.). Корректная обработка ошибок позволит вашей программе оставаться стабильной.
  3. Видимость приложения: Решите, нужно ли делать Word видимым для пользователя. Для фоновых операций лучше установить WordПриложение.Visible = Ложь;. Это повышает производительность и предотвращает мигание окна Word. Для интерактивной работы, где пользователь должен видеть изменения, WordПриложение.Visible = Истина; является обязательным.
  4. Константы Word: Как мы выяснили, константы VBA (например, wdCollapseEnd) не могут быть использованы напрямую в 1С. Вам нужно найти их числовые значения (обычно это легко гуглится или находится в документации Word VBA) и использовать эти значения. В нашем случае wdCollapseEnd = 0.
  5. Установка ссылок: В некоторых случаях, для более удобной работы с COM-объектами и использования "подсказок" (intellisense) в средах разработки, можно зарегистрировать библиотеки типов Word (например, "Microsoft Word 16.0 Object Library"). Однако в 1С это обычно не делается явно для каждого разработчика, и мы работаем через позднее связывание (late binding), что является стандартной практикой.
  6. Метод Find.Execute() и его параметры: Метод Execute() имеет множество параметров, которые позволяют выполнять очень сложный поиск. Изучите их, если вам потребуется более тонкая настройка. К ним относятся:
    • MatchCase (Булево): Учитывать регистр.
    • MatchWholeWord (Булево): Искать только целые слова.
    • MatchWildcards (Булево): Использовать подстановочные знаки.
    • MatchSoundsLike (Булево): Искать похожие слова.
    • MatchAllWordForms (Булево): Искать все словоформы.
    • Forward (Булево): Направление поиска (вперед или назад).
    • Wrap (Целое): Действия при достижении конца документа (0 - wdFindAsk, 1 - wdFindStop, 2 - wdFindContinue).
    • Format (Булево): Учитывать форматирование.
    • ReplaceWith (Строка): Текст для замены (используется с методом Replace()).
    • Replace (Целое): Тип замены (0 - wdReplaceNone, 1 - wdReplaceOne, 2 - wdReplaceAll).
    По умолчанию, если не указано иное, большинство параметров сброшены к значениям, соответствующим простому поиску.

Следуя этим рекомендациям и используя предоставленный пример кода, вы сможете эффективно автоматизировать задачи, связанные с обработкой документов Word из 1С, значительно упрощая работу пользователей и повышая общую производительность.

← На главную