Работа с файлами Microsoft Excel на стороне сервера 1С — это классическая задача, которая часто оборачивается труднодиагностируемыми ошибками. Типичная ситуация: код прекрасно работает на компьютере разработчика (в режиме тонкого или толстого клиента), но при попытке выполнить тот же фрагмент в серверном модуле или в фоновом задании система выдает лаконичное: «Ошибка при получении значения атрибута контекста (Workbooks): Неизвестная ошибка».
В этой статье мы подробно разберем, почему Excel «капризничает» на сервере, как правильно настроить операционную систему для работы COM-объектов и какие альтернативные способы чтения данных существуют в современных версиях платформы 1С:Предприятие.
Разберем ситуацию: когда вы запускаете Excel на своем компьютере, операционная система создает процесс под вашей учетной записью, у которой есть графическая оболочка, рабочий стол и временные папки. Служба сервера 1С (обычно usr1cv8) работает как системная служба. У нее нет «рабочего стола» в привычном понимании Windows. Программа Microsoft Excel, будучи изначально интерактивным приложением, при запуске пытается инициализировать свой интерфейс и обращается к системным папкам профиля пользователя. Если она их не находит, возникает та самая «Неизвестная ошибка».
Прежде чем пытаться «починить» COM-объект, проанализируем, действительно ли нам нужен установленный Excel на сервере. Начиная с версии платформы 8.3.6, объект ТабличныйДокумент умеет читать файлы формата .xlsx (OpenXML) напрямую. Это работает значительно быстрее, не требует лицензии Microsoft Office на сервере и не создает зависших процессов в памяти.
Рассмотрим пример кода для прямого чтения файла на сервере:
&НаСервере
Процедура ПрочитатьФайлЭксельНаСервере(ПутьКФайлу)
ТабДок = Новый ТабличныйДокумент;
Попытка
// Читаем файл напрямую в объект 1С
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Ошибка при чтении файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Работаем с данными как с обычной таблицей 1С
КоличествоСтрок = ТабДок.ВысотаТаблицы;
Для НомерСтроки = 1 По КоличествоСтрок Цикл
Значение = ТабДок.Область(НомерСтроки, 1).Текст;
// Обработка данных...
КонецЦикла;
КонецПроцедуры
Преимущества этого метода:
excel.exe.Если специфика задачи требует использования именно Excel.Application (например, нужно выполнять сложные макросы или использовать специфическое форматирование), нам придется подготовить «почву» для работы COM-объекта. Выясним причину ошибки: Excel не может найти папку Desktop в профиле системной учетной записи.
Разберем шаги по исправлению:
C:\Windows\SysWOW64\config\systemprofile\DesktopC:\Windows\System32\config\systemprofile\Desktop1C:Enterprise 8.3 Server Agent.После создания этих папок Excel сможет инициализировать свой контекст, и обращение к коллекции Workbooks перестанет вызывать ошибку.
Иногда создание папок недостаточно, так как у службы 1С нет прав на запуск и активацию COM-сервера. Проанализируем настройки безопасности компонентов:
dcomcnfg (Службы компонентов) через «Выполнить».usr1cv8.Существует «промежуточный» вариант, который не требует запуска полноценного приложения Excel, но позволяет читать файлы как базы данных. Рассмотрим этот подход, если ТабличныйДокумент по каким-то причинам не подходит.
Для этого метода требуется установленный драйвер Microsoft Access Database Engine. Посмотрим на пример подключения:
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ПутьКФайлу + ";Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
Connection = Новый COMОбъект("ADODB.Connection");
Попытка
Connection.Open(СтрокаПодключения);
Recordset = Новый COMОбъект("ADODB.Recordset");
Recordset.Open("SELECT * FROM [Лист1$]", Connection);
// Перебор данных...
Recordset.Close();
Connection.Close();
Исключение
// Обработка ошибок
КонецПопытки;
Если вы все же решили использовать Excel.Application через COM, помните о безопасности сервера. Обязательно используйте блок Попытка...Исключение и всегда закрывайте приложение в блоке завершения, иначе ваш сервер быстро заполнится сотнями «висящих» процессов excel.exe, что в итоге приведет к нехватке оперативной памяти и падению службы 1С.
Проанализируем правильный шаблон закрытия объекта:
Эксель = Новый COMОбъект("Excel.Application");
Попытка
Книга = Эксель.Workbooks.Open(ПутьКФайлу);
// Код обработки данных
Книга.Close(Ложь);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
// Принудительное завершение процесса
Эксель.Quit();
Эксель = Неопределено;
Резюмируем: для стабильной работы сервера 1С старайтесь максимально уходить от использования COM-объектов Microsoft Office в пользу встроенного метода ТабличныйДокумент.Прочитать(). Это избавит вас от проблем с правами доступа, разрядностью систем и утечками памяти.