Создание внешних компонент 1С по технологии NativeAPI на языке Eiffel

15.07.16

Разработка - Математика и алгоритмы

Статья знакомит с новым средством создания NativeAPI внешних компонент для 1С - языком Eiffel. Она будет интересна высококвалифицированным разработчикам 1С, которые имеют также опыт программирования на других языках. Eiffel - это высокоуровневый кроссплатформенный полностью объектно-ориентированный язык, обладающий красотой и элегантностью. Как инструмент создания внешних компонент он способен составить конкуренцию C++.

Скачать исходный код

Наименование Файл Версия Размер
Шаблон компоненты
.zip 33,45Kb
11
.zip 33,45Kb 11 Скачать

Вступление

За годы своего развития платформа 1С:Предприятия становилась все более открытой. Возможность работы с текстовыми файлами и табличными данными в dbf-формате в 90-е годы в 2000-е дополнилась доступностью многих современных средств интеграции. Здесь и веб-сервисы, и поддержка схем xml при обменах со сторонними системами, и возможность подключения к внешним источникам данных, и встроенный почтовый клиент. К сожалению, в развитии технологии внешних компонент наблюдается противоположный процесс. Это можно видеть, последовательно просмотрев диски ИТС с демонстрационными примерами от самой фирмы 1С. С выходом технологии разработчикам были доступны образцы создания компонент на C++ и Delphi, затем в список языков включили Visual basic 6, еще позже C#. Тогда 1С декларировала, что компоненту можно создать на любом компилируемом языке, поддерживающем COM. Ситуация резко изменилась после выхода версии 8.2 и создания технологии NativeAPI. Теперь программисты вынуждены довольствоваться ее демонстрацией только на C++. Причины такого сужения доступных средств лежат на поверхности, прежде всего это необходимость поддержки 64-битной архитектуры и кроссплатформенность.

