Using Caché Direct
Basics of Using the VisM Control
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes the basics of using the VisM control:

This chapter also discusses constraints on Caché Direct messages that may affect your code on either side. It concludes with a couple of simple examples.
Note:
A leading underline indicates a callback reference to the Visual Basic user interface. Note that Caché does not allow this usage in any other situation.
Accessing the VisM Control
When you install the Caché client software, it installs and registers the VisM control so that it is available to any ActiveX host, such as Visual Basic.
Note:
If the Caché client is not installed on a given machine, you can manually copy the Caché Direct client files into place and register them. See the section Installing VisM on a New Machine, near the end of this manual.
In the case of Visual Basic, to add this control to your project, click Project —>Components, scroll to VisM, and select the check box. Then you can add instances of the control to your forms as you do any other control.
Connecting and Disconnecting
To connect or disconnect the Caché Direct client from the server, you can use the Server property, the ConnTag property, the SetServer() method, the Connect() method, and the DeleteConnection() method. Each of these tools has specific uses, but there is overlap. The SetServer() and Connect() methods are similar, but have small differences for historical reasons and to preserve backward compatibility. The Server property and the SetServer() method are the same except for the second argument to SetServer().
Also see the appendix Notes for Users of Previous Version.
Connection Strings and Connection Tags
Before describing the specific syntax for connecting to Caché, it is useful to know about the connection strings and connection tags that are used in that syntax.
Basic Connection String
A connection string is a pieced string of the following form:
"CN_IPTCP:server[port]"
The first piece of this argument, CN_IPTCP, is the connection method, which is always TCP. The second piece is the server name or IP address and port where the Caché superserver is running. For example, you could use the following syntax to set the connection of a VisM named VisM1:
VisM1.Server="CN_IPTCP:127.0.0.1[57772]"
There are extensions to this basic string (as described in VisM Extended Connection String Syntax in the chapter on VisM.ocx Control Details). These extensions are not commonly used.
Connecting with an Indirect Reference
Alternatively, you can use an indirect reference to a locally defined database alias. In this case, you use a string of the form "@servername" where servername is the server name as specified within the Caché Server Manager. (For details on using the Caché Server Manager, see Define a Remote Server Connection in the Caché System Administration Guide). Note that these aliases are local to the client machine. You would hard code this approach only if the client machines followed a naming convention for their Caché server aliases.
For example, you could use the following syntax to set the connection of a VisM object named VisM1 to server name unix1:
VisM1.Server="@unix1"
Note:
An indirect reference is the preferred way to open a connection that uses Kerberos authentication. The Caché Server Manager allows you to set Kerberos as the authentication method, specify the connection security level, and define the Service Principal Name.
User Prompt
In any place where you can use a connection string, you can instead use a quoted question mark ("?"). In this case, the user is prompted to choose one of the server aliases defined on the client machine.
For example, the following syntax would cause the user to be prompted for the connection of a VisM named VisM1:
VisM1.Server="?"
Connection Tags
In some cases, when you create a new connection to Caché, you can provide an optional connection tag. This is meant to serve as a name for the CDConnect that you are creating and its channel. It is your responsibility to ensure that all tags are unique within a given client process.
Then, when you connect a VisM, you can specify the connection tag of an existing CDConnect, rather than using a connection string. This is the main way to explicitly share a channel. For example, you could use the following syntax to set the connection of a VisM named VisM1:
VisM1.Server="TagA"
Alternatively, suppose that we wanted to connect VisM1 to the same CDConnect to which VisM2 is connected and that CDConnect has a tag assigned to it. If we did not want to use a connection tag itself, we could use the ConnTag property as follows:
VisM1.Server=VisM2.ConnTag
Connecting to Caché
Connecting is the action of attaching a VisM to a CDConnect (creating the CDConnect if necessary). If the VisM is currently attached to a CDConnect object, it is disconnected from that CDConnect first.
If Not Yet Connected
If the VisM is not yet connected to Caché, you can connect it to Caché by using any of the following techniques, which are listed here in order by how commonly they are used:
In each case, Caché Direct creates a CDConnect and creates a connection from the VisM to the CDConnect object. It also starts a server process and creates a channel from the CDConnect to the server process.
If you use the SetServer() or the Connect() method, you can provide a connection tag as the second argument. For example:
 VisM1.SetServer("CN_IPTCP:127.0.0.1[57772]","tagA")
