1С:Предприятие 8.x. Работа через COM-интерфейс с 1С:Предприятие 7.7.

Разработка платформы 1С:Предприятие 7.7 давно уже прекращено, однако некоторые ошибки остались. Проекты на базе этой платформы вполне стабильны и довольно не прихотливы, ее по сей день используют многие крупные фирмы. Конечно при рассмотрении крупных фирм использующих 1С:Предприятие в качестве корпоративной КИС можно наблюдать некую смесь 1С:Предприятие 8.x и 1С:Предприятие 7.7, чаще 1С:Предприятие 7.7 + прямой доступ к SQL. Такой выбор обоснован недостаточной гибкостью компоненты "Расчет" в 1С:Предприятие 7.7 и неповоротливой избыточностью в 1С:Предприятие 8.x, что в итоге дает смесь "Учет зарплаты" на 1С:Предприятие 8.x и товароучетная система на 1С:Предприятие 7.7.

Как всегда после определения топологии и архитектуры КИС, не важно основанной на 1С:Предприятие или нет, возникают вопросы связанные с интеграцией и взаимодействием компонентов системы, в нашем случае меж платформенное взаимодействие.

Одним из простых методов организации обмена между информационными базами, является COM-интерфейс, о нем и пойдет речь в данной статье. Идеология платформы 1С:Предприятие 8.x позволила построить практически универсальный COM-интерфейс, ибо идентификаторы типов и объектов в информационной базе базируются на GUID-идентификаторах, а у платформе 1С:Предприятие 7.7 идентификатор составной.

При работе через COM-интерфейс с платформой 1С:Предприятие 7.7 в режиме получения данных, проблем не возникает, но при решении задачи записи объектов мы рано или поздно натыкаемся на глюки платформы Итак, рассмотрим частный случай, из платформы 1С:Предприятие 8.x подключаемся к базе на платформе 1С:Предприятие 7.7 например для записи справочника [Материалы]. Справочник [Материалы] имеет реквизит [СчетУчета] типа [Счет.Основной] и соответственно план счетов [Основной].

Подключаемся к платформе 1С:Предприятие 7.7 через COM-интерфейс:

Перем мПерефирийнаяБаза Экспорт;

//Создает подключение к ИБ на платформе 1С:Предприятие 7.7 через COM-интерфейс
//При удачном подключении к ИБ устанавливает переменую мПерефирийнаяБаза значением COM-объект
//ВхПараметрыПодключения - Тип:[Структура] содержит путь к ИБ, логин и пароль
//ВхПроверкаПодключения - Тип:[Булево] флаг проферки подключения, после попытки подключения отключается от ИБ
Функция v77_ПодключитьИБ(ВхПараметрыПодключения, ВхПроверкаПодключения = Ложь)
 ВрмВозврат = Ложь;
 ВрмСтрокаПодключения = "" +
  "/D" + ВхПараметрыПодключения["БазаПуть"] + " " +
  "/N" + ВхПараметрыПодключения["БазаПользователь"] + " " +
  "/P" + ВхПараметрыПодключения["БазаПароль"];
 Попытка
  мПерефирийнаяБаза = Новый COMОбъект("V77.Application");
  Если Число(мПерефирийнаяБаза.Initialize(мПерефирийнаяБаза.RMTrade, ВрмСтрокаПодключения, "NO_SPLASH_SHOW")) = 0 Тогда
   v77_ОтключитьИБ();
   ВызватьИсключение "Неудачная попытка инициализации соединения с перефирийной ИБ!";
  Иначе
   ВрмВозврат = Истина;
  КонецЕсли;
 Исключение
  Сообщить(ОписаниеОшибки());
  Возврат ВрмВозврат;
 КонецПопытки;
 Если ВхПроверкаПодключения Тогда
  v77_ОтключитьИБ();
 КонецЕсли;
 Возврат ВрмВозврат;
КонецФункции

//Освобождает ссылки на COM-объект
Процедура v77_ОтключитьИБ()
 мПерефирийнаяБаза = Неопределено;
КонецПроцедуры
Так же имеем функции для работы с объектами в ИБ на платформе 1С:Предприятие 7.7:
//Определяет тип переданного значения
//Параметр: ВхОбъект - COM-объект 1С:Предприятие 7.7
//Возвращаемое значение: Строка типа переданного значения в формате 1С:Предприятие 7.7 
Функция v77_ТипЗначенияСтр(ВхОбъект)
  Возврат мПерефирийнаяБаза.EvalExpr("ТипЗначенияСтр(ЗначениеИзСтрокиВнутр("""+ СтрЗаменить(мПерефирийнаяБаза.ЗначениеВСтрокуВнутр(ВхОбъект), """", """""")+ """))");
