This document covers the following topics:
Plug-ins access Natural Studio functionality through an Automation
interface. All individual interfaces that form the Natural Studio Automation
interface can be reached from the root interface,
INatAutoStudio
. A
handle to this interface is passed to each plug-in during activation and
deactivation.
The following tree diagram shows the hierarchical structure of the Automation interface:
INatAutoStudio INatAutoObjects INatAutoDataAreas INatAutoDataArea INatAutoDialogs INatAutoDialog INatAutoPrograms INatAutoProgram INatAutoGenericDocuments INatAutoGenericDocument INatAutoGenericTexts INatAutoGenericText INatAutoObjectLists INatAutoObjectList INatAutoObjectTrees INatAutoObjectTree INatAutoObjectTreeNode INatAutoSelectedObjects INatAutoSelectedObject INatAutoRefreshObject INatAutoControlBars INatAutoImages INatAutoCommands INatAutoCommand INatAutoToolBars INatAutoToolBar INatAutoFrameMenus INatAutoFrameMenu INatAutoPopupMenu INatAutoContextMenus INatAutoContextMenu INatAutoPopupMenu INatAutoTypes INatAutoNodeTypes INatAutoNodeType INatAutoNodeImages INatAutoPlugIns INatAutoPlugIn INatAutoResultViews INatAutoResultView INatAutoSystem INatAutoEnvironments INatAutoEnvironment INatAutoNatparm INatAutoNatsvar INatAutoApplications INatAutoApplication INatAutoLinkedApplications INatAutoEnvironment INatAutoSysmain INatAutoProgressIndicator
Natural Studio users access plug-in functionality by using commands. A plug-in identifies each command by a number. The number can be freely chosen, but must of course be unique per plug-in. A command can have a caption and an image assigned. Caption and image represent the command in menus and toolbars.
To provide a command to the user, a plug-in first creates an
INatAutoCommand
interface in the INatAutoCommands
collection:
send "Add" to #commands with 4711 "MyCommand" #myImage return #myCommand
While creating the command, in the above example the plug-in
refers to an image #myImage
. This image is used to represent the
command visually in menus and toolbars. The plug-in may have loaded the image
before, using the method INatAutoImages::LoadImage
:
send "LoadImage" to #images with "e:\images\myimage.bmp" return #myImage
This results in an IPictureDisp
interface
that can be passed to the method INatAutoCommands::Add
.
The IPictureDisp
interface is a predefined interface in
Windows. An IPictureDisp
interface can be created in
Natural using the method INatAutoImages::LoadImage
.
Alternatively, the plug-in can pass the image file name directly
to the method INatAutoCommands::Add
:
send "Add" to #commands with 4711 "MyCommand" "e:\images\myimage.bmp" return #myCommand
When the user later chooses the command in a menu or toolbar, the
plug-in is notified by using the method
INaturalStudioPlugIn::OnCommand
.
But in order to make the command accessible to users in the first place, the plug-in must insert it into a menu or toolbar. We show this with a toolbar as example. Here the plug-in first locates the Tools toolbar. Then it inserts the previously created command into the toolbar.
send "Item" to #toolbars with "Tools" return #toolsToolbar send "InsertCommand" to #toolsToolbar with #myCommand
The plug-in needs to create the command only once and can then assign it to different toolbars or menus.
The plug-in might as well create its own toolbar and add the command to this toolbar:
send "Add" to #toolbars with "MyToolbar" return #myToolbar send "InsertCommand" to #myToolbar with #myCommand
We saw the plug-in use the interfaces
INatAutoCommands
,
INatAutoImages
and other interfaces. But how does the plug-in get access to these interfaces
in the first place? The plug-in accesses them by querying properties of the
root interface, INatAutoStudio
. A
handle to this interface is passed to each plug-in during activation and
deactivation. From this interface the plug-in can navigate to any other section
of the Natural Studio Automation interface.
To work with control bars, a plug-in uses the interfaces described in the following sections:
INatAutoControlBars
INatAutoImages
INatAutoCommands
INatAutoCommand
INatAutoToolBars
INatAutoToolBar
INatAutoContextMenus
INatAutoContextMenu
INatAutoFrameMenus
INatAutoFrameMenu
INatAutoPopupMenu
Natural Studio frequently uses tree views and list views to display development objects and to navigate through them. Each node in a tree view or list view is characterized by a node type. The node type defines how nodes of a given type are represented in the user interface.
Each node type is identified by an integer number. A development object belonging to a given node type is identified by the number of that node type and by an alphanumeric key. The format of the key varies from node type to node type.
Plug-ins that wish to create their own tree views and list views in Natural Studio can refer to the predefined node types. In addition, plug-ins can define their own node types and can then refer to these user-defined node types.
The following topics are covered below:
The built-in Natural Studio development objects such as program, dialog, class, library or application have a predefined node type and key format. Many interfaces and methods in the Natural Studio Automation interface refer to the predefined node types. The full list of available predefined node types and the format of their keys is defined in the following tables.
Node Type Number | Node Type Name | Key Format |
---|---|---|
1001 | Parameter data area | NATID |
1002 | Copycode | NATID |
1003 | DDM | NATID |
1004 | Global data area | NATID |
1005 | Helproutine | NATID |
1006 | Local data area | NATID |
1007 | Map | NATID |
1008 | Subprogram | NATID |
1009 | Program | NATID |
1010 | Subroutine | NATID |
1011 | Text | NATID |
1012 | View | NATID |
1013 | Dialog | NATID |
1014 | Class | NATID |
1015 | Command processor | NATID |
1017 | Mainframe DDM | DDMID |
1018 | Function | NATID |
1019 | Shared resource | RESID |
1020 | Error message file | NATID |
1021 | Adapter | NATID |
1051 | Parameter data area (in application) | NATID |
1052 | Copycode (in application) | NATID |
1053 | DDM (in application) | NATID |
1054 | Global data area (in application) | NATID |
1055 | Helproutine (in application) | NATID |
1056 | Local data area (in application) | NATID |
1057 | Map (in application) | NATID |
1058 | Subprogram (in application) | NATID |
1059 | Program (in application) | NATID |
1060 | Subroutine (in application) | NATID |
1061 | Text (in application) | NATID |
1062 | View (in application) | NATID |
1063 | Dialog (in application) | NATID |
1064 | Class (in application) | NATID |
1065 | Command processor (in application) | NATID |
1067 | Mainframe DDM (in application) | DDMID |
1068 | Function (in application) | NATID |
1069 | Shared resource (in application) | RESID |
1070 | Error message file (in application) | NATID |
1071 | Adapter (in application) | NATID |
1101 | System file | FILEID |
1102 | Natural system file | FILEID |
1103 | User system file | FILEID |
1104 | DDM system file | FILEID |
1111 | Library | LIBID |
1112 | Library (in application) | LIBID |
1121 | Environment | BSTR |
1131 | Base application | BSTR |
1132 | Compound application | BSTR |
1141 | Application server | BSTR |
Syntax | Description |
---|---|
name library fnr dbnr | Identifies the Natural development object with the given name in the given library in the given system file. The individual parts of the identifier are separated by spaces. |
name library | Identifies the Natural object with the given name in the given library. The system file is then determined from the library according to the usual Natural logic, depending on the library name. The individual parts of the identifier are separated by spaces. |
name | Identifies the Natural object with the given name in the current logon library. |
Syntax | Description |
---|---|
name/library/fnr/dbnr | Identifies the shared resource with the given name in the given library in the given system file. The individual parts of the identifier are separated by slashes. |
name/library | Identifies the shared resource with the given name in the given library. The system file is then determined from the library according to the usual Natural logic, depending on the library name. The individual parts of the identifier are separated by slashes. |
name | Identifies the shared resource with the given name in the current logon library. |
Syntax | Description |
---|---|
name fnr dbnr | Identifies the mainframe DDM with the
given name in the given FDIC system file. The individual parts of
the identifier are separated by spaces.
|
name | Identifies the mainframe DDM with the
given name in the current FDIC system file.
|
Syntax | Description |
---|---|
name fnr dbnr | Identifies the Natural library with the given name in the given system file. The individual parts of the identifier are separated by spaces. |
name | Identifies the Natural library with the given name. The system file is then determined from the library according to the usual Natural logic, depending on the library name. |
Syntax | Description |
---|---|
fnr dbnr | Identifies the Natural system file with the given numbers. The individual parts of the identifier are separated by spaces. |
Assume that in a certain development environment, we have a
system file with the database number "101" and the
file number "99", containing a library
MYLIB
with a program MYPROG
.
In the given environment
the program is identified by the node type 1009 and the key "MYPROG MYLIB 99 101",
the library is identified by the node type 1111 and the key "MYLIB 99 101",
the system file is identified by the node type 1103 and the key "99 101".
Plug-ins can define their own node types. This is useful if a plug-in wants to display tree views or list views of development objects not belonging to the predefined set of Natural Studio objects. An example is the Object Description plug-in. It is also useful for plug-ins that want to display certain aspects of Natural Studio objects not covered by built-in Natural Studio functionality. An example is the XRef Evaluation plug-in.
When defining its own node type, a plug-in is free to choose an arbitrary positive integer value starting with "20000". Values below "20000" are reserved for predefined node types. It does not matter if different plug-ins chose the same integer value for a node type. Internally, Natural Studio distinguishes the node types by their numbers and by the plug-in that defined the node type.
The plug-in is free to define the key format for each user-defined node type. Natural Studio does not interpret the keys of user-defined node types, but treats them as opaque strings.
To define new node types and their visual representations, a plug-in uses the interfaces described in the following sections:
INatAutoTypes
INatAutoNodeImages
INatAutoNodeTypes
INatAutoNodeType
Through the interfaces described in this section, plug-ins can access the set of objects the user has currently selected in Natural Studio. A plug-in might need this information to decide if a specific menu or toolbar command is applicable to the current selection and must hence be enabled in the user interface. If the user then executes the command, the plug-in again needs to know the set of selected objects in order to apply the command to each of them. A plug-in has access to the current selection through the interfaces described in this section.
In order to work with the current selection, a plug-in starts with
the root interface INatAutoStudio
,
retrieves the INatAutoObjects
interface and then the INatAutoSelectedObjects
interface. We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#objs := #studio.Objects #selobjs := #objs.SelectedObjects
The returned INatAutoSelectedObjects
interface gives access to the set of objects the user has currently selected.
Using this interface, the plug-in can, for instance, iterate across the
selected objects and inspect them. The method
Item
returns an INatAutoSelectedObject
interface to a specific selected object.
#iCount := #selobjs.Count for #i := 1 to #iCount send "Item" to #selobjs with #i return #selobj #iType := #selobj.Type #aKey := #selobj.Key end-for
The property FocusObject
returns the
index of the specific selected object that currently has the focus. This index
can be used to retrieve the INatAutoSelectedObject
interface of the focus object.
#iFocus := #selobjs.FocusObject send "Item" to #selobjs with #iFocus return #focus
The method ContainsObjectType
can be used
for a quick check if the current selected set contains objects of a specific
type. This might be sometimes sufficient to decide if a specific command shall
be enabled or not.
send "ContainsObjectType" to #selobjs with 1009 return #bContainsPrograms
For specific checks the plug-in can also retrieve and process the current selection as an XML document.
#aSelectedObjectsXML := #selobjs.SelectedObjects
To work with selections, a plug-in uses the interfaces described in the following sections:
INatAutoObjects
INatAutoSelectedObjects
INatAutoSelectedObject
Through the interfaces described in this section, plug-ins can create and edit Natural development objects. Being able to create new development objects, load existing objects into an editor, manipulate their contents and to save and stow them, enables plug-ins to provide generation functions and thus to help automating the development process. An example is the Program Generation plug-in.
To open a program in the program editor, for instance, a plug-in
starts with the root interface INatAutoStudio
,
retrieves the INatAutoObjects
interface and then the INatAutoPrograms
interface. Now it uses the method INatAutoPrograms::Open
to load the program into the editor.
We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#objects := #studio.Objects #programs := #objects.Programs send "Open" to #programs with 1009 "MYPGM" "MYLIB" return #program
The resulting INatAutoProgram
interface can now be used to operate on the program, for instance, to stow it
and then to close the editor.
send "Stow" to #program send "Close" to #program
A new program source is created by using the method
Add
.
send "Add" to #programs with 1009 return #program
Source code is added to the program either as a whole by using the
property Source
:
#program.Source := "WRITE ""HELLO, WORLD!"" END
Or incrementally by using the method
InsertLines
.
send "InsertLines" to #program with "WRITE ""HELLO, WORLD!" #return #next send "InsertLines" to #program with "END" #next return #next
The interface INatAutoProgram
provides also search and replace methods and other methods to modify the source
code.
send "Search" to #program with "HELLO" return #found send "ReplaceLines" to #program with "WRITE ""Good morning" #found
Dialogs and data areas are accessed in a similar way by using the
interfaces INatAutoDialog
and
INatAutoDataArea
.
But there is one particularity with these objects: Even though there is a
graphical or structured editor in the user interface for these objects, they
are edited textually through the Automation interface. Applied to data areas
this means: If a plug-in wants to generate a data area, it actually has to
generate a DEFINE
DATA
statement.
#objects := #studio.Objects #dataareas := #objects.DataAreas send "Add" to #dataareas with 1006 return #lda * send "StartEdit" to #lda send "InsertLines" to #lda with "DEFINE DATA LOCAL" return #next send "InsertLines" to #lda with "1 MYSTRING(A10)" #next return #next send "InsertLines" to #lda with "1 MYNUMBER(I4)" #next return #next send "InsertLines" to #lda with "END-DEFINE" #next return #next send "EndEdit" to #lda * send "Stow" to #lda send "Close" to #lda
The calls to the methods
INatAutoDataArea::StartEdit
and INatAutoDataArea::EndEdit
are used to mark the beginning and end of a series of editing operations.
To work with Natural development objects, a plug-in uses the interfaces described in the following sections:
INatAutoObjects
INatAutoPrograms
INatAutoProgram
INatAutoDialogs
INatAutoDialog
INatAutoDataAreas
INatAutoDataArea
Through the interfaces described in this section, plug-ins can use the Natural Studio program editor as editor for arbitrary text objects. A plug-in can open a program editor session, pass a buffer with text data to it, let the user edit the data and then retrieve the modified data back. The plug-in itself is responsible for providing and storing the data to be edited. The program editor provides the usual editing functions, as far as they are appropriate for generic text objects.
To let the user edit a given text in the program editor, a plug-in
starts with the root interface INatAutoStudio
,
retrieves the INatAutoObjects
interface and then the INatAutoGenericTexts
interface. Now it uses the method
INatAutoGenericTexts::Open
to load the text buffer into the editor.
We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
Also we assume that the text to be edited is contained in the alphanumeric
variable #buffer
.
#objects := #studio.Objects #texts := #objects.GenericTexts send "Open" to #texts with "Curriculum Vitae" "Dana Scully" #buffer return #text
The editor is then opened and the user can edit the text interactively.
The plug-in can use the resulting
INatAutoGenericText
interface to operate on the text, for instance, to insert lines:
send "InsertLines" to #text with "Taught for two years at Quantico Medical School"
If the user chooses the PLUGIN-NOTIFY-SAVE
.
In response to this notification, it will usually retrieve the edited text from
the editor and save it.
#buffer := #text.Source * Now save the text in a plug-in specific way.
To work with generic text documents, a plug-in uses the interfaces described in the following sections:
INatAutoGenericTexts
INatAutoGenericText
INatAutoObjects
A plug-in that maintains own development objects might want to provide its own editors for each of its development object types. Editors in Natural Studio typically maintain development objects in MDI (Multiple Document Interface) windows. In the following, we call them document windows. Natural Studio has a number of built-in editors, for instance, the program editor and the dialog editor. A plug-in can implement its own editor with a so-called generic document window.
Implementing such an editor as a generic document window makes the editor behave like the built-in editors in Natural Studio. Essentially this means: Several editor windows on different objects can be opened in parallel and the user can switch between them.
In order to implement a generic document window, you first create
a Natural dialog of type "Plug-in MDI window". In your plug-in
code, you can then open this dialog with the OPEN DIALOG
statement and let
Natural Studio display the dialog as a document window. Normally you will do
this in the command handler of your plug-in, that is in the method
INaturalStudioPlugIn::OnCommand
:
open dialog "mydlg" null-handle giving #dialogid #objects := #studio.Objects #genericdocs := #objects.GenericDocuments send "Add" to #genericdocs with #dialogid return #doc
The resulting INatAutoGenericDocument
interface can now be used to operate on the document window.
The plug-in has several other means to communicate with the Natural dialog contained in the generic document window:
The plug-in can send events to the dialog with the
SEND EVENT
statement
and using the dialog ID.
The dialog can send method calls to the plug-in. To achieve
this, the plug-in should pass its own
*THIS-OBJECT
handle
to the dialog in the OPEN
DIALOG
statement.
The dialog can call the Natural Studio Automation interface.
To achieve this, the plug-in should pass the
INatAutoStudio
interface pointer to the dialog in the OPEN DIALOG
statement.
Whenever the user activates a document window, Natural Studio automatically switches the frame menu to a menu that contains the commands applicable to the active document. In the case of built-in document windows, these frame menus are predefined. In the case of a generic document window, the plug-in itself can provide an appropriate frame menu.
The plug-in can create a frame menu of its own by cloning an
existing frame menu using the method
INatAutoFrameMenus::Clone
and adding new commands to the clone as necessary using the method
INatAutoFrameMenu::InsertCommand
.
Afterwards it passes the resulting
INatAutoFrameMenu
interface to Natural Studio when calling the method
INatAutoGenericDocuments::Add
.
To work with generic documents, a plug-in uses the interfaces described in the following sections:
INatAutoGenericDocuments
INatAutoGenericDocument
INatAutoObjects
Through the interfaces described in this section, a plug-in can display its own tree views and list views in Natural Studio. Tree views and list views are frequently used in Natural Studio to display development objects and to navigate through them.
In order to display objects in tree views and list views, the plug-in must first register the types of the tree or list view nodes that it is going to display. This procedure is described in Working with Node Types.
A plug-in that displays objects in tree views and list views must
also implement the methods of the interface
INaturalStudioPlugInTree
appropriately. Natural Studio calls the methods of this interface when
expanding or refreshing the tree.
In order to open a tree view, the plug-in starts with the root
interface INatAutoStudio
,
retrieves the INatAutoObjects
interface and then the INatAutoObjectTrees
interface. We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#objs := #studio.Objects #trees := #objs.ObjectTrees
The resulting INatAutoObjectTrees
interface gives access to the currently open tree view document windows.
Through this interface the plug-in can open a new tree view with a given root
object.
send "Open" to #trees with #type #key #caption return #tree
The node type specified in the method
Open
must have been registered before, as described in
Working with Node
Types. The INatAutoObjectTree
interface returned from the method Open
gives access
to the tree view document window just opened. Through this interface the
plug-in can, for instance, later close the document window.
send "Close" to #tree
When opening a tree view, the plug-in specifies at least the type
and key of the root object and a caption to be displayed on the tree view
document window. Natural Studio will retrieve additional information needed to
expand the tree view by using the interface
INaturalStudioPlugInTree
that must be implemented by the plug-in.
The nodes of a tree view can be accessed through the interface
INatAutoObjectTreeNode
.
The root node of a tree view is retrieved with the method
INatAutoObjectTree::GetRootNode
,
which returns an interface INatAutoObjectTreeNode
. This
interface can then be used, for instance, to expand the node and to access the
child nodes. In the same way, the currently selected node of a tree view can be
retrieved.
send "GetRootNode" to #tree return #rootnode send "Expand" to #rootnode send "GetChild" to #rootnode return #firstchildnode send "GetNext" to #firstchildnode return #nextchildnode send "Expand" to #nextchildnode send "GetSelectedNode" to #tree return #selectednode send "Expand" to #selectednode
The interface INatAutoObjectTreeNode
controls only the visual appearance of an individual tree view, not the
underlying object structure, which is possibly represented differently in
several views at a time. The object structure itself is under the control of
the plug-in that defines and provides it through its
INaturalStudioPlugInTree
interface.
List view document windows are created in a similar way as tree
view document windows, except that the interface
INatAutoObjectLists
is used instead of INatAutoObjectTrees
.
To work with tree views and list views, a plug-in uses the interfaces described in the following sections:
INatAutoObjects
INatAutoObjectTrees
INatAutoObjectTree
INatAutoObjectTreeNode
INatAutoObjectLists
INatAutoObjectList
INatAutoRefreshObject
Through the interfaces described in this section, a plug-in can display the results of its work in the Natural Studio result view. Objects displayed in a result view can be target of commands and can be used as starting point for navigation. Examples of built-in functions that use result views are the
command and the command.In order to display objects in result views, the plug-in must first register the types of nodes that it is going to display. This procedure is described in the section Working with Node Types.
In order to work with result views, the plug-in starts with the
root interface INatAutoStudio
and
retrieves the INatAutoResultViews
interface. We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#resultviews := #studio.ResultViews
The resulting INatAutoResultViews
interface gives access to the result view control bar and the currently open
result views. The plug-in can use this interface, for instance, to show or hide
the result view control bar.
send "Show" to #resultviews
Through the interface INatAutoResultViews
the plug-in can open a new result view.
send "Open" to #resultviews with #caption #image #headers return #resultview
When opening a result view, the plug-in specifies a caption and an image to be displayed on the result view tab and (if needed) column headers for the result view.
The INatAutoResultView
interface returned from the method
Open
gives access to the result view just opened. Through this interface the plug-in
can activate the result view, insert rows into it and update the display. The
method SetVisible
scrolls a specific row into view.
#resultview.Active := true send "InsertRows" to #resultview with #rows return #last send "Update" to #resultview send "SetVisible" to #resultview with #last
Finally the plug-in can close its result view.
send "Close" to #resultview
To work with result views, a plug-in uses the interfaces described in the following sections:
INatAutoResultViews
INatAutoResultView
Through the interfaces described in this section, plug-ins can inspect the available local and remote development environments, map environments, connect to and disconnect from a remote environment and activate an environment.
In order to work with environments, a plug-in starts with the root
interface INatAutoStudio
,
retrieves the INatAutoSystem
interface and then the INatAutoEnvironments
interface. We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#system := #studio.System #envs := #system.Environments
The returned INatAutoEnvironments
interface gives access to the local environment and all remote environments
that have once been connected during the current Natural Studio session.
Through this interface the plug-in can, for instance, map a new remote environment, specifying host name, port number, user ID, password and other arguments.
send "Add" to #envs with "IBM2" "4712" "SCULLY" "secret" "STACK=(LOGON XFILES)" return #env
The returned interface INatAutoEnvironment
gives access to attributes of the environment.
#bIsActive := #env.Active #bIsConnected := #env.Connected
The property Parameters
gives access to the interface INatAutoNatparm
.
This interface contains properties that represent the Natural parameters under
which the environment is running. Only a subset of the Natural parameters is
available through this interface.
#natparm := #env.Parameters #fuserDBnr := #natparm.FuserDBnr #fuserFnr := #natparm.FuserFnr
The property
SystemVariables
gives access to the interface INatAutoNatsvar
.
This interface contains properties that represent the system variables
currently set in the environment. Only a subset of the system variables is
available through this interface.
#natsvar := #env.SystemVariables #language := #natsvar.Language
The plug-in uses the method
Disconnect
to disconnect from the remote environment.
send "Disconnect" to #env
To work with environments, a plug-in uses the interfaces described in the following sections:
INatAutoEnvironments
INatAutoEnvironment
INatAutoSystem
INatAutoNatparm
INatAutoNatsvar
Through the interfaces described in this section, plug-ins can inspect the applications available on the application server, map applications into the Natural Studio session, connect to and disconnect from an application, activate an application and create and modify applications. An example of a plug-in that uses this section of the interface is the Application Wizard.
In order to work with applications, the plug-in starts with the
root interface INatAutoStudio
,
retrieves the INatAutoSystem
interface and then the INatAutoApplications
interface. We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#system := #studio.System #apps := #system.Applications
The resulting INatAutoApplications
interface gives access to the currently active application server and the
applications it contains. Through this interface the plug-in can, for instance,
ask for the currently active application.
#app := #apps.ActiveApplication
The plug-in can also create a new application and map it into the Natural Studio session.
send "Add" to #apps with "MYAPPLICATION" return #app
The resulting INatAutoApplication
interface gives access to attributes of the application.
#bIsActive := #app.Active #bIsConnected := #app.Connected
For a compound application, the property
LinkedApplications
returns the interface INatAutoLinkedApplications
.
This interface allows accessing the base applications that are linked to the
compound application.
#linkedapps:= #app.LinkedApplications #iCount := #linkedapps.Count
For a base application, the property
LinkedObjects
returns an XML document containing the list of objects linked to the
application.
#aObjects:= #app.LinkedObjects
The plug-in can also link and unlink objects to and from the application.
send "UnlinkObject" to #app with 1009 "OLDPROG" "MYLIB" send "LinkObject" to #app with 1009 "NEWPROG" "MYLIB"
Finally the plug-in can disconnect and unmap the application.
send "Disconnect" to #app send "Unmap" to #app
To work with applications, a plug-in uses the interfaces described in the following sections:
INatAutoApplications
INatAutoApplication
INatAutoLinkedApplications
Through the interfaces described in this section, a plug-in can inspect the currently installed plug-ins, read their properties and activate or deactivate a plug-in. This includes the possibility that a plug-in deactivates itself. An example for a plug-in that uses this section of the interface is the Plug-in Manager.
In order to work with plug-ins, the plug-in starts with the root
interface INatAutoStudio
and
retrieves the interface INatAutoPlugIns
.
We assume here that the plug-in has kept a handle to the interface
INatAutoStudio
in a variable named #studio
.
This handle was passed to the plug-in during activation, in the method
INaturalStudioPlugIn::OnActivate
.
#plugins := #studio.PlugIns
The resulting INatAutoPlugIns
interface gives access to the currently installed plug-ins. Using this
interface, the plug-in can, for instance, iterate across the installed plug-ins
and inspect their attributes. The method
Item
returns an INatAutoPlugIn
interface to a specific plug-in.
#iCount := #plugins.Count for #i := 1 to #iCount send "Item" to #plugins with #i return #plugin #aName := #plugin.Name #aProgID := #plugin.ProgID #bIsActive := #plugin.Active end-for
Through the interface INatAutoPlugIn
the
plug-in can also activate or deactivate a specific plug-in by modifying the
property Active
.
The following sample toggles the activation state of a plug-in.
#bIsActive := #plugin.Active if #bIsActive #plugin.Active := false else #plugin.Active := true end-if
The interface INatAutoPlugIn
can
be used to send a command to the plug-in. The following sample checks whether
the plug-in command with the ID "200" is currently
enabled and if so, lets the plug-in execute the command. Of course this
requires that we know that the plug-in implements a command with the ID
"200" and what this command does.
#bEnabled = false #bChecked := false send "OnCommandStatus" to #plugin with 200 #bEnabled #bChecked if #bEnabled send "OnCommand" to #plugin with 200 end-if
Through the interface INatAutoPlugIn
, the
plug-in can get access to arbitrary services that another plug-in provides with
a so-called custom interface. The following sample retrieves the custom
interface of a plug-in and calls one of its services. Of course this requires
that the plug-in has documented the services it provides with its custom
interface.
#icustom := null-handle send "GetCustomInterface" to #plugin return #icustom if #icustom ne null-handle #result := 0 send "GetMaritalStatus" to #icustom with "Anderson, Gillian" return #result end-if
In order to provide a custom interface, a plug-in must implement
an additional interface beside the two predefined interfaces
INaturalStudioPlugIn
and INaturalStudioPlugInTree
and make this interface the default dispatch interface. For a plug-in
implemented in Natural this means placing this interface at the first position
in the DEFINE CLASS
statement.
define class ... object using ... id "..." interface icustom id "..." method GetMaritalStatus id 1 is gstat-n parameter using gstat-a end-method end-interface interface using nstplg-i interface using nstplt-i end-class end
To work with plug-ins, a plug-in uses the interfaces described in the following sections:
INatAutoPlugIns
INatAutoPlugIn
If a plug-in wants to open dialog boxes in Natural Studio, some special considerations have to be taken. The support of dialog boxes in plug-ins depends mainly on the condition if the plug-in is running in as an in-process ActiveX component or if it is running in a separate process.
The following topics are covered below:
In general, an ActiveX component running in a separate process cannot open a dialog box in the client process. This restriction of the Windows system itself is overcome in the special case that a plug-in is written in Natural.
If a plug-in is written in Natural, it can open modal dialog boxes in Natural Studio. Precisely this means: Natural dialogs that are defined in the dialog editor with the Type attribute set to "Standard window" and the Style attribute set to "Dialog box". Other styles of the dialog type "Standard window" cannot be used in plug-ins.
To open a dialog box, a plug-in uses the usual
OPEN DIALOG
statement.
If a plug-in is implemented as an in-process ActiveX component (this means: as a DLL), it can open modal and non-modal dialogs in Natural Studio. To open a dialog, the plug-in uses the statements usual in the programming language it is written in. Plug-ins written in Natural always run in a separate process, so this applies only to plug-ins written in programming languages that support implementing in-process ActiveX components.
For details on how to implement plug-ins in programming languages other than Natural, see Developing Plug-ins in Other Programming Languages.