gifts2017

Работа с 1С через OLE 8.* (V81.Application, V81.COMConnector)

Опубликовал Алексей (artspeed) в раздел Программирование - Теория программирования

Решил серьезно заняться изучением OLE. Конечно OLE это не КД, но все же...

Попалась в интернете хорошая статья и решил ее поместить сюда. Думаю будет полезна как для начинающих, так и для продвинутых, чтобы закрепить свои знания.

Введение

При установке 1С на компьютер в реестре регистрируется ряд компонент. Это

  • V81.Application
  • V81.COMConnector
  • V81.InfoBaseList
  • V81.InfoBaseListLink
  • V81.ServerAbout
  • V81.ServerAdminScope

Данная статья рассматривает два из этих объектов V81.Application, V81.COMConnector, служащих для подключения с использованием COM-технологий к базе 1С 8.1 не зависимо от того находится ли данная база на сервере или представлена в виде файлового варианта.

Так же мы рассмотрим нюансы подключения к базе из 1C v7.7.

К данной статье будет приложен иллюстративный материал в виде конфигурации с демо-обработкой, входящей в состав данной базы, и обработка для 7.7, демонстрирующая соединение с данной базой.

Создание каркасной базы

Создадим новую конфигурацию

В ней мы создадим ПараметрСеанса МиниЛогЗапуска и глобальный модуль с атрибутами

  • Глобальный
  • Клиент
  • Сервер

Приведу код глобального модуля

#Если Клиент Тогда
Функция ВернутьТипПодключения() Экспорт
    Возврат("Клиент");
КонецФункции
#Иначе
Функция ВернутьТипПодключения() Экспорт
    Возврат("Сервер");
КонецФункции
#КонецЕсли


Функция ВернутьНеопределено() Экспорт
    Возврат Неопределено;
КонецФункции

Функция ВернутьNULL() Экспорт
    Возврат Null;
КонецФункции

Функция ВернутьИстину() Экспорт
    Возврат Истина;
КонецФункции

Функция ВернутьЛожь() Экспорт
    Возврат Ложь;
КонецФункции

Функция ВернутьСистемноеПеречисление()Экспорт
    Возврат(ВидДвиженияНакопления.Расход);
КонецФункции

Функция ВернутьПараметр(ИмяПараметра)Экспорт
    Попытка
        Зн=ПараметрыСеанса[ИмяПараметра];
    Исключение
        Возврат Неопределено;
    КонецПопытки;
    Возврат Зн;
КонецФункции

Кроме этих функций добавим функцию возвращающую по имени справочник в виде ТаблицыЗначений

Функция ЗапросКСправочнику(ИмяСправочника) Экспорт
    Попытка
        МетСпр=Метаданные.Справочники[ИмяСправочника];
    Исключение
        Возврат Неопределено
    КонецПопытки;
    Запрос=Новый Запрос;
    ТекстЗапроса="";
    ТекстЗапроса="Выбрать Спр.Ссылка,Спр.ПометкаУдаления,Спр.Предопределенный,";
    Если МетСпр.Иерархический Тогда
        ТекстЗапроса=ТекстЗапроса+"Спр.Родитель,Спр.ЭтоГруппа,";
    КонецЕсли;
    Если МетСпр.ДлинаКода<>0 Тогда
        ТекстЗапроса=ТекстЗапроса+"Спр.Код,";
    КонецЕсли;
    Если МетСпр.ДлинаНаименования<>0 Тогда
        ТекстЗапроса=ТекстЗапроса+"Спр.Наименование,";
    КонецЕсли;
    Для Каждого Рекв из МетСпр.Реквизиты Цикл
        ТекстЗапроса=ТекстЗапроса+"Спр."+Рекв.Имя+",";
    КонецЦикла;
    ТекстЗапроса=ТекстЗапроса+"Спр.Представление
    |ИЗ Справочник."+ИмяСправочника+" КАК Спр";
    Запрос.Текст=ТекстЗапроса;
    Возврат(Запрос.Выполнить().Выгрузить());
КонецФункции

Также определим процедуру в модуле внешнего соединения

Процедура ПриНачалеРаботыСистемы()
    Попытка
        ПараметрыСеанса.ПараметрСеанса1=СокрЛП(ПараметрыСеанса.ПараметрСеанса1)+"
        |Внешнее Соединение";
    Исключение
        ПараметрыСеанса.ПараметрСеанса1="Внешнее Соединение";
    КонецПопытки;
КонецПроцедуры

И процедуру в модуле приложения

