Как исправить ошибку ПолучитьИзВременногоХранилища при передаче ActiveDocument в управляемом приложении?

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

При разработке в управляемом приложении «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда код, успешно работавший в обычных формах, начинает выдавать ошибки. Одна из самых распространенных проблем — попытка передачи макета типа ActiveDocument с сервера на клиент через временное хранилище. В этой статье мы подробно разберем, почему возникает ошибка при вызове метода ПолучитьИзВременногоХранилища, и как правильно организовать работу с шаблонами Microsoft Word и Excel в клиент-серверной архитектуре.

Анализируем причину ошибки: почему ActiveDocument «не проходит» через хранилище?

Разберем ситуацию, описанную в теме. Автор пытается получить макет на сервере, поместить его во временное хранилище и извлечь на клиенте. В момент вызова ПолучитьИзВременногоХранилища система выдает ошибку. Проанализируем, почему это происходит.

Ключевая причина кроется в понятии сериализации. В управляемом приложении взаимодействие между клиентом и сервером (и временным хранилищем как промежуточным звеном) возможно только для тех типов данных, которые могут быть преобразованы в последовательность байтов и восстановлены обратно. Тип ActiveDocument по своей сути является оболочкой над COM-объектом (OLE-объектом). COM-объекты не сериализуемы. Они неразрывно связаны с адресным пространством того процесса, в котором они были созданы.

Когда мы выполняем ПоместитьВоВременноеХранилище(Макет, ...) на сервере, где Макет — это ActiveDocument, 1С пытается сохранить ссылку на этот объект. Однако при попытке прочитать его на клиенте через ПолучитьИзВременногоХранилища, система понимает, что она не может «перетащить» живой COM-объект из памяти сервера в память клиента. Именно в этот момент происходит аварийное завершение метода.

Кроме того, важно помнить о техническом окружении. Если на сервере не установлен Microsoft Office, попытка инициализации ActiveDocument через ПолучитьМакет() может привести к ошибкам еще на этапе сервера, так как 1С требует наличия соответствующих библиотек (интерфейсов) для работы с этим типом данных.

Правильная стратегия: использование двоичных данных

Посмотрим, как можно обойти это ограничение. Поскольку «живой» объект передать нельзя, мы должны передать «контент» этого объекта. Рассмотрим по шагам алгоритм, который является стандартом для работы в управляемых формах:

  1. На сервере: Получаем макет из конфигурации.
  2. На сервере: Преобразуем макет в тип ДвоичныеДанные. Этот тип прекрасно сериализуется и передается через хранилище.
  3. На сервере: Помещаем двоичные данные во временное хранилище, привязывая их к идентификатору формы.
  4. На клиенте: Получаем двоичные данные из хранилища.
  5. На клиенте: Сохраняем эти данные в локальный временный файл на диске пользователя.
  6. На клиенте: Открываем этот файл с помощью локально установленного офисного приложения через COM-соединение (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С создаст запись в хранилище, которая будет жить до момента завершения сеанса или пока не будет вытеснена механизмом очистки. Это приводит к неоправданному росту объема временных файлов на сервере.

Правильнее всего передавать УникальныйИдентификатор текущей управляемой формы. В этом случае платформа жестко связывает время жизни данных в хранилище с временем жизни формы. Как только пользователь закроет окно — данные на сервере будут удалены автоматически. Это критически важно для высоконагруженных систем.

Что делать, если на сервере Linux?

Проанализируем ситуацию, когда сервер 1С работает под управлением Linux. В этом случае тип макета ActiveDocument вообще не сможет быть инициализирован на сервере, так как он требует Win32-библиотек. Единственный выход — хранить все шаблоны как Двоичные данные. В этом случае сервер 1С просто передает массив байтов из базы данных в хранилище, не пытаясь понять его структуру. Это универсальный и кроссплатформенный подход, который избавит вас от множества проблем в будущем.

Выводы и рекомендации

Подведем итог нашему разбору. Чтобы успешно передать макет для формирования печатной формы в управляемом приложении, придерживайтесь следующих правил:

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

← На главную