Компиляции Кода 1С 8 Во Внешние Компоненты
Posted By admin On 01.10.19О чем эта статья Статья продолжает цикл «Первые шаги в разработке на 1С», в ней детально рассмотрены следующие вопросы:. Что такое программный модуль и из каких разделов он состоит?. Для чего нужен модуль приложения?
Почему их два? Когда какой запускается? Какие есть тонкости работы?.
Oct 10, 2009 - Net-классам из 1С:Предприятие (7.7/8.0/8.1/8.2). Недостатки внешних компонентов C# выражаются в том, что их практически невозможно. Net framework речь заходит о компиляции исходного кода, на помощь.
Какие события связаны с началом работы системы, как и где их обрабатывать?. Для чего нужен модуль внешнего соединения? Когда и как его использовать?. Когда используется модуль сеанса?. Что такое общие модули? Какие у него свойства и правила работы?
Для чего нужно использовать свойство “Повторное использование возвращаемых значений”?. Когда используется модуль формы и какие события в нем могут быть обработаны?. Для чего предназначен модуль объекта? Из каких разделов он состоит? Как посмотреть доступные события модуля?. Какие тонкости работы существуют с модулями менеджера значения (для констант) и модулями набора записей (для регистров)?. В чем отличия между модулем объекта и модулем менеджера?
Когда нужно использовать последний? Модули в «1С:Предприятие 8.3». Модули – это те объекты, где содержится программный код. В Платформе существует достаточно большое количество видов модулей, каждый из которых имеет свое предназначение и особенности. Любая строка кода должна находиться в каком-либо модуле. Различают модули общего предназначения и модули объекта. Некоторые модули могут быть скомпилированы как на Клиенте, так и на Сервере, а некоторые только на Сервере.
Модуль может состоять из нескольких разделов. В разделе описания переменных описываются локальные переменные данного модуля, которые впоследствии могут быть использованы в любой процедуре.
Внутри каждой процедуры можно обращаться к переменной модуля. Кроме того, внутри самой процедуры может быть еще одно объявление переменной с таким же именем.
Это будет локальная переменная данной процедуры. Несмотря на одинаковое название, это две разные переменные: одна используется внутри конкретной процедуры, а другая – вне ее. В некоторых модулях для переменных может указываться место компиляции (доступность) на Сервере или на Клиенте.
Например: За разделом описания переменных следует раздел процедур и функций, где указываются локальные методы данного модуля. В некоторых модулях следует указывать, где будет скомпилирована процедура или функция. В принципе, директиву компиляции можно не указывать. В этом случае директивой компиляции по умолчанию является Сервер. Тем не менее, для удобства анализа программного кода рекомендуется явно указывать, где будет скомпилирована данная процедура. Порядок описания процедур никакого значения не имеет. В конце модуля, после описания всех процедур и функций, располагается раздел основной программы, где могут содержаться некоторые операторы, инициализироваться локальные переменные модуля формы.
Данный раздел выполняется при обращении к модулю. Так, например, при открытии формы элемента прежде всего выполняется раздел основной программы модуля формы. Следует отметить, что раздел объявления переменных и раздел основной программы существуют не для всех модулей (т.е. В некоторых модулях данные разделы недопустимы). Раздел описания процедур и функций может существовать абсолютно в любом модуле. Модуль приложения Данный модуль предназначен для того, чтобы обработать события запуска приложения и завершения его работы. Например, при запуске приложения можно загружать курсы валют из Интернета.
При завершении приложения можно удостовериться у пользователя о его намерениях закончить работу. Также в модуле приложения существуют специальные обработчики, которые позволяют перехватить внешние события от оборудования. Это могут быть события от ридера магнитных карт, фискального регистратора. И эти события можно каким-то образом тоже обработать.
Следует обратить внимание, что в модуле приложения отслеживается именно интерактивный запуск системы. Модуль приложения не будет работать, если запуск программы 1С осуществляется, например, в режиме com-соединения. В этом случае окно программы не создается. Следует отметить, что в Платформе 8.3 существует два разных модуля приложения: модуль Управляемого приложения и модуль Обычного приложения.
События модуля управляемого приложения отрабатываются при запуске Тонкого и Толстого клиента Управляемого приложения и Веб-клиента. Модуль Обычного приложения работает при запуске Толстого клиента в режиме Обычного приложения, в котором присутствует обычный командный интерфейс в виде Главного меню. Если приложение работает и в режиме Управляемого, и в режиме Обычного приложения, то необходимо описывать процедуры-обработчики как для модуля Управляемого приложения, так и для модуля Обычного приложения.
Модуль Управляемого приложения можно выбрать из контекстного меню корневого узла конфигурации. Также этот модуль можно открыть из палитры свойств корневого элемента конфигурации. Чтобы открыть модуль Обычного приложения, следует обратиться к настройкам конфигурации (команда Параметры в меню Сервис). Откроется форма Параметры. На закладке Общие должен быть указан режим редактирования конфигурации Управляемое приложение и Обычное приложение. В этом случае модуль Обычного приложения также можно будет открыть из свойств корневого узла. Список событий, которые можно обрабатывать, для Управляемого и Обычного приложения одинаков.
В данном модуле можно размещать раздел объявления переменных, раздел описания произвольных процедур и функций и раздел основной программы. Но кроме произвольных процедур и функций в модуле могут быть расположены специальные обработчики событий. Список доступных обработчиков можно посмотреть, если при открытом модуле вызвать список процедур и функций текущего модуля. В раскрывшемся окне Процедуры и функции отображаются все процедуры и функции данного модуля, а также события, для которых обработчики еще не созданы. Есть два события, связанные с началом работы системы (“перед” и “при”). Два события, связанные с завершением работы системы (“перед” и “при”).
А также обработка внешнего события (например, события торгового оборудования). Когда выполняется обработчик события “перед”, считается, что действие еще не совершено. Когда выполняется обработчик события “при” – действие уже совершено.
Событие ПередНачаломРаботыСистемы возникает в тот момент, когда производится запуск Предприятия 8.3, но само приложение еще не появилось на экране. У данного события есть такой параметр, как Отказ. Если этот параметр примет значение Истина, то приложение не запустится. Событие ПриНачалеРаботыСистемы предполагает, что действие уже совершено, окно уже создано, и в этом случае мы можем, например, отобразить какую-то специальную форму. От запуска отказаться уже нельзя.
Аналогично перед завершением работы системы приложение еще открыто и можно отказаться от его завершения. При завершении работы системы окно приложения уже закрылось. Возможно выполнить лишь дополнительные действия, например, по удалению каких-то файлов или отправке электронного письма.
В модуле Управляемого приложения не указываются директивы компиляции процедур и функций, так как модуль целиком компилируется на стороне Клиента. Это означает, что в процедурах и функциях модуля мы не сможем непосредственно обратиться, например, к справочникам. Если из модуля Управляемого приложения необходимо сделать Серверный вызов, то для этого нужно будет создавать специальные Общие модули с выставленным флагом Вызов Сервера. В модуле Обычного приложения подобных ограничений нет, так как данный модуль будет компилироваться при загрузке Толстого клиента. В Толстом клиенте доступны практически все типы данных.
Процедуры, функции и переменные модуля приложения могут быть описаны как экспортные. Поскольку модуль скомпилирован целиком на Клиенте, это означает, что в клиентских процедурах мы можем обращаться к данному методу и данному свойству. Например, из модуля формы какого-либо объекта можно вызвать процедуру или функцию модуля приложения.
Однако для описания общих алгоритмов рекомендуется использовать Общие модули. Основное предназначение модуля приложения – обработать точку старта и точку завершения.
Модуль внешнего соединения По аналогии с модулем приложения данный модуль предназначен для того, чтобы обработать событие открытия программы и событие завершения работы. В отличии от модуля приложения, который инициируется в момент интерактивного запуска приложения, модуль внешнего соединения работает в режиме com-соединения, т.е. Когда создается объект 1С:Предприятие 8 и осуществляется подключение к определенной базе. В этом модуле есть события: ПриНачалеРаботыСистемы и ПриЗавершенииРаботыСистемы. Модуль внешнего соединения можно открывать используя либо контекстное меню на уровне корневого объекта конфигурации, либо палитру свойств для корневого узла.
Сам процесс внешнего соединения – это процесс программной работы с информационной базой, а не интерактивный. Соответственно, в этот момент нельзя использовать диалоговых форм, выводить предупреждающие сообщения, так как нет пользовательского интерфейса. В Модуле внешнего соединения возможно описывать экспортные переменные и экспортные методы, которые будут доступны на той стороне, где происходит внешний вызов 1С:Предприятие 8.3. Поскольку во внешнем соединении нет пользовательского интерфейса, Модуль внешнего соединения компилируется целиком на Сервере. Модуль сеанса Данный модуль нужен для того, чтобы инициализировать параметры сеанса. Параметры сеанса – это быстрые глобальные переменные, значения которых доступны в любом месте конфигурации.
Открыть Модуль сеанса можно либо через контекстное меню, либо через палитру свойств корневого узла. В Модуле сеанса предусмотрено событие УстановкаПараметровСеанса. При старте приложения данная процедура вызывается самой первой. Параметры сеанса нужны при любой работе приложения: как при интерактивном запуске, так и при запуске в режиме внешнего соединения. В Модуле сеанса описываются различные действия по инициализации параметров сеанса в зависимости от разных условий. В данном модуле, как правило, описываются несколько процедур, которые вызываются из процедуры УстановкаПараметровСеанса. Поэтому все эти процедуры выделены в отдельный модуль.
Модуль сеанса всегда исполняется в привилегированном режиме. Это означает, что не будет выполняться проверка прав доступа при обращении к базе данных. Модуль сеанса компилируется на Сервере, т.е.
Возможно обращение к любым серверным методам (в том числе и чтение значений из базы). В Модуле сеанса возможно определять только процедуры и функции, т.е. Нет раздела описания переменных и нет раздела основной программы. В Модуле сеанса нельзя описывать экспортные методы. Если при запуске системы необходимо выполнить некоторые действия на Сервере, например, создать элемент какого-либо справочника, то, как вариант, возможно использовать Модуль сеанса, т.к. Он компилируется на Сервере и всегда достоверно выполняется при старте системы. Однако при этом необходимо учитывать следующие моменты:.
процедура УстановкаПараметровСеанса выполняется не только при старте системы, а также при обращении к неинициализированным параметрам сеанса. Обработчик УстановкаПараметровСеанса может вызываться неоднократно в процессе работы приложения;. если количество элементов в массиве параметров сеанса равно нулю (у массива требуемых параметров тип данных Неопределено), то это момент запуска приложения;. поскольку Модуль сеанса работает в привелигированном режиме и проверки прав доступа не будет, следует очень аккуратно работать с объектами базы данных, так как пользователь может получить доступ к тем данным, которые ему не должны быть предоставлены;.
при запуске системы достоверно еще не известно: будет ли запущено приложение. При этом в обработчике события УстановкаПараметровСеанса могут быть произведены лишние действия. Общие модули Данные модули представляют собой описание некоторых общих алгоритмов, т.е. Процедур и функций, которые могут вызываться из различных мест.
Логически связанные методы можно группировать в разные Общие модули. Эти модули создаются внутри ветки Общие. Можно добавить любое количество общих модулей. Чтобы методы Общих модулей были доступны в других местах конфигурации, необходимо их определять с ключевым словом Экспорт. Клиентские процедуры общих модулей будут доступны на Клиенте, а серверные – на Сервере. В Общих модулях доступен только раздел описания процедур и функций.
В Общем модуле нельзя описывать переменные и нельзя описывать раздел основной программы. Если необходима глобальная переменная, то можно использовать либо параметры сеанса, либо экспортные переменные модуля приложения.
Для Общих модулей можно задавать некоторые параметры, которые будут влиять на поведение данного модуля. Если для Общего модуля выставлено свойство Глобальный, то объявленные в данном модуле экспортные методы будут доступны из вне напрямую, без каких-либо дополнительных указаний. Данный Общий модуль будет участвовать в формировании глобального контекста конфигурации.
Свойство Глобальный для общих модулей может быть полезным. Однако не стоит его использовать повсеместно для всех общих модулей. Те Общие модули, которые отмечены признаком Глобальный, будут компилироваться при старте системы. Чем больше таких модулей, тем медленнее программа будет стартовать. Если флаг Глобальный для Общего модуля не указан, то компиляция данного модуля будет выполняться в момент первого обращения к нему (т.е. Уже после старта системы).
Кроме того, использование глобальных общих модулей влияет на понимание кода. Вызов методов не глобального общего модуля осуществляется через имя Общего модуля и имя метода, например: МодульРасчетаСебестоимости.РаспределитьКосвенныеЗатраты; При этом имена Общих модулей должны отражать содержание описываемых в них процедур.
Указание имени Общего модуля при вызове процедуры способствует лучшему пониманию кода. Для Общего модуля в Палитре свойств можно установить свойство Привилегированный. В привилегированном модуле не контролируются права доступа. Это необходимо в том случае, если в Общем модуле требуется выполнять массовую обработку данных, получение данных из базы.
Контроль прав доступа увеличивает время обращения к базе данных, а массовые алгоритмы, зачастую, должны работать как можно быстрее. Например, ресурсоемкой операцией является расчет заработной платы. Необходимо, чтобы она выполнялась как можно быстрее.
Для этого алгоритмы, которые рассчитывают заработную плату, помещают в привилегированные Общие модули. При этом все процедуры, которые обеспечивают заполнение документов по начислению заработной платы, находятся вне этих Общих модулей. Именно в этих процедурах и выполняется контроль прав доступа. Таким образом можно достичь значительного повышения быстродействия. Особенно это касается случая применения механизма построчного разграничения доступа к записям таблицы.
Если Общий модуль является привилегированным, то процедуры этого модуля могут быть скомпилированы только на Сервере. Бывают ситуации, когда пользователю какой-то объект должен быть недоступен, например, определенный справочник. Но при проведении какого-то одного документа обращение к данному справочнику необходимо. Возникает потребность временно расширить права пользователя, а потом вернуть их в исходное состояние. Этот эффект может быть получен при использовании привилегированных Общих модулей. Для этого в привилегированном Общем модуле следует оформить процедуру, которая обращается к нужным данным.
Данная процедура будет вызываться из соответствующего документа. Пользователю на момент вызова этой процедуры фактически предоставляются расширенные права. Для Общих модулей существует возможность указывать место компиляции. С помощью флагов устанавливается: будет ли доступен Общий модуль на Клиенте (управляемое приложение), на Сервере, в режиме работы Внешнего соединения.
Кроме того, если перевести режим редактирования конфигурации в Управляемое приложение и обычное приложение, то будет возможен еще один контекст компиляции – Клиент (обычное приложение). Таким образом, выделяется четыре варианта функционирования программы. В зависимости от запущенного приложения, в зависимости от работы на Клиенте или на Сервере будут доступны или недоступны определенные Общие модули.
Кроме возможности указывать флаги компиляции имеется возможность указывать директивы компиляции для процедур и функций, располагающихся в Общем модуле. Если для метода указана директива компиляции, то не смотря на то, что Общий модуль доступен во всех указанных контекстах, доступность конкретного метода будет ограничена директивой компиляции. При этом процедура не может быть доступна в контексте, который не доступен в целом для всего модуля. Если директиву компиляции для процедуры (функции) не указывать, то она будет скомпилирована во всех контекстах, определенных для модуля. По сути будет сделано несколько копий процедуры. Выбор конкретного скомпилированного экземпляра зависит от места вызова процедуры (по правилу ближайшего вызова). При этом следует учитывать, что код такой процедуры должен быть написан с учетом его доступности во всех определенных для модуля контекстах.
Общие модули, одновременно доступные в нескольких различных контекстах, в основном предназначены для того, чтобы создавать процедуры, доступные в нескольких контекстах. При создании Общего модуля, правилом хорошего тона считается не указывать директивы компиляции. Доступность процедур и функций должна определяться свойствами самого модуля. При таком подходе в отдельных Общих модулях будут располагаться клиентские процедуры, и в отдельных Общих модулях – процедуры серверные. В названиях общих модулей рекомендуется это указывать.
Например: РегламентныеПроцедурыСервер, РегламентныеПроцедурыКлиент. Модули, у которых установлено несколько флагов компиляции, на практике используются крайне редко. Это некоторые общие действия, доступные как на Клиенте, так и на Сервере. Обычно, это какие-то простейшие вычисления. С Клиента возможно обращаться к экспортным серверным методам Общего модуля, но только в том случае, если данный Общий модуль скомпилирован только на Сервере.
При этом для обеспечения доступа с Клиента предназначен специальный флажок Вызов Сервера. Для неглобальных Общих модулей существует возможность кэширования тех значений, которые возвращаются функциями. Система может после первого вызова функции запомнить результат ее выполнения. Если данная функция будет вызвана еще раз с теми же параметрами, система выдаст значение уже из кэша.
Цель данного механизма – ускорить повторные вызовы. Для настройки подобного поведения необходимо в Палитре свойств модуля выставить соответствующее значение для свойства Повторное использование возвращаемых значений. По умолчанию для данного свойства определено значение Не использовать. Другие возможные значения: кэшировать На время вызова, либо На время сеанса.
Данное свойство имеет смысл использовать только для тех функций, результат которых зависит исключительно от входных параметров. Данный механизм доступен только для не глобальных Общих модулей. Если выбрано значение соответствующего параметра На время вызова, то кэш будет действовать до тех пор, пока работает та процедура, откуда был сделан вызов метода Общего модуля.
Если выбрано значение На время сеанса, то условно считается, что кэш будет действовать, пока пользователь работает. Тем не менее, существуют определенные временные ограничения. Очистка кэша происходит автоматически через 20 минут после попадания значения в кэш. Модуль формы Данный модуль предназначен для того, чтобы обработать действия пользователя. Например, описать алгоритм реакции программы при нажатии кнопки. Или, например, в момент ввода в поле значения сразу же выполнить проверку на корректность. Кроме событий, связанных с элементами управления формы (кнопки, поля ввода) существуют события, связанные непосредственно с самой формой. Nokia ps suite 7.1.60.
Например, можно обработать событие открытия формы и провести некую начальную инициализацию. Также можно обработать событие закрытия формы и проверить, а все ли правильно ввел пользователь. Существуют формы управляемые и формы обычные. Модули данных форм различаются прежде всего тем, что модуль управляемой формы четко разделяется на контекст.
Каждая процедура (функция) должна иметь директиву компиляции. В обычной форме весь код используется на Клиенте.
В модуле управляемой формы можно объявлять процедуры и функции, можно объявлять переменные и описывать раздел основной программы. Программный код основной программы будет выполняться в момент инициализации формы, т.е.
Когда пользователь начинает ее открывать. На рисунке представлен список стандартных событий для управляемой формы. Список событий управляемой формы виден также в списке свойств непосредственно для самой формы. Данный список вызывается в редакторе управляемых форм. В управляемой форме можно обработать событие записи элемента. Данное событие присутствует только для форм объектов (справочников, документов и некоторых других).
Если форма не привязана к конкретному объекту, то событие записи отсутствует. Для модуля обычной формы перечень стандартных событий несколько меньше, т.к. В управляемой форме многие события сделаны парными (одно выполняется на Клиенте, а другое на Сервере). В обычной форме весь код исполняется на Клиенте. Модуль объекта Данные модули характерны для справочников, документов, планов видов расчетов, планов счетов и многих других объектов.
Модуль объекта предназначен для обработки стандартных событий. Например, событие на ввод элемента справочника, событие на запись элемента, удаление, проведение документа и т.д. В принципе, событие записи существует и в Модуле формы. Но событие записи в Модуле формы возникает в процессе интерактивной записи, при работе с конкретной формой. Событие записи в Модуле объекта будет выполняться при любой записи из любой формы данного объекта.
Кроме того, если объект записывается программно, в этом случае будет срабатывать событие модуля объекта. В событии записи Модуля объекта можно встраивать все проверки на корректность записываемых данных, так как эта процедура будет отрабатывать в момент абсолютно любой записи. Модуль данного объекта можно вызывать через контекстное меню, из Палитры свойств объекта и из окна редактирования объекта.
Ниже на рисунке представлен перечень доступных событий модуля справочника. В Модуле объекта можно размещать раздел описания переменных, описывать произвольные функции, которые могут быть и не связаны с событием, а также раздел основной программы. В разделе основной программы можно, например, выполнять инициализацию локальных переменных данного модуля. Этот программный код будет выполняться при обращении к данному Модулю объекта. Следует отметить, что все процедуры Модуля объекта скомпилированы на Сервере.
Соответственно директивы компиляции у процедур и функций Модуля объекта указывать не требуется. У некоторых объектов конфигурации не существует Модулей объектов. Это связано с особенностями самих объектов. К таким объектам относятся Константы и Регистры.
Для Констант не существует модуля объекта, но существует очень похожий модуль, который называется Модулем менеджера значения. В Модуле менеджера значения можно выполнить обработку событий записи Константы и обработку проверки заполнения. Весь контекст модуля исполняется на Сервере. Для регистров существует Модуль набора записей. В данном модуле также имеется возможность обрабатывать события записи и выполнять проверку заполнения. В Модулях объектов, Модулях менеджера значения (для констант) и Модулях набора записей (для регистров) можно описывать методы, которые можно делать экспортными, и эти методы будут доступны из вне.
Помимо использования фиксированных методов класса объектов можно создавать для объекта дополнительные методы в Модуле объекта. В данном модуле следует описать соответствующую процедуру с ключевым словом Экспорт. Тогда будет возможно обращаться к этой процедуре из вне. Причем данный метод будет отображаться в контекстной подсказке. Новые методы в контекстной подсказке выделяются синим шрифтом (синий значок p( ) для процедур и f( ) для функций).
Аналогичным образом можно создавать новое свойство, объявив переменную с ключевым словом Экспорт. К этому свойству также можно будет обращаться из вне. Таким образом возможно расширять функциональность объектов (доопределять новые методы и новые свойства). При этом свойства являются динамическими и не сохраняются в базе данных. Если необходимо использовать для объекта свойство, которое будет храниться в базе данных, следует создавать реквизит объекта. Модуль менеджера Данный модуль существует для многих объектов (справочники, документы, регистры и др.).
Модуль открывается либо через контекстное меню для объекта, либо через Палитру свойств, либо через окно редактирования. В Модуле менеджера можно переопределить некоторые стандартные события.Например, в ОбработкеПолученияДанныхВыбора, когда выбирается элемент из справочника, можно сделать какую-то дополнительную фильтрацию или проверку. Кроме этого в Модуле менеджера можно создать дополнительные методы и указать, что они являются экспортными. В этом случае возможно обращение к данным методам из вне. Для того, чтобы выполнить данное обращение, необходимо получить тип данных СправочникМенеджер.
Отличие экспортных методов Модуля менеджера и Модуля объекта состоит в том, что для обращения к методу Модуля объекта вначале нужно получить сам объект (т.е каким-то образом получить ссылку и далее эту ссылку преобразовать в объект). После этого будут доступны экспортные переменные и методы Модуля объекта.
Для Модуля менеджера обращение более простое, например: Справочники.Контрагенты.ИмяМетода Это два разных обращения. Преобразование из ссылки в объект (метод ПолучитьОбъект) – это достаточно серьезное действие для системы, так как при получении объекта читаются абсолютно все данные этого объекта, что может быть достаточно длительным. Второе отличие в том, что МодульОбъекта вызывается в контексте конкретного элемента. Соответственно можно считать, что он применим для данного элемента (в большинстве случаев закладывается именно такая логика). Что касается Модуля менеджера, то в нем описывается какое-то общее действие для группы или для всех элементов справочника или какого-то документа. Например, если необходимо напечатать элемент справочника, можно использовать Модуль объекта.
Но в Модуле менеджера возможно сделать более универсальный механизм, который будет печатать, в том числе, и группу элементов. Кроме того, обращение к Модулю объекта – это все-таки более длительное действие. Поэтому решать данную задачу в модуле менеджера более предпочтительно. На этом завершим наше знакомство с модулями в конфигурации системы «1С:Предприятие». Если подвести краткое резюме всему вышенаписанному, то в сухом остатке получаются следующие выводы:.
Программный модуль – это часть конфигурации, которая может содержать только текст на встроенном языке 1С. Программные модули классифицируются по видам, которые мы рассмотрели в этой статье. Каждый вид определяется местом размещения и доступным программным контекстом. Структура модуля состоит из некоторых разделов, которые располагаются в определенной последовательности.
Состав разделов определяется видом модуля. Также отметим, что мы сознательно опустили один вид модуля, а именно модуль команды. Ничего примечательного он из себя не представляет, и мы предлагаем вам самостоятельно ознакомиться с его функциональностью. Пока весь наш программный код мы рассматривали отрывочно от прикладного решения, и как правило, писали его в какой-то своей небольшой тестовой конфигурации. А вы в курсе, что «нельзя просто так взять» и начать редактировать код типовой конфигурации? Тогда в мы все это объясним!
Вступление За годы своего развития платформа 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С ее разворачивает и устанавливает сама.
А недостатком является сложность их создания. Фактически, сейчас 1С в качестве примера компонент использует только C. Конечно, можно создавать внешние компоненты и на Delphi.
Но нюанс в том, что Kylix (компилятор приложений, написанных на Delphi, для работы под Linux) начиная с 2002 года уже не поддерживается, поэтому, у таких компонент могут возникнуть проблемы с кроссплатформенностью. Язык программирования Eiffel Язык Eiffel был разработан Бертраном Мейером, одним из ведущих специалистов по объектно-ориентированному программированию (ООП) во второй половине 80-х годов, промышленный компилятор и среда разработки выпущены в середине 90-х, им же основанной фирмой (тогда 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. Кортеж TUPLEX1Xn в Eiffel определяется как последовательность n элементов, которая может быть больше чем n. Они широко используются в агентах (указателях на функции), inline агентах (анонимных функциях) и лямбда выражениях.
Класс EiffelAddIn содержит также служебные процедуры для преобразования строк и параметров, передаваемых из 1С в Eiffel и обратно. Типу tVariant соответствует тип V8ARG, который будет рассмотрен позже. Базовый класс 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С и указателя на менеджер памяти в компоненте. Также они инициализируют описатели свойств и методов V8PROP и V8METHOD, код которых рассмотрим позднее. Описатели хранятся списком LINKEDLISTG: Инварианты класса очевидны и всегда подразумеваются программистом, пишущим класс, но только в Eiffel’е они имеют явное выражение.
Класс V8ARG является представление типа Variant, а это означает, что он может содержать значение переменной языка 1С:Предприятия, которая передается в компоненту. На его примере рассмотрим неявную конвертацию типов в Eiffel: Конструктор класса может быть одновременно конвертером, если он дополнительно объявлен в секции convert и в этой же секции объявлена функция обратной конверсии. И в заключение, рассмотрим устройство механизма рефлексии для параметров и свойств компоненты. Класс V8FEATURE определяет общие свойства свойств и методов и алгоритм их поиска для методов FindMethods и FindProps: Переопределив сущность is equal базового класса ANY, мы получаем возможность поиска путем пообъектного сравнения в списках LINKED LIST. В Eiffel в отличие от платформы NET отсутствует рефлексия типов, поэтому описатели свойств и методов компоненты приходится писать в подобном стиле: Пожалуй, это единственный минус в архитектуре компоненты. В заключение раздела на примере сущности callasfunc познакомим читателей с синтаксисом попытки приведения типов в Eiffel: В кортеже параметров ( TUPLE ) могут быть члены любого типа, поэтому такая проверка гарантирует правильную обработку типов и исключает вызов к нулевой ссылке ( Void reference exception ). Ее использование в данном контексте – требование языка, оно необходимо для правильной работы динамического связывания Заключение Как известно, описание любого паттерна должно состоять из двух частей: указания по применению («как использовать») и описание самого шаблона.
В предыдущих разделах мы постарались обратить внимание на ключевые места внутреннего строения компоненты, сейчас же нам осталось дать пошаговый алгоритм использования. Он очень простой: Шаблон компоненты приложен к даной статье. Данная статья написана по итогам доклада, прочитанного на конференции INFOSTART EVENT 2015 CONNECTION 15-17 октября 2015 года. Приглашаем вас на новую конференцию.
Ситуация резко изменилась после выхода версии 8.2 и создания технологии NativeAPI. Теперь программисты вынуждены довольствоваться ее демонстрацией только на C.
Обычный com-объект, написанный на любом языке никто не отменял, эта технология всё еще работает и на клиенте и на сервере. А кому надо NativeAPI писать на C#, тот использует технологию CLR Hosting API (между прочим, эту технологию юзает ms sql server, ms office и т.д.): если сильно хочется, c# (CoreCLR) можно и на линукс юзать: java можно по такому-же принципу использовать, используя JNI.