LAST PAGE  BACK TO INDEX  NEXT PAGE

[10.0] UserObjects, UserFunctions, & RPCs

[10.0] UserObjects, UserFunctions, & RPCs

v5.0 / 10 of 23 / 01 sep 99 / gvg

* A VEE UserObject llows you to collect a set of objects into a high-level, user-defined object -- a subprogram. UserObjects can be nested. You can also convert UserObjects into UserFunctions that can be called from multiple places in a program, as well as be incorporated into formulas in Formula boxes.

This chapter provides a quick overview of these two VEE features.


[10.1] USEROBJECTS & USERFUNCTIONS
[10.2] VEE REMOTE PROCEDURE CALLS

 BACK TO INDEX

[10.1] USEROBJECTS & USERFUNCTIONS

* A VEE UserObject allows you to encapsulate functions inside a single object. You can then "streamline" the UserObject into a UserFunction, which becomes part of the program's invisible "background", only becoming visible when it is invoked.

The invisibility of UserFunctions makes them harder to edit than UserObjects, but a UserFunction has several advantages over a UserObject:

* Let's build a simple UserObject to, say, take the square root of a number, and then convert it into a UserFunction. To get a UserObject, use the menu entry "Device -> UserObject". This gives you:


   +-------------------------------------------------------+
   |                      UserObject                       |
   +---+-----------------------------------------------+---+
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   |   |                                               |   |
   +---+-----------------------------------------------+---+
 
Next select a formula box (from "Math -> Formula"), place it in the UserObject, and put the expression "sqr(A)" into it:

  +-------------------------------------------------------+
  |                      UserObject                       |
  +---+-----------------------------------------------+---+
  |   |                                               |   |
  |   |                                               |   |
  |   |        +------------------------------+       |   |
  |   |        |           Formula            |       |   |
  |   |        +-------+-----------+----------+       |   |
  |   |        | A Any |[ sqr(A)  ]| [result] |       |   |
  |   |        +-------+-----------+----------+       |   |
  |   |                                               |   |
  |   |                                               |   |
  +---+-----------------------------------------------+---+
 
To complete the UserObject, move the cursor over the left margin of the object and press Ctrl+A to get an input pin, move the cursor over the right margin and press Ctrl+A to get an output pin, and wire the Formula object to these pins:

   +-------------------------------------------------------+
   |                      UserObject                       |
   +---+-----------------------------------------------+---+
   |   |                                               |   |
   |   |                                               |   |
   |   |        +------------------------------+       |   |
   |   |        |           Formula            |       |   |
   |   |        +-------+-----------+----------+       |   |
   | A +------->| A Any |[ sqr(A)  ]| [result] +------>| X |
   |   |        +-------+-----------+----------+       |   |
   |   |                                               |   |
   |   |                                               |   |
   +---+-----------------------------------------------+---+
 
* To convert the UserObject into a UserFunction, click on the UserObject's toaster box to get its menu:

   +-------------------------------------------------
   |                      UserObject   
   +---------------------+-------------
   | Move                |
   | Size                |
   | Clone               |
   | Help                |
   +---------------------+
   | Show Description    |
   | Breakpoint          |
   |*Show Title          |
   | Change Title...     |
   | Terminals          >|
   +---------------------+
   | Make UserFunction   | <---
   | UnPack              |
 
Select this and a dialog box pops up to allow you to specify the function name. Give it a name, say "RootMap" (for "square root mapping"):

   +---------------------------------+
   |        Make UserFunction        |
   +---------------------------------+
   |                                 |
   | Function Name [    RootMap    ] |
   |                                 |
   |    +--------+     +--------+    |
   |    |   OK   |     | Cancel |    |
   |    +--------+     +--------+    |
   +---------------------------------+
 
-- and click on "OK". The UserObject disappears, to be replaced by a Call Function object:

   +-------------------------------------------+
   |               Call Function               |
   +-------+-------------------------------+---+
   | A Any | Function Name [   RootMap   ] | X |
   +-------+-------------------------------+---+ 
 
Note that this is not the UserFunction itself. The UserFunction has become invisible. All it does it call the UserFunction.

You have now completed a UserFunction. You can add more in the same fashion.