КонецФункции

//Проверяет является ли переданное значение пустым
//Параметр: ВхОбъект - COM-объект 1С:Предприятие 7.7
//Возвращаемое значение: 0 - Заполненно, 1 - Пустое значение
Функция v77_ПустоеЗначение(ВхОбъект)
  Возврат мПерефирийнаяБаза.EvalExpr("ПустоеЗначение(ЗначениеИзСтрокиВнутр("""+ СтрЗаменить(мПерефирийнаяБаза.ЗначениеВСтрокуВнутр(ВхОбъект), """", """""")+ """))");
КонецФункции

//Получает пустое значение заданного типа
//Параметр: ВхТип - Строка типа в формате 1С:Предприятие 7.7 
//Возвращаемое значение: COM-объект 1С:Предприятие 7.7
Функция v77_ПолучитьПустоеЗначение(ВхТип)
  Возврат мПерефирийнаяБаза.EvalExpr("ПолучитьПустоеЗначение(""" + ВхТип + """)");
КонецФункции

//Создает объект заданного типа
//Параметр: ВхТип - Строка типа в формате 1С:Предприятие 7.7 
//Возвращаемое значение: COM-объект 1С:Предприятие 7.7
Функция v77_СоздатьОбъект(ВхТип)
  Возврат мПерефирийнаяБаза.EvalExpr("СоздатьОбъект(""" + ВхТип + """)");
КонецФункции

Пробуем найти/создать элемент справочника в ИБ на платформе 1С:Предприятие 7.7 через COM-интерфейс:

//Устанавливает объекту значение реквизита
//Параметр: ВхОбъект - Объект
//Параметр: ВхИмяРеквизита - Имя реквизита
//Параметр: ВхЗначение - Значение реквизита
//Возвращаемое значение: Булево: Истина - реквизит установлен, Ложь -не установлен
Функция v77_УстановитьАтрибут(ВхОбъект, ВхИмяРеквизита, ВхЗначение)
 ВрмЗначениеСтарое = ВхОбъект.ПолучитьАтрибут(ВхИмяРеквизита);
 ВхОбъект.УстановитьАтрибут(ВхИмяРеквизита, ВхЗначение);
 ВрмЗначение = ВхОбъект.ПолучитьАтрибут(ВхИмяРеквизита);
 Возврат (ВрмЗначениеСтарое = ВхЗначение);
КонецФункции

Процедура ВыполнитьОбмен() Экспорт
 ВрмНастройки = v77_ПолучитьНастройки("OLE");
 Если Не v77_ПодключитьИБ(ВрмНастройки) Тогда
  Возврат;
 КонецЕсли;
 ВрмКод = "010101";
 ВрмСправочник = v77_СоздатьОбъект("Справочник.Материалы");
 //Ищем элемент справочника по коду. Если не найден - создаем
 Если ВрмСправочник.НайтиПоКоду(ВрмКод) = 0 Тогда
  ВрмСправочник.Новый();
  ВрмСправочник.Код = ВрмКод;
 Иначе
  ВрмСправочник.ТекущийЭлемент();
 КонецЕсли;
 //Получаем объект типа ПланСчетов
 ВрмПланСчетов = мПерефирийнаяБаза.ПланыСчетов.ЗначениеПоИдентификатору("Основной");
 //Получаем объект типа Счет
 ВрмСчет = v77_СоздатьОбъект("Счет"); 
 //Устанавливаем счету план счетов
 ВрмСчет.ИспользоватьПланСчетов(ВрмПланСчетов);
 //Ищем счет
 ВрмСчет.НайтиПоКоду("10.5");
 ВрмЗначение = ВрмСчет.ТекущийСчет();
 
 //Устанавливаем значение реквизита в 
 v77_УстановитьАтрибут(ВрмСправочник, "СчетУчета", ВрмЗначение);
 
 ВрмСправочник.Записать();
 
 v77_ОтключитьИБ();
КонецПроцедуры

Запускаем процедуру ВыполнитьОбмен(), ждем завершения и проверяем в ИБ 7.7 результат работы... Элемент создан, код элементу присвоился, а реквизит [СчетУчета] остался пустым.

Необходимо в глобальном модуле конфигурации ИБ на платформе 1С:Предприятие 7.7 объявить функцию:

Процедура OLE_УстановитьАтрибутИзСтрокиВнутр(ВхОбъект, ВхИмяРеквизита, ВхСтрокаВнутр) Экспорт
 ВхОбъект.УстановитьАтрибут(ВхИмяРеквизита, ЗначениеИзСтрокиВнутр(ВхСтрокаВнутр));
КонецПроцедуры

И вызывать в 8.x следующим образом:

Функция v77_МассивИзСтрокиВнутр(ВхСтрокаВнутр)
 ВрмВозврат = Новый Массив;
 ВрмСтрока = "";
 ВрмДлина = СтрДлина(ВхСтрокаВнутр);
 Для ВрмПозиция = 1 По ВрмДлина Цикл
  ВрмСимвол = Сред(ВхСтрокаВнутр, ВрмПозиция, 1);
  Если ВрмСимвол = "{" Тогда
   
  ИначеЕсли ВрмСимвол = "," Или ВрмСимвол = "}" Тогда
   ВрмВозврат.Добавить(ВрмСтрока);
   ВрмСтрока = "";
  Иначе
   ВрмСтрока = ВрмСтрока + ВрмСимвол;
  КонецЕсли;
 КонецЦикла;
 Возврат ВрмВозврат;
КонецФункции

Функция v77_МассивВСтрокуВнутр(ВхМассив)
 ВрмВозврат = "";
 Для Каждого ВхЭлемент Из ВхМассив Цикл
  Если ВрмВозврат <> "" Тогда
   ВрмВозврат = ВрмВозврат + ","
  КонецЕсли;
  ВрмВозврат = ВрмВозврат + ВхЭлемент;
 КонецЦикла;
 Возврат "{" + ВрмВозврат + "}";
КонецФункции

Функция v77_НазначитьТипВСтрокуВнутр(ВхБаза77, ВхОбъектИсточник, ВхОбъектПриемник)
 ВрмМассивИсточник = v77_МассивИзСтрокиВнутр(ВхБаза77.ЗначениеВСтрокуВнутр(ВхОбъектИсточник));
 ВрмМассивПриемник = v77_МассивИзСтрокиВнутр(ВхБаза77.ЗначениеВСтрокуВнутр(ВхОбъектПриемник));
 ВрмТипИсточник = СтрЗаменить(ВрмМассивИсточник[6], """", "");
 ВрмТипПриемник = СтрЗаменить(ВрмМассивПриемник[6], """", "");
 ВрмМассивПриемник[6] = """" + Лев(ВрмТипИсточник, 10) + Прав(ВрмТипПриемник, 13) + """"; 
 Возврат v77_МассивВСтрокуВнутр(ВрмМассивПриемник);
КонецФункции

Исправляем нашу функцию:

Процедура ВыполнитьОбмен() Экспорт
 ВрмНастройки = v77_ПолучитьНастройки("OLE");
 Если Не v77_ПодключитьИБ(ВрмНастройки) Тогда
  Возврат;
 КонецЕсли;
 ВрмКод = "010101";
 ВрмСправочник = v77_СоздатьОбъект("Справочник.Материалы");
 //Ищем элемент справочника по коду. Если не найден - создаем
 Если ВрмСправочник.НайтиПоКоду(ВрмКод) = 0 Тогда
  ВрмСправочник.Новый();
  ВрмСправочник.Код = ВрмКод;
 Иначе
  ВрмСправочник.ТекущийЭлемент();
 КонецЕсли;
 //Получаем объект типа ПланСчетов
 ВрмПланСчетов = мПерефирийнаяБаза.ПланыСчетов.ЗначениеПоИдентификатору("Основной");
 //Получаем объект типа Счет
 ВрмСчет = v77_СоздатьОбъект("Счет"); 
 //Устанавливаем счету план счетов
 ВрмСчет.ИспользоватьПланСчетов(ВрмПланСчетов);
 //Ищем счет
 ВрмСчет.НайтиПоКоду("10.5");
 ВрмЗначение = ВрмСчет.ТекущийСчет();
 //Преобразуем в строку внутр и явно устанавливаем тип плана счетов
 ВрмЗначениеСтр = v77_НазначитьТипВСтрокуВнутр(мПерефирийнаяБаза, ВрмПланСчетов, ВрмЗначение);
 
 //Устанавливаем значение реквизита вызывая процедуру глобального модуля
 мПерефирийнаяБаза.OLE_УстановитьАтрибутИзСтрокиВнутр(ВрмСправочник, "СчетУчета", ВрмЗначениеСтр);
 
 ВрмСправочник.Записать();
 
 v77_ОтключитьИБ();
КонецПроцедуры

Теперь все работает!