If Already Connected
If the VisM is already connected to Caché, that means that a CDConnect has been created, possibly with an associated server process. You can connect the VisM to a different CDConnect, disconnecting from the original CDConnect and creating a server for the new CDConnect. To connect to a different CDConnect, use any of the following techniques.
These actions do not destroy the original CDConnect; nor do they affect its server channel, if it has one. The CDConnect exists until it is no longer accessible (when it will be destroyed automatically) or until it is explicitly destroyed, as described in Destroying a CDConnect.
Changing the Channel of a CDConnect
To change the channel of an existing CDConnect, use either of the following equivalent techniques:
In either case, the CDConnect stops the server process to which it is currently connected, disconnects from it, and then starts and connects to a new server process.
Disconnecting from Caché
To disconnect from the Caché server, use either of the following equivalent techniques:
These actions do not destroy the CDConnect; nor do they affect its server channel, if it has one. The CDConnect exists until it is no longer accessible (when it will be destroyed automatically) or until it is explicitly destroyed, as described in the next section.
Destroying a CDConnect
To destroy the CDConnect and its channel, call the DeleteConnection() method. This method also stops the server process, of course. For example:
VisM1.DeleteConnection()
Summary of Techniques
The following table summarizes how to connect and disconnect from Caché. Notice that setting the Server property has the same effect as calling the SetServer() method, in all cases.
Action How To Do This
Connecting to a new CDConnect, if not yet connected
Use any of the following techniques:
  • Set the Server property equal to a connection string.
  • Call the SetServer() method with a connection string as the first argument.
  • Call the Connect() method with a connection string as the first argument.
Connecting to a new CDConnect, if already connected*
Call the Connect() method with a connection string as the first argument.
Connecting to an existing CDConnect (after disconnecting from current CDConnect, if any)*
Use any of the following techniques:
  • Call the Connect() method with a connection tag as the first argument.
  • Set the Server property equal to a connection tag (permitted as of Caché 2007.1).
  • Call the SetServer() method with a connection tag as the first argument (permitted as of Caché 2007.1).
Connecting to the last opened CDConnect (after disconnecting from current CDConnect, if any)* Call the Connect() method with an empty string as the first argument.
Changing the channel of the existing CDConnect
Use either of the following techniques:
  • Set the Server property equal to a connection string.
  • Call the SetServer() method with a connection string as the first argument.
Disconnecting*
Use either of the following techniques:
  • Set the Server property equal to an empty string.
  • Call the SetServer() method with an empty string as the argument.
Destroying the CDConnect and its channel Call the DeleteConnection() method.
Key: *These actions do not destroy the CDConnect; nor do they affect its server channel, if it has one. The CDConnect exists until it is no longer accessible (when it will be destroyed automatically) or until it is explicitly destroyed.
The following figure summarizes the differences between the Connect() and the SetServer() methods.
Establishing the Namespace
When you connect to a server, the namespace is initially set to the current namespace of the superserver, which is generally not a suitable place to execute your application code. There are three equivalent ways to switch the namespace:
Remember that changing namespace is a relatively expensive operation. In particular, the global and routine buffers are purged. For example, it would be undesirable to have messages alternating between namespaces, which would entirely eliminate the advantages of buffering data in memory. If you need to work alternately in two namespaces, you should instead establish connections to two server jobs, each running in its own namespace – then each job can take advantage of the buffering efficiencies.
Executing Code
There are two general ways to use Caché Direct to execute Caché ObjectScript:
These techniques have exactly the same net effect. (When you call Execute(), the client stores the string temporarily in the Code property and internally changes the ExecFlag setting to 1.) Choosing one method or the other depends on the application. If the code string is not changing, or is chosen by some separate computation, the ExecFlag technique is slightly more convenient. If you just need to execute a line of code, the Execute() technique is more convenient and more direct.
The line of code to be executed can be any legal line of code or expression.
If you call Execute() and the client fails to connect to a remote Cache instance, Caché Direct will try to connect to the default server. This behavior allows an application, including a non-interactive one, to connect to a default server without having to prompt the user or code the server into the application. If there is no default, then the client will prompt the user with a 'Communication Error' dialog. Clicking the 'Cancel' button causes the client to connect to the local default instance.
Because it is common to evaluate expressions, there is a useful convention: the server looks at the beginning of the line of code and tries to determine if the line has the form of an expression. Specifically, it checks whether the line begins with an equal sign or at least one dollar sign. If so, the server code prepends either "Set VALUE " or "Set VALUE = " to create a command that sets the VALUE property to the result of the expression. For example, "$zv" on the client side would be expanded to "Set VALUE=$zv" on the server side. Except for this special treatment, the VALUE property is no different from any of the other mirrored properties; see the next section.
Using Mirrored Properties
Caché Direct mirrors the values of certain VisM properties between the client and server, as follows.
  1. When the client communicates with the server, it creates a message that contains the values of the mirrored properties (as well as other needed information). When the server receives the message, it creates and sets local variables that have the same names.
  2. On the server side, you can use the local variables in the same way you would use any other local variables. There are no limitations on how you can use them, including, for example, indirection.
  3. When the server replies, it creates and sends another message that contains the values of all the mirrored properties, whether or not they have changed, as well as other information.
  4. The server then destroys (via $KILL) these local variables (but leaves your other local server variables untouched).
    Therefore the mirrored variables are not preserved on the server between calls; they exist only while the server is executing a client command.
