При формировании печатных форм и заполнении шаблонов договоров через COM-соединение с Microsoft Word разработчики 1С нередко сталкиваются с ошибкой: «Метод или свойство недоступны, поскольку эту команду нельзя использовать в режиме чтения». При этом документ отказывается принимать изменения через объект Selection или коллекцию Bookmarks, а свойство документа ReadOnly принимает значение Истина.
Проанализируем причины такого поведения платформы и офисного приложения, а также разберем по шагам надежные способы решения этой проблемы.
Выделим основные технические факторы, из-за которых Word блокирует редактирование файла:
Записать() платформа 1С в некоторых сценариях создает на диске файл с системным атрибутом «Только для чтения» или оставляет открытый OLE-дескриптор в памяти процесса.Documents.Open без параметров. По умолчанию Word при открытии файла с признаками шаблона или защищенного каталога переводит его в режим чтения, если явно не указано обратное.WINWORD.EXE. Если предыдущие COM-сессии не были корректно закрыты методами Quit(), невидимые экземпляры Word могут удерживать файловые блокировки.Наиболее надежным решением является отказ от устаревшего типа макета Active document в пользу обычных двоичных данных. При выгрузке двоичных данных на диск файл сохраняется как чистый байтовый поток без наложения OLE-оболочек и скрытых атрибутов только для чтения.
Рассмотрим, как правильно сохранить и открыть шаблон из макета двоичных данных:
// Получаем макет двоичных данных
ДвоичныеДанныеШаблона = РеквизитФормыВЗначение("Объект").ПолучитьМакет("ПФ_DOCX_Шаблон");
// Формируем уникальный путь во временном каталоге
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("docx");
ДвоичныеДанныеШаблона.Записать(ИмяВременногоФайла);
// Инициализируем COM-соединение с Word
Попытка
Word = Новый COMОбъект("Word.Application");
Word.Visible = Ложь;
Исключение
ВызватьИсключение "Не удалось инициализировать Microsoft Word: " + ОписаниеОшибки();
КонецПопытки;
// Открываем документ для редактирования
ДокументВорд = Word.Documents.Open(ИмяВременногоФайла, Ложь, Ложь);
Разберем классический подход к созданию печатных форм. Вместо открытия самого файла шаблона на редактирование правильнее создавать новый документ на базе имеющегося шаблона с помощью метода Documents.Add. Это исключает блокировки исходного файла и гарантирует, что создаваемый документ всегда будет доступен для записи.
// Создаем новый документ на основе файла-шаблона
НовыйДокумент = Word.Documents.Add(ИмяВременногоФайла);
// Заполняем закладку в созданном документе
Если НовыйДокумент.Bookmarks.Exists("ДатаДоговора") Тогда
Закладка = НовыйДокумент.Bookmarks("ДатаДоговора");
Закладка.Select();
Word.Selection.TypeText(Формат(ТекущаяДата(), "ДЛФ=DD"));
КонецЕсли;
// Делаем Word видимым для пользователя или сохраняем результат
Word.Visible = Истина;
Если в силу архитектуры конфигурации макет обязательно должен оставаться объектом Active document, перед передачей пути в Word проверим и принудительно снимем системный атрибут файла средствами 1С.
Посмотрим на пример реализации с объектом Файл:
Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("ПФ_MXL_МОЛ");
ПолноеИмяФайла = КаталогВременныхФайлов() + "Шаблон.doc";
Макет.Записать(ПолноеИмяФайла);
// Снимаем системный флаг ReadOnly средствами 1С
ФайлНаДиске = Новый Файл(ПолноеИмяФайла);
Если ФайлНаДиске.Существует() И ФайлНаДиске.ПолучитьТолькоЧтение() Тогда
ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
КонецЕсли;
// Явно передаем параметр ReadOnly = Ложь при открытии в Word
ДокументВорд = Word.Documents.Open(ПолноеИмяФайла, Ложь, Ложь);
// Принудительно включаем режим обычной разметки страницы (wdPrintView = 3)
Word.ActiveWindow.View.Type = 3;
Проанализируем ситуацию с зависанием процессов: если при возникновении ошибок COM-объект не освобождается, Word остается висеть в диспетчере задач Windows и блокирует повторно создаваемые файлы в папке временных файлов.
Для предотвращения утечек обязательно используем конструкцию Попытка ... Исключение с гарантированным закрытием приложения в блоке очистки:
Word = Неопределено;
Документ = Неопределено;
Попытка
Word = Новый COMОбъект("Word.Application");
Документ = Word.Documents.Add(ПолноеИмяФайла);
// Выполняем алгоритм заполнения закладок
// ...
Word.Visible = Истина;
Исключение
// В случае ошибки принудительно закрываем Word без сохранения
Если Документ <> Неопределено Тогда
Документ.Close(Ложь);
КонецЕсли;
Если Word <> Неопределено Тогда
Word.Quit();
КонецЕсли;
ВызватьИсключение "Ошибка при формировании документа Word: " + ОписаниеОшибки();
КонецПопытки;
Резюме: для стабильной работы печатных форм Word храните шаблоны как Двоичные данные, создавайте результирующие файлы через Documents.Add и всегда предусматривайте корректное освобождение COM-объектов при исключениях.