Как исправить ошибку создания COMОбъекта Excel.Application на сервере 1С?

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

При переносе базы 1С из файлового варианта в клиент-серверный режим работы (под управлением Microsoft SQL Server или PostgreSQL) разработчики часто сталкиваются с ошибкой при чтении файлов Microsoft Excel. Код, который штатно отрабатывал на рабочей станции пользователя, в серверном контексте аварийно завершается с ошибкой -2147467262 (0x80004002): Интерфейс не поддерживается.

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

Причины сбоя COM-соединения в серверном контексте

Выясним причину, почему в файловой базе или на клиенте код работает, а на сервере падает в исключение. При выполнении кода на стороне сервера инициализация COM-объекта происходит в контексте изолированной неинтерактивной службы (Session 0) под учетной записью пользователя службы сервера 1С (обычно usr1cv8). Это накладывает ряд системных ограничений:

  1. Несовпадение битности и повреждение веток реестра TypeLib: Если на сервере обновлялся Microsoft Office, в системном реестре могут остаться устаревшие ссылки на библиотеки типов COM-сервера Excel. Ошибка 0x80004002 напрямую указывает на сбой маршалинга COM-интерфейсов из-за конфликта веток реестра.
  2. Отсутствие специальных каталогов рабочего стола (Desktop): Архитектура Excel требует физического наличия папки рабочего стола в системном профиле для создания временных файлов при неинтерактивном запуске.
  3. Ограничения прав DCOM: Служебная учетная запись сервера 1С по умолчанию не имеет прав на удаленный или локальный запуск и активацию COM-компонентов Office.

Способ 1. Настройка системных папок и службы DCOM на сервере

Если отказаться от использования Excel.Application на сервере невозможно, выполним настройку операционной системы Windows Server.

  1. Создание системных папок Desktop:
    В зависимости от разрядности операционной системы и сервера 1С создадим папки профиля (если они отсутствуют):
    Для 32-битных процессов: C:\Windows\SysWOW64\config\systemprofile\Desktop
    Для 64-битных процессов: C:\Windows\System32\config\systemprofile\Desktop
    Выдадим полные права на эти папки учетной записи, от имени которой запущена служба сервера 1С (например, usr1cv8).
  2. Настройка прав DCOM для Microsoft Excel:
    Завершим все зависшие процессы Excel в диспетчере задач или через командную строку: taskkill /im excel.exe /f Откроем оснастку Службы компонентов (dcomcnfg.exe), перейдем по дереву: Службы компонентов → Компьютеры → Мой компьютер → Настройка DCOM.
    Найдем в списке компонент Microsoft Excel Application и откроем его свойства:
    На вкладке Удостоверение (Identity) установим переключатель в положение Текущий пользователь (The interactive user) или укажем конкретную учетную запись администратора.
    На вкладке Безопасность (Security) в блоках «Разрешения на запуск и активацию» и «Разрешения доступа» настроим особые права и добавим пользователя службы 1С, выдав ему флаги Локальный запуск и Локальная активация.
  3. Исправление веток реестра TypeLib (при ошибке 0x80004002):
    Откроем regedit и найдем ветку HKEY_CLASSES_ROOT\TypeLib\{00020813-0000-0000-C000-000000000046}.
    Если внутри находятся подразделы нескольких версий (например, 1.7, 1.8, 1.9), удалим ключи, соответствующие старым, не установленным в данный момент версиям Office.

Способ 2. Чтение файла через объект «ТабличныйДокумент» (Рекомендуемый)

Наиболее надежным и платформенно-независимым решением является полный отказ от COM-объектов в пользу встроенного объекта платформы ТабличныйДокумент. Этот метод работает на сервере без установки Microsoft Office, корректно функционирует в базах под управлением Linux и не блокирует память серверов зависшими процессами excel.exe.

Рассмотрим пример кода для серверного чтения файлов формата .xlsx и .xls:


&НаСервере
Процедура ПрочитатьФайлExcelЧерезТабличныйДокумент(ПолноеИмяФайла)
    
    ТабДок = Новый ТабличныйДокумент;
    
    Попытка
        // Читаем файл формата xlsx или xls напрямую средствами платформы
        ТабДок.Прочитать(ПолноеИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    Исключение
        ВызватьИсключение "Не удалось прочитать файл: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
    ВсегоСтрок = ТабДок.ВысотаТаблицы;
    ВсегоКолонок = ТабДок.ШиринаТаблицы;
    
    // Обходим строки полученного документа (начиная со 2-й, если 1-я — заголовок)
    Для НомерСтроки = 2 По ВсегоСтрок Цикл
        
        Артикул = ТабДок.ПолучитьОбласть(НомерСтроки, 1).Текст;
        НоменклатураНаименование = ТабДок.ПолучитьОбласть(НомерСтроки, 2).Текст;
        Количество = ТабДок.ПолучитьОбласть(НомерСтроки, 3).ТекущаяОбласть.Значение;
        Цена = ТабДок.ПолучитьОбласть(НомерСтроки, 4).ТекущаяОбласть.Значение;
        
        Если ПустаяСтрока(Артикул) И ПустаяСтрока(НоменклатураНаименование) Тогда
            Продолжить; // Пропускаем пустые строки
        КонецЕсли;
        
        // Обработка полученных данных и заполнение реквизитов или табличных частей
        
    КонецЦикла;
    
КонецПроцедуры

Способ 3. Перенос чтения COM на сторону клиента

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

Посмотрим на пример организации взаимодействия клиента и сервера:


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

&НаСервере
Процедура ЗагрузитьДанныеВДокументНаСервере(МассивДанных)
    // Заполнение табличной части документа и запись объекта базы
КонецПроцедуры

Способ 4. Чтение через провайдер ADO (Microsoft OLE DB / ACE)

Если требуется высокая скорость обработки объемных файлов на сервере без создания ресурсоемкого процесса excel.exe, можно использовать подключение через ADODB. Для этого на сервере устанавливается компонент Microsoft Access Database Engine.

Разберем пример подключения к файлу как к источнику реляционных данных:


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

Итог: Использование ТабличныйДокумент.Прочитать() — самый надежный и простой способ интеграции, решающий проблему несовместимости прав и архитектурных ограничений серверного вызова COM-объектов.

← На главную