Using Basic Mirrored Values
The basic VisM properties that are mirrored are string properties named P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, and VALUE. When the server is executing a client command, the server process will have local variables with the same names, with values equal to the properties in VisM. A change on the server is followed by a change to the properties on the client when the response message is received from the server.
For the VALUE property, there is one additional feature. If the value of the Code property is an expression (that is, if it begins with a dollar sign or an equal sign), then the server returns the result of that expression in the VALUE property, as noted in the section on Executing Code.
Using PLIST
One other VisM property is mirrored, the PLIST property. Caché Direct uses this property to pass array-like values between the server and client. Because the client and Caché have different representations of arrays, it is important to understand the transformations in both directions. The PLIST property has a different form in these two environments:
If the PDELIM property is an empty string, PLIST is considered to be a single piece.
When the server assembles its reply message, it treats PLIST as follows:
The preceding behavior means that typically if the server changes the number of list elements, it should either update PLIST to the new count or clear PLIST (and let the server count the list elements).
Callbacks to the Visual Basic User Interface
If you use Visual Basic, VisM includes a special feature that allows your Caché ObjectScript code to refer to elements of the client user interface. These property and method references are called callbacks because they cause a message to be sent from the server to the client when the reference is made. The client looks up the form and control, issues an OLE call, and returns the result to the server.
Specifically, you can access properties of any controls on the client user interface, via getter and setter methods. Your ObjectScript can also use the following Visual Basic methods, if your form includes controls that provide these methods:
Requirements to Support Visual Basic Callbacks
In order to make callbacks available for a particular form, there are two requirements:
Referring to Properties of a Control
To refer to a property of a control, use the following special ObjectScript syntax:
_[formname!]controlname[(controlindex)].propertyname[(propertyindex)]
The elements in square brackets are optional, and the brackets are not part of the syntax. The leading underline is required. If you omit formname, it is assumed to be the form whose VisM sent the current message. The controlname and propertyname are required. If the control is one of a collection, controlindex is required. If the property is a collection, propertyindex is required. For example, to get the text property of a text control named txt1 on the current form, use the following code:
Set x=_txt1.Text
To set the text property, use the following code:
Set _txt1.Text="something"
Because the underline is also a concatenation operator in ObjectScript, if there is any ambiguity about its meaning, use parentheses.
Executing Methods of a Control
To execute a method of a control, use the following syntax:
Do _[formname!]controlname[(controlindex)].method[(args)]
For example, to add an item to a list box named list1, use the following code:
Do _list1.AddItem("item data")
Using Windows Functions and Caché Utility Functions
Your ObjectScript code can also use the following general Windows functions:
Also, it can use the following Caché Direct utilities, also available in the %CDSrv routine:
To execute any of these functions, use syntax like the following:
Set varname=$$function^%CDSrv(arguments)
For example, to call the Windows MsgBox function, use code like the following:
Set reply=$$MsgBox^%CDSrv("Are you finished?",1)
Understanding Message Constraints
All communication between the CDConnect and the server is done as Caché Direct messages. These messages are sent over TCP connections (even when all components are local).
There are certain constraints on messages that in turn impose constraints on how you set the properties whose contents are sent in the messages. These constraints also affect how you write callbacks. While you do not need to know the internal details of the message structure, a general description is useful. Generally, a message consists of a 56-byte header followed by a series of fields for the data. Flags in the header describe the type of message and, by implication, what fields to expect. Types of messages include NewTask, BeginTask, ExecuteCode, EndTask, and other types. In addition to internal information, the message includes the mirrored properties plus a few additional ones noted in the Other VisM Properties section.
Unicode and Locale Issues
For all properties that are sent to the server, the values must have only text characters. This restriction also applies to any Visual Basic properties that are set or retrieved by Caché Direct; see the section Callbacks to the Client User Interface. (There are exceptions to this constraint that work in some environments, but the general requirement still exists.)
Caché servers operate in either 8-bit or 16-bit (Unicode) mode. In the initial communications between the client and server, the server notifies the client of the mode of the server. Then:
Note:
The requirement for properties to be strings arises from the conversions that are performed for Unicode servers. However, there are two situations in which non-text data is preserved: 8–bit servers and control codes with values in the range $c(1) to $c(31).
Because no conversion occurs for 8–bit servers, no corruption can take place. And because the low-range control codes are the same in all 8–bit locales and in Unicode, they also survive for any server.
However, because the client is written in C++ and uses C string conventions, embedded null values ($c(0)) may cause strings to be truncated.
Message Size
For historical reasons, the limit on the size of a single message in either direction between the client and server is 32Kb. Caché Direct does not split long messages into multiple shorter messages and cannot recover from an attempt to send a message that is too large. As a result, it is the responsibility of your application to make sure that no attempt is made to construct a message that exceeds this limit. To transmit more data than that, you send a series of messages. Tests have shown that there is no speed penalty for this arrangement, because TCP breaks large messages into small segments for transmission. All else being equal, optimum speed – in terms of total bytes per second – seems to be achieved with messages in the 12-20 Kb range.
To estimate message size, consider all characters in the VisM properties that are sent to the server, plus a few hundred bytes of overhead. The properties sent are the mirrored properties, plus a few smaller ones like CODE and NameSpace. A normal message has about a dozen fields plus the pieces of the PLIST property, which are each transmitted as a field. The data fields are one byte per character if the server is 8-bit or if the string is all Latin-1 characters. (Latin-1 characters have no bits on in the high byte of their Unicode representation. Such strings can be sent as 8-bit strings.) If the server is Unicode and the property contains any non-Latin-1 characters, the field contains two bytes per character. The result is that the maximum capacity of a message, instead of being about 30K characters, is less than half of that. A good guideline, which does not sacrifice any efficiency, is to make sure none of your messages are larger than about 12K characters.
Examples
Simple Example: A Lightweight Caché Terminal
This is a minimal sample application that shows how to create a single client form in Visual Basic, where the user can enter a single line of Caché ObjectScript and get its result. You will use defaults wherever they are available. There is also almost no error checking.
This sample assumes you have a Caché server running on your local machine and have also installed the Caché Direct components. Make sure Caché is running locally on your machine.
Start Visual Basic. Create a new Standard EXE project with one form. Using the Project/Components menu, add the VisM control to your toolbox. On your form, add a command button (Command1), two text boxes (Text1 and Text2), and a VisM control. Make the first text box wide enough to enter a simple line of Caché ObjectScript and the second big enough to hold a result string. In the Command1_Click event code, enter the following:
VisM.Execute Text1.Text
If VisM1.Error <> 0 Then
   Text2.Text = "Error " & VisM1.Error & ": " & VisM1.ErrorName
