Почему не отображается окно Excel при вызове COM-объекта на сервере 1С и как правильно загружать данные?

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

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

Причины скрытого выполнения и ошибки класса Range

Проанализируем типовую ситуацию: в серверной процедуре (директива &НаСервере) создается объект Excel.Application и устанавливается свойство Excel.Visible = 1. Однако окно на экране пользователя не появляется. Выясним технические причины такого поведения:

  1. Изоляция нулевой сессии (Session 0 Isolation): Серверная служба 1С (процесс rphost) работает в отдельной системной сессии Windows, которая полностью изолирована от интерактивного рабочего стола пользователя. Любое приложение, запущенное службой, физически не имеет доступа к графическому экрану текущего терминального или локального сеанса. Окно открывается исключительно внутри контекста учетной записи службы.
  2. Ошибки методов Select() и Activate(): Попытка использовать интерактивное позиционирование (например, Лист.Cells(н, 1).Select()) в скрытом фоновом режиме или под системной службой гарантированно приводит к исключению COM. Данные методы предназначены только для управления курсором в графическом интерфейсе. При программной обработке обращаться к данным следует напрямую через свойство Value или Value2.
  3. Ограничения серверного COM: Вендор Microsoft официально не поддерживает и не рекомендует запуск приложений пакета MS Office на стороне сервера. Это приводит к зависанию процессов EXCEL.EXE, блокировке потоков и утечкам оперативной памяти. Для минимальной инициализации COM на сервере часто требуются дополнительные настройки прав DCOM и наличие каталогов Desktop в профиле systemprofile.

Способ 1. Загрузка через штатный объект ТабличныйДокумент (рекомендуемый)

Наиболее надежный, кроссплатформенный и быстрый способ, встроенный в платформу 1С:Предприятие 8.3 — использование объекта ТабличныйДокумент. Он не требует установленного Microsoft Office, работает на Linux и Windows, и полностью исключает зависимость от COM-соединений.

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

Посмотрим на пример клиентского кода:


&НаКлиенте
Процедура ЗагрузитьФайлНаКлиенте(Команда)
    ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
    ПараметрыДиалога.Заголовок = "Выберите файл Excel для загрузки";
    ПараметрыДиалога.Фильтр = "Файлы Excel (*.xlsx;*.xls)|*.xlsx;*.xls";
    
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект);
    НачатьПомещениеФайлаНаСервер(Оповещение, , , ПараметрыДиалога, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораФайла(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ПрочитатьФайлНаСервере(Результат.Адрес);
КонецПроцедуры

Разберем серверную часть обработки файла:


&НаСервере
Процедура ПрочитатьФайлНаСервере(АдресВХранилище)
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХранилище);
    ВременныйФайл = ПолучитьИмяВременногоФайла("xlsx");
    ДвоичныеДанные.Записать(ВременныйФайл);
    
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Прочитать(ВременныйФайл, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    
    УдалитьФайлы(ВременныйФайл);
    
    ВсегоСтрок = ТабДок.ВысотаТаблицы;
    ВсегоКолонок = ТабДок.ШиринаТаблицы;
    
    Для НомерСтроки = 2 По ВсегоСтрок Цикл
        ЗначениеКолонки1 = ТабДок.Область(НомерСтроки, 1).Текст;
        ЗначениеКолонки2 = ТабДок.Область(НомерСтроки, 2).Текст;
        
        // Выполняем заполнение реквизитов документа или справочника
    КонецЦикла;
КонецПроцедуры

Способ 2. Выполнение COM-автоматизации на стороне клиента

Если специфика задачи требует обязательного отображения окна Excel пользователю или использования специфических макросов, весь COM-объект необходимо инициализировать в контексте &НаКлиенте. На клиенте считываем данные, упаковываем их в структуры и массивы, после чего единым пакетом передаем на сервер для записи в базу данных.

Рассмотрим реализацию данного подхода:


&НаКлиенте
Процедура ЗагрузитьЧерезCOMНаКлиенте(ПутьКФайлу)
    Попытка
        Excel = Новый COMObject("Excel.Application");
    Исключение
        Сообщить("Не удалось запустить Excel: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    Excel.Visible = Истина; // Окно отобразится пользователю
    Книга = Excel.Workbooks.Open(ПутьКФайлу);
    Лист = Книга.WorkSheets(1);
    
    ТаблицаДанных = Новый Массив;
    ВсегоСтрок = Лист.UsedRange.Rows.Count;
    
    // Обращение напрямую к свойству Value без методов Select и Activate
    Для НомерСтроки = 2 По ВсегоСтрок Цикл
        СтрокаДанных = Новый Структура;
        СтрокаДанных.Вставить("Артикул", СокрЛП(Лист.Cells(НомерСтроки, 1).Value));
        СтрокаДанных.Вставить("Количество", Лист.Cells(НомерСтроки, 2).Value);
        СтрокаДанных.Вставить("Цена", Лист.Cells(НомерСтроки, 3).Value);
        
        ТаблицаДанных.Добавить(СтрокаДанных);
    КонецЦикла;
    
    Книга.Close(Ложь);
    Excel.Quit();
    Excel = Неопределено;
    
    // Передаем собранный массив на сервер для записи
    ЗаписатьДанныеВДокументНаСервере(ТаблицаДанных);
КонецПроцедуры

Способ 3. Прямое чтение структуры XLSX через XML и ZIP

Файлы современного формата .xlsx представляют собой сжатые ZIP-архивы, содержащие таблицы в формате XML. При необходимости обработать сотни тысяч строк с максимальной производительностью без участия сторонних программ можно применить объекты ЧтениеZipФайла и ЧтениеXML.

  1. Распаковываем архив во временный каталог с помощью объекта ЧтениеZipФайла.
  2. Считываем пул общих строк из файла /xl/sharedStrings.xml.
  3. Последовательно читаем целевой лист из файла /xl/worksheets/sheet1.xml потоковым объектом ЧтениеXML.

Этот подход обеспечивает предельную скорость парсинга больших объемов данных как на клиенте, так и на сервере.

Способ 4. Чтение файла через ADO / OLE DB

Еще один способ быстро прочитать файл Excel без визуального открытия приложения — использование технологии ADO. В этом случае файл воспринимается как база данных, а листы — как таблицы.

Разберем пример подключения через OLE DB:


&НаСервере
Процедура ПрочитатьЧерезADO(ПутьКФайлу)
    Соединение = Новый COMObject("ADODB.Connection");
    СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ПутьКФайлу + ";Extended Properties=""Excel 12.0 XML;HDR=YES;"";";
    
    Попытка
        Соединение.Open(СтрокаПодключения);
        НаборЗаписей = Новый COMObject("ADODB.Recordset");
        НаборЗаписей.Open("SELECT * FROM [Лист1$]", Соединение);
        
        Пока Не НаборЗаписей.EOF() Цикл
            Значение1 = НаборЗаписей.Fields(0).Value;
            Значение2 = НаборЗаписей.Fields(1).Value;
            
            НаборЗаписей.MoveNext();
        КонецЦикла;
        
        НаборЗаписей.Close();
        Соединение.Close();
    Исключение
        Сообщить("Ошибка чтения через ADO: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

Итог: Для стабильной работы клиент-серверной архитектуры 1С следует отказаться от серверной COM-автоматизации Excel в пользу платформенного объекта ТабличныйДокумент или передачи предварительно собранных структур с клиента на сервер.

← На главную