Не будем уподобляться многим программистам (в том числе очень авторитетным), которые не переносят C++. Автор этой статьи придерживается более философского подхода, который можно сформулировать, как «каждому инструменту - свое место», но он не уверен, что технология внешних компонент является монопольным правом C++. Другое дело, что этот язык трудно вытеснить из-за жестких ограничений, накладываемых на формат компоненты 1С: необходимость создания машинных исполняемых файлов для каждой платформы (а не промежуточных образов как в Java или C#), возможность статической сборки компоненты в один, независящий от внешних библиотек и сред, файл. Кроме того, возросшие вкусы современных программистов выдвигают повышенные требования к инструменту замены: полноценная поддержка ООП, включая автоматическую сборку мусора, красота и элегантность; иными словами, необходимо оставить всю мощь, гибкость и эффективность C++, но убрать его недостатки и сложность. Казалось бы, требования невыполнимые и невозможно найти такой язык и платформу. Но автор смело заявляет: Есть такой язык!

История развития технологии внешних компонент

Давайте посмотрим, как менялся подход 1С к созданию внешних компонент с конца 90-х по настоящее время.

Кроме перечисленных плюсов и минусов COM-компонент, следует отметить, что для их создания программисту 1С достаточно незначительно расширить багаж своих знаний. Недостаток, указанный в третьем пункте думаю знаком даже программистам, не писавшим компоненты: стоит написать вместо ПодключитьВнешнююКомпоненту -  ЗагрузитьВнешнююКомпоненту в надежде что 1С сама установит файл, и (привет системным администраторам!) потребуется регистрация компоненты в реестре Windows, которая невозможна без прав локального администратора. А если мы создаем компоненту на .NET, то нужно писать свой инсталлятор или пользоваться инструментами платформы .NET ( утилита regasm).

Технология внешних компонент на основе NativeAPI

Теперь посмотрим на внешние компоненты, разработанные на основе NativeAPI.

  • Эта технология удобна для 1С-разработчиков тем, что установка компоненты не требуется, 1С ее разворачивает и устанавливает сама.
  • А недостатком является сложность их создания. Фактически, сейчас в качестве примера компонент использует только C++.
    Конечно, можно создавать внешние компоненты и на Delphi. Но нюанс в том, что Kylix (компилятор приложений, написанных на Delphi, для работы под Linux) начиная с 2002 года уже не поддерживается, поэтому, у таких компонент могут возникнуть проблемы с кроссплатформенностью.

Язык программирования Eiffel

Язык Eiffel был разработан Бертраном Мейером, одним из ведущих специалистов по объектно-ориентированному программированию (ООП) во второй половине 80-х годов, промышленный компилятор и среда разработки выпущены в середине 90-х, им же основанной фирмой Eiffel Software (тогда ISE). Уже в те годы Eiffel удовлетворял всем критериям объектной-ориентированного языка, которые указаны на слайде:

Сила языка Eiffel заключается в его бескомпромиссном рационализме. Никаких лишних понятий и концепций, не имеющих выражения в языке или математической модели, которой является теория абстрактных типов данных. По сути, абстрактный тип данных – это класс без его конкретной реализации. Абстрактный тип данных определяется набором аксиом, характеризующих его поведение. Аксиомы при реализации типа как класса преобразуются в сущности (features), которые делятся на запросы, команды и конструкторы. Запрос возвращает данные о состоянии экземпляра класса (объекта), команда – изменяет это состояние, конструктор создает объект класса.

Уже первые версии реализации языка и среды разработки (Eiffel Studio) значительно опережали «конкурентов» (Java и позже появившейся C#) в плане следования стандартам ООП. Eiffel служил и служит лабораторией, где впервые реализуются новые (и как правило успешные) возможности, которые со временем появляются в более распространенных языках и средах. Например, множественное наследование до сих пор недоступно программистам Java и C#, ковариантность шаблонов появилась в C# только в net framework 3.5 и в это же время в Java. Ковариантное согласование параметров (аргументов) невозможно в других языках. Например, для команды копирования в базовом классе в Eiffel можно написать:

copy (other: like Current)

В классе-потомке аргумент other будет согласованно изменять свой тип. Неотъемлемой чертой Eiffel является идея контрактного программирования, берущая начало в теории абстрактных типов данных. Контракты позволяют на порядок повысить качество программного продукта и облегчают отладку. Контракты – прямое выражение алгебраического подхода моделирования внешнего мира, присущего программным объектам. Аксиоматические сущности предельно четко выражаются через классы и контракты. (Контракты были введены в C# начиная с версии 4.5.)

Синтаксис класса в Eiffel

На скриншоте показано, как может выглядеть реализация класса натуральных чисел в аксиоматике Пеано.

  • В разделе invariant в конце класса описываются инварианты (аксиомы) класса.
  • Члены класса (features) не делятся как в традиционных языках на поля, свойства и методы. По их функциональности они могут быть разделены на запросы и команды. Запросы предоставляют информацию и состоянии класса, команды - модифицируют это состояние. 

Примеры технологий, реализованных в Eiffel раньше других языков программирования

В Eiffel были реализованы многие революционные подходы, которые потом "перетекли" в другие промышленные языки. Например:

  • Ковариантность, которая в .NET появилась в 2000-х годах, а в Eiffel была изначально.
  • Контрактное программирование, для которого только после выхода .NET версии 4.5 появились аддон для VisualStudio и соответствующий namespace.
  • Многопоточное программирование на основе async/await, которые совсем недавно появились в .NET. Аналогичный по простоте механизм был введен в Eifel в серенине 2000-х.
  • Проблема обращение к нулевой ссылке, когда вызывается метод или свойство переменной, которая еще не инициализирована. В Eiffel изначально предлагается очень простое решение этой проблемы. (см. операторы detachable/attached языка).

Дополнительные возможности Eiffel, которые позволяют создавать полноценные внешние компоненты

Рассмотрим, как Eiffel удовлетворяет требованиям по сборке внешних компонент:

 

Первое требование реализуется средой разработки от Eiffel Software. Реализация же второго пункта во многих языках представляет сложную задачу, но не в Eiffel, который имеет несколько средств интеграции с кодом на C++. Они нам потребуются для создания этих интерфейсов, поэтому вкратце рассмотрим их.

Средства интеграции Eiffel c С++

В первом примере читатели статьи, пасавшие NativeAPI компоненты лего узнают выделение памяти для объектов, создаваемых в компоненте и передаваемых в 1С. Имена параметров из Eiffel предваряются в C++ знаком $. Пример демонстрирует интеграцию кода C++ в Eiffel. Второй пункт слайда - вызов процедур Eiffel из C++ реализуется с помощью библиотеки CECIL, которая включает функции и макросы преобразования типов и API для управления сборщиком мусора. Для использования CECIL скомпилированный проект на Eiffel studio собирается утилитой make (nmake) в статическую библиотеку (*.lib), которая затем подключается к проекту на C++. Именно этим способом собирается внешняя компонента, реализуемая на языке Eiffel.

Архитектура шаблона внешней компоненты для 1С, написанного на Eiffel

Рассмотрим строение компоненты на Eiffel с точки зрения модульной архитектуры:

EiffelStudio для диаграмм классов употребляет BON (business object notation) нотацию, которую будем использовать и мы. В ней класс отображается в виде овала, связи между классами в виде сплошной (родитель – потомок) или пунктирной стрелки (поставщик – клиент). В виде прямоугольника мы обозначили набор экспортируемых для dll функций. Как известно, их назначение – дать декларативное описание объекта (или объектов) компоненты и создать по запросу указанный объект. Чтобы не заставлять программиста, использующего этот шаблон, каждый раз модифицировать код на C++, требуется Eiffel класс COMPONENTNAMES, который возвращает имена объектов компоненты. Как и в EiffelStudio класс выделен более светлым фоном, потому что он заморожен, т.е. не допускает наследования.

Запуск движка Eiffel средствами CECIL рассмотрим на примере экспортной функции GetClassNames:

Для старта необходимо подготовить ряд параметров среды (командную стоку, глобальные переменный ОС) и вызвать функцию eif_rtinit(), что делается в процедуре EifEnvInit. Окончание работы должно завершаться reclaim() для освобождения памяти и принудительного вызова сборщика мусора либо завершение работы произойдет автоматически при завершении процесса или выгрузке DLL, что актуально для внешней компоненты. Код функции представляет собой пример вызова сущности класса Eiffel из C++. eif_create выделяет память для объекта, но не вызывает конструктор класса, поэтому за ее вызовом требуется вызов конструктора для инициализации свойств и соблюдения инварианта класса. В данном примере инициализация не требуется, поэтому вызов отсутствует. Объекты Eiffel в C++ могут иметь тип EIF_OBJECT или EIF_REFERENCE, а также для некоторых типов EIF_INTEGER, EIF_POINTER и др. Оба типа представляют собой указатели, различие между ними в том, что EIF_OBJECT является «зафиксированным» в памяти объектом, который защищен от манипуляций сборщика мусора (перемещение в памяти с целью оптимизации), а EIF_REFERENCE – нет. Понятно, что вызовы сущностей из C++ должны производится только от EIF_OBJECT, но по окончании работы с объектом необходимо обязательно перевести его в нефиксированный статус вызовом eif_wean. Аналогичная инициализация среды Eiffel выполняется функцией GetClassObject, возвращающей EiffelAddIn, который служит по сути классом-оберткой над объектом компоненты в Eiffel. Его методы вызывают соответствующие сущности класса ECOMPONENTBASE. Их структура однотипна, приведем для примера код метода CallAsProc:

Массив параметров tVariant преобразуется тип TUPLE. Кортеж TUPLE[X1…Xn] в Eiffel определяется как последовательность n элементов, которая может быть больше чем n. Они широко используются в агентах (указателях на функции), inline агентах (анонимных функциях) и лямбда выражениях. Класс EiffelAddIn содержит также служебные процедуры для преобразования строк и параметров, передаваемых из 1С в Eiffel и обратно. Типу tVariant соответствует тип V8_ARG, который будет рассмотрен позже.

Базовый класс ECOMPONENTBASE, реализация свойств и методов компоненты

Класс ECOMPONENTBASE является передаточным звеном между декларативными вызовами свойств и методов компоненты из 1С и реальным ее объектом в Eiffel. Таким образом он должен выполнять две функции: предоставлять сущности для вызовов из промежуточного слоя C++ (класс EiffelAddIn) и отражать вызовы на объект компоненты, который от него наследуется. Поскольку среда и компилятор языка Eiffel не использует промежуточные метаданные, вроде байт-кода или msil, он не имеет развернутых средств рефлексии. В какой-то степени класс ECOMPONENTBASE их заменяет. Посмотрим на его инициализацию и некоторые свойства:

Напомним, что свойства (запросы) класса, которые в других языках называются полями в Eiffel’е всегда доступны только для чтения. Запрос addinname должен быть обязательно переопределен в классе-потомке (deferred), это имя класса-компоненты в 1С, которое создается инструкцией Новый(«AddIn.name»). Команда make – вспомогательная и служит для вызова из конструктора наследника, например:

В секции объявления наследования (inherit) указывается, что сущность make базового класса переопределяется. Кроме инструкции redefine в этой секции могут встречаться ряд других (undefined, select, rename, export), служащих для управления видимостью и разрешения конфликтов при множественном и дублируемом наследовании. Eiffel позволяет сделать любую сущность – конструктором, в свою очередь конструкторы базового класса не являются таковыми у потомка. В секции create происходит объявление make конструктором, а внутри можно видеть вызов предшественника Precursor. Сущность make служит для сохранения контекста 1С и указателя на менеджер памяти в компоненте. Также они инициализируют описатели свойств и методов V8_PROP и V8_METHOD, код которых рассмотрим позднее. Описатели хранятся списком LINKED_LIST[G]:

Инварианты класса очевидны и всегда подразумеваются программистом, пишущим класс, но только в Eiffel’е они имеют явное выражение.

Класс V8_ARG является представление типа Variant, а это означает, что он может содержать значение переменной языка 1С:Предприятия, которая передается в компоненту. На его примере рассмотрим неявную конвертацию типов в Eiffel:

Конструктор класса может быть одновременно конвертером, если он дополнительно объявлен в секции convert и в этой же секции объявлена функция обратной конверсии.

И в заключение, рассмотрим устройство механизма рефлексии для параметров и свойств компоненты.

Класс V8_FEATURE определяет общие свойства свойств и методов и алгоритм их поиска для методов FindMethods и FindProps:

Переопределив сущность is_equal базового класса ANY, мы получаем возможность поиска путем пообъектного сравнения в списках LINKED_LIST.

В Eiffel в отличие от платформы NET отсутствует рефлексия типов, поэтому описатели свойств и методов компоненты приходится писать в подобном стиле:

Пожалуй, это единственный минус в архитектуре компоненты.

В заключение раздела на примере сущности callasfunc познакомим читателей с синтаксисом попытки приведения типов в Eiffel:

В кортеже параметров (TUPLE) могут быть члены любого типа, поэтому такая проверка гарантирует правильную обработку типов и исключает вызов к нулевой ссылке (Void reference exception). Ее использование в данном контексте – требование языка, оно необходимо для правильной работы динамического связывания

Заключение

Как известно, описание любого паттерна должно состоять из двух частей: указания по применению («как использовать») и описание самого шаблона. В предыдущих разделах мы постарались обратить внимание на ключевые места внутреннего строения компоненты, сейчас же нам осталось дать пошаговый алгоритм использования. Он очень простой:

Шаблон компоненты приложен к даной статье.

**************

Данная статья написана по итогам доклада, прочитанного на конференции INFOSTART EVENT 2015 CONNECTION 15-17 октября 2015 года.

Приглашаем вас на новую конференцию INFOSTART EVENT 2019 INCEPTION.

См. также

Метод Дугласа-Пойкера для эффективного хранения метрик

Математика и алгоритмы Платформа 1C v8.2 Конфигурации 1cv8 Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    1870    stopa85    12    

34

Алгоритм симплекс-метода для решения задачи раскроя

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    4666    user1959478    50    

34

Регулярные выражения на 1С

Математика и алгоритмы Инструментарий разработчика Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

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

1 стартмани

09.06.2023    7654    4    SpaceOfMyHead    17    

56

Модель распределения суммы по базе

Математика и алгоритмы Платформа 1С v8.3 Россия Абонемент ($m)

Обычно под распределением понимают определение сумм пропорционально коэффициентам. Предлагаю включить сюда также распределение по порядку (FIFO, LIFO) и повысить уровень размерности до 2-х. 1-ое означает, что распределение может быть не только пропорциональным, но и по порядку, а 2-ое - это вариант реализации матричного распределения: по строкам и столбцам. Возможно вас заинтересует также необычное решение этой задачи через создание DSL на базе реализации текучего интерфейса

1 стартмани

21.03.2022    7930    7    kalyaka    11    

44

Изменения формата файлов конфигурации (CF) в 8.3.16

Математика и алгоритмы Платформа 1С v8.3 Бесплатно (free)

Дополнение по формату файлов конфигурации (*.cf) в версии 8.3.16.

16.12.2021    4546    fishca    13    

36

Интересная задача на Yandex cup 2021

Математика и алгоритмы Бесплатно (free)

Мое решение задачи на Yandex cup 2021 (frontend). Лабиринт. JavaScript.

12.10.2021    8937    John_d    73    

46

Механизм анализа данных. Кластеризация.

Математика и алгоритмы Анализ учета Платформа 1С v8.3 Анализ и прогнозирование Бесплатно (free)

Подробный разбор, с примером использования, встроенного механизма кластеризации 1С.

31.08.2021    7958    dusha0020    8    

70
Комментарии
Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. I_G_O_R 69 22.08.16 22:51 Сейчас в теме
Ситуация резко изменилась после выхода версии 8.2 и создания технологии NativeAPI. Теперь программисты вынуждены довольствоваться ее демонстрацией только на C++.

Обычный com-объект, написанный на любом языке никто не отменял, эта технология всё еще работает и на клиенте и на сервере.

А кому надо NativeAPI писать на C#, тот использует технологию CLR Hosting API (между прочим, эту технологию юзает ms sql server, ms office и т.д.):
http://infostart.ru/public/300091/
если сильно хочется, c# (CoreCLR) можно и на линукс юзать:
http://infostart.ru/public/534901/

java можно по такому-же принципу использовать, используя JNI
2. dreadlord 23.05.17 11:10 Сейчас в теме
Благодарочка за труды!
Познавательно, кругозоро расширятельно !
Вот чего мне нужно было...
Ушел учить Eiffel ))
3. DenisCh 23.05.17 12:10 Сейчас в теме
4. o.nikolaev 212 18.10.17 14:18 Сейчас в теме
(3) Скажу больше - активно развивается! Eiffel слишком сильно опередил свое время. Общение Мейера с советскими учеными из Новосибирска :) позволило ему создать язык, лет на 20 перепрыгнувший все разработки в этой области.

Статья хорошая, компактная и толковая. Очень приятно видеть практичное и обоснованное использование лучшего языка программирования в мире :) применительно к платформе 1С.
5. DenisCh 18.10.17 14:28 Сейчас в теме
(4)Мне помнится, когда я с ним знакомился, нарисовал хелловорлд и получил екзешник на несколько мегабайт... Я был в шоке.. По тем временам (где-то 2003й год) это было очень много...
7. IgorKissil 350 18.10.17 19:40 Сейчас в теме
(4) Совершенно точно, Бертран гениально развил идеи академика Ершова (вспоминаю Е-нотацию на младших курсах универа в начале 90х :))
(5) Это и достоинство - вся ооп-машина со сборщиком мусора в нем, не нужен ни framework ни виртуальная машина. В современных реализациях можно формировать маленькие exe, если движок уже есть на компьютере.
6. SaschaL 18.10.17 15:04 Сейчас в теме
Статья написана познавательно. Возможно кому то она принесет пользу и в практическом плане
8. СергейЩ 08.08.18 11:23 Сейчас в теме
Интересно к 1с из Эйфель обратиться можно,? или к Excel?
Оставьте свое сообщение