Else
   Text2.Text = VisM1.VALUE
Endif
In the Form_Unload method, add the following line:
VisM1.Server = ""
Run the project. When the form appears, click the command button. You should get a Choose Server Connection dialog. Choose LOCALTCP and press OK. Leave the Text1 field empty and click the Command1 command button. A syntax error message should appear in Text2, because you did not enter a line of Caché ObjectScript.
Now enter "$H" in Text1. Click the command button again. The current date and time in $H format should appear in Text2.
Then exit the application.
Explanation
When you click the command button, the contents of Text1 are temporarily put into the VisM Code property and sent to the server to be executed (by means of the VisM Execute() method). On the first click, because “Text1 ”(the default contents of the text box) is not valid Caché ObjectScript, you receive a syntax error in the Error and ErrorName properties. The code in the Command1_Click event routine displays the error in Text2.
In the second case, the server can execute the code you provide, and it sets the VALUE property to the current $H. The code in the Command1_Click event routine again displays the contents of the VALUE property in the Text2 text box.
As you exit, the code in the Form_Unload event routine sets the Server property to the empty string, which disconnects the client from the server gracefully.
On the one hand, this is clearly a very simple example. On the other hand, it is also very powerful. Any line of ObjectScript can be executed on the client and any (small) result can be retrieved and displayed. A value from a global could be retrieved. A computation could be performed and the result returned. You could start a long-running background process via $JOB.
Another Example
Consider the following example code:
VisM1.P0 = "pig"
VisM1.Execute "Set VALUE=$e(P0,2,$l(P0))_$e(P0,1)_""ay"""
Print VisM1.VALUE
This would result in the VALUE property being set to "igpay". In slightly more detail, the P0 property is sent to the server and becomes a local server variable named P0. The server executes the line of code, which computes a variable named VALUE, and sends a message back to the client. The client updates the VALUE property correspondingly and then prints it.