При интеграции современных конфигураций на платформе 1С:Предприятие 8 со старыми базами на платформе 1С:Предприятие 7.7 разработчики часто сталкиваются со специфической технической проблемой. Если при программном подключении по OLE (через COM-соединение) передать неверное имя пользователя или ошибочный пароль, вызывающий процесс в 1С 8 «намертво» зависает на этапе инициализации соединения. В диспетчере задач операционной системы при этом появляется фоновый процесс 1cv7.exe, который не закрывается самостоятельно и блокирует выполнение кода.
В этой статье мы подробно разберем физику происходящих процессов в операционной системе Windows, выясним истинные причины такого поведения платформы 1С 7.7 и рассмотрим несколько надежных практических способов обхода и решения данной проблемы.
Давайте проанализируем ситуацию на системном уровне. Когда мы выполняем инициализацию OLE-соединения с помощью метода Initialize() COM-объекта V77.Application, платформа 1С 7.7 запускается в фоновом режиме. Если учетные данные указаны неверно, система 1С 7.7 не генерирует классическую программную ошибку (исключение), которую можно было бы перехватить стандартной конструкцией Попытка — Исключение в 1С 8. Вместо этого она пытается обработать ошибку стандартным интерактивным способом — открытием модального диалогового окна (окна выбора пользователя, ввода пароля или предупреждения о неверных данных).
Поскольку процесс OLE запускается в неинтерактивном (скрытом) режиме, это модальное окно создается на невидимом рабочем столе. Из-за архитектурных особенностей изоляции сессий в современных операционных системах Windows (Session 0 Isolation) пользователь физически не может увидеть это окно и нажать кнопку «ОК» или «Отмена». В результате процесс 1С 7.7 уходит в бесконечное ожидание ответа пользователя, а вызывающий поток 1С 8 блокируется на синхронном вызове метода Initialize().
Разберем наиболее надежный архитектурный подход на стороне вызывающей системы (1С:Предприятие 8). Так как мы не можем заставить синхронный метод OLE вернуть ошибку при неверном пароле, мы можем изолировать это подключение, запустив его в отдельном Фоновом задании.
Основной сеанс пользователя запускает фоновое задание и ожидает его завершения в течение строго отведенного времени (например, 10 секунд). Если фоновое задание не успело отработать за этот таймаут, мы принудительно отменяем его, а зависший в операционной системе процесс 1cv7.exe уничтожаем программно с помощью системной утилиты taskkill.
Рассмотрим пример кода. Сначала создадим процедуру в общем модуле 1С 8 (модуль должен выполняться на сервере):
Процедура ВыполнитьПодключениеOLE(ПараметрыПодключения, АдресРезультата) Экспорт
// Инициализируем COM-соединение с базой 1С 7.7
V7 = Новый COMОбъект("V77.Application");
// Пытаемся подключиться
СоединениеУстановлено = V7.Initialize(V7.RMTrade, ПараметрыПодключения.СтрокаПодключения, "NO_SPLASH_SHOW");
Если СоединениеУстановлено Тогда
// Сохраняем успешный результат во временное хранилище
ПоместитьВоВременноеХранилище(Истина, АдресРезультата);
Иначе
ПоместитьВоВременноеХранилище(Ложь, АдресРезультата);
КонецЕсли;
КонецПроцедуры
Теперь реализуем логику вызова этой процедуры с контролем времени выполнения на стороне клиента или в основном серверном потоке:
// Подготавливаем параметры подключения
Параметры = Новый Структура;
Параметры.Вставить("СтрокаПодключения", СтрокаПодключения);
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
ПараметрыПроцедуры = Новый Структура("ПараметрыПодключения, АдресРезультата", Параметры, АдресРезультата);
// Запускаем фоновое задание
ФоновоеЗадание = ФоновыеЗадания.Выполнить("ИнтеграцияОбщийМодуль.ВыполнитьПодключениеOLE", ПараметрыПроцедуры);
МассивЗаданий = Новый Массив;
МассивЗаданий.Добавить(ФоновоеЗадание);
Попытка
// Ожидаем завершения фонового задания не более 10 секунд
ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий, 10);
РезультатПодключения = ПолучитьИзВременногоХранилища(АдресРезультата);
Если РезультатПодключения = Истина Тогда
Сообщить("Соединение с 1С 7.7 успешно установлено!");
Иначе
Сообщить("Не удалось установить соединение. Проверьте параметры.");
КонецЕсли;
Исключение
// Сюда мы попадаем, если превышен таймаут в 10 секунд
ФоновоеЗадание.Отменить();
// Принудительно уничтожаем зависший процесс 1cv7.exe на уровне операционной системы
КомандаУничтоженияПроцесса = "taskkill /F /IM 1cv7.exe";
ЗапуститьПриложение(КомандаУничтоженияПроцесса, , Истина);
ВызватьИсключение "Превышено время ожидания авторизации в 1С 7.7. Возможно, указан неверный логин или пароль.";
КонецПопытки;
Чтобы полностью исключить запуск OLE-сервера с заведомо неверным логином, мы можем выполнить предварительную проверку существования пользователя. В каталоге базы данных 1С 7.7 в подпапке \usrdef\ находится служебный файл users.usr, содержащий список всех зарегистрированных пользователей системы.
Проанализируем этот файл перед вызовом OLE. Перед тем как инициализировать соединение, мы можем прочитать файл users.usr средствами 1С 8 (например, как текстовый файл или бинарные данные) и убедиться, что пользователь с указанным именем действительно существует в списке.
Если пользователь в файле отсутствует, мы можем мгновенно вывести сообщение об ошибке «Пользователь не найден в базе-источнике» без запуска тяжелого COM-объекта, предотвращая тем самым зависание системы.
Если у вас есть возможность вносить изменения в конфигурацию базы-источника 1С 7.7, мы рекомендуем организовать проверку успешности входа через создание временных файлов на диске.
Для этого в глобальном модуле 1С 7.7 в предопределенной процедуре ПриНачалеРаботыСистемы() пропишем создание файла-маркера:
Процедура ПриНачалеРаботыСистемы()
// Создаем маркер успешного входа в каталоге пользователя
ИмяФайлаМаркера = КаталогПользователя() + "auth_success.tmp";
ФС.УдалитьФайл(ИмяФайлаМаркера); // Удаляем старый маркер
ТекстМаркера = СоздатьОбъект("Текст");
ТекстМаркера.ДобавитьСтроку("Успешно");
ТекстМаркера.Записать(ИмяФайлаМаркера);
КонецПроцедуры
На стороне 1С 8 перед инициализацией OLE-соединения мы удаляем этот файл-маркер из папки пользователя 1С 7.7, запускаем OLE-соединение в фоновом режиме и контролируем появление файла auth_success.tmp. Если файл не создался в течение короткого промежутка времени — авторизация не удалась, и мы завершаем зависший процесс.
На практике предоставление обычным пользователям возможности вручную вводить логины и пароли для OLE-соединений крайне нежелательно. Опечатки неизбежны, и бороться с постоянными зависаниями процессов на сервере будет трудно.
Рассмотрим более правильное и безопасное решение:
Robot_OLE) со сложным паролем.В заключение отметим, что технология OLE Automation для платформы 1С 7.7 морально устарела. Работа с ней на современных 64-битных операционных системах Windows Server часто приводит к падению производительности, утечкам оперативной памяти и зависаниям из-за строгих ограничений безопасности DCOM.
Рекомендуется рассмотреть альтернативные, более стабильные варианты интеграции, которые не требуют запуска платформы 1С 7.7:
ADODB.Connection. Это работает в десятки раз быстрее OLE и не вызывает зависаний процессов. Для файловых баз DBF можно использовать соответствующие ODBC-драйверы.