При разработке механизмов выгрузки данных в Excel или работе с печатными формами программисты 1С часто сталкиваются с необходимостью передачи макета с сервера на клиент. Одной из самых коварных проблем является использование макетов типа ActiveDocument, которые при попытке инициализации на стороне клиента могут выдавать пугающие ошибки вроде 0x80080005 (Ошибка при выполнении приложения-сервера). В этой статье мы подробно разберем, почему это происходит, как правильно передавать файлы и какие системные настройки могут блокировать работу COM-объектов.
Рассмотрим стандартный сценарий: макет типа ActiveDocument хранится в обработке. Программист пытается извлечь его на сервере, поместить во временное хранилище, а на клиенте получить эти данные, записать во временный файл и открыть через Excel. Однако метод ПолучитьCOMОбъект() внезапно завершается аварией. Ошибка 0x80080005 сигнализирует о том, что операционная система не смогла запустить COM-сервер (в данном случае Excel) или не смогла подключиться к уже запущенному экземпляру.
Проанализируем базовый код, который часто становится источником проблем:
&НаСервере
Функция ПоместитьМакетВХранилище()
ОтчетОбъект = РеквизитФормыВЗначение("Объект");
Макет = ОтчетОбъект.ПолучитьМакет("МакетExcel"); // Тип ActiveDocument
ИмяВрем = ПолучитьИмяВременногоФайла(".xls");
Макет.Записать(ИмяВрем);
Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяВрем));
Возврат Адрес;
КонецФункции
&НаКлиенте
Процедура Тест()
Адрес = ПоместитьМакетВХранилище();
Данные = ПолучитьИзВременногоХранилища(Адрес);
ИмяФ = ПолучитьИмяВременногоФайла("xls");
Данные.Записать(ИмяФ);
// Ошибка часто возникает здесь:
МакетCOM = ПолучитьCOMОбъект(ИмяФ);
КонецПроцедуры
Первое, что важно понять: ActiveDocument в 1С — это не то же самое, что ТабличныйДокумент. Разберем основные отличия:
Записать() у ActiveDocument принимает только один параметр — путь к файлу. В отличие от табличного документа, вы не можете указать тип файла (например, ТипФайлаТабличногоДокумента.XLSX) вторым параметром. Если вы попытаетесь это сделать, система выдаст ошибку "Слишком много фактических параметров".ActiveDocument сохраняет файл ровно в том формате, в котором он был загружен в макет. Если вы загрузили .xls, он и будет записан как .xls.Функция ПолучитьCOMОбъект() является универсальной, но иногда ведет себя непредсказуемо. Она пытается самостоятельно определить приложение по расширению файла. Если в системе установлены разные версии Office или есть проблемы с ассоциациями файлов, она может "зависнуть".
Выясним, как сделать инициализацию более надежной. Рекомендуется использовать явное создание объекта Excel.Application. Рассмотрим правильный подход:
&НаКлиенте
Процедура ОткрытьМакетНадежно()
Адрес = ПоместитьМакетВХранилище();
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
ПутьКФайлу = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанные.Записать(ПутьКФайлу);
Попытка
Эксель = Новый COMОбъект("Excel.Application");
Эксель.Visible = Истина;
Книга = Эксель.Workbooks.Open(ПутьКФайлу);
Исключение
Сообщить("Ошибка запуска Excel: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Если код выше всё равно выдает ошибку 0x80080005, проблема кроется в настройках Windows. Проанализируем ключевые моменты:
EXCEL.EXE, это верный признак того, что предыдущие сессии не были закрыты корректно. Завершите их все.C:\Windows\SysWOW64\config\systemprofile\Desktop (для 64-битных ОС)C:\Windows\System32\config\systemprofile\DesktopЧтобы избежать "капризов" ActiveDocument, переведем хранение макета в формат Двоичные данные. Это наиболее стабильный вариант для обмена между сервером и клиентом.
Рассмотрим по шагам, как это реализовать:
Шаг 1. Подготовка макета. Удалите старый макет ActiveDocument. Создайте новый макет, выберите тип Двоичные данные и загрузите в него ваш файл Excel.
Шаг 2. Код на сервере. Теперь нам не нужно сохранять макет во временный файл на диске сервера, мы можем сразу поместить его в хранилище:
&НаСервере
Функция ПолучитьАдресМакета()
// Получаем двоичные данные напрямую из макета
ДанныеМакета = УправляемоеПриложение.ПолучитьМакет("МойExcelМакет");
Возврат ПоместитьВоВременноеХранилище(ДанныеМакета);
КонецФункции
Шаг 3. Код на клиенте. Получаем данные и открываем их. Обратите внимание на использование расширения файла:
&НаКлиенте
Процедура ВыполнитьПечать()
Адрес = ПолучитьАдресМакета();
Данные = ПолучитьИзВременногоХранилища(Адрес);
// Используем расширение, соответствующее вашему макету
Путь = ПолучитьИмяВременногоФайла(".xlsx");
Данные.Записать(Путь);
// Запускаем Excel
Попытка
ExcelApp = Новый COMОбъект("Excel.Application");
ExcelApp.Workbooks.Open(Путь);
ExcelApp.Visible = Истина;
Исключение
Сообщить("Не удалось запустить Excel. Проверьте настройки системы.");
КонецПопытки;
КонецПроцедуры
Использование Двоичных данных гарантирует, что 1С никак не вмешивается в структуру файла при его получении из метаданных. Мы просто передаем набор байтов. ActiveDocument же пытается инициализировать OLE-оболочку еще на этапе обращения к макету, что на сервере (особенно под управлением Linux или в специфических сессиях) может привести к сбою еще до того, как данные попадут в ваше распоряжение.
Важный совет: Всегда закрывайте COM-объекты после завершения работы. Несмотря на то, что 1С делает это автоматически при уничтожении переменной, явное ExcelApp.Quit() в блоках завершения гарантирует отсутствие "фантомных" процессов в системе.
Подведем итог: если вы столкнулись с ошибкой выполнения приложения-сервера, первым делом проверьте корректность инициализации COM-объекта, наличие системных папок Desktop и, по возможности, откажитесь от использования ActiveDocument в пользу Двоичных данных. Это сделает вашу систему выгрузки более устойчивой к обновлениям платформы и смене операционных систем.