Written by Victor Yukhtenko. Email: firstname.lastname@example.org
The necessary conditions to acknowledge the class as the pzl-component
Any class, which creates an objects (which has an interface), may be acknowledged as the component if:
- The name of the interface and the name of the class are different;
- The interface of the class supports the interface pzlComponent;
- The interface of the class includes the constants declarations:
- componentID_C of pzlDomains::entityUID_D type
- componentAlias_C of string type
- componentRunAble_C of core::booleanInt type
- componentMetaInfo_C of core::namedValue*. type
- сomponentDescriptor_C of pzlDomains::pzlComponentInfo_D type
- The declaration of the class contains the only constructor new(object ExistingObject);
- The implementation of the class derives the class pzlComponent;
- The package declarations file (.PH) of the class includes the file "System\Packs\pzlcomponent\pzlcomponent.ph".
The examples of the parts of the component declarations and implementations are shown below.
- Contains the only constructor new:(object UsingObject). The name of the interface different from the name of the class.
class сomponentExample:iComponentExample constructors new:(object UsingObject). end class
Interface of the Class
- Contains the qualifiyer supports pzlComponent and the declaration of constants
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="ExampleOfTheComponent". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=. predicates show:(). end interface iComponentExample
- Contains the inharitance statement inherits pzlComponent and also contains the clause for the constructor new(UsingObject)
implement componentExample inherits pzlComponent clauses new(UsingObject):- ... clauses show():- ... end implement componentExample
The Package Header File ComponentExample.PH
- Contains the include file 'PzlComponent.ph statement
#requires ... #include @"System\Packs\pzlcomponent\pzlcomponent.ph" #include @"pfc\core.ph"
The Interface pzlComponent corresponds to the class pzlComponent and this makes the class to be the pzl-component. The class PzlComponent , binds the component with other parts of the pzl-system. Also Interface PzlComponent helps in getting the information regarding the component.
The following predicates supported by the Pzl-system
- getContainerVersion() - returns the information regarding the version of the container, where the given component placed
- getContainerName() - returns the name of the file, where the given component placed
- getClassInfo(className,classVersion) - returns the name and the version of the class pzlComponent
The other predicates of the interface PzlComponent:
- getComponentVersion()-> string
- getComponentID() -> entityUID_D
- getComponentAlias() -> string
- getComponentMetaInfo() -> namedValue*
must be defined in the implementation of the base class of the component. Otherwise the exception is generated while the appropriate call.
Predefined constants of the base interface of the pzl-component
The constant сomponentID_С defines the identifier of the component, which must be unique if possible in the global sense. It means that two programs in the global information space (and we do not even mention one computer), which use the component with the same identifier, may be sure that they use exactly the same pzl-component. This may be reached by the using of the Microsoft company approach to identify MSCOM components. To fit this the pzl-technology uses the data structure with the functor 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).
and this is in reality the analogue of the structure core::nativeGuid of the Visual Prolog system. The identifier componentID_С used in two cases:
- It is the identifier, which is used to register the component in the Windows registry or(and) in the user controlled component registry file
- It is the identifier, which is used to register the component in the pzl-container
Because of the identifier in the form uid is combersome sequence of letters and figures, it is not convenient to use it while the learning of the pzl-technology.
To make the learning process easier, there is another way to represent the identifier - the string form str(string). Naturally, the uniqueness is not provided in that case, but for the educational purposes we may sacrifice the glibal uniqueness and to control the uniaueness of the identifier on the given computer only.
As the result we get two alternative forms to define identifier in the domain entityUID_D declaration:
entityUID_D= str(string); uid(unsined16,...).
Together with the unique identifier, the pzl-technology gives the possbility to assign to a component the string name (Alias). To do so the name must be assigned to the constant ComponentAlias_C. The uniqueness of this name is not the hard demand.
You may create many text editors with the differenct features, which support the same interfaces. Each if these text editors will have the unique identifier of the entityUID_D type and possibly each of them will have it's own name of the base class. But all of them will have the same Alias (say "Text Editor". Then your applicaion (not knowing the name of the class), may use the name "Text Editor" while the creation of the instance of the Editor. The component, wich is registered at your computer this moment will be used to create an appropriate object. Changing the registration of the Editor you may use another Editor with the other features.
You must understand that all the collisions зкщмщсфеув by uniqueness of the aliases must be resolved by the programmer.
The Alias may be used by many tools of the pzl-technology to identify components on the screen or in the error messages.
The constant componentRunable_C informs about the possibility for the given component to run independently by calling the predicate spbRun:(string UserInfo). The predicate spbRun is declared in the interface spbRun (file VpPuZzle/Interfaces/spbRun.i).
The component must support the interface spbRun, if the possibility to call the predicate spbRun expected.
If the component supports the interface spbRun then the constant componentRunable_C must have the value core::b_true otherwise it must have value core::b_false.
Predicate spbRun is the only one predicate, which may be supported by the component at least and the name of this predicate is known.
The predicate spbRun has the single input parameter UserInfo of string type. The meaning of the parameter may be defined by the developer of the pzl-component.
If the given component may be invoked using the predicate spbRun, then it means, that the applicaion has the conditions that give that component the possbility to run.
It is similar a little to the declaration GOAL - the initial point of the program. The only difference is that in case of the predicate spbRun it may be invoked or maybe not.
If the applicaion based on the User Interface (pfc/GUI или pfc/VPI), then the possibility to run using the predicate spbRun may lead to the creation of the form or the creation of the dialog, and this graphical entity will do something (not necessery useful).
If the user interface is not used, then the predicate spbRun may be used by the programmer for some other purposes.
The predicate spbRun:(string UserInfo) is declared in the interface spbRun, and it is the only predicate of that interface. If the component supports the interface spbRun, then it must be declared in the standard way:
interface componentInterface supports pzlComponent supports spbRun constants ... ComponentRunable_C = b_true. ... end interface componentInterface
I may be the case, when the one of the interfaces, which supported by the base component interface must support the interface spbRun as it is shown below
interface componentInterface supports pzlComponent supports textEditor constants ... componentRunable_C = b_true. ... end interface componentInterface interface textEditor supports spbRun ... end interface textEditor
The constant componentMetaInfo_C belongs to the type core::namedValue* and it may contain the list of named values, which have the sense, relative to the given component (meta information regarding the component).
Pzl-system does nothing with this information. This information may be requested from the container and from the component by programmer.
If there is no metainformation regarding the component, the constant componentMetaInfo_C must be defined anyway (as the empty list).
constants componentMetaInfo_C = .
The constant сomponentDescriptor_C integrates the most important features of the component defined by the constants listed above:
The constant сomponentDescriptor_C corresponds to the domain pzlDomains::pzlComponentInfo_D, declared in in the interface pzlDomains (the file VpPuZzle/Domains/pzlDomains.i):
pzlComponentInfo_D=pzlComponentInfo ( string Alias, entityUID_D ComponentID, booleanInt Runable, core::namedValue_List UserDefinedInfo ).
The pzl-component description example
In the real component the constants describing the component may look like shown below:
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="TheComponentExample". componentRunAble_C=b_True. componentMetaInfo_C:namedValue_List=.
or it may look like
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")) ].
The constructor of the component new:(object UsingObject)
The base class of the pzl-componentmust includes the only one constructor, which must have the format new:(object UsingObject).
Here the parameter UsingObject (which means "with using the object") has no special purpose and it may be used by the author of the pzl-component.
For instance, in case of the component based on the User Interface (GUI) this parameter may be the object of window type, which corresponds to the parent window object. We should have in mind that the call new(ParentWindow) automatically converts the window type to the object type. And the clause of the constructor will get it as the object type. Thus explicite access to this object is not possible.
To access to the object transferred as the parameter, it must be converted to the known type of the initially transferred object.
Let's consider the case when the parent window is transferred and we need to get the height of the window. We must convert the ParentWindowAsObject to the window type:
clauses new(ParentWindowAsObject):- ParentWindow=convert(window,ParentWindowAsObject), WindowHeight=ParentWindow:getHeight(), ...
The habits of use pzl-components as Vip-classes
Pzl-components being the usual classes of the Visual Prolog programming system (Vip-classes), doens't need any special way of proramming. Moreover in the real programming there is no difference in the usual Vip-classes and pzl-components. But we must make some notes regarding some details of their creation and their use.
The creation of the pzl-component
It is possible to create the pzl-component in two ways:
- By the special tools of the pzl-technology
- By the standard the IDE procedures (not recommended) - see demands as described above
The ways to create an instance of the component
There are three ways to invoke the creation of the instance of the pzl-component:
- By calling the class constructor new()
- By calling the predicate newByName() of the pzl class.
- By calling the predicate newByID() of the pzl class.
The first way looks like
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
It corresponds to the usual VIP rules.
The second way uses Pzl-system explicitly and looks like
... MyClassObj=pzl::newByName(“MyClass”,...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Here iMyClass is the base interface of the class myClass and “MyClass” is the string name (alias) of the class myClass.
The third way also uses Pzl-system explicitly and looks like
... MyClassObj=pzl::newByID(str(“MyClass”),...), MyClassInstance=tryConvert(iMyClass, MyClassObj), MyClassInstance:сallNeededPredicate(…),
Here iMyClass is the interface of the class myClass, and str(“MyClass”) is the string form of the class identifier.
Acessing to other classes and components
The accessing to other classes and components from the current component does not differ from the usual style of communication with classes and objects. It is needed to have in mind that to communicate with the component in the style like
... ComponentObject=componentClass::new(SomeObject), ComponentObject:componentPredicate(Argument1,...), ...
the component componentClass must be represented in the project by it's class-delegate (proxy).
But for the accessing in the style
... ComponentObjectObj=pzl::newByName("ComponentAlias",Object), ComponentObject=convert(componentInterface,ComponentObjectObj), ComponentObject:componentPredicate(Argument1,...), ...
... ComponentObjectObj=pzl::newByID(ComponentID,Object), ComponentObject=convert(componentInterface,ComponentObjectObj), ComponentObject:componentPredicate(Argument1,...), ...
the class-delegate is not needed.
The end of use
When the use of the component is complete the all references to the object must be removed. This is the standard way of object handling in VIP and pzl-components have no difference here.
Pzl-containers are unloading automatically, when there is no active objects in it.
If the pzl-component placed in the main executable applicaion, then the debugging style is the same as the debugging style for the usual vip-classes.
If the pzl-component is placed to the dll-container, then the debugging process must be started from the project of the dll-container. And this is the standard way of debugging the Dll in the Visual Prolog programming system.
If some class and pzl-component are placed in the same entity (.EXE or the same DLL), and the calling is made in the form
... MyClassInstance =myClass::new(SomeObject), MyClassInstance:callNeededPredicate(…) ...
then the registration of the called pzl-component is not necessary.
In all other cases the pzl-component must be registered at least in one of the places
- local user-defined file
- in the LocalUser Windows registry (the folder name HKEY_CURRENT_USER)
- in the LocalMashine Windows registry (the folder name HKEY_LOCAL_MACHINE)
Notice. To register pzl-components it is recommended to use the special tools of the pzl-technology. The manual regitration is not recommended.
The pzl-components are registered in the folders of the Windows registry (listed in the file 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".
The constants used for the registration:
Getting the information about the component
As it was menioned before the following predicates are declared in the interface pzlComponent and these predicates are supported by the pzl-system
- getContainerVersion() - returns the information about the pzl-container version
- getContainerName() - returns the information about the name of the file-container, where the given component is placed
- getClassInfo(className,classVersion) - returns the information about the name and the version of the class pzlComponent
To give the possbility to the external tools to access to the information about component identifier, component alias и comonent metainfo, it is recommended to put the clauses listed below to the implementation of the base class of the component:
clauses getComponentID()= componentID_C. getComponentAlias() = componentAlias_C. getComponentMetaInfo() = componentMetaInfo_C
Remind that the declarations of these predicates you can find in the interface pzlComponent.
Pzl-componene doesn't contain any facility to restrict it's use. If the program can get an access to the pzl-container, where the pzl-component is placed, and the program knows the interfaces to communicate with the component, then this component is acessible by the program.
Being the author of the component, you may provide the additional arrangements to restrict the rigts to use the pzl-component.
Say, you may provide the special procedure to identify the rights to communicate with the pzl-component.
If the source code of the component is not widely known, then this way of the setting of the safety may be enough efficient.