При интеграции современных систем на базе 1С:Предприятие 8.3 с унаследованными базами 1С 7.7, используя средства обмена данными между базами 1С, разработчики часто сталкиваются с необходимостью получать данные в режиме реального времени. Если на клиенте OLE-соединение работает стабильно, то при переносе кода на сторону сервера возникают специфические проблемы: первый вызов проходит успешно, а второй и последующие (выполняемые параллельно) завершаются ошибкой при вызове метода Initialize. Разберем подробно, почему это происходит и как настроить сервер для стабильной работы.
Рассмотрим типичный сценарий. В общем модуле 1С 8.3 с установленным флагом Сервер создается функция для подключения к внешней базе. Проблема заключается в том, что когда два пользователя одновременно пытаются выполнить перенос объектов 1С или сформировать отчет, второй процесс блокируется, хотя первый еще продолжает работу. Проанализируем стандартный код подключения:
Функция ПодключитьБазу77(ВнешняяБаза) Экспорт
Попытка
// Создаем COM-объект. Используем версионно-независимый ключ.
БазаОЛЕ = Новый COMОбъект("V1CEnterprise.Application");
Исключение
Возврат "Ошибка создания объекта: " + ОписаниеОшибки();
КонецПопытки;
Путь = ВнешняяБаза.Путь;
Пользователь = ВнешняяБаза.Пользователь;
Пароль = ВнешняяБаза.Пароль;
// Попытка инициализации соединения
ПараметрыЗапуска = "/D" + Путь + " /n" + Пользователь + " /p" + Пароль;
Если БазаОЛЕ.Initialize(БазаОЛЕ.RMTrade, ПараметрыЗапуска, "NO_SPLASH_SHOW") Тогда
Возврат БазаОЛЕ;
Иначе
Возврат "Ошибка метода Initialize. Возможно, база занята или недостаточно прав.";
КонецЕсли;
КонецФункции
Как мы видим, основная проблема возникает не на этапе Новый COMОбъект, а именно при выполнении метода Initialize. В серверном окружении 1С 7.7 ведет себя капризно, так как она изначально не проектировалась для работы в многопоточном режиме службы, хотя и поддерживает современные механизмы отправки API запросов.
Выясним причину, по которой Initialize возвращает Ложь. 1С 7.7 — это 32-битное приложение, которое даже в режиме OLE пытается инициализировать определенные графические ресурсы. В Windows для сервисов (к которым относится сервер 1С) выделяется отдельный неинтерактивный рабочий стол с очень ограниченным объемом памяти, называемым Desktop Heap.
Когда запускается один экземпляр 7.7, он занимает часть этой памяти. При попытке запуска второго экземпляра памяти под графические объекты не хватает, и ядро 7.7 аварийно завершает инициализацию. Рассмотрим, как это исправить через реестр Windows:
regedit.HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems.Windows. Это длинная строка.SharedSection=xxxx,yyyy,zzzz.zzzz) отвечает за размер кучи для неинтерактивных сессий. По умолчанию оно может быть 512. Увеличьте его до 1024 или 2048.Проанализируем ситуацию, когда сервер 1С 8.3 работает как 64-битный процесс. Напрямую загрузить 32-битную библиотеку 1С 7.7 в адресное пространство 64-битного процесса невозможно. В этом случае Windows использует COM Surrogate (процесс dllhost.exe). Однако стандартный суррогат плохо справляется с параллельностью для 7.7.
Для решения этой задачи создадим собственную «обертку» в службах компонентов:
dcomcnfg (Службы компонентов).1C77_Legacy_Bridge.dbeng32.dll или регистрация через V1CEnterprise.Application).Этот метод заставит каждый экземпляр 1С 7.7 запускаться в своем собственном процессе dllhost.exe, что обеспечит полную изоляцию и позволит запускать десятки параллельных соединений.
Разберем еще один важный аспект. 1С 7.7 при запуске создает временные файлы в папке TEMP и обращается к файлу настроек 1cv7.cfg. Если все OLE-сессии запускаются от имени одного пользователя службы usr1cv8, может возникнуть конфликт доступа к файлам (File Lock).
Рекомендация: Убедитесь, что у пользователя 1С 7.7 в конфигураторе не указан конкретный каталог пользователя, либо этот каталог уникален для каждой интеграционной задачи. Также проверьте, что папки Temp системного профиля (например, C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Temp) доступны для записи и не переполнены.
Проанализируем, какой именно объект мы создаем. В системе могут быть зарегистрированы разные версии 7.7. Вместо универсального V1CEnterprise.Application попробуйте использовать специфичные ключи, чтобы исключить ошибки поиска в реестре:
V77.Application — стандартная версия.V77S.Application — SQL-версия (наиболее стабильна для многопоточности).V77L.Application — локальная версия.V77M.Application — сетевая версия.Пример изменения кода для работы с SQL-версией:
БазаОЛЕ = Новый COMОбъект("V77S.Application");
Если манипуляции с DCOM и Desktop Heap кажутся слишком рискованными для рабочего сервера, рассмотрим архитектурное решение проблемы. Вместо прямого OLE-запроса из HTTP-сервиса, можно использовать «промежуточное звено»:
Такой подход медленнее на 1–2 секунды, но он абсолютно стабилен, так как исключает конфликты OLE-инициализации в контексте системных служб. Рассмотрим также вариант использования внешних компонент, таких как 1с++, которые позволяют выполнять прямые SQL-запросы к базе 7.7, минуя механизм OLE. Это самый быстрый способ получения данных, который не требует запуска графического ядра 7.7 вообще.
Мы выяснили, что параллельное подключение к 1С 7.7 из 8.3 на сервере возможно, но требует глубокой настройки операционной системы. Посмотрим на итоговый чек-лист действий:
Применяя эти методы, вы сможете построить высокопроизводительный «веб-сервер» на базе 1С 8.3, который будет бесперебойно отдавать данные из старых баз 7.7 в современные мобильные приложения или внешние системы.