При работе с платформой 1С:Предприятие версии 8.3 (и старше) разработчики часто сталкиваются с необходимостью формирования файлов различных форматов, включая Microsoft Excel. Хотя для создания табличных документов в 1С существуют встроенные механизмы, в некоторых случаях удобнее использовать прямой COM-объект Excel для сложных отчетов или взаимодействия с уже существующими шаблонами. Однако при попытке выполнения операций с COM-объектом Excel на сервере 1С, особенно связанных с сохранением файлов, мы можем столкнуться с неожиданными зависаниями и непредсказуемым поведением. В этой статье мы подробно разберем, почему возникают такие проблемы и как их эффективно решить.
Давайте рассмотрим типичную ситуацию, описанную в исходной теме форума. Разработчик пытается создать и сохранить Excel-файл из конфигурации 1С:Зарплата и Управление Персоналом 2.5 (или любой другой конфигурации на платформе 8.3, использующей управляемые формы) на сервере 1С. При этом, при запуске той же операции в файловом варианте базы (т.е. на клиентской машине, где и запускается 1С), все работает корректно: Excel-файл создается и сохраняется без проблем.
Однако при выполнении кода на сервере 1С мы наблюдаем следующее:
Попытка...Исключение в код создания COM-объекта, добавления книги и сохранения файла, никаких ошибок не возникает. Процесс просто не заканчивается, а исключения не перехватываются.Это явно указывает на то, что Excel или операционная система чего-то ожидают, но не получают, что приводит к зависанию процесса 1С-сервера.
Проанализируем основные причины, которые приводят к описанным зависаниям, и предложим конкретные шаги для их устранения.
Первостепенная причина кроется в фундаментальном различии между клиентским и серверным окружениями 1С:Предприятия.
ragent.exe, rmngr.exe, rphost.exe) обычно запускается от имени специальной сервисной учетной записи (например, "Локальная система" или выделенной учетной записи типа "USR1CV8"). Эта учетная запись не имеет интерактивного рабочего стола, не может отображать диалоговые окна и имеет свой собственный набор прав доступа, которые могут сильно отличаться от прав интерактивного пользователя.Microsoft Office, и Excel в частности, изначально не предназначен для работы в серверном окружении без интерактивного пользователя. Он может пытаться отобразить различные диалоговые окна (например, "Файл уже существует, заменить?", "Сохранить изменения перед закрытием?", "Проблемы совместимости") или ожидать доступа к каким-либо ресурсам, доступным только интерактивному пользователю. На сервере эти диалоги просто не появляются, и Excel зависает, ожидая ответа, который никогда не получит.
Самым простым и надежным решением является перенос всего процесса создания и сохранения Excel-файла на клиентскую сторону. Этот подход был успешно применен в обсуждаемой теме и является рекомендуемым Microsoft для интерактивных сценариев.
&НаКлиенте или вызывается из клиентской процедуры.СписокЗначений, передавая их как параметры клиентской функции.Пример адаптации кода (на основе сообщения 9):
Предположим, что данные ДанныеДляКонсоли формируются на сервере. Мы можем передать их на клиент и уже там выполнить формирование Excel.
// В серверной процедуре (или в обработчике команды на управляемой форме)
&НаСервере
Функция ПолучитьДанныеДляОтчета()
// Здесь формируем необходимые данные на сервере
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("ФИО");
// Пример заполнения
Для Каждого СтрокаТЗ Из Справочники.ФизическиеЛица.Выбрать() Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.ФИО = СтрокаТЗ.Наименование;
КонецЦикла;
Возврат ТаблицаДанных;
КонецФункции
// В клиентской процедуре
&НаКлиенте
Процедура КомандаСохранитьExcel(Команда)
ШырПуть = "";
// Открываем диалог выбора файла на клиенте
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Выберите место для сохранения файла Excel";
Диалог.Фильтр = "Файлы Excel (*.xlsx)|*.xlsx";
Диалог.ПолноеИмяФайла = "Отчет_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".xlsx";
Если Диалог.Выбрать() Тогда
ШырПуть = Диалог.ПолноеИмяФайла;
Иначе
Возврат; // Пользователь отменил сохранение
КонецЕсли;
// Получаем данные с сервера
ДанныеДляКонсоли = ПолучитьДанныеДляОтчета();
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
ВызватьИсключение("COMОбъект(Excel) не создан. Возможно, Excel не установлен на компьютере!");
КонецПопытки;
// Добавляем эту строку, чтобы Excel не выводил диалоговые окна
Excel.DisplayAlerts = 0;
Попытка
Книга = Excel.WorkBooks.Add;
Исключение
Excel.Quit(); // Корректно закрываем Excel в случае ошибки
ВызватьИсключение("COMОбъект(Excel) создан, но книга НЕ ДОБАВЛЕНА!");
КонецПопытки;
Лист = Книга.WorkSheets(1);
Лист.Cells(1, 1).Value = "ФИО";
СтрНом = 2;
Для Каждого СтрКон Из ДанныеДляКонсоли Цикл
Лист.Cells(СтрНом, 1).Value = СтрКон.ФИО;
СтрНом = СтрНом + 1;
КонецЦикла;
Попытка
Книга.SaveAs(ШырПуть);
Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
Excel.Quit();
Сообщить("Файл успешно сохранен: " + ШырПуть, СтатусСообщения.Информация);
Исключение
Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
Excel.Quit();
Сообщить("ОШИБКА сохранения файла!", СтатусСообщения.ОченьВажное);
Ошибка = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("ОШИБКА сохранения файла!", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
КонецПопытки;
КонецПроцедуры
Обратите внимание, что в данном примере мы добавили вызов Excel.DisplayAlerts = 0; перед работой с книгой. Это вторая важная часть решения.
Как мы уже выяснили, одной из основных причин зависаний являются скрытые диалоговые окна Excel, которые сервер не может отобразить и обработать. Для решения этой проблемы существует специальное свойство COM-объекта Excel.
Excel.DisplayAlerts: Это свойство управляет отображением предупреждений и сообщений Excel. Если установить его в 0 (или Ложь в контексте 1С), Excel не будет выводить никаких диалоговых окон, а вместо этого будет принимать действия по умолчанию.Excel.DisplayAlerts = 0; сразу после успешного создания COM-объекта Excel (Новый COMОбъект("Excel.Application")).Пример кода из сообщения 9 с учетом DisplayAlerts:
&НаСервере // Предположим, вы все же решили попробовать на сервере
Процедура СохрФайлНаСервере(ШырПуть, ДанныеДляКонсоли)
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
// Здесь можно добавить более детальную обработку ошибки,
// например, запись в журнал регистрации и вывод сообщения пользователю через клиентскую процедуру.
ВызватьИсключение("COMОбъект(Excel) не создан. Возможно, Excel не установлен на компьютере!");
КонецПопытки;
// *** ВАЖНО: Отключаем вывод всех предупреждений и диалоговых окон Excel ***
Excel.DisplayAlerts = 0;
// Создание книги
Попытка
Книга = Excel.WorkBooks.Add;
Исключение
Excel.Quit(); // Корректно закрываем Excel
ВызватьИсключение("COMОбъект(Excel) создан, но книга НЕ ДОБАВЛЕНА!");
КонецПопытки;
Лист = Книга.WorkSheets(1);
Лист.Cells(1, 1).Value = "ФИО";
СтрНом = 2;
Для Каждого СтрКон Из ДанныеДляКонсоли Цикл
Лист.Cells(СтрНом, 1).Value = СтрКон.ФИО;
СтрНом = СтрНом + 1;
КонецЦикла;
// Сохранение книги
Попытка
Книга.SaveAs(ШырПуть);
Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
Excel.Quit();
// На сервере нельзя вызывать Сообщить(). Нужно передать информацию на клиент.
// Сообщить("Файл успешно сохранен: " + ШырПуть,СтатусСообщения.Информация);
Исключение
Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
Excel.Quit();
// Аналогично, на сервере нельзя вызывать Сообщить().
// Сообщить("ОШИБКА сохранения файла!", СтатусСообщения.ОченьВажное);
Ошибка = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("ОШИБКА сохранения файла!", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
ВызватьИсключение("ОШИБКА сохранения файла! " + Ошибка); // Пробрасываем ошибку на клиент
КонецПопытки;
КонецПроцедуры
Даже с Excel.DisplayAlerts = 0, работа с Excel на сервере все еще не является идеальным решением из-за других потенциальных проблем, которые мы рассмотрим далее.
Хотя перенос формирования Excel на клиентскую сторону и отключение сообщений с помощью Excel.DisplayAlerts = 0 являются основными решениями, существуют и другие важные аспекты, которые следует учитывать, если вы все же решаете (или вынуждены) использовать COM-объект Excel на сервере 1С.
Как уже упоминалось, сервер 1С работает под определенной системной или сервисной учетной записью. Эта учетная запись должна иметь:
rphost.exe (рабочий процесс сервера 1С), имеет полные права на чтение и запись в каталоге, куда сохраняется Excel-файл. Сисадмин должен это проверить. Это касается не только самой папки, но и всего пути к ней.dcomcnfg).Некорректные настройки DCOM часто приводят к ошибкам типа "COM-объект не создан" или к невозможности взаимодействия с уже созданным объектом.
Microsoft официально не рекомендует использовать COM-автоматизацию Office (включая Excel) на сервере по нескольким причинам:
Очень важно после каждой операции с Excel корректно завершать все связанные процессы. В приведенном коде используются Книга.Close() и Excel.Quit(), что является правильным подходом. Однако, в случае возникновения ошибок до вызова Quit(), экземпляры Excel могут оставаться висеть в фоновых процессах. Это приводит к накоплению "мертвых" процессов Excel, которые продолжают потреблять ресурсы сервера. Чтобы избежать этого, можно:
Попытка...Исключение...КонецПопытки: Оборачивайте операции с Excel в такие блоки и в секции Исключение всегда вызывайте Книга.Close(Ложь) и Excel.Quit().COMОбъект.Disconnect() (доступен для некоторых COM-объектов) или явно устанавливать переменные в Неопределено.EXCEL.EXE на сервере и, при необходимости, принудительно их завершайте (хотя это является временным решением, а не устранением причины).Если вам критически важно формировать Excel-файлы на сервере без интерактивного участия и вы хотите избежать проблем с COM-автоматизацией Microsoft Office, рассмотрите альтернативные решения:
Проблема зависания при сохранении Excel-файла на сервере 1С в большинстве случаев сводится к различиям в контексте выполнения между клиентом и сервером, а также к интерактивным запросам, которые Excel пытается отобразить. Наиболее простым и надежным решением является перенос формирования Excel-файлов на клиентскую сторону и использование свойства Excel.DisplayAlerts = 0. Если же серверное использование Excel является неизбежным, необходимо уделить пристальное внимание настройкам безопасности DCOM, правам доступа файловой системы и корректному завершению всех процессов Excel. Для наиболее стабильной и масштабируемой работы на сервере рекомендуется использовать специализированные библиотеки для работы с форматом XLSX, не требующие наличия установленного Microsoft Office.