При разработке в управляемом приложении «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда код, успешно работавший в обычных формах, начинает выдавать ошибки. Одна из самых распространенных проблем — попытка передачи макета типа ActiveDocument с сервера на клиент через временное хранилище. В этой статье мы подробно разберем, почему возникает ошибка при вызове метода ПолучитьИзВременногоХранилища, и как правильно организовать работу с шаблонами Microsoft Word и Excel в клиент-серверной архитектуре.
Разберем ситуацию, описанную в теме. Автор пытается получить макет на сервере, поместить его во временное хранилище и извлечь на клиенте. В момент вызова ПолучитьИзВременногоХранилища система выдает ошибку. Проанализируем, почему это происходит.
Ключевая причина кроется в понятии сериализации. В управляемом приложении взаимодействие между клиентом и сервером (и временным хранилищем как промежуточным звеном) возможно только для тех типов данных, которые могут быть преобразованы в последовательность байтов и восстановлены обратно. Тип ActiveDocument по своей сути является оболочкой над COM-объектом (OLE-объектом). COM-объекты не сериализуемы. Они неразрывно связаны с адресным пространством того процесса, в котором они были созданы.
Когда мы выполняем ПоместитьВоВременноеХранилище(Макет, ...) на сервере, где Макет — это ActiveDocument, 1С пытается сохранить ссылку на этот объект. Однако при попытке прочитать его на клиенте через ПолучитьИзВременногоХранилища, система понимает, что она не может «перетащить» живой COM-объект из памяти сервера в память клиента. Именно в этот момент происходит аварийное завершение метода.
Кроме того, важно помнить о техническом окружении. Если на сервере не установлен Microsoft Office, попытка инициализации ActiveDocument через ПолучитьМакет() может привести к ошибкам еще на этапе сервера, так как 1С требует наличия соответствующих библиотек (интерфейсов) для работы с этим типом данных.
Посмотрим, как можно обойти это ограничение. Поскольку «живой» объект передать нельзя, мы должны передать «контент» этого объекта. Рассмотрим по шагам алгоритм, который является стандартом для работы в управляемых формах:
ДвоичныеДанные. Этот тип прекрасно сериализуется и передается через хранилище.Word.Application или Excel.Application).Проанализируем исправленный код. Начнем с серверной части. Нам необходимо убедиться, что мы возвращаем именно двоичные данные, а не объект макета.
Важное замечание: Чтобы избежать проблем с отсутствием Office на сервере, рекомендуется в конфигурации хранить макеты не как ActiveDocument, а как Двоичные данные. Если же макет уже создан как ActiveDocument, нам придется применить небольшую хитрость.
&НаСервере
Функция ПолучитьАдресМакетаНаСервере(ИмяМакета) Экспорт
// Получаем макет. Если тип макета в метаданных - "Двоичные данные",
// то ПолучитьМакет() сразу вернет нужный тип.
Макет = Справочники.гпаДоговора.ПолучитьМакет(ИмяМакета);
// Если макет все же ActiveDocument, его нужно привести к Двоичным Данным.
// В некоторых случаях 1С позволяет это сделать напрямую через объект ХранилищеЗначения
// или путем сохранения во временный файл на сервере (если Office установлен).
// Но самый надежный способ - хранить шаблоны как двоичные данные изначально.
// Помещаем во временное хранилище.
// Вместо нового UUID обязательно используем УникальныйИдентификатор формы,
// переданный с клиента, чтобы данные удалились после закрытия формы.
Возврат ПоместитьВоВременноеХранилище(Макет, ЭтаФорма.УникальныйИдентификатор);
КонецФункции
Теперь рассмотрим клиентскую часть. Здесь мы должны принять адрес, получить данные и «приземлить» их на диск пользователя, так как Word не умеет открывать документы прямо из оперативной памяти 1С.
&НаКлиенте
Процедура Тест(Команда)
// 1. Получаем адрес данных во временном хранилище
АдресХранилища = ПолучитьАдресМакетаНаСервере("Макет");
Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда
// 2. Извлекаем двоичные данные на клиенте
ДанныеМакета = ПолучитьИзВременногоХранилища(АдресХранилища);
// 3. Формируем путь к временному файлу на клиентском компьютере
ПутьКФайлу = ПолучитьИмяВременногоФайла("docx"); // или "doc", "xlsx"
// 4. Записываем данные на диск
ДанныеМакета.Записать(ПутьКФайлу);
// 5. Теперь работаем с файлом через COM
Попытка
MSWord = Новый COMОбъект("Word.Application");
Документ = MSWord.Documents.Open(ПутьКФайлу);
MSWord.Visible = Истина;
MSWord.Activate();
Исключение
Сообщить("Ошибка при запуске Microsoft Word: " + ОписаниеОшибки());
MSWord.Quit();
КонецПопытки;
КонецЕсли;
КонецПроцедуры
В исходном коде автора была строка: АдресХранилища = Новый УникальныйИдентификатор();. Это архитектурная ошибка. Выясним почему:
Метод ПоместитьВоВременноеХранилище вторым параметром может принимать либо конкретный адрес (строку), либо УникальныйИдентификатор. Если передать новый идентификатор, созданный «на лету», 1С создаст запись в хранилище, которая будет жить до момента завершения сеанса или пока не будет вытеснена механизмом очистки. Это приводит к неоправданному росту объема временных файлов на сервере.
Правильнее всего передавать УникальныйИдентификатор текущей управляемой формы. В этом случае платформа жестко связывает время жизни данных в хранилище с временем жизни формы. Как только пользователь закроет окно — данные на сервере будут удалены автоматически. Это критически важно для высоконагруженных систем.
Проанализируем ситуацию, когда сервер 1С работает под управлением Linux. В этом случае тип макета ActiveDocument вообще не сможет быть инициализирован на сервере, так как он требует Win32-библиотек. Единственный выход — хранить все шаблоны как Двоичные данные. В этом случае сервер 1С просто передает массив байтов из базы данных в хранилище, не пытаясь понять его структуру. Это универсальный и кроссплатформенный подход, который избавит вас от множества проблем в будущем.
Подведем итог нашему разбору. Чтобы успешно передать макет для формирования печатной формы в управляемом приложении, придерживайтесь следующих правил:
ДвоичныеДанные.ActiveDocument в Двоичные данные прямо в дереве метаданных конфигурации. Это обеспечит стабильность работы даже без установленного Office на сервере.Соблюдение этих рекомендаций позволит вам создавать надежные и быстрые механизмы печати документов, которые будут работать корректно вне зависимости от сложности инфраструктуры вашего предприятия.