COM-объект живёт на клиенте, данные нужны на сервере: рабочие схемы для 1С 8.3
Содержание
Передать COM-объект с клиента на сервер в 1С нельзя: значение типа COMОбъект не сериализуется и не переживает серверный вызов. На сервер передают не сам объект, а то, что из него прочитано, — числа, строки, даты, массивы и структуры, либо файл через временное хранилище. Если без COM на сервере не обойтись, объект создают прямо там: Новый COMОбъект(...) в процедуре с директивой &НаСервере.
Типичная ситуация: на клиенте открыли Excel через Excel.Application, хотите отдать лист в процедуру &НаСервере для записи в справочник — и получаете ошибку передачи параметра. Решение зависит от того, где установлена COM-программа: у пользователя, на сервере или нигде.
Как устроены клиент и сервер 1С и что можно передать между ними
В управляемом приложении код формы выполняется в двух местах. Процедуры с &НаКлиенте работают в процессе 1cv8c.exe (тонкий клиент) или 1cv8.exe (толстый клиент) на компьютере пользователя. Процедуры с &НаСервере и &НаСервереБезКонтекста выполняются в рабочем процессе кластера rphost.exe — часто на другой машине.
Каждый серверный вызов — это пересылка параметров по сети. Платформа упаковывает значения, передаёт их и распаковывает на другой стороне. Поэтому через границу проходят только сериализуемые типы.
| Можно передать | Нельзя передать |
|---|---|
| ✅ Число, Строка, Дата, Булево, Неопределено | ❌ COMОбъект |
| ✅ Массив, Структура, Соответствие из простых значений | ❌ COMSafeArray |
✅ Ссылки на объекты базы (СправочникСсылка...) | ❌ Объекты внешних компонент |
✅ ДвоичныеДанные, УникальныйИдентификатор | ❌ Значения, которые содержат хотя бы один из типов выше |
| ✅ Адрес во временном хранилище (строка) | ❌ Открытые файлы и потоки клиента |
Структура, в которую положили хотя бы одно COM-значение, тоже не передастся. Проверяйте не только сам параметр, но и всё, что лежит внутри.
Отдельно про файловый вариант базы. Там «сервер» работает внутри того же клиентского процесса, но правила контекстов действуют так же. Код, который передаёт COM-объект на сервер, упадёт и в файловой базе — платформа проверяет типы параметров независимо от режима.
Почему COM-объект не передаётся на сервер напрямую
COM-объект — это не данные, а указатель на объект в памяти конкретного процесса Windows. Excel, Word или другая COM-программа запущены на машине пользователя. Сервер 1С физически не может обратиться к этой памяти.
Причин, по которым платформа запрещает такую передачу, несколько:
- 🔌 Нет сериализации. COM-объект нельзя превратить в поток байтов и восстановить на другой стороне — он живёт, пока жив процесс, который его создал.
- 🖥️ Разные машины. Клиент — рабочая станция пользователя, сервер — отдельный компьютер. Ссылка на объект в памяти одного не имеет смысла на другом.
- 🐧 Сервер может работать под Linux. Там технологии COM нет вообще, и переносимого кода с COM на сервере не получится.
- 🌐 Веб-клиент. В браузере COM практически недоступен, а серверная часть одна для всех клиентов.
Отсюда вывод: вопрос «как передать COM-объект» всегда превращается в вопрос «где создать COM-объект и что из него передать». Рабочих схем три: читать на клиенте, отдавать файл или создавать объект на сервере.
Схема 1. Прочитать данные на клиенте и передать на сервер простые значения
Самый надёжный вариант, когда COM-программа установлена только у пользователя. Клиент открывает файл, читает нужные поля в массив структур, закрывает COM-объект и одним вызовом отдаёт массив на сервер.
&НаКлиенте
Процедура ЗагрузитьИзExcel(Команда)
Данные = Новый Массив;
Excel = Неопределено;
Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = Ложь;
Книга = Excel.Workbooks.Open(ПутьКФайлу);
Лист = Книга.Worksheets(1);
ВсегоСтрок = Лист.UsedRange.Rows.Count;
Для НомерСтроки = 2 По ВсегоСтрок Цикл
Строка = Новый Структура("Артикул, Количество, Цена");
Строка.Артикул = СокрЛП(Лист.Cells(НомерСтроки, 1).Value);
Строка.Количество = Лист.Cells(НомерСтроки, 2).Value;
Строка.Цена = Лист.Cells(НомерСтроки, 3).Value;
Данные.Добавить(Строка);
КонецЦикла;
Книга.Close(Ложь);
Исключение
Сообщить("Не удалось прочитать файл: " + ОписаниеОшибки());
КонецПопытки;
Если Excel <> Неопределено Тогда
Excel.Quit();
Excel = Неопределено;
КонецЕсли;
Если Данные.Количество() > 0 Тогда
ЗаписатьНаСервере(Данные);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаписатьНаСервере(Данные)
Для Каждого Строка Из Данные Цикл
// Поиск номенклатуры по Строка.Артикул и запись в базу
КонецЦикла;
КонецПроцедуры
Что здесь важно:
- Чтение и закрытие — на клиенте. COM-объект не покидает клиентскую процедуру. На сервер уходит
МассивизСтруктурас примитивами — он сериализуется без проблем. - Значения ячеек уже приведены к типам 1С. Свойство
Valueвозвращает Число, Строку или Дату, а не COM-обёртку. Их можно класть в структуру как есть. - Один серверный вызов на весь файл. Не вызывайте сервер в цикле по строкам: 5 000 строк — это 5 000 сетевых обращений вместо одного.
Excel.Quit()в любом случае. Иначе на компьютере пользователя останется висеть процессEXCEL.EXE.
Для ВсегоСтрок используется UsedRange.Rows.Count — это верно, если данные начинаются с первой строки листа. Если над таблицей есть пустые строки, берите номер последней строки как UsedRange.Row + UsedRange.Rows.Count - 1.
Обращение к каждой ячейке — отдельный COM-вызов, и на больших листах это медленно. Быстрее прочитать весь диапазон одним обращением: Лист.UsedRange.Value вернёт COMSafeArray. Но его тоже нельзя передать на сервер — сначала выгрузите его в обычный массив методом Выгрузить() и уже массив передавайте.
Если COM-объект нужен на клиенте между несколькими вызовами, храните его в переменной модуля формы, объявленной с &НаКлиенте. В реквизит формы COM-объект положить нельзя: реквизиты хранятся на сервере.
Схема 2. Передать на сервер файл, а не COM-объект
Часто COM на клиенте нужен только для того, чтобы прочитать файл. Тогда проще отдать серверу сам файл: двоичные данные сериализуются, а разбирать их можно уже там.
&НаКлиенте
Процедура ОтправитьФайл(Команда)
ДД = Новый ДвоичныеДанные(ПутьКФайлу);
Адрес = ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор);
ОбработатьФайлНаСервере(Адрес);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ОбработатьФайлНаСервере(Адрес)
ДД = ПолучитьИзВременногоХранилища(Адрес);
ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
ДД.Записать(ИмяФайла);
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ИмяФайла);
// Разбор ТабДок.Область(...) построчно
УдалитьФайлы(ИмяФайла);
КонецПроцедуры
Плюсы этого пути:
- 📄
ТабличныйДокумент.Прочитать()читаетxlsxбез Excel вообще — ни на клиенте, ни на сервере ничего ставить не нужно. - 🐧 Код работает и на сервере под Linux.
- 🌐 Подходит для веб-клиента: там файл выбирают через диалог и отправляют асинхронными методами помещения файла, а не через конструктор
ДвоичныеДанные.
Временный файл на сервере удаляйте после разбора, в том числе при ошибке. Иначе каталог временных файлов рабочего процесса разрастается до гигабайтов.
Если файл большой (сотни мегабайт), временное хранилище нагружает память рабочего процесса. Такие файлы лучше класть в общий сетевой каталог и передавать на сервер только путь к нему — строкой.
Схема 3. Создать COM-объект прямо на сервере 1С
Когда COM-компонента нужна для серверной логики — регламентное задание, фоновая обработка, интеграция с внешней системой, — объект создают на сервере. Синтаксис тот же:
&НаСервереБезКонтекста
Функция ПолучитьДанныеЧерезCOM(ИмяФайла)
Объект = Новый COMОбъект("Excel.Application");
// ...работа с объектом...
Объект.Quit();
Объект = Неопределено;
КонецФункции
Код короткий, но сервер под него нужно подготовить. Проверьте по порядку:
- Сервер 1С работает под Windows. Под Linux конструктор
COMОбъектна сервере недоступен. - Компонента установлена и зарегистрирована на сервере, а не на компьютере программиста. ProgID ищется в реестре той машины, где запущен
rphost.exe. - Совпадает разрядность. 64-битный сервер 1С не загрузит 32-битную внутрипроцессную компоненту (DLL) — будет ошибка «класс не зарегистрирован». Внепроцессные серверы вроде Excel работают при любой разрядности.
- У учётной записи службы 1С есть права. Служба агента обычно запущена от отдельного пользователя (например,
USR1CV8). Права на запуск и активацию COM-приложения настраиваются в оснасткеdcomcnfg→Службы компонентов→Компьютеры→Мой компьютер→Настройка DCOM. - Для Excel и Word — каталог Desktop. Office, запущенный из службы без профиля, часто не открывает файлы и возвращает пустой объект. Помогает создание пустых папок
C:\Windows\System32\config\systemprofile\DesktopиC:\Windows\SysWOW64\config\systemprofile\Desktop.
Для подключения к другой базе 1С на сервере используют V83.COMConnector. Его библиотека comcntr.dll лежит в каталоге bin платформы и регистрируется командой от администратора:
regsvr32 "C:\Program Files\1cv8\8.3.24.1548\bin\comcntr.dll"
Номер версии в пути подставьте свой — он должен совпадать с версией и разрядностью сервера 1С.
Microsoft официально не поддерживает автоматизацию Office из служб и серверных процессов. Excel на сервере зависает на модальных окнах, плодит процессы и плохо переносит параллельную работу нескольких пользователей. Для чтения таблиц на сервере выбирайте схему 2.
Зависшие процессы EXCEL.EXE на сервере, запущенные от учётной записи службы 1С, можно завершить через диспетчер задач. Перед этим убедитесь, что сейчас не идёт загрузка у пользователей: их операция оборвётся с ошибкой. Безопаснее делать это вне рабочего времени.
Ошибки при работе с COM и как их перехватывать
Любую работу с COM оборачивайте в Попытка ... Исключение. COM-программа живёт своей жизнью: файл может быть занят, лист переименован, сама программа не установлена. Без перехвата пользователь увидит системное окно с кодом и потеряет данные формы.
Минимальный шаблон для серверной стороны:
Попытка
Объект = Новый COMОбъект("Excel.Application");
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("Загрузка.COM", УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(Инфо));
ВызватьИсключение "Не удалось запустить Excel на сервере. Обратитесь к администратору.";
КонецПопытки;
Подробности уходят в журнал регистрации, пользователь видит понятный текст. Администратор потом найдёт запись по событию Загрузка.COM в Администрирование → Обслуживание → Журнал регистрации.
Чем заменить COM-взаимодействие
COM — старая технология с жёсткой привязкой к Windows. Для большинства задач в 1С 8.3 есть способы без неё, и они работают одинаково на клиенте и на сервере.
| Задача | Вместо COM | Где работает |
|---|---|---|
| Прочитать или сохранить xlsx | ТабличныйДокумент.Прочитать() / Записать() | Клиент и сервер, Windows и Linux |
| Обмен с другой базой 1С | HTTP-сервис, веб-сервис, план обмена | Сервер |
| Обмен с внешней программой | HTTP-запрос (HTTPСоединение), JSON, XML | Клиент и сервер |
| Работа с внешней СУБД | Внешние источники данных | Сервер |
| Оборудование и нестандартные функции | Внешняя компонента по технологии Native API | Клиент и сервер, в том числе Linux |
| Разбор CSV и текстовых выгрузок | ЧтениеТекста, СтрРазделить() | Клиент и сервер |
Внешние компоненты Native API — главная замена COM для своих библиотек. Компоненту подключают методом ПодключитьВнешнююКомпоненту(), она может работать и на сервере, если собрана под нужную операционную систему и разрядность. Объект внешней компоненты, как и COM-объект, между клиентом и сервером не передаётся: его подключают там, где он нужен.
Если код пишется для типовой конфигурации, загляните в общие модули БСП перед тем, как писать свою загрузку. Готовые механизмы загрузки из файла там уже решают передачу файла на сервер.
Частые вопросы
Можно ли передать COM-объект на сервер через временное хранилище?
Работает ли COM на сервере 1С под Linux?
Почему в файловой базе COM в серверной процедуре работает, а в клиент-серверной — нет?
Можно ли хранить COM-объект в реквизите формы?
&НаКлиенте.Как ускорить чтение большого листа Excel на клиенте?
Value и выгружайте полученный COMSafeArray в массив, вместо обращения к каждой ячейке. Сервер вызывайте один раз с готовым массивом.