|
||||||||||||||||||||||||||||||||||||
|
5.1. Overview
5.4. AutoStart Processes 5.1. OverviewThis chapter contains an introduction to the features of the UCM Active-X control Ucm.ocx. To make full use of the control, it is important to understand the underlying concepts. Please read the following section carefully. All examples used in this chapter assume a VB program with a form named Form1 containing an UCM control named Ucm1. 5.2. UCM MessagesAn UCM message consists of a message ID and the message body. The message ID serves as the lowest level addressing component in the data transport. Sending a message requires the OutputID(P) property to be set. To receive UCM messages a control must set the InputID(P) property to the message type it is ready to accept. Except when specifying the wildcard ID "*", which means 'any', only one message type can be received by a control at a given time.
5.3. Addressing Methods5.3.1. Message IDUCM supports several addressing methods. As stated above, the message ID constitutes the lowest level in the addressing scheme. It controls data distribution of messages sent from the local or a remote system. The control in the following example will receive all local and remote messages with ID someID:
The special wildcard InputID "*" matches any message ID value. 5.3.2. TCP/IP AddressThe next higher addressing level consists of the TCP/IP address of the server thread or process. To establish a TCP/IP Client-Server connection, the client must know the IP address of the system providing the server functionality. In addition, each connection type is identified through a unique port number. The TCP/IP hosts and services control files define symbolic names for the standard IP addresses (hosts) and for most of the ports (services) used in a network environment. Using these symbolic names requires the hosts and services file to be present on each network node, i.e. on the host and on all client systems. On Unix systems, the files are located in the /etc directory. On Windows systems the location varies depending on OS type and version. Each line in the hosts file contains the standard four number IP address and one or more symbolic alias names. Each line in the services file holds the service name, a port number and a port type (for UCM communication the type should always be tcp). To avoid conflicts with standard TCP/IP ports, these numbers should have values > 5000 assigned by convention. Unitec products use port numbers in the range from 6800 to 6999.
There remains one problem: what if two invocations of the same program are running? Since they both use the same message IDs on say Form1, and the same TCP address, will not each program also get response messages to requests that origin from the other copy of the program? The answer is yes, they both share the same socket (i.e. communicate with the same copy of the server thread or process) and the broadcast feature of UCM will duplicate input messages for each control listening for the same message ID. This might be what we require, but normally it is exactly the behavior we do not want. Before introducing the highest addressing level, the communication space, we have to take one more close look at the example above. The AdrMode(P) property is used as: Ucm1.AdrMode = ucmTCP An alternative to the ucmTCP mode is ucmService. It uses the Service(P) property to specify the server address instead of the Host and Port properties. By using the UcmConf(U) utility, a symbolic service name can be defined for a host and port address pair. This UCM service name can then be assigned to the Service property. When installing software in many different environments, the advantages of symbolic names that can be configured externally over hard coded addresses are obvious.
5.3.3. Communication SpaceRemember the problem of two or more concurrent invocations of the same program described above? In such a situation, we normally do not want to share the same socket connection between different processes. Starting with UCM Release 2.0 an additional addressing level, the so called communication space, has been introduced. It is identified by a long integer and can be set using the CommID(P) property. Each control belongs to a communication space, by default to ID 0 (zero). Also each socket created by the client side communication manager Ucm.exe, belongs to a communication space, namely to the space of the control, that caused the socket to be established. With one exception (explained below), input messages are not distributed across communication space boundaries. Since only one connection to a given address may exist in each space, all controls referring the same TCP address and CommID share one single connection. In local communication, the CommID of the sending control identifies the target space. It is important to note, that communication spaces are system local entities. The server does not need to know to which space the other end of the socket belongs to. The CommID property should be set prior to the first output operation. A perfect value is the ID of the main thread of a process, since it is guaranteed to be unique:
|
| Term | Description |
| message ID | Each UCM message is identified by an ID with data type string. Sending a message requires the OputputID(P) property to be set, whose value will become the message ID. To enable a control to receive UCM messages, the InputID(P) property must be set. Only messages that match this value will be received (i.e. will cause an DataInput(E) event to be fired). The special wildcard value "*" matches any ID. |
| message data | To launch a message transfer, the contents data must be assigned to the OutputMsg(P) property. If the AutoSend(P) property is set to True, transfer is immediate, otherwise the Send(M) method must be used to initiate the send operation. The value of an incoming message is available in the InputMsg(P) property whenever a DatInput(E) event occurs. |
| message field | UCM messages are optionally subdivided into fields. The field delimiter can be set in the Delimiter(P) property. Individual field values may be accessed with the Field(M) method and the number of fields contained in an input message is available in the NoOfFields(P) property. |
| bound control | An UCM control is said to be bound if one of
the following is true:
|
| unbound control | An Ucm control is said to be unbound, if it is not bound (see above). Output operations of unbound controls are local only. |
| communication space | Each control operates within the context of a communication space, which is identified by the CommID(P) property. Also each socket established by the communication manager is attached to a communication space, namely the space the control belongs to, that caused the socket to be created. Message forward occurs only within the given space. This enables multiple copies of the same client program to each communicate with its own server process or thread. |
| global space | The global communication space is identified by ID 0 (zero). Unbound controls will receive input messages from any space when their InputID(P) matches the ID of the message to be distributed. |
With the help of the configuration utility UcmConf(U) automatic program startup on message arrival can be defined. Each entry in the AutoStart table defines a message type (InputID) and the full path to the executable that will handle that message. Whenever a message (local or remote) has to be delivered, and no active UCM control is currently ready to receive that message type (i.e. has its InputID property set to the type in question), the communication manager scans the AutoStart table for a matching entry. If an entry is found, the program specified is started automatically. One of the first actions an AutoStart program must perform, is to initialize an UCM control with the required InputID. Failing to do so may lead to multiple invocations of the same program and to undeliverable messages that will be silently discarded.
UCM connections are dropped automatically when the last Active-X control object using the socket exits, i.e. when the container of the control terminates.
When an error occurs, UCM controls fire the Error(E) event. Why does UCM not use the Err object and the error trapping methods built into the VB language? Communication errors are not immediate, an application program just initiates operations that are handled asynchronously by UCM. Waiting for each communication request to terminate would lead to unacceptable slow programs. All error events will thus happen unsolicited.
Communication errors must normally be considered as severe. The situation can be compared to memory allocation failures, where in almost all cases, there exists no reasonable way to continue execution of a program. The same holds true for UCM errors.
Since multiple UCM controls may be using the same communication link, all of them might receive the same Error(E) event, e.g. when a connection is dropped by the remote process. Error handling in such situations is a little bit tricky, since you must prevent multiple user notifications for the same error. The code involved might look like this:
| Option Explicit Public g_ucmError as Boolean Public Sub UcmError(ByVal ErrNumber As UcmOcx.ucmErrors, _ ByVal ErrText As String) If (g_ucmError) Then Exit Sub End If g_ucmError = True If (ErrNumber = ucmErrHost _ Or ErrNumber = ucmErrServiceUnknown) Then Call MsgBox("No connection could be established." & vbCr & _ "Please verify your host or port configuration.", _ vbInformation, "UCM Error") Call TermApp ' terminate application Exit Sub End If If (ErrNumber = ucmErrMngrShutdown) Then Call MsgBox("The UCM manager has been stopped!" & vbCr & _ "Please restart your program.", _ vbInformation, "UCM Error") Call TermApp ' terminate application Exit Sub End If Call MsgBox("A communication error has occurred!" & vbCr & _ "Please close your program and restart.", _ vbInformation, "UCM Error") Call TermApp ' terminate application End Sub |
Once the public g_ucmError flag is set, UCM output should be
avoided. This is best done by wrapping output operations like this:
| If (Not
g_ucmError) Then Ucm1.OutputMsg = "some output" End If |
As a final step, implement error event handling for each control:
| Private Sub Ucm1_Error(ByVal
ErrNumber As UcmOcx.ucmErrors, _ ByVal ErrText As String) Call UcmError(ErrNumber, ErrText) End Sub |