Процедура ПриНачалеРаботыСистемы()
    Попытка
        ПараметрыСеанса.ПараметрСеанса1=СокрЛП(ПараметрыСеанса.ПараметрСеанса1)+"
        |Приложение";
    Исключение
        ПараметрыСеанса.ПараметрСеанса1="Приложение";
    КонецПопытки;
КонецПроцедуры

Также добавим ещё один не глобальный модуль с атрибутами

  • Клиент
  • Сервер

И с единственной функцией

Функция ВозвратСтроки() Экспорт
    Возврат("ОбщийМодуль1");
КонецФункции

Application и ComConnector сравнение соединение из 1С 8

Для исследования вызова функций не глобальных модулей Сохраняем конфигурацию, и теперь нам есть что исследовать.

Для целого ряда методов в синтаксис помощнике указанно "Не используется в модуле внешнего соединения". Это упоминание не даёт полной картины.

Объект V81.Application соответствует объекту V77.Aplication, а именно происходит загрузка сервера с интерфейсными библиотеками в режиме клиент, объект же V81.COMConnector при загрузке не имеет ничего из того что отвечает за интерфейс с пользователем, что повышает производительность при работе с внешним соединением.

Создаём обработку в нашей конфигурации, для проверки вызова наших методов.

В обработке объявляем две переменных и функцию установления соединения с базой

Перем cntr,connection;
Функция ОткрытиеБазы(ТипОткрытия)
    cntr = Новый COMObject(ТипОткрытия);
    connection=Истина;
    Попытка
        Если ЭлементыФормы.Панель1.ТекущаяСтраница.Заголовок="Файловая версия" Тогда
            connection = cntr.Connect("File="""+СокрЛП(ПутьКбазе)+""";Usr="""+СокрЛП(Логин)+""";Pwd = """ + СокрЛП(Пасворд) + """;");
        Иначе
            connection = cntr.Connect("Srvr="""+СокрЛП(ИмяСервера)+""";Ref="""+СокрЛП(ИмяБазы)+""";Usr="""+СокрЛП(Логин)+""";Pwd = """ + СокрЛП(Пасворд) + """;");
        КонецЕсли;
    Исключение
        Предупреждение(ОписаниеОшибки());
        connection=Ложь;
    КонецПопытки;
    Возврат connection;
КонецФункции

В переменной открытия мы передаём либо строку "V81.Application", либо строку "V81.ComConnector"

При этом для V81.Application возвращается Истина в connection, а cntr является нашим объектом через который мы обращаемся к базе

Для ComConnector в connection возвращается объект для обращения к базе, а cntr является объектом описанным в синтаксис помощнике как COM-соединитель.

Свойства и методы COM-соединителя.
HighBoundDefault Свойство, только чтение, Тип: Число. Содержит верхнюю границу диапазона IP портов сервера кластера по умолчанию.
LowBoundDefault Свойство, только чтение, Тип: Число. Содержит нижнюю границу диапазона IP портов сервера кластера по умолчанию.
MaxConnections Свойство, только чтение, Тип: Число. Определяет максимальное число одновременно существующих объектов COM-соединение, созданных через данный COM-соединитель. Число одновременно существующих соединений включает также число соединений, находящихся в пуле COM-соединений. Значением по умолчанию 0 (число одновременно существующих объектов COM-соединение не ограничено). Устанавливать свойству не нулевое значение можно только в том случае, если сам объект COM-соединитель был создан в Multithreaded Apartment (MTA), что обеспечивает реальное функционирование самого COM-соединителя и созданных им объектов COM-соединение в многопотоковой (multithreaded) среде. Это условие соблюдается в частности, если COM-соединитель был создан в приложении ASP.NET. Если же объект COM-соединитель был создан в Singlethreaded Apartment (STA), то реально все действия с COM-соединителем и созданными им объектами COM-соединение будут выполняться в одном потоке. В этом случае, если метод Connect не сможет на первом проходе найти подходящее или создать новое COM-соединение, то выполнение этого метода зациклится, так как освободить уже, возможно, ненужное другое COM-соединение будет нельзя по той причине, что операция освобождения объекта COM-соединение должна быть выполнена в том же потоке, в котором уже выполняется метод Connect. Следует помнить, что создание COM-объектов из приложения 1C:Предприятие 8.1 выполняется из STA. Это же справедливо для большинства GUI-приложений Windows.
PoolCapacity Свойство, только чтение, Тип: Число. Максимальное количество соединений с информационной базой, которые могут одновременно находиться в пуле.
PoolTimeout Свойство, только чтение, Тип: Число. Максимальное время нахождения в пуле неиспользуемого соединения с информационной базой. После истечения этого времени неиспользуемое соединение освобождается.
RAgentPortDefault Свойство, только чтение, Тип: Число. Содержит номер IP порта агента сервера по умолчанию.
RMngrPortDefault Свойство, только чтение, Тип: Число. Содержит номер IP порта менеджера кластера по умолчанию.
Connect (Connect) Синтаксис:
Connect(<Строка соединения>)
Параметры:
<Строка соединения> (обязательный)
Тип: Строка. Строка параметров, используемая 1С:Предприятием для соединения с информационной базой. Строка соединения представляет собой набор параметров, каждый из которых является фрагментом вида: <Имя параметра=><Значение>, где Имя параметра — имя параметра, а Значение — его значение. Фрагменты отделяются друг от друга символами ';'. Если значение содержит пробельные символы, то оно должно быть заключено в двойные кавычки ("). Для файлового варианта определен параметр: File — каталог информационной базы (файловый режим); Для клиент-серверного варианта определены параметры: Srvr — имя сервера 1С:Предприятия; Ref — имя информационной базы на сервере; Для всех вариантов определены параметры: Usr — имя пользователя; Pwd — пароль и UC<Код доступа> позволяет выполнить установку соединения с информационной базой, на которую установлена блокировка установки соединений. Если при установке блокировки задан непустой код доступа, то для установки соединения необходимо в параметре /UC указать этот код доступа. Возвращаемое значение:
Тип: COM-соединение.
Описание:
Создает соединение с информационной базой 1С:Предприятия 8.1.
Устанавливает соединение с информационной базой 1С:Предприятия 8.1 и возвращает ссылку на объект COM-соединение.
Установка соединения выполняется по следующему алгоритму:
  1. COM-соединение с требуемыми параметрами ищется в пуле соединений. Если найдено, то используется оно.
  2. Если COM-соединение с требуемыми параметрами не найдено, то анализируется не исчерпан ли лимит по числу одновременно существующих соединений. Если не исчерпан, то создается новое COM-соединение.
  3. Если лимит исчерпан, но при этом в пуле имеются неиспользуемые COM-соединение, то соединение, дольше всех находящееся в пуле, удаляется и создается новое COM-соединение.
  4. Если никаким способом найти подходящее или создать новое COM-соединение не удалось, то происходит ожидание освобождения COM-соединение другим потоком, после чего весь процесс повторяется, начиная с пункта 1.
ConnectAgent(<Идентификатор>) Синтаксис:
ConnectAgent(<Идентификатор>)
Параметры:
<Идентификатор> (обязательный)
Тип: Строка. Идентификатор протокола (по умолчанию tcp), имя компьютера или IP адрес агента сервера (обязательно), номер IP порта агента сервера (по умолчанию 1540). Например, значением параметра могут быть следующие строки: «server1», «tcp://server1», «tcp://server1:1540», «server1:1540».
Возвращаемое значение:
Тип: Соединение с агентом сервера.
Описание:
Выполняет подсоединение к агенту сервера 1С:Предприятия 8.1, работающему на указанном серверном компьютере.
Примечание:
Если подсоединение невозможно, то вызывается исключение.
ConnectWorkingProcess (ConnectWorkingProcess) Синтаксис:
ConnectWorkingProcess(<Имя>)
Параметры:
<Имя> (обязательный)
Тип: Строка. Имя или IP адрес рабочего процесса, с которым должно быть установлено соединение, в формате: <протокол>://<адрес_или_имя>:<порт> Например:
testcomp
tcp://testcomp
tcp://testcomp:2354
tcp://43.73.34.11:5342.
Возвращаемое значение:
Тип: Соединение с рабочим процессом.
Описание:
Создает административное соединение с рабочим процессом кластера серверов 1С:Предприятия 8.1.


Для установки соединения с базой надо методу Connect нашего объекта передать строку соединения.

Для файловой версии данная строка содержит параметры:

  • File с указанием пути к папке с файлом базы
  • Usr с указанием имени прользователя
  • Pwd с указанием пароля прользователя

Для соединения с сервером Usr и Pwd прежние параметры, а вот вместо File два параметра Srvr с указанием имени сервера и Ref с указанием имени Базы

Вызовы из восьмёрки через Application и ComConnector

Пробуем организовать вызов функций нашей конфигурации из обработки на 8.1

Пишем процедуру вызова функций с определением, что возвращается при вызове

Процедура ОсновныеДействияФормыВызовФункции(Кнопка)
    Если Не ОткрытиеБазы("V81.Application") Тогда Возврат; КонецЕсли;
    Сообщить("Вернули неопределено? "+(cntr.ВернутьНеопределено()=Неопределено));
    Сообщить("Вернули NULL? "+(cntr.ВернутьNULL()=NULL));
    Сообщить("Вернули Истину? "+(cntr.ВернутьИстину()=Истина));
    Сообщить("Вернули Ложь? "+(cntr.ВернутьЛожь()=Ложь));
    Сообщить("Вернули параметр "+cntr.ВернутьПараметр("ПараметрСеанса1"));
    Сообщить("Не глобальный модуль "+cntr.ОбщийМодуль1.ВозвратСтроки());
    Сообщить("ТипПодключения="+cntr.ВернутьТипПодключения());
    cntr = "";
КонецПроцедуры

Рассмотрим лог сообщений:

 Вернули неопределено? истина
 Вернули NULL? истина
 Вернули Истину? истина
 Вернули Ложь? истина
 Вернули параметр Приложение
 Не глобальный модуль ОбщийМодуль1
 ТипПодключения=Клиент

Что это нам даёт?

Значения типа неопределено,NULL,Истина,Ложь передаются в соединение с базой корректно.

Модуль внешнего соединения при подключении через V81.Application не отрабатывает.

Модуль приложения при подключении через V81.Application отрабатывает.

Тип подключения, в котором мы подключаемся к базе, соответствует типу подключения клиент

Пишем аналогичную процедуру, но уже с использованием ComConnector

Процедура ОсновныеДействияФормыВызовФункции2(Кнопка)
    Если ОткрытиеБазы("V81.ComConnector")<>Ложь Тогда
        Сообщить("Вернули неопределено? "+(connection.ВернутьНеопределено()=Неопределено));
        Сообщить("Вернули NULL? "+(connection.ВернутьNULL()=NULL));
        Сообщить("Вернули Истину? "+(connection.ВернутьИстину()=Истина));
        Сообщить("Вернули Ложь? "+(connection.ВернутьЛожь()=Ложь));
        Сообщить("Вернули параметр "+connection.ВернутьПараметр("ПараметрСеанса1"));
        Сообщить("Не глобальный модуль "+connection.ОбщийМодуль1.ВозвратСтроки());
        Сообщить("ТипПодключения="+connection.ВернутьТипПодключения());
        cntr = "";connection="";
    КонецЕсли;
КонецПроцедуры

Лог сообщений у нас отличается в строчках

Вернули Параметр Внешнее Соединение
ТипПодключения=Сервер

То есть, при обращении через объект V81.ComConnector подключение осуществляется в режиме север, даже если мы подключаемся к локальной файловой базе.

Теперь попробуем обратиться к нашим объектам, ну хотя бы к V81.Application из 1С 7.7

Пишем примерно тот же код

Перем НомерЗакладки;
Перем connection,cntr;
Перем Истина,Ложь;
Функция ОткрытиеБазы(ТипОткрытия)
    cntr = СоздатьОбъект(ТипОткрытия);
    Попытка
        Если НомерЗакладки=1 Тогда
            connection = cntr.Connect("File="""+СокрЛП(ПутьКбазе)+""";Usr="""+СокрЛП(Логин)+""";Pwd = """ + СокрЛП(Пасворд) + """;");
        Иначе
            connection = cntr.Connect("Srvr="""+СокрЛП(ИмяСервера)+""";Ref="""+СокрЛП(ИмяБазы)+""";Usr="""+СокрЛП(Логин)+""";Pwd = """ + СокрЛП(Пасворд) + """;");
        КонецЕсли;
    Исключение
        Предупреждение(ОписаниеОшибки());
    КонецПопытки;
КонецФункции
Функция ВызовФункций()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Сообщить("Вернули неопределено= "+cntr.ВернутьНеопределено());
        Сообщить("Вернули NULL= "+cntr.ВернутьNULL());
        Сообщить("Вернули Истину= "+cntr.ВернутьИстину());
        Сообщить("Вернули Ложь= "+cntr.ВернутьЛожь());
    КонецЕсли;
    cntr = "";
КонецФункции

Истина=-1;Ложь=0;

Лог сообщений выглядит так

Вернули неопределено=
Вернули NULL=
Вернули Истину= -1
Вернули Ложь= 0

Так мы убеждаемся что Ложь соответствует 0, Истина -1, а NULL и неопределено ничего в стандартах 1Cv7.7 не возвращают

Как же отличить NULL от неопределено?

Для этого у объекта cntr в случае V81.Application и у connection в случае V81.ComConnector есть метод String

В описание данного метода сказано "Получает строковое представление значения произвольного типа".

Пробуем использовать этот метод из 7.7

Добавив в нашу Функцию ВызовФункций() несколько строк кода

Сообщить("ВернулиНеопределено="+cntr.String(cntr.ВернутьНеопределено()));
Сообщить("ВернулиNULL="+cntr.String(cntr.ВернутьNULL()));
Сообщить("ВернулиСистемноеПеречисление="+cntr.String(cntr.ВернутьСистемноеПеречисление()));

Результат в логе сообщений

ВернулиНеопределено=Неопределено
ВернулиNULL=
ВернулиСистемноеПеречисление=Расход

Так мы отмечаем, что NULL возвращается пустой строкой, неопределено строкой "Неопределено" и системное перечисление своим представлением

Итак, у нас есть конфигурация с модулем, но у неё нет метаданных.

Добавим перечисление, справочник, и три константы одну типа строка, одну типа перечисления и одну составного типа

Разбор метаданных через ОЛЕ

Добавим в обработку на 1С 7.7 и 8.1 функцию работы с метаданными

Функция РаботаСметаданными()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Сообщить("Версия "+cntr.Метаданные.Версия);
        Сообщить("==================Константы==================");
        Для Инд=0 по cntr.Метаданные.Константы.Количество()-1 Цикл
            Конст=cntr.Метаданные.Константы.Получить(Инд);
            Сообщить(Конст.Имя);
            Сообщить("Тип:");
            Массив = Конст.Тип.Типы();
            Типов = Массив.Количество() - 1;
            для а = 0 по Типов цикл
                сообщить(cntr.String(Массив.Получить(а)));
            конеццикла;
        КонецЦикла;
        cntr = "";
    КонецЕсли;
КонецФункции

Сохраним обработки и запустив просмотрим лог сообщений

Версия V81.Application
==================Константы==================
Константа1
Тип:
Строка
Константа2
Тип:
Справочник ссылка: Справочник1
Константа3
Тип:
Справочник ссылка: Справочник1
Перечисление ссылка: Перечисление1

Мы можем получить тип любых метаданных используя этот пример и описание работы с метаданными

Использование менеджеров для работы с данными через ОЛЕ

Мы прояснили процесс работы с метаданными, а теперь обратимся к работе с данными

Функция РаботаСБазой()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Стр="";
        Если ВвестиСтроку(Стр,"Наименование",40)=1 Тогда
            Эл=cntr.Справочники.Справочник1.НайтиПоНаименованию(СокрЛП(Стр));
            Если Эл.Пустая()=Истина Тогда
                Эл=cntr.Справочники.Справочник1.СоздатьЭлемент();
                Эл.Наименование=СокрЛП(Стр);
                Эл.Записать();
                Сообщить("ЗначениеВСтрокуВнутр="+cntr.ЗначениеВСтрокуВнутр(Эл.Ссылка));
                Сообщить("XMLСтрока="+cntr.XMLСтрока(Эл.Ссылка));
                Сообщить("=======XMLТипЗнч======");
                XMLРез=cntr.XMLТипЗнч(Эл.Ссылка);
                Сообщить("URIПространстваИмен="+XMLРез.URIПространстваИмен);
                Сообщить("ИмяТипа="+XMLРез.ИмяТипа);
            КонецЕсли;
            cntr.Константы.Константа3.Установить(Эл.Ссылка);
        КонецЕсли;
    КонецЕсли;
    cntr = "";
КонецФункции

В данной процедуре мы указываем наименование справочника, и если такого наименования нет, то мы создаём элемент справочника. Выводим всю информацию которую можем получить и присваиваем значение элемента справочника нашей константе

Создадим элемент и просмотрим лог сообщений

ЗначениеВСтрокуВнутр={"#",3395433c-d726-4c7e-ae3a-45f785811756,1:a68d00142a16c0f211de2d7a6de7a9eb}
XMLСтрока=6de7a9eb-2d7a-11de-a68d-00142a16c0f2
=======XMLТипЗнч======
URIПространстваИмен=
ИмяТипа=CatalogRef.Справочник1


Запросы,Конструкторы запросов и произвольные объекты 8.* через ОЛЕ

Мы использовали работу менеджеров для получения и изменения, данных базы,но более высокой производительностью в восьмёрке обладают запросы и их мы так же можем использовать.

Пишем функцию:

Функция РаботаСЗапросами()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Констр=cntr.NewObject("КонструкторЗапроса");
        Если Констр.ОткрытьМодально()=Истина Тогда
            ТекстЗапроса=Констр.Текст;
            cntr = "";
            ОткрытиеБазы("V81.ComConnector");
            Запрос=connection.NewObject("Запрос");
            Запрос.Текст=ТекстЗапроса;
            Рез=Запрос.Выполнить().Выгрузить();
            Таб=СоздатьОбъект("Таблица");
            Для Инд=0 по Рез.Колонки.Количество()-1 Цикл
                Кол=Рез.Колонки.Получить(Инд);
                Обл=Таб.Область("R1C"+Строка(Инд+1));
                Обл.Текст=Кол.Имя;
            Конеццикла;
            Для Инд=0 по Рез.Количество()-1 Цикл
                Стр=Рез.Получить(Инд);
                Кол=0;
                Для Кол=0 по Рез.Колонки.Количество()-1 Цикл
                    Обл=Таб.Область("R"+Строка(Инд+2)+"C"+Строка(Кол+1));
                    Обл.Текст=connection.String(Стр.Получить(Кол));
                КонецЦикла;
            КонецЦикла;
            Таб.Показать();
        Иначе
            Сообщить("!Запрос не создан");
        КонецЕсли;
    КонецЕсли;
    cntr = "";
    connection = "";
КонецФункции

В данном примере мы сначала пользуемся V81.Application, у которого есть интерфейсные библиотеки и методом NewObject (являющимся конструкцией языка 1С 8.* Новый) для вызова конструктора запроса.

Потом мы закрываем базу, и подключившись через V81.ComConnector создаём сам запрос и результат запроса в линейном порядке выводим в объект 7.7 таблица.

В принципе такой порядок использования запроса необязателен, но из ComConnector мы не сможем вызвать метод ОткрытьМодально() по причине отсутствия интерфейсных библиотек.

Проблема булева типа из 7.7 (можем передать, но не можем вернуть)

Изменим структуру нашей базы, а именно. Для Константы Константа1 изменим тип с простого типа Строка на составной Булево,Число

Разместим в глобальном модуле функцию, которая нам вернет значение в виде строки.

Так же предположим, что мы не хотим, что бы код нашей функции компилировался при запуске в режиме приложения, а хотим что бы наш код работал только в режиме внешнего соединения независимо от того подключаемся мы через V81.ComConnector или через V81.Application.

Функция РаботаСЗапросами()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Констр=cntr.NewObject("КонструкторЗапроса");
        Если Констр.ОткрытьМодально()=Истина Тогда
            ТекстЗапроса=Констр.Текст;
            cntr = "";
            ОткрытиеБазы("V81.ComConnector");
            Запрос=connection.NewObject("Запрос");
            Запрос.Текст=ТекстЗапроса;
            Рез=Запрос.Выполнить().Выгрузить();
            Таб=СоздатьОбъект("Таблица");
            Для Инд=0 по Рез.Колонки.Количество()-1 Цикл
                Кол=Рез.Колонки.Получить(Инд);
                Обл=Таб.Область("R1C"+Строка(Инд+1));
                Обл.Текст=Кол.Имя;
            Конеццикла;
            Для Инд=0 по Рез.Количество()-1 Цикл
                Стр=Рез.Получить(Инд);
                Кол=0;
                Для Кол=0 по Рез.Колонки.Количество()-1 Цикл
                    Обл=Таб.Область("R"+Строка(Инд+2)+"C"+Строка(Кол+1));
                    Обл.Текст=connection.String(Стр.Получить(Кол));
                КонецЦикла;
            КонецЦикла;
            Таб.Показать();
        Иначе
            Сообщить("!Запрос не создан");
        КонецЕсли;
    КонецЕсли;
    cntr = "";
    connection = "";
КонецФункции

Вызов из 77 я описывать не буду, он уже для вас довольно тривиален.

В принципе вместо напсиания данного кода мы можем, запустив восьмёрку, вычислить выражение в табло и убедиться, что

ЗначениеВстрокуВнутр(Истина)={"B",1}
ЗначениеВстрокуВнутр(Ложь)={"B",0} 

Определим функцию работы с нашей константой в обработке вызываемой из 7.7

Функция УстановитьИстина()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        cntr.Константы.Константа1.Установить(cntr.ЗначениеИзСтрокиВнутр("{""B"",1}"));
        Сообщить(cntr.Константы.Константа1.Получить());
        Сообщить(cntr.ЗначениеВстрокуВнутр(cntr.Константы.Константа1.Получить()));
        cntr = "";
    КонецЕсли;
КонецФункции

Функция УстановитьЛожь()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        cntr.Константы.Константа1.Установить(cntr.ЗначениеИзСтрокиВнутр("{""B"",0}"));
        Сообщить(cntr.Константы.Константа1.Получить());
        Сообщить(cntr.ЗначениеВстрокуВнутр(cntr.Константы.Константа1.Получить()));
        cntr = "";
    КонецЕсли;
КонецФункции

Функция УстановитьЧисло()
    ОткрытиеБазы("V81.Application");
    Если connection=Истина Тогда
        Чис=0;
        Если ВвестиЧисло(Чис,"Константа1",12,2)=1 Тогда
            cntr.Константы.Константа1.Установить(Чис);
            Сообщить(cntr.Константы.Константа1.Получить());
            Сообщить(cntr.ЗначениеВстрокуВнутр(cntr.Константы.Константа1.Получить()));
            cntr = "";
        КонецЕсли;
    КонецЕсли;
КонецФункции

Функция РаботаСконстантой()
    Меню=СоздатьОбъект("СписокЗначений");
    Меню.ДобавитьЗначение("УстановитьИстина()","Установить Истина");
    Меню.ДобавитьЗначение("УстановитьЛожь()","Установить Ложь");
    Меню.ДобавитьЗначение("УстановитьЧисло()","Установить Число");
    Зн="";
    Поз=0;
    Если Меню.ВыбратьЗначение(Зн,,Поз,,1)=1 Тогда
        Шаблон("["+Зн+"]");
    КонецЕсли;
КонецФункции

Рассмотрим лог сообщений после вызова всех трех вариантов функций и просмотра базы в режиме предпрития

-1
{"N",-1}
0
{"N",0}
56
{"N",56}

Какой вывод мы можем сделать из этого лога

Что тип булево возвращается стороннему приложению как число.

Мы можем установить значение булева и любого неизвестного 7.7 типа через ЗначениеИзСтрокиВнутр, но как минимум в случае с булевым типом мы не сможем его прочитать обратно иначе чем число.

Сам собой напрашивается вывод, что надо быть аккуратным при проектировании внешних функций и метаданных, проектируя их таким образом что бы мы могли одназначно опредилить по возвращенному параметру булев тип и никогда бы не смогли спутать его с числом.

Проблема времени из 7.7 (не можем передать)

Добавляем в нашу базу регистр накопления и документ регистратор и пишем в 7.7 простую функцию, формирующую движения данного документа

Функция ТипаПереносОстатков()
    Попытка
        ОткрытиеБазы("V81.ComConnector");
    Исключение
        Сообщить("Не удалось открыть базу с заданными параметрами");
        Возврат "";
    КонецПопытки;
    Стр="";
    Если ВвестиСтроку(Стр,"Справочник",50)=1 Тогда
        Спр=connection.Справочники.Справочник1.НайтиПоНаименованию(Стр);
        Если Спр.Ссылка=connection.Справочники.Справочник1.ПустаяСсылка() Тогда
            Спр=connection.Справочники.Справочник1.СоздатьЭлемент();
            Спр.Наименование=Стр;
            Спр.Записать();
        КонецЕсли;
        Док=connection.Документы.Документ1.СоздатьДокумент();
        Док.Дата=connection.ЗначениеИзСтрокиВнутр("{""D"",20081231235959}");
        Док.Реквизит1=Спр.Ссылка;
        Док.Записать();
        Движение=Док.Движения.РегистрНакопления1.ДобавитьПриход();
        Движение.Период=connection.ЗначениеИзСтрокиВнутр("{""D"",20081231235959}");
        Движение.Измерение1=Спр.Ссылка;
        Движение.Ресурс1=15;
        Док.Движения.РегистрНакопления1.Записать();
        Сообщить(connection.String(Док.Ссылка));
    КонецЕсли;
    connection = "";
    cntr = "";
КонецФункции

Рассмотрим лог сообщений

Документ1 000000001 от 31.12.2008 0:00:00

Вывод из этого лога прост. Время даже при передаче через ЗначениеИзСтрокиВнутр теряется.

Класс не существует

И в заключение - если выскакивает ошибка с "Класс не существует", значит, что не зарегистрирован COM-объект 1С:Предприятия.

Для регистрации V81.COMConnector необходимо выполнить:
regsvr32 "C:\Program Files\1cv81\bin\comcntr.dll"

Для регистрации V81.Application необходимо выполнить:
"C:\Program Files\1cv81\bin\1cv8.exe" /regserver

http://1cniku.ru/Articles/V8OLE.html

См. также

Подписаться Добавить вознаграждение

Комментарии

0. Алексей (artspeed) 07.04.11 22:43
Решил серьезно заняться изучением OLE. Конечно OLE это не КД, но все же...

Перейти к публикации

1. mirco brons (mirco) 07.04.11 22:43
Перед тем как публиковать - прочтите вот это
http://infostart.ru/public/66592/
2. Алексей (artspeed) 08.04.11 00:53
3. mirco brons (mirco) 08.04.11 09:52
уже лучше, ну только отступы осталось :D
сейас почитаем.
4. Андрей (lamer19) 08.04.11 15:26
Можно мое авторство указать при желании
5. Ирина Пятакова (Alraune) 08.04.11 15:30
Авторство надо указать обязательно, а не "по желанию"
Necytij; lamer19; +2 Ответить 1
6. Banderas Banderas (volsh77) 11.04.11 02:53
У меня все перебросы через ОЛЕ, пытаюсь получше усвоить конвертацию данных :)
7. Андрей (lamer19) 13.04.11 17:01
(5) Хорошо ссылку на исходный материал дал, так посещаемость сайта резко увеличилась
8. Виталий (nafa) 15.04.11 12:20
[quote]Попалась в интернете хорошая статья и решил ее поместить сюда. Думаю будет полезна как для начинающих, так и для продвинутых, что бы закрепить свои знания.[/quote]
Просто статья, попавшаяся в интернете - это то же самое, что и ОБС (одна баба сказала). Достаточно лишь внимательно посмотреть на ее начало
[quote]Приведу код глобального модуля
#Если Клиент Тогда
Функция ВернутьТипПодключения() Экспорт
Возврат("Клиент");
КонецФункции
#Иначе
Функция ВернутьТипПодключения() Экспорт
Возврат("Сервер");
КонецФункции
#КонецЕсли[/quote]
чтобы предположить, что писал ее "профессиональный писатель" - т.е. человек, зарабатывающий на жизнь написанием книг о предмете, в котором он понятия не имеет. (Каковых среди писателей технической литературы в последнее время, к сожалению, стало большинство).
Во-первых, в 8ке нет "глобального" модуля, есть модули приложения/соединения... и есть общие модули
Во-вторых, в инструкции #Если Клиент и Сервер описывают место выполнения кода а не тип подключения.
В третьих, читая выводы типа
[quote]То есть при обращении через объект V81.ComConnector подключение осуществляется в режиме север, даже если мы подключаемся к локальной файловой базе.[/quote]
думаю что пора учредить приз - 'Серебряную утку' или что-то вроде этого.
Пояснение при вызове через Комконнектор данная функция всегда будет возвращать "Сервер", потому что в ней вообще забыли что кроме 'Клиента' и 'Сервера', есть еще и 'Внешнее соединение'.
Остальную часть комментировать просто времени нет.
9. Андрей Хорошулин (dinopopyys) 15.04.11 17:48
ну че тут такого необычного написано? Общеизвестные факты выложили в оч. раз в интернету.
10. Евгений Фамилия (internetname) 02.12.11 11:22
11. Сергей Онучин (sonuchin3) 29.01.12 21:20
Лучший способ проверить работу функций УстановитьИстина(), УстановитьЛожь() - посмотреть, что произошло в каркасной базе. Обращаюсь к 8.2 из 7.7. У меня после выполнения команды:

Base8.Константы.Константа1.Установить(Base8.ЗначениеИзСтрокиВнутр("{""B"",1}"));

- в каркасной базе установилось именно то, что потом возвращается в логе сообщений, т.е. число -1.
Установить же булевское значение Истина удалось только вызывая экспортную функцию общего модуля в 8.2, возвращающую Истина.
Так что для меня вопрос о том, можно ли извне из 7.7 установить булевское значение в 8.2, не прибегая к заранее написанным функциям в конфигурации 8.2, остался открытым.
12. Дмитрий Кокотов (m2d3) 20.04.12 14:05
13. Алекс Одинэсник (Alex1Cnic) 02.10.13 14:56
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа