Как исправить ошибку при работе с макетами Word через ОболочкаActiveDocument на 64-битном сервере 1С?

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

При разработке внешних печатных форм или сложных отчетов программисты 1С часто сталкиваются с необходимостью вывода данных в формат Microsoft Word. Одной из наиболее "капризных" технологий в этом контексте является использование макетов типа Active Document (в системе 1С они представляются как ОболочкаActiveDocument). Проблемы кратно возрастают, когда код выполняется на 64-разрядном сервере 1С, в то время как на сервере или рабочих станциях установлен 32-разрядный пакет Microsoft Office.

В этой статье мы подробно разберем, почему возникают ошибки при вызове метода Получить(), почему серверные процессы могут зависать при попытке поиска и замены текста, и как правильно организовать архитектуру печатной формы, чтобы она работала стабильно в гетерогенных средах.

Разберем причину: почему падает серверная функция?

Рассмотрим типичную ситуацию: у нас есть внешняя печатная форма, в которой макет Word внедрен непосредственно в объект. При попытке выполнить код на сервере мы получаем ошибку на этапе инициализации макета. Проанализируем пример кода, который вызывает сбой:


Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет"); 
// В переменной Макет оказывается объект ОболочкаActiveDocument
Попытка
    MSWord = Макет.Получить(); // Здесь происходит падение или молчаливое завершение
Исключение
    Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;

Основная причина кроется в конфликте разрядности. Процесс сервера 1С (rphost.exe) имеет разрядность x64, а COM-объекты Microsoft Office чаще всего имеют разрядность x86. Windows пытается использовать механизм COM Surrogate (dllhost.exe) для связи этих процессов, но объект ОболочкаActiveDocument — это устаревшая технология, которая требует графического контекста (GUI) для своей инициализации. Поскольку серверная служба 1С работает в так называемой "Сессии 0", где нет графической оболочки, попытка инициализировать визуальный компонент внутри макета приводит к критической ошибке доступа к памяти.

Проблема зависания метода Find.Execute

Если нам удается создать объект Word.Application напрямую через Новый COMОбъект, мы можем столкнуться со второй проблемой — бесконечным ожиданием (зависанием) сервера. Выясним причину на примере операции поиска и замены текста:


Замена = Документ.Content.Find;
Замена.Execute("%НомерДокумента%", Ложь, Истина, Ложь, , , Истина, , Ложь, СокрЛП(НомерДляПечати));

Почему это происходит? Word — это приложение, изначально ориентированное на взаимодействие с пользователем. Если в процессе поиска возникает ситуация, требующая уточнения (например, поиск дошел до конца документа и Word хочет спросить: "Продолжить поиск сначала?"), он выбрасывает модальное диалоговое окно. В серверной сессии это окно невидимо, его никто не может нажать, и поток 1С замирает навсегда, ожидая ответа от COM-объекта. Установка свойства DisplayAlerts = ложь помогает не во всех случаях, особенно в старых версиях Office.

Решение №1: Перенос формирования на сторону клиента

Это самый надежный способ, который позволяет избежать проблем с правами доступа и разрядностью на сервере. Рассмотрим алгоритм действий:

  1. На сервере получаем макет и преобразуем его в ДвоичныеДанные.
  2. Передаем эти данные на клиент.
  3. На клиенте сохраняем данные во временный файл.
  4. Используем стандартный Word.Application для работы с файлом.

Проанализируем пример реализации серверной функции для получения макета:


&НаСервере
Функция ПолучитьМакетСервер()
    // Получаем объект обработки или документа
    ОбъектПечати = РеквизитФормыВЗначение("Объект");
    Макет = ОбъектПечати.ПолучитьМакет("Макет");
    
    // Записываем макет во временный файл на сервере, чтобы прочитать его как двоичные данные
    ПутьКФайлу = ПолучитьИмяВременногоФайла("doc");
    Макет.Записать(ПутьКФайлу);
    
    ДвоичныеДанныеМакета = Новый ДвоичныеДанные(ПутьКФайлу);
    УдалитьФайлы(ПутьКФайлу);
    
    Возврат ДвоичныеДанныеМакета;
КонецФункции

Теперь рассмотрим клиентскую процедуру, которая будет выполнять основную работу. Обратите внимание, как мы работаем с объектом Word.Application:


&НаКлиенте
Процедура ПечатьНаКлиенте()
    // 1. Получаем данные макета с сервера
    ДД = ПолучитьМакетСервер();
    
    // 2. Сохраняем во временный файл на клиентском компьютере
    ИмяФайла = ПолучитьИмяВременногоФайла("doc");
    ДД.Записать(ИмяФайла);
    
    // 3. Работаем через COM-объект Word
    Попытка
        MSWord = Новый COMОбъект("Word.Application");
        MSWord.Visible = Ложь; // Скрываем окно на время заполнения
        MSWord.DisplayAlerts = 0;
        
        Документ = MSWord.Documents.Open(ИмяФайла);
        Документ.Activate();
    Исключение
        Сообщить("Не удалось запустить Microsoft Word: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // 4. Выполняем замену параметров
    Замена = Документ.Content.Find;
    // Пример замены тега %НомерДокумента%
    Замена.Execute("%НомерДокумента%", Ложь, Истина, Ложь, , , Истина, , Ложь, "№123-АБ");
    
    // 5. Показываем результат пользователю
    MSWord.Visible = Истина;
КонецПроцедуры

Решение №2: Настройка сервера для работы с COM (если клиент не подходит)

Если бизнес-логика требует формирования документа строго на стороне сервера (например, для регламентной рассылки почты), необходимо выполнить "магические" настройки операционной системы. Без них Word на сервере будет работать крайне нестабильно.

Создание системных папок профиля:

Word требует наличия папки Desktop для инициализации своего окружения, даже если он не собирается ничего отрисовывать. Для учетной записи, под которой запущен сервер 1С (обычно это USR1CV8), нужно вручную создать следующие директории:

После создания папок необходимо предоставить пользователю USR1CV8 полные права доступа к ним. Это решит большинство проблем с "тихим" зависанием метода Open().

Решение №3: Отказ от COM в пользу XML (формат .docx)

Рассмотрим наиболее современный и технологичный подход. Формат .docx — это фактически ZIP-архив, внутри которого лежат XML-файлы с текстом и оформлением. Мы можем манипулировать содержимым документа без использования установленного Microsoft Word на сервере.

Проанализируем шаги этого метода:

  1. Используем ЧтениеZipФайла для распаковки макета (предварительно сохраненного как .docx).
  2. Извлекаем файл word/document.xml.
  3. С помощью простых строковых функций СтрЗаменить или через ЧтениеXML меняем наши параметры-заполнители на реальные данные.
  4. Записываем XML обратно и упаковываем архив с помощью ЗаписьZipФайла.

Этот метод работает в десятки раз быстрее, не зависит от разрядности сервера и никогда не "вешает" систему модальными окнами, так как мы работаем с файлом как с набором байтов, а не как с запущенным приложением.

Подведем итоги

Работа с ОболочкаActiveDocument на сервере 1С x64 является устаревшим подходом, ведущим к труднодиагностируемым ошибкам. Для стабильной работы рекомендуем придерживаться следующих правил:

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

← На главную