Pzl-Компонента: различия между версиями
(не показаны 73 промежуточные версии этого же участника) | |||
Строка 1: | Строка 1: | ||
=Необходимые условия признания класса компонентой= | {{copyright}} | ||
=Необходимые условия признания класса pzl-компонентой= | |||
Любой класс, порождающий объекты (имеющий интерфейс), может быть признан компонентой, если | Любой класс, порождающий объекты (имеющий интерфейс), может быть признан компонентой, если | ||
#Имя интерфейса и имя класса различаются; | #Имя интерфейса и имя класса различаются; | ||
#Интерфейс класса поддерживает интерфейс ''pzlComponent''; | |||
#Интерфейс класса поддерживает интерфейс pzlComponent; | #Интерфейс класса включает декларации констант: | ||
#Интерфейс класса включает | ##''componentID_C'' с типом ''pzlDomains::entityUID_D'' | ||
#Имплементация класса наследует от класса pzlComponent; | ##''componentAlias_C'' с типом ''string'' | ||
#Пакетный файл деклараций класса (.PH) включает файл "System\Packs\pzlcomponent\pzlcomponent.ph". | ##''componentRunAble_C'' с типом ''core::booleanInt'' | ||
##''componentMetaInfo_C'' с типом ''core::namedValue*''. | |||
##''сomponentDescriptor_C'' с типом ''pzlDomains::pzlComponentInfo_D''; | |||
#Декларация класса содержит единственный конструктор ''new(object ИспользуемыйОбъект)''; | |||
#Имплементация класса наследует от класса ''pzlComponent''; | |||
#Пакетный файл деклараций класса (.PH) включает файл ''"System\Packs\pzlcomponent\pzlcomponent.ph".'' | |||
Ниже приведены фрагменты различных составляющих компоненты, удовлетворяющей перечисленным выше условиям. | Ниже приведены фрагменты различных составляющих компоненты, удовлетворяющей перечисленным выше условиям. | ||
'''Декларация класса''' | '''Декларация класса''' | ||
:Содержит единственный коструктор ''new:(object UsingObject)''. Имя интерфейса отличается от имени класса. | |||
<vip> | <vip> | ||
class сomponentExample:iComponentExample | class сomponentExample:iComponentExample | ||
Строка 18: | Строка 25: | ||
end class | end class | ||
</vip> | </vip> | ||
'''Интерфейс класса''' | '''Интерфейс класса''' | ||
:Cодержит квалификатор '''''supports pzlComponent''''' и декларацию констант | |||
:*componentID_C | |||
:*componentAlias_C | |||
:*componentRunAble_C=b_True | |||
:*componentMetaInfo_C | |||
:*componentDescriptor_C | |||
<vip> | <vip> | ||
interface iComponentExample | interface iComponentExample | ||
Строка 42: | Строка 56: | ||
end interface iComponentExample | end interface iComponentExample | ||
</vip> | </vip> | ||
'''Имплементация класса''' | '''Имплементация класса''' | ||
:Содержит директиву наследования '''''inherits pzlComponent''''' и содержит клаузу для конструктора '''''new(UsingObject)''''' | |||
<vip> | <vip> | ||
implement componentExample | implement componentExample | ||
Строка 49: | Строка 64: | ||
clauses | clauses | ||
new(UsingObject):- | new(UsingObject):- | ||
... | ... | ||
Строка 57: | Строка 71: | ||
end implement componentExample | end implement componentExample | ||
</vip> | </vip> | ||
'''Файл деклараций пакета''' ComponentExample.PH | '''Файл деклараций пакета''' ComponentExample.PH | ||
:Содержит директиву включения файла '''''PzlComponent.ph''''' | |||
<vip> | <vip> | ||
#requires ... | #requires ... | ||
Строка 65: | Строка 80: | ||
</vip> | </vip> | ||
=Интерфейс pzlComponent= | |||
Интерфейс pzlComponent соответствует наследуемому pzl-Компонентой классу pzlComponent и делает класс pzl-компонентой, связывая ее с другими частями pzl-системы. Кроме того, этот интерфейс позволяет получать часть информации о компоненте. | |||
В частности следующие предикаты поддерживаются содержательно pzl-системой | |||
*getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится | |||
*getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента | |||
*getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent | |||
Остальные предикаты интерфейса: | |||
*getComponentVersion()-> string | |||
*getComponentID() -> entityUID_D | |||
*getComponentAlias() -> string | |||
*getComponentMetaInfo() -> namedValue* | |||
*release | |||
должны быть определены пользователем в имплементации базового класса компоненты. В противном случае генерируют исключения при обращении. | |||
=Предопределенные константы интерфейса pzl-компоненты= | |||
===Константа componentID_С=== | |||
Константа сomponentID_С определяет идентификатор компоненты, который (по-возможности) должен быть уникальным в глобальном смысле. То есть две программы в глобальном информационном пространстве (не говоря уже об одном копьютере), использующие компоненты с одним и тем же идентификатором могут быть уверены, что они используют точно одну и ту же pzl-компоненту. Этого можно добиться, если использовать способ, аналогичный способу, применяемому Microsoft для идентификации COM-компонент. | |||
Для этого в pzl-технологии используется структура с функтором uid: | |||
<vip> | |||
uid( | |||
core::unsigned32 Unsigned, | |||
core::unsigned16 Short1, | |||
core::unsigned16 Short2, | |||
core::unsigned8 Byte1, | |||
core::unsigned8 Byte2, | |||
core::unsigned8 Byte3, | |||
core::unsigned8 Byte4, | |||
core::unsigned8 Byte5, | |||
core::unsigned8 Byte6, | |||
core::unsigned8 Byte7, | |||
core::unsigned8 Byte8). | |||
</vip> | |||
что, на самом деле является полным аналогом структуры core::nativeGuid системы Visual Prolog. | |||
Идентификатор ComponentID используется в двух случаях: | |||
*Он является идентификатором, под которым в реестре Windows или в файле регистрации приложения записывается регистрационная информация о компоненте | |||
*Он является идентификатором, под которым эта компонента зарегистрирована в pzl-контейнере | |||
Поскольку идентификатор в форме uid является громоздкой последовательностью цифр и букв, то применять его в процессе освоения технологии неудобно. | |||
С целью упрощения процесса освоения имеется вторая версия представления идентификатора - строковая - в форме str(string). Естественно, уникальность строкового представления обеспечить крайне трудно, но в процессе освоения, можно пожертвовать глобальной уникальностью и контролировать только уникальность идентификатора на данном компьютере. | |||
В результате мы получаем две альтернативные формы представления идентификатора в объявлении домена entityUID_D: | |||
<vip> | |||
entityUID_D= | |||
str(string); | |||
uid(unsined16,...). | |||
</vip> | |||
===Константа componentAlias_C (Условное имя)=== | |||
Наряду с уникальным идентификатором, pzl-технология предоставляет воможность присвоить каждой компоненте условное, содержательное имя, являющееся строкой символов. Для этого выбранное имя должно быть присвоено константе ComponentAlias_C. Однако уникальность Условного Имени (Alias) не является жестким требованием. | |||
Так, Вы можете создать несколько текстовых редакторов с различными свойствами, которые поддерживают одни и те же интерфейсы. Каждый из этих текстовых редакторов будет иметь уникальный идентификатор типа entityUID_D и, возможно каждый из них будет иметь свое имя базового класса. Но все они могут иметь одно и то же условное имя "Текстовый Редактор". Тогда Ваша программа (подчеркнем, не зная имени класса), может при создании экземпляра pzl-компоненты использовать имя "Текстовый Редактор" и будет создаваться экземпляр той компоненты, которая в данный момент зарегистрирована на Вашем компьютере. Перерегистрировав новый редактор, вместо старого, Ваша программа будет использовать новый редактор с другими свойствами. | |||
Однако не следует забывать, что все коллизии, связанные с возможной неуникальностью условных имен, должны разрешаться программистом. | |||
Условное имя может использоваться различными средствами pzl-технологии для идентификации компонент как на экране, так и в сообщениях об ошибках. | |||
===Константа componentRunable_C=== | |||
Эта константа сообщает о возможности запуска данной компоненты путем вызова предиката '''spbRun:(string UserInfo)'''. Предикат spbRun декларируетс в одноименном интерфейсе spbRun. | |||
Соответственно, компонента должна поддерживать интерфейс spbRun, если возможность вызова предиката spbRun предусматривается. | |||
Если интерфейс spbRun компонентой поддерживается, то константа componentRunable_C должна иметь значение core::b_true и core::b_false - если не поддерживается. | |||
Предикат spbRun - это, по крайней мере, один предикат в pzl-компоненте, который может этой компонентой поддерживаться и имя этого предиката известно. | |||
Предикат spbRun имеет единственный входной параметр UserInfo типа string, назначение которого определяется создателем компоненты. | |||
Если данная компонента может быть вызвана с помощью предиката spbRun, это означает, что в приложении для данной компоненты всегда имеются условия, которые позволяют этой компоненте выполнить какую-то функциональную задачу. | |||
Это несколько напоминает функцию раздела GOAL - точка начала работы программы, но в случае с предикатом spbRun этот предикат может быть вызван, а может быть и не вызван. | |||
Если приложение основано на использовании графического пользовательского интерфейса (pfc/GUI или pfc/VPI), то возможность запуска компоненты предикатом spbRun может означать, что будет создана какая-то форма на экране и эта форма далее позволит сделать что-то значимое (не обязательно полезное). | |||
Если пользовательский интерфейс не используется, то предикат spbRun может быть использован и для других целей по усмотрению программиста. | |||
Предикат '''spbRun:(string UserInfo)''' объявлен в интерфейсе spbRun, где он является единственным. Если компонента поддерживает интерфейс spbRun, то это декларируется стандартным способом: | |||
<vip> | |||
interface componentInterface | |||
supports pzlComponent | |||
supports spbRun | |||
constants | |||
... | |||
ComponentRunable_C = b_true. | |||
... | |||
end interface componentInterface | |||
</vip> | |||
либо один из интерфейсов, поддерживаемых базовым интерфейсом компоненты, должен поддерживать интерфейс spbRun, как показано ниже | |||
<vip> | |||
interface componentInterface | |||
supports pzlComponent | |||
supports textEditor | |||
constants | |||
... | |||
componentRunable_C = b_true. | |||
... | |||
end interface componentInterface | |||
interface textEditor | |||
supports spbRun | |||
... | |||
end interface textEditor | |||
</vip> | |||
===Константа componentMetaInfo_C=== | |||
Константа componentMetaInfo_C имеет тип core::namedValue* и представляет список именованных данных, относящихся к данной компоненте - метаинформация о компоненте. | |||
pzl-Система никак эту метаинформацию не обрабатывает, но при соотвествующем запросе к контейнеру данные этого списка доступны программисту. | |||
Если метаинформация о компоненте отсутствует, то константа componentMetaInfo_C все равно должна быть определена и должна представлять пустой список. | |||
<vip> | |||
constants | |||
componentMetaInfo_C = []. | |||
</vip> | |||
===Константа Описания Компоненты сomponentDescriptor_C=== | |||
Константа сomponentDescriptor_C включает описания важнейших свойств компоненты перечисленные выше: | |||
*ComponentID_C, | |||
*ComponentAlias_C, | |||
*ComponentRunable_C | |||
*ComponentMetainfo_C | |||
Константа сomponentDescriptor_C соответствует домену pzlDomains::pzlComponentInfo_D, объявленному в интерфейсном файле pzlDomains: | |||
<vip> | |||
pzlComponentInfo_D=pzlComponentInfo | |||
( | |||
string Alias, | |||
entityUID_D ComponentID, | |||
booleanInt Runable, | |||
core::namedValue_List UserDefinedInfo | |||
). | |||
</vip> | |||
===Пример описания констант pzl-компоненты=== | |||
В реальной компоненте константы описания могут выглядеть так: | |||
<vip> | |||
constants | |||
componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo | |||
( | |||
componentAlias_C, | |||
componentID_C, | |||
componentRunAble_C, | |||
componentMetaInfo_C | |||
). | |||
componentID_C:pzlDomains::entityUID_D=pzlDomains::str("ComponentExample"). | |||
componentAlias_C="ПримерКомпоненты". | |||
componentRunAble_C=b_True. | |||
componentMetaInfo_C:namedValue_List=[]. | |||
</vip> | |||
или так | |||
<vip> | |||
constants | |||
componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo | |||
( | |||
componentAlias_C, | |||
componentID_C, | |||
componentRunAble_C, | |||
componentMetaInfo_C | |||
). | |||
componentID_C:pzlDomains::entityUID_D=pzlDomains::uid(0x5701809E,0x0453,0x43A2,0xB1,0x82,0x8F,0xAE,0x2A,0x6B,0xA5,0x63). | |||
componentAlias_C="PzlAboutDialog". | |||
componentRunAble_C=b_False. | |||
componentMetaInfo_C:namedValue_List= | |||
[ | |||
namedValue("CodeExporter",string("AboutExporter")) | |||
]. | |||
</vip> | |||
=Конструктор компоненты new:(object UsingObject)= | |||
Базовый класс pzl-Компоненты должен включать только один конструктор, имеющий формат | |||
'''new:(object UsingObject)'''. | |||
Здесь параметр UsingObject (что предполагает трактовку "С использованием объекта") не имеет никакого назначения и может быть использован автором pzl-Компоненты по своему усмотрению. | |||
Например, в случае компоненты на базе GUI этот параметр может передавать объект типа window, соответствующий родительскому окну. Но если вызов конструктора в форме new(ParentWindow) автоматически преобразует тип window в тип object, то следует иметь в виду, что клауза конструктора, получит этот параметр именно как параметр типа object и непосредственное обращение к этому объекту невозможно. | |||
Для обращения к объекту, переданному в виде параметра, необходимо привести параметр к типу, соответствующему возможному типу существующего объекта. | |||
Например, в рассматриваемом случае с передачей объекта родительского окна для получения его высоты (height) надо привести объект ParentWindowAsObject в тип window: | |||
<vip> | |||
clauses | |||
new(ParentWindowAsObject):- | |||
ParentWindow=convert(window,ParentWindowAsObject), | |||
WindowHeight=ParentWindow:getHeight(), | |||
... | |||
</vip> | |||
=Особенности использования pzl-компонент как VIP-классов= | |||
Pzl-Компоненты, являясь обычными классами системы программирования Visual Prolog (VIP-классы), не требуют каких-либо специальных приемов программирования. Более того, при практическом программировании никакой разницы между использованием обычных VIP-классов и pzl-компонент нет. Тем не менее мы отметим здесь некоторые детали техники их созданиия и использования. | |||
==Создание pzl-компоненты== | |||
Создание pzl-компоненты возможно двумя способами: | |||
*[[Elementary PzlStudio#Создание Pzl-Компоненты|Специальными средствами pzl-технологии]] | |||
*Стандартными средствами IDE ('''не рекомендуется''') | |||
Процедура создания pzl-компоненты стандартными средствами IDE '''не является рекомендуемой''' и приводится для разрешения коллизий в экстраординарных случаях | |||
*Создать '''в проекте, являющемся pzl-контейнером''' новый класс в пакете, который будет всегда связан с этим классом | |||
*При создании класса указать, что класс порождает объекты | |||
*После создания создания класса вручную модифицировать код для обеспечения всех ранее | |||
[[#Необходимые_условия_признания_класса_pzl-компонентой|'''перечисленных требований''']] | |||
Компиляция проекта, содержащего созданную таким образом pzl-компоненту, может привести к генерации множества ошибок, если не "зарегистрирована" в проекте-контейнере. | |||
Для регистрации pzl-компоненты в pzl-контейнере необходимо: | |||
*В файле PzlConfig.i определить константу '''''usePzl[ИмяКомпоненты]_C:boolean=true'''''. | |||
*В файле PzlConfig.pack в раздел % privately used packages добавить полное имя заголовочного файла пакета<br/><vip>#include @"ИмяФайлаКомпоненты.ph"</vip> | |||
*В файле PzlConfig.pro: | |||
**в список, возвращаемый предикатом getComponentIDInfo() добавить элемент вида<br/> <vip>[ИмяБазовогоИнтерфейсаКомпоненты]::componentDescriptor_C</vip> | |||
**добавить клаузу<br/> | |||
<vip>new([ИмяБазовогоИнтерфейсаКомпоненты]::componentID_C,Container)=Object:- | |||
!, | |||
Object = [ИмяБазовогоКлассаКомпоненты]::new(Container)</vip>. | |||
==Обращения к pzl-Компоненте== | |||
Существуют три способа вызова создания экземпляра pzl-компоненты: | |||
*путем вызова конструктора new(...) | |||
*путем вызова предиката newByName(...) | |||
*путем вызова предиката newByID(...) | |||
Первый способ выглядит следующим образом: | |||
<vip> | |||
... | |||
MyClassInstance =myClass::new(SomeObject), | |||
MyClassInstance:callNeededPredicate(…) | |||
... | |||
</vip> | |||
Это соответствует обычным правилам VIP. | |||
Второй способ использует pzl-систему явно и выглядит так: | |||
<vip> | |||
... | |||
MyClassObj=pzl::newByName(“MyClass”,...), | |||
MyClassInstance=tryConvert(iMyClass, MyClassObj), | |||
MyClassInstance:сallNeededPredicate(…), | |||
</vip> | |||
Здесь iMyClass является интерфейсом класса myClass, а “MyClass” является строковым именем класса (alias) myClass. | |||
Третий способ также явно использует pzl-систему и выглядит так: | |||
<vip> | |||
... | |||
MyClassObj=pzl::newByID(str(“MyClass”),...), | |||
MyClassInstance=tryConvert(iMyClass, MyClassObj), | |||
MyClassInstance:сallNeededPredicate(…), | |||
</vip> | |||
Здесь iMyClass является интерфейсом класса myClass, а str(“MyClass”) является строковым представлением идентификатора класса. | |||
==Обращение к другим классам и компонентам== | |||
Обращение к другим классам и компонентам из текущей компоненты ничем не отличается от обычного стиля обращений к классам, объектам классов и объектам компонент. | |||
Следует иметь в виду, что для обращения к компоненте в стиле | |||
<vip> | |||
... | |||
ОбъектКомпоненты=классКомпоненты::new(SomeObject), | |||
ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), | |||
... | |||
</vip> | |||
компонента ''классКомпоненты'' должна быть представлена в проекте, из которого производится это обращение, своим классом-представителем. | |||
Однако, для обращения к компоненте в стиле | |||
<vip> | |||
... | |||
ОбъектКомпонентыObj=pzl::newByName("УсловноеИмяКомпоненты",Object), | |||
ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), | |||
ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), | |||
... | |||
</vip> | |||
или | |||
<vip> | |||
... | |||
ОбъектКомпонентыObj=pzl::newByID(ИдентификаторКомпоненты,Object), | |||
ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), | |||
ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), | |||
... | |||
</vip> | |||
класс-представитель компоненты не требуется. | |||
==Завершение использования== | |||
По завершении использования объекта компоненты все указатели на нее должны быть удалены. Такое стандартное для VIP обращение с объектами в случае pzl-Компоненты также приводит к гибели ее объекта. | |||
==Отладка== | |||
Если pzl-компонента находится в главном (исполняемом) приложении, то отладка текста ее праграммы ничем не отличается от приемов отладки обычного класса системы Visual Prolog. | |||
Если pzl-компонента находится в pzl-Контейнере, представляющем собой DLL, то процесс отладки должен начинаться с проекта этого контейнера (DLL). Впрочем, это типичный подход к отладке DLL, принятый в системе Visual Prolog. | |||
==Регистрация== | |||
Если какой-либо класс и pzl-компонента находятся в одной и той же сущности (.EXE или та же самая DLL), и при этом обращение производится в форме | |||
<vip> | |||
... | |||
MyClassInstance =myClass::new(SomeObject), | |||
MyClassInstance:callNeededPredicate(…) | |||
... | |||
</vip> | |||
то регистрация pzl-Компоненты, к которой производится обращение, может не производиться. | |||
Во всех остальных случаях компонента должна быть зарегистрирована | |||
*либо в локальном файле пользователя | |||
*либо в реестре LocalUser системы Windows (имя раздела HKEY_CURRENT_USER) | |||
*либо в реестре LocalMashine системы Windows (имя раздела HKEY_LOCAL_MACHINE) | |||
'''Примечание.''' Для регистрации компонент следует использовать специальные средства pzl-Технологии. Регистрация компонент вручную не рекомендуется. | |||
При регистрации компоненты в реестре системы Windows используются следующие имена директорий windows-реестра (указаны в файле VpPuZzle/System/Packs/pzlDomains.i) | |||
<vip> | |||
constants | |||
registryVPPuZzleAtGlobal_C = "vp_PuZzle". | |||
registryComponentsAtGlobal_C = "vp_PuZzle\\pzlComponents". | |||
registryVPPuZzleAtLocalUser_C = "Software\\vp_PuZzle". | |||
registryComponentsAtLocalUser_C = "Software\\vp_PuZzle\\pzlComponents". | |||
registryRunAble_C = "RunAble". | |||
</vip> | |||
При этом для именования свойств компонент используются константы | |||
<vip> | |||
registryRunAbleTrue_C="True". | |||
registryRunAbleFalse_C="False". | |||
</vip> | |||
==Получение информации о компоненте== | |||
Как уже упоминалось, следующие предикаты объявлены в интерфейсе pzlComponent и поддерживаются содержательно pzl-системой | |||
*getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится | |||
*getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента | |||
*getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent | |||
Для того, чтобы внешние по отношению к данной компоненте средства могли бы получить информацию об [[#Константа_componentID_С|'''идентификаторе''']], [[#Константа_ componentAlias_C_(Условное_имя)|'''условном наименовании''']] и [[#Константа_componentMetaInfo_C|'''метаинформации''']], рекомендуется помещать следующие клаузы в базовый класс pzl-компоненты: | |||
<vip> | |||
caluses | |||
getComponentID()= componentID_C. | |||
getComponentAlias() = componentAlias_C. | |||
getComponentMetaInfo() = componentMetaInfo_C | |||
</vip> | |||
Напоминаем, что объявления этих предикатов содержатся в интерфейсе pzlComponent. | |||
==Ограничения в несанкционированном использовании== | |||
Pzl-Компонента не содержит никаких средств для ограничения ее использования. Если программа получает доступ к контейнеру, в котором расположена pzl-Компонента, и программе известны интерфейсы для общения с компонентной, то эта pzl-Компонента оказывается доступной программе. | |||
Вы, как автор pzl-Компоненты, можете предусмотреть дополнительные меры по ограничению прав использования pzl-Компоненты. | |||
Например, Вы можете предусмотреть сеанс идентификации прав, в ходе которого в pzl-Компоненту должна быть передана информация, подтверждающая права на использование данной компоненты. | |||
Если текст программы pzl-Компоненты недоступен широкому кругу пользователей, то такого рода защита от несанкционированного использования может оказаться достаточно эффективной. | |||
=Ссылки= | |||
[[Категория:VpPuZzle]] | [[Категория:VpPuZzle]] |
Текущая версия на 14:16, 21 ноября 2007
Автор: Виктор Юхтенко
Необходимые условия признания класса pzl-компонентой
Любой класс, порождающий объекты (имеющий интерфейс), может быть признан компонентой, если
- Имя интерфейса и имя класса различаются;
- Интерфейс класса поддерживает интерфейс pzlComponent;
- Интерфейс класса включает декларации констант:
- componentID_C с типом pzlDomains::entityUID_D
- componentAlias_C с типом string
- componentRunAble_C с типом core::booleanInt
- componentMetaInfo_C с типом core::namedValue*.
- сomponentDescriptor_C с типом pzlDomains::pzlComponentInfo_D;
- Декларация класса содержит единственный конструктор new(object ИспользуемыйОбъект);
- Имплементация класса наследует от класса pzlComponent;
- Пакетный файл деклараций класса (.PH) включает файл "System\Packs\pzlcomponent\pzlcomponent.ph".
Ниже приведены фрагменты различных составляющих компоненты, удовлетворяющей перечисленным выше условиям.
Декларация класса
- Содержит единственный коструктор new:(object UsingObject). Имя интерфейса отличается от имени класса.
class сomponentExample:iComponentExample constructors new:(object UsingObject). end class
Интерфейс класса
- Cодержит квалификатор supports pzlComponent и декларацию констант
- componentID_C
- componentAlias_C
- componentRunAble_C=b_True
- componentMetaInfo_C
- componentDescriptor_C
interface iComponentExample supports pzlComponent open core constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::str("ComponentExample"). componentAlias_C="ПримерКомпоненты". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=[]. predicates show:(). end interface iComponentExample
Имплементация класса
- Содержит директиву наследования inherits pzlComponent и содержит клаузу для конструктора new(UsingObject)
implement componentExample inherits pzlComponent clauses new(UsingObject):- ... clauses show():- ... end implement componentExample
Файл деклараций пакета ComponentExample.PH
- Содержит директиву включения файла PzlComponent.ph
#requires ... #include @"System\Packs\pzlcomponent\pzlcomponent.ph" #include @"pfc\core.ph"
Интерфейс pzlComponent
Интерфейс pzlComponent соответствует наследуемому pzl-Компонентой классу pzlComponent и делает класс pzl-компонентой, связывая ее с другими частями pzl-системы. Кроме того, этот интерфейс позволяет получать часть информации о компоненте.
В частности следующие предикаты поддерживаются содержательно pzl-системой
- getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится
- getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента
- getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent
Остальные предикаты интерфейса:
- getComponentVersion()-> string
- getComponentID() -> entityUID_D
- getComponentAlias() -> string
- getComponentMetaInfo() -> namedValue*
- release
должны быть определены пользователем в имплементации базового класса компоненты. В противном случае генерируют исключения при обращении.
Предопределенные константы интерфейса pzl-компоненты
Константа componentID_С
Константа сomponentID_С определяет идентификатор компоненты, который (по-возможности) должен быть уникальным в глобальном смысле. То есть две программы в глобальном информационном пространстве (не говоря уже об одном копьютере), использующие компоненты с одним и тем же идентификатором могут быть уверены, что они используют точно одну и ту же pzl-компоненту. Этого можно добиться, если использовать способ, аналогичный способу, применяемому Microsoft для идентификации COM-компонент. Для этого в pzl-технологии используется структура с функтором uid:
uid( core::unsigned32 Unsigned, core::unsigned16 Short1, core::unsigned16 Short2, core::unsigned8 Byte1, core::unsigned8 Byte2, core::unsigned8 Byte3, core::unsigned8 Byte4, core::unsigned8 Byte5, core::unsigned8 Byte6, core::unsigned8 Byte7, core::unsigned8 Byte8).
что, на самом деле является полным аналогом структуры core::nativeGuid системы Visual Prolog. Идентификатор ComponentID используется в двух случаях:
- Он является идентификатором, под которым в реестре Windows или в файле регистрации приложения записывается регистрационная информация о компоненте
- Он является идентификатором, под которым эта компонента зарегистрирована в pzl-контейнере
Поскольку идентификатор в форме uid является громоздкой последовательностью цифр и букв, то применять его в процессе освоения технологии неудобно. С целью упрощения процесса освоения имеется вторая версия представления идентификатора - строковая - в форме str(string). Естественно, уникальность строкового представления обеспечить крайне трудно, но в процессе освоения, можно пожертвовать глобальной уникальностью и контролировать только уникальность идентификатора на данном компьютере. В результате мы получаем две альтернативные формы представления идентификатора в объявлении домена entityUID_D:
entityUID_D= str(string); uid(unsined16,...).
Константа componentAlias_C (Условное имя)
Наряду с уникальным идентификатором, pzl-технология предоставляет воможность присвоить каждой компоненте условное, содержательное имя, являющееся строкой символов. Для этого выбранное имя должно быть присвоено константе ComponentAlias_C. Однако уникальность Условного Имени (Alias) не является жестким требованием.
Так, Вы можете создать несколько текстовых редакторов с различными свойствами, которые поддерживают одни и те же интерфейсы. Каждый из этих текстовых редакторов будет иметь уникальный идентификатор типа entityUID_D и, возможно каждый из них будет иметь свое имя базового класса. Но все они могут иметь одно и то же условное имя "Текстовый Редактор". Тогда Ваша программа (подчеркнем, не зная имени класса), может при создании экземпляра pzl-компоненты использовать имя "Текстовый Редактор" и будет создаваться экземпляр той компоненты, которая в данный момент зарегистрирована на Вашем компьютере. Перерегистрировав новый редактор, вместо старого, Ваша программа будет использовать новый редактор с другими свойствами.
Однако не следует забывать, что все коллизии, связанные с возможной неуникальностью условных имен, должны разрешаться программистом.
Условное имя может использоваться различными средствами pzl-технологии для идентификации компонент как на экране, так и в сообщениях об ошибках.
Константа componentRunable_C
Эта константа сообщает о возможности запуска данной компоненты путем вызова предиката spbRun:(string UserInfo). Предикат spbRun декларируетс в одноименном интерфейсе spbRun.
Соответственно, компонента должна поддерживать интерфейс spbRun, если возможность вызова предиката spbRun предусматривается.
Если интерфейс spbRun компонентой поддерживается, то константа componentRunable_C должна иметь значение core::b_true и core::b_false - если не поддерживается.
Предикат spbRun - это, по крайней мере, один предикат в pzl-компоненте, который может этой компонентой поддерживаться и имя этого предиката известно.
Предикат spbRun имеет единственный входной параметр UserInfo типа string, назначение которого определяется создателем компоненты.
Если данная компонента может быть вызвана с помощью предиката spbRun, это означает, что в приложении для данной компоненты всегда имеются условия, которые позволяют этой компоненте выполнить какую-то функциональную задачу.
Это несколько напоминает функцию раздела GOAL - точка начала работы программы, но в случае с предикатом spbRun этот предикат может быть вызван, а может быть и не вызван.
Если приложение основано на использовании графического пользовательского интерфейса (pfc/GUI или pfc/VPI), то возможность запуска компоненты предикатом spbRun может означать, что будет создана какая-то форма на экране и эта форма далее позволит сделать что-то значимое (не обязательно полезное).
Если пользовательский интерфейс не используется, то предикат spbRun может быть использован и для других целей по усмотрению программиста.
Предикат spbRun:(string UserInfo) объявлен в интерфейсе spbRun, где он является единственным. Если компонента поддерживает интерфейс spbRun, то это декларируется стандартным способом:
interface componentInterface supports pzlComponent supports spbRun constants ... ComponentRunable_C = b_true. ... end interface componentInterface
либо один из интерфейсов, поддерживаемых базовым интерфейсом компоненты, должен поддерживать интерфейс spbRun, как показано ниже
interface componentInterface supports pzlComponent supports textEditor constants ... componentRunable_C = b_true. ... end interface componentInterface interface textEditor supports spbRun ... end interface textEditor
Константа componentMetaInfo_C
Константа componentMetaInfo_C имеет тип core::namedValue* и представляет список именованных данных, относящихся к данной компоненте - метаинформация о компоненте.
pzl-Система никак эту метаинформацию не обрабатывает, но при соотвествующем запросе к контейнеру данные этого списка доступны программисту.
Если метаинформация о компоненте отсутствует, то константа componentMetaInfo_C все равно должна быть определена и должна представлять пустой список.
constants componentMetaInfo_C = [].
Константа Описания Компоненты сomponentDescriptor_C
Константа сomponentDescriptor_C включает описания важнейших свойств компоненты перечисленные выше:
- ComponentID_C,
- ComponentAlias_C,
- ComponentRunable_C
- ComponentMetainfo_C
Константа сomponentDescriptor_C соответствует домену pzlDomains::pzlComponentInfo_D, объявленному в интерфейсном файле pzlDomains:
pzlComponentInfo_D=pzlComponentInfo ( string Alias, entityUID_D ComponentID, booleanInt Runable, core::namedValue_List UserDefinedInfo ).
Пример описания констант pzl-компоненты
В реальной компоненте константы описания могут выглядеть так:
constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::str("ComponentExample"). componentAlias_C="ПримерКомпоненты". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=[].
или так
constants componentDescriptor_C:pzlDomains::pzlComponentInfo_D=pzlDomains::pzlComponentInfo ( componentAlias_C, componentID_C, componentRunAble_C, componentMetaInfo_C ). componentID_C:pzlDomains::entityUID_D=pzlDomains::uid(0x5701809E,0x0453,0x43A2,0xB1,0x82,0x8F,0xAE,0x2A,0x6B,0xA5,0x63). componentAlias_C="PzlAboutDialog". componentRunAble_C=b_False. componentMetaInfo_C:namedValue_List= [ namedValue("CodeExporter",string("AboutExporter")) ].
Конструктор компоненты new:(object UsingObject)
Базовый класс pzl-Компоненты должен включать только один конструктор, имеющий формат new:(object UsingObject).
Здесь параметр UsingObject (что предполагает трактовку "С использованием объекта") не имеет никакого назначения и может быть использован автором pzl-Компоненты по своему усмотрению.
Например, в случае компоненты на базе GUI этот параметр может передавать объект типа window, соответствующий родительскому окну. Но если вызов конструктора в форме new(ParentWindow) автоматически преобразует тип window в тип object, то следует иметь в виду, что клауза конструктора, получит этот параметр именно как параметр типа object и непосредственное обращение к этому объекту невозможно.
Для обращения к объекту, переданному в виде параметра, необходимо привести параметр к типу, соответствующему возможному типу существующего объекта.
Например, в рассматриваемом случае с передачей объекта родительского окна для получения его высоты (height) надо привести объект ParentWindowAsObject в тип window:
clauses new(ParentWindowAsObject):- ParentWindow=convert(window,ParentWindowAsObject), WindowHeight=ParentWindow:getHeight(), ...
Особенности использования pzl-компонент как VIP-классов
Pzl-Компоненты, являясь обычными классами системы программирования Visual Prolog (VIP-классы), не требуют каких-либо специальных приемов программирования. Более того, при практическом программировании никакой разницы между использованием обычных VIP-классов и pzl-компонент нет. Тем не менее мы отметим здесь некоторые детали техники их созданиия и использования.
Создание pzl-компоненты
Создание pzl-компоненты возможно двумя способами:
- Специальными средствами pzl-технологии
- Стандартными средствами IDE (не рекомендуется)
Процедура создания pzl-компоненты стандартными средствами IDE не является рекомендуемой и приводится для разрешения коллизий в экстраординарных случаях
- Создать в проекте, являющемся pzl-контейнером новый класс в пакете, который будет всегда связан с этим классом
- При создании класса указать, что класс порождает объекты
- После создания создания класса вручную модифицировать код для обеспечения всех ранее
Компиляция проекта, содержащего созданную таким образом pzl-компоненту, может привести к генерации множества ошибок, если не "зарегистрирована" в проекте-контейнере.
Для регистрации pzl-компоненты в pzl-контейнере необходимо:
- В файле PzlConfig.i определить константу usePzl[ИмяКомпоненты]_C:boolean=true.
- В файле PzlConfig.pack в раздел % privately used packages добавить полное имя заголовочного файла пакета
#include @"ИмяФайлаКомпоненты.ph"
- В файле PzlConfig.pro:
- в список, возвращаемый предикатом getComponentIDInfo() добавить элемент вида
[ИмяБазовогоИнтерфейсаКомпоненты]::componentDescriptor_C
- добавить клаузу
- в список, возвращаемый предикатом getComponentIDInfo() добавить элемент вида
new([ИмяБазовогоИнтерфейсаКомпоненты]::componentID_C,Container)=Object:- !, Object = [ИмяБазовогоКлассаКомпоненты]::new(Container)
.
Обращения к pzl-Компоненте
Существуют три способа вызова создания экземпляра pzl-компоненты:
- путем вызова конструктора new(...)
- путем вызова предиката newByName(...)
- путем вызова предиката newByID(...)
Первый способ выглядит следующим образом:
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
Это соответствует обычным правилам VIP.
Второй способ использует pzl-систему явно и выглядит так:
... MyClassObj=pzl::newByName(“MyClass”,...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Здесь iMyClass является интерфейсом класса myClass, а “MyClass” является строковым именем класса (alias) myClass.
Третий способ также явно использует pzl-систему и выглядит так:
... MyClassObj=pzl::newByID(str(“MyClass”),...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Здесь iMyClass является интерфейсом класса myClass, а str(“MyClass”) является строковым представлением идентификатора класса.
Обращение к другим классам и компонентам
Обращение к другим классам и компонентам из текущей компоненты ничем не отличается от обычного стиля обращений к классам, объектам классов и объектам компонент. Следует иметь в виду, что для обращения к компоненте в стиле
... ОбъектКомпоненты=классКомпоненты::new(SomeObject), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
компонента классКомпоненты должна быть представлена в проекте, из которого производится это обращение, своим классом-представителем.
Однако, для обращения к компоненте в стиле
... ОбъектКомпонентыObj=pzl::newByName("УсловноеИмяКомпоненты",Object), ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
или
... ОбъектКомпонентыObj=pzl::newByID(ИдентификаторКомпоненты,Object), ОбъектКомпоненты=convert(интерфейсКомпоненты,ОбъектКомпонентыObj), ОбъектКомпоненты:предикатКомпонеты(Аргумент1,...), ...
класс-представитель компоненты не требуется.
Завершение использования
По завершении использования объекта компоненты все указатели на нее должны быть удалены. Такое стандартное для VIP обращение с объектами в случае pzl-Компоненты также приводит к гибели ее объекта.
Отладка
Если pzl-компонента находится в главном (исполняемом) приложении, то отладка текста ее праграммы ничем не отличается от приемов отладки обычного класса системы Visual Prolog.
Если pzl-компонента находится в pzl-Контейнере, представляющем собой DLL, то процесс отладки должен начинаться с проекта этого контейнера (DLL). Впрочем, это типичный подход к отладке DLL, принятый в системе Visual Prolog.
Регистрация
Если какой-либо класс и pzl-компонента находятся в одной и той же сущности (.EXE или та же самая DLL), и при этом обращение производится в форме
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
то регистрация pzl-Компоненты, к которой производится обращение, может не производиться.
Во всех остальных случаях компонента должна быть зарегистрирована
- либо в локальном файле пользователя
- либо в реестре LocalUser системы Windows (имя раздела HKEY_CURRENT_USER)
- либо в реестре LocalMashine системы Windows (имя раздела HKEY_LOCAL_MACHINE)
Примечание. Для регистрации компонент следует использовать специальные средства pzl-Технологии. Регистрация компонент вручную не рекомендуется.
При регистрации компоненты в реестре системы Windows используются следующие имена директорий windows-реестра (указаны в файле VpPuZzle/System/Packs/pzlDomains.i)
constants registryVPPuZzleAtGlobal_C = "vp_PuZzle". registryComponentsAtGlobal_C = "vp_PuZzle\\pzlComponents". registryVPPuZzleAtLocalUser_C = "Software\\vp_PuZzle". registryComponentsAtLocalUser_C = "Software\\vp_PuZzle\\pzlComponents". registryRunAble_C = "RunAble".
При этом для именования свойств компонент используются константы
registryRunAbleTrue_C="True". registryRunAbleFalse_C="False".
Получение информации о компоненте
Как уже упоминалось, следующие предикаты объявлены в интерфейсе pzlComponent и поддерживаются содержательно pzl-системой
- getContainerVersion() - возвращает информацию о версии контейнера, в котором данная компонента содержится
- getContainerName() - возвращает информацию об имени файла-контейнера, в котором содержится данная компонента
- getClassInfo(className,classVersion) - возвращает информации об имени и версии класса pzlComponent
Для того, чтобы внешние по отношению к данной компоненте средства могли бы получить информацию об идентификаторе, условном наименовании и метаинформации, рекомендуется помещать следующие клаузы в базовый класс pzl-компоненты:
caluses getComponentID()= componentID_C. getComponentAlias() = componentAlias_C. getComponentMetaInfo() = componentMetaInfo_C
Напоминаем, что объявления этих предикатов содержатся в интерфейсе pzlComponent.
Ограничения в несанкционированном использовании
Pzl-Компонента не содержит никаких средств для ограничения ее использования. Если программа получает доступ к контейнеру, в котором расположена pzl-Компонента, и программе известны интерфейсы для общения с компонентной, то эта pzl-Компонента оказывается доступной программе.
Вы, как автор pzl-Компоненты, можете предусмотреть дополнительные меры по ограничению прав использования pzl-Компоненты.
Например, Вы можете предусмотреть сеанс идентификации прав, в ходе которого в pzl-Компоненту должна быть передана информация, подтверждающая права на использование данной компоненты.
Если текст программы pzl-Компоненты недоступен широкому кругу пользователей, то такого рода защита от несанкционированного использования может оказаться достаточно эффективной.