* Once you have completed a set of UserFunctions, you can edit them or incorporate them into programs. Suppose you have created a set of UserFunctions with the names RootMap, LogMap, and SqrMap; you can edit any of these UserFunctions by using the VEE Edit menu's "Edit UserFunction" entry:


    Edit  Debug  Flow  Device
  -+----------------------------+-
   |  Cut                       |  Cuts an object or objects from program.
   |  Copy                      |  Copies an object or objects.
   |  Paste                     |  Inserts object or objects to program.
   |  Clone                     |  Duplicates an object or objects.
   +----------------------------+
   |  Delete Line Shift+Ctrl+LB |
   |  Clean Up Lines            | 
   +----------------------------+
   |  Select Objects    Ctrl+LB | 
   |  Move Objects              |
   |  Add To Panel              |
   +----------------------------+
   |  Create UserObject         |
   |  Edit UserFunction ...     |<--
   +----------------------------+
 
Click on that entry and you'll get a list of UserFunctions currently residing in VEE. Select one and you get a "window" into the UserFunction:

   +------------------------------------------------+
   |             UserFunction: RootMap              |
   +---+----------------------------------------+---+
   |   |                                        |   |
   |   |                                        |   |
   |   |    +------------------------------+    |   |
   |   |    |           Formula            |    |   |
   |   |    +-------+-----------+----------+    |   |
   | A +--->| A Any |[ sqr(A)  ]| [result] +--->| X |
   |   |    +-------+-----------+----------+    |   |
   |   |                                        |   |
   |   |                                        |   |
   +---+----------------------------------------+---+
   |                   [ Done ]                     |
   +------------------------------------------------+
 
This viewport has the following menu:

   +------------------------------
   |              UserFunction: RootMap
   +---------------------+-----------------
   | Move                |           
   | Size                |
   | Help                |
   +---------------------+
   | Change Properties   |
   | To Panel            |
   | To Detail           |
   | Show Description    |
   +---------------------+
   | Show Panel on Exec  |
   | Trig Mode          >|
   | Terminals          >|
   | Edit               >|
   +---------------------+
   | Make UserObject     | 
   | Delete              |
   +---------------------+
   | Done                |
   +---------------------+
 
There's only a few elements in this menu that are particularly useful to the UserFunction view: "Change Properties" allows you to change the UserFunction name; "Make UserObject" allows you to convert the UserFunction back into a UserObject; and "Delete" of course deletes the UserFunction from the system.

This is largely intuitive, but one thing that quickly comes to mind as useful to do is to make a copy of a UserFunction so you can modify it into a new UserFunction. This is also a little tricky, since if you don't do it just right you'll end up with the first UserFunction modified to the coding of the second. The correct process is as follows:

* Anyway, once you have created a set of UserFunctions you can then delete any Call Function objects and save the result to a file as a UserLibrary.

Suppose you have a UserLibrary named "lib1.vee". You can then use the "File" menu's "Merge Library" (not "Merge" -- "Merge Library" ... "Merge" adds in a separate program) to add the UserFunctions to a program you are working on. You can add as many UserLibraries as you like in this way -- as long as you don't try to add two UserLibraries that contain a function with the same name (VEE doesn't like that too much).

However, this merges the UserFunctions permanently into your VEE program; you can only get rid of them by individually deleting them. If you want to dynamically load UserLibraries, you can use the Import Library object:


           +------------------------------------------+
           |             Import Library               |
           +------------------------------------------+
           | Library Type    [    User Function     ] |
           | Library Name    [        lib1          ] |
           | File Name       [       LIB1.VEE       ] |
           +--------------------+---------------------+
                                |
              +-----------------+------------------+
              |            Call Function           |
   +------+   +---+----------------------------+---+   +-------+
   | 2    +-->| A | Function Name [ RootMap  ] | X +-->| 1.414 |
   +------+   +---+-------------+--------------+---+   +-------+
                                |
                 +--------------+-------------+
                 |       Delete Library       |
                 +----------------------------+
                 | Library Name  [   lib1   ] |
                 +----------------------------+
 
This little program loads the LIB1.VEE UserLibrary, executes a function out of it, then deletes it when it is done. (The "Library Name" -- "lib1" in this case -- is an arbitrary handle for the program to cross-reference the library; you can make it anything you like.) You can load multiple libraries in the same program and delete each when you please. Again, the libraries cannot have two functions with the same name.

* Note that there is one subtlety with UserObjects and UserFunctions: if you perform a loop within one and send a series of values to an output pin, you'll only get the last value it wrote when the UserObject or UserFunction exits.

This is because these elements really are subprograms of sorts, and of course if you wrote a subprogram in BASIC:


   SUB Test( N )
     INTEGER I
     FOR I = 1 TO N
        N = I^2
     NEXT N
   END SUB
 
-- you'll only get the last value of N^2 out of it. To return a set of values, you have to put them in an array and return the entire array.

Similarly, one user wrote a VEE program of the form:


       +-------+
       | Until |
       | Break +------------------------+
       +---+---+                        |
           |           +----------------+---------------+
   +-------+-------+   |            UserObject          |
   | Message Box:  |   +--------------------------------+
   |    "DONE!"    |   | +---------------+   +--------+ |
   +---------------+   | | For Count: 10 +-->| 3      | |
                       | +-------+-------+   +--------+ |
                       |         |                      |
                       |     +---+---+                  |
                       |     | Break |                  |
                       |     +-------+                  |
                       +--------------------------------+
 
The Until Break never executed, even though there was a Break object in the UserObject. The reason was simple: the Break object was in a separate context and it did not apply to the outer loop.

 TOP OF PAGE

[10.2] VEE REMOTE PROCEDURE CALLS

* With the introduction of Win95, which provided much more robust networking facilities than Win3, it became possible to use various networking features with VEE 3.2 on that platform that had been previously available for VEE on HP-UX. One of the more interesting of these features is the remote procedure call, or RPC.

With RPCs, a VEE on one computer on a network (a "client") can execute the functions of a UserFunction library (a "UserLibrary") on VEE on another computer on the LAN (a "server").

The trick is to use the Import Library object on the VEE client to specify loading a UserLibrary at the remote VEE server. The UserFunctions in the server's UserLibrary can then be invoked by the client with Call Function objects. The inputs to the UserFunctions are sent from the client to the server over the network, the UserFunctions are executed on the server, and the results are sent back to the client over the network.

VEE operates invisibly on the server. There is a special program that is installed along with VEE called "veesm.exe" (the VEE service manager) that has to be run beforehand to allow VEE server operation. You can either run it manually before beginning the network session, or include it in the Win95 StartUp menu to ensure it is always running after Win95 boots.

When the VEE client sends a message to the server to import the UserLibrary, the VEE service manager brings up VEE without displaying its user interface and loads the UserLibrary. The client can then execute the various UserFunctions on the server.

While by default, the VEE user interface will not appear on the server, if one of the UserFunctions is in the form of a "Show Panel On Execute" pop-up, the VEE user interface will be displayed when the pop-up is executed.

* Let's look at this in more detail, in the reverse order from how it was described above. Let's build a UserLibrary with three UserFunctions, one named "TestFn":


   +--------------------------------------------------------------------+
   |                     UserFunction:  TestFn                          |
   +---+------------------------------------------------------------+---+
   |   |                                                            |   |
   |   |   +----------------------------------------------------+   |   |
   | A +-->|[ (A>0 ? "Greater" : (A<0 ? "Less Than" : "Zip")) ] +-->| X | 
   |   |   +----------------------------------------------------+   |   |
   |   |                                                            |   |
   +---+------------------------------------------------------------+---+
 
-- one named "PopUp:

   +---------------------------------------------------------+
   |                UserFunction:  PopUp                     |
   +---+-------------------------------------------------+---+
   |   |                                                 |   |
   |   |                         +----+                  |   |
   |   |                         | OK +---+              |   |
   |   |                         +----+   |              |   |
   |   |                                  |              |   |
   | A +--+   +--------------+    +-------+-------+  +-->| X |
   |   |  |   | AlphaNumeric |    |     Text      |  |   |   |
   |   |  |   +--------------+    +---------------+  |   |   |
   |   |  +-->|              |    |               +--+   |   |
   |   |      +--------------+    +---------------+      |   |
   |   |                                                 |   |
   +---+-------------------------------------------------+---+
 
-- and one named "SqrFn":

   +-------------------------------------+
   |        UserFunction:  SqrFn         |
   +---+-----------------------------+---+
   |   |                             |   |
   |   |      +---------------+      |   |
   |   |      |    Formula    |      |   |
   |   |      +---+-----------+      |   |
   |   +----->| A | A*A       +----->| X |
   |   |      +---+-----------+      |   |
   |   |                             |   |
   |   |                             |   |
   +---+-----------------------------+---+
 
"TestFn" simply checks the value of the input and identifies whether it is lest than, equal to, or greater than by returning a string. "PopUp" creates a pop-up panel on the server to allow display of an output prompt and return of an input string. It has the "Show Panel On Execute" flag set and generates a pop-up panel of the form:

   +------------------------+
   |                        |
   |    +--------------+    |
   |    | AlphaNumeric |    |
   |    +--------------+    |
   |    | <prompt>     |    |
   |    +--------------+    |
   |                        |
   |    +--------------+    |
   |    |     Text     |    |
   |    +--------------+    |
   |    | <input text> |    |
   |    +--------------+    |
   |                        |
   |        +------+        |
   |        |  OK  |        |
   |        +------+        |
   |                        |
   +------------------------+
 
"SqrFn" simply returns the squared contents of a scalar or array.

* Anyway, I created these three UserFunctions and stored them in a UserLibrary named xrpctest.lib. I then ran the "veesm.exe" program and it popped up a little window. I hid it on the Win95 TaskBar, since there was no particular reason in this case for it to be visible.

* This done, I was ready to invoke the three UserFunctions as RPCs. I went to another machine and wrote the following program (see xrpctest.vee for the source):


           +-------------------------------------------------+
           |                 Import Library                  |
           +-------------------------------------------------+
           | Library Type             [  Remote Function   ] |
           | Library Name             [         tl         ] |
           | Host Name                [     hplvcoyote     ] |
           | Remote File Name         [c:/vlib/xrpctest.lib] |
           | Remote Timeout           [         60         ] |
           | XWindow Display Server   [                    ] |
           | geometry (800x500+0-0)   [                    ] |
           | Remote Debug             [ ]                    |
           +------------------------+------------------------+
                                    |
                        +-----------+----------+
                        |    Call tl.TestFn    |    
              +-----+   +----------------------+   +-------+
              | 0   +-->|[      tl.TestFn      +-->|  Zip  |
              +-----+   +-----------+----------+   +-------+
                                    |
                        +-----------+----------+
                        |    Call tl.PopUp     |    
   +----------------+   +----------------------+   +------------+
   | THIS IS A TEST +-->|[      tl.PopUp       +-->|  HI THERE  |
   +----------------+   +-----------+----------+   +------------+
                                    |
      +-------------+               |              +--------------+
      |   Integer   |               |              | Alphanumeric |
      +-------------+   +-----------+----------+   +--------------+
      | 0000: 3     |   |    Call tl.SqrFn     |   | 0: 9         |
      | 0001: 5     |   +----------------------+   | 1: 25        |
      | 0002: 9     +-->|[      tl.SqrFn       +-->| 2: 81        |
      | 0003: 25    |   +-----------+----------+   | 3: 625       |
      | 0004: 13    |               |              | 4: 169       |
      +-------------+               |              +--------------+
                                    |
                      +-------------+------------+
                      |      Delete Library      |    
                      +-------------+------------+
                      | Library Name [    tl   ] |
                      +--------------------------+
 
The key to this program is the settings in the Import Library box:

   +-------------------------------------------------+
   |                 Import Library                  |
   +-------------------------------------------------+
   | Library Type             [  Remote Function   ] |
   | Library Name             [         tl         ] |
   | Host Name                [     hplvcoyote     ] |
   | Remote File Name         [c:/vlib/xrpctest.lib] |
   | Remote Timeout           [         60         ] |
   | XWindow Display Server   [                    ] |
   | geometry (800x500+0-0)   [                    ] |
   | Remote Debug             [ ]                    |
   +-------------------------------------------------+
 
Setting the "Remote Function" option gives the appropriate following fields You then can specify a library name ("tl" in this case -- it's quite arbitrary, all it does is give a handle for the rest of the program to use), the name of the server computer ("hplvcoyote" in this case), the name of the UserLibrary on the server computer ("c:/vlib/xrpctest.vee"), and a timeout for the network interaction. (Note that you use "/" in describing the path, not "\" -- the Import Library box won't swallow "\" -- but it works OK.)

The XWindow Display Server specifies where popups will appear (this doesn't apply to PCs). Geometry specifies the size of the VEE user interface if it pops up on the server, the default is OK in this case. Remote Debug allows tracing the operation of the UserFunctions on the remote server (nice to know, but we won't tinker with it here).

Anyway, running this program invokes the "TestFn" UserFunction invisibly and generates results; then the "PopUp" UserFunction is invoked, and the popup panel appears on the server with the prompt: "THIS IS A TEST". I type in: "HI THERE" -- to the panel on the server and click on OK; the string is sent back to the client. Finally, the "SqrFn" UserFunction takes a list of integers and returns their squares.

The cleanliness of client-server operation is quite surprising. As long as the networking is set up OK, it works without much trouble.

 TOP OF PAGE


 LAST PAGE  BACK TO INDEX  NEXT PAGE