# Compaq TP Desktop Connector
for ACMS
Client Application Programming Guide

Previous | Contents | Index

## 8.2.5 Ending an Active Session

To end an active session, the desktop client program calls DBEnd as shown in Example 8-12.

Example 8-12 Calling DBEnd

    short    status;        /* Status Variable */
    long     sessid1;       /* Session Id   */

    status = DBEnd (sessid1, NULL);

The DBEnd service also deletes a zombie session created by the DBInit service.

If an error status is returned on the DBEnd service, the session resources are still returned to the Macintosh system and any active connection is broken. You cannot call the DBGetErr service to obtain additional information about an error on the DBEnd service.

In the HyperCard implementation of AVERTZ, DBEnd is called by the ACMSEnd XFCN, invoked in the main stack script, as shown in Example 8-13.

Example 8-13 Calling ACMSEnd

    on killSession sessionID
       .
       .
       .
            put ACMSEnd (sessionID) into stat
       .
       .
       .
    end killSession

## 8.2.6 Getting Error Information

A desktop client program calling a TP Desktop Connector client service on the Macintosh typically expects a return status of NoErr.1 If the desktop client program receives an unexpected return status, it can usually call the DBGetErr service to retrieve additional information concerning the error condition. For the specified session identification, the DBGetErr service returns the information shown in Table 8-5.

Table 8-5 DBGetErr Information
Parameter | Information
--- | ---
err1 | TP Desktop Connector DDEV status value (--4000 range)
err2 | ACMS system status value (--3000 range), status value from the communications toolbox in use by the session (--1 or 0 through 11), or other status values
item1 | Symbol name for the status value returned in the err1 parameter
item2 | Symbol name for the status value returned in the err2 parameter
errorMsg | Symbol name for the status returned on the original TP Desktop Connector client service call

Using information returned in the DBGetErr parameters, the desktop client program can decide how to handle the error condition. Depending on the error, the condition is possibly recoverable. For example, if the return status from the DBState service indicates that a requested task cannot be accessed for security reasons (ACMSDI_SECCHK is returned in the err2 parameter), the desktop client program can simply report the error to the user and allow another task selection without signing the user out of the ACMS system.

Many errors returned on TP Desktop Connector client services are not recoverable. If an unrecoverable error is specific to a particular sign-in, the desktop client program can simply terminate the session and continue processing for other sessions. If the error is more severe, the desktop client program can report the problem to the user, terminate all active sessions, and exit. Example 8-14 shows example code calling the DBGetErr service.

Example 8-14 Calling DBGetErr

    /*
     *  EXIT PROCEDURE - Call DBGetErr to see what happened
     */
    my_exit (short status, long sessid1, char *msg )
    {
        static long int error1;           /* Error Declarations for DBGetErr */
        static long int error2;
        static char     item1[255];
        static char     item2[255];
        static char     errorMsg[255];
        static long int error_status;

        printf ("\n Returned Status code is %d, Message is %s\n", status, msg );

        if (sessid1)
        {

        error_status = DBGetErr(sessid1,&error1,&error2,&item1,&item2,&errorMsg,NULL);
        if (error_status != noErr)
               printf (" DBGetErr error code is %d\n", error_status);
        else
        {
          printf(" Primary Error Message is %s\n",&errorMsg[1]);
          printf(" Error Message one is %s\n",&item1[1]);
          printf(" Error Message two is %s\n",&item2[1]);
          printf(" Status code one is %d, Status code two is %d\n", error1, error2);
        }

               status = DBEnd (sessid1, NULL);
               if (status != noErr)
                       printf (" DBEnd error code is %d\n", status);

               printf( "\n" );

        }

        exit (0);
    }

Because the DBGetErr service requires a valid session identification as a parameter, errors returned on the DBInit service require special handling. If an error occurs on a DBInit call, a session is established but no connection to the ACMS system is established. In most cases, a session identification and the bad return status are passed back to the desktop client program. The desktop client program should handle all errors on DBInit; if the desktop client program receives a bad return status and a session identification on the DBInit call, it must provide special handling for this session, known as a zombie session. The zombie session associated with this session identification differs from a normal session in the following ways:

- A zombie session has no connection to the ACMS system.
- Only DBGetErr and DBEnd services can be called using a zombie session identification.

A zombie session counts toward the maximum number of sessions supported by the TP Desktop Connector DDEV. Use the DBEnd service to remove a zombie session from the desktop system.

Two error conditions can cause a zero session identification to be returned on the DBInit service. These two error conditions are:

- "Not enough storage available to start a session"
- "Maximum sessions already exist (32)"

If a zero session identification is returned, no zombie session is allocated and no additional error information can be obtained by calling DBGetErr.

The DBGetErr service is called by the ACMSGetErr XFCN. Example 8-15 shows the call to the ACMSGetErr XFCN.

Note Some characters that can print only in a Macintosh environment are deleted from this example. Check the file supplied with TP Desktop Connector for the precise format.

Example 8-15 Calling ACMSGetErr

    function GetErr currentsession, cstring
      global gerr1, gerr2, gitem1, gitem2, gmsg
      global itemtext1,itemtext2,msgtext,errorfile,avertzlogfile

      put 0 into got1
      put 0 into got2
      put bg fld "error" into "gerr1"
      put ACMSGetErr (currentsession,"gerr1","gerr2","gitem1","gitem2",
      "gmsg")  into status
      if status <> 0 then
        return status
      end if

      open file errorfile

      repeat forever
        read from file errorfile until return
        if it is empty then
          write "Error not found" &return to file avertzlogfile
          exit repeat
        else
          if it is return then
            next repeat
          end if
          if item 1 of it = gerr1 then
            put item 2 of it into errtext1
            put 1 into got1
            if got2 = 1 then
              exit repeat
            end if
          end if
          if item 1 of it = gerr2 then
            put item 2 of it into errtext2
            put 1 into got2
            if got1 = 1 then
              exit repeat
            end if
          end if
        end if
      end repeat
      close file errorfile
      if got1 <> 0 and got2 <> 0 then
        write  "Error in "&cstring&" = "&errtext1&","&errtext2
        &gitem1&gitem2&gmsgÂ
        &" for session"&currentsession&return to file avertzlogfile
      end if
      if got1 <> 0 and got2 = 0 then
        write  "Error in "&cstring&" = "&errtext1Â
        &" for session"&currentsession&return to file avertzlogfile
      end if
      if got2 <> 0 and got1 = 0 then
        write  "Error in "&cstring&" = "&errtext2Â
        &" for session"&currentsession&return to file avertzlogfile
      end if
      if got1 = 0 and got2 = 0 then
        write "Error in "&cstring&" = "&gerr1&","&gerr2&" - text not found"
        &" for session"&currentsession&return to file avertzlogfile
      end if
      return status
    end GetErr

## 8.2.7 Canceling Active Tasks on the Macintosh System

You can cancel an active task on a Macintosh system with the DBBreak client service. You cannot use DBBreak while processing and exchange step request. If you call cancel while processing an exchange step request, TP Desktop Connector returns "ACMSDI_EXCHACTV" in DBGetErr. If you issue a cancel when another cancel is already in progress, TP Desktop Connector returns the message "ACMSDI_CANCELACTV".

If you issue a DBGetErr right after a DBBreak, you receive the status of the DBBreak, and not the task call. Issue the client services in the following sequence to receive the anticipated result:

- DBExec --- task call
- DBBreak --- cancels task
- DBGetErr --- for DBBreak
- DBState --- for status of the task
- DBGetErr --- for task call

If you are using HyperCard or 4th Dimension, you must write your own externals to cancel a session.

Note Because of limitations in the MacTCP transport, you cannot use DBBreak with this transport.

## 8.2.8 Deleting Orphaned Sessions

TP Desktop Connector provides two programs on the Macintosh system to delete an orphaned session, a session that remains active even though the application that created it has terminated. Orphaned sessions usually occur during application development, when an application aborts for various reasons leaving the session attached on the gateway end. The two programs are:

- Search and Destroy
  The Search and Destroy program is a HyperCard tool that allows you to selectively delete sessions one by one. Search and Destroy searches Macintosh memory for TP Desktop Connector sessions. As each session is found, information about that session is displayed in a window. You have the option to delete that session or continue to the next.
- end_session
  The end_session program deletes all active sessions at once, without prompting for information. Information about the deleted sessions is displayed.

Note #### 1 DBState and DBGetItem are exceptions; they do not return the NoErr status.

# 8.3 Exchange Step Support and Other Advanced Features

This section describes how to implement exchange steps in the TP Desktop Connector Macintosh client using the DAM application programming interface (API).

## 8.3.1 DAM Constraints

The DAM API assumes a strict client/server model wherein the desktop device always acts as the client requesting services of the back-end gateway. Sign In, Sign Out and CallTask are three services implemented with DAM using its client/server model. However, exchange steps change this model, reversing the roles of client and server. Thus, after a task is initiated, instead of receiving a response to the CallTask Request in the form of a CallTask Response (End Task) from the back end, the client can receive, instead, a request for services in the form of an exchange step.

The TP Desktop Connector portable API recognizes this reversal of roles by implementing special presentation procedures wherein the application running on the desktop device can play its role of gateway:

- Displaying information to the user for a Send exchange step
- Soliciting more data from the user for a Receive exchange step
- Performing both functions (displaying and soliciting) for a Transceive exchange step

The DAM API does not allow for the implementation of presentation procedure callbacks. Therefore, every transmission from the back end must be treated as if it were a response to the previous transmission from the desktop. Thus, a CallTask Request from the desktop can receive any of the following responses:

- CallTask response
- Send request
- Receive request
- Transceive request
- TDMS request

The back end can send any of these responses (four of which are actually requests) in response to any transmission from the desktop. The desktop, however, must reply to each of these responses as shown in Table 8-6.

Table 8-6 Desktop Constrained Transmissions
Transmission from the Back End | Required Transmission from the Desktop
--- | ---
CallTask response | None allowed
Send request | Send response
Receive request | Receive response
Transceive request | Transceive response
TDMS request | TDMS response

During the processing of exchange steps, the desktop becomes the gateway, and must respond with predefined message types to the back-end requests. The DDEV can do very little to assure that the proper responses are received from the back end, except to assure that:

- The back end sends only legal message types.
- A CallTask Response is eventually received.
- No exchange step requests are sent from the back end until a CallTask is sent from the desktop system.

## 8.3.2 Message Types

From the client application perspective, six message types are related to calling a task. Each message is a two-way message: request and response. See Table 8-7.

Table 8-7 Message Types
Message Type | Requestor | Respondent
--- | --- | ---
CallTask | Desktop | Back end
Enable | Back end | Desktop
Send | Back end | Desktop
Receive | Back end | Desktop
Transceive | Back end | Desktop
TDMS | Back end | Desktop

The application identifies the message types using keywords.

Table 8-8 shows the keywords and corresponding message types.

Table 8-8 Keywords
Keyword | Message Type
--- | ---
CALLTASK | CallTask request/response
ENABLE | Enable request/response
SEND | Send request/response
RECEIVE | Receive request/response
TRANSCEIVE | Transceive request/response
TDMS | TDMS request/response

## 8.3.3 Keyword Acquisition

The desktop application program can both send all keywords to the DDEV and acquire all keywords from the DDEV. The CALLTASK keyword, when acquired, identifies a CallTask Response message (End Task) from the back end. When sent, CALLTASK identifies a CallTask Request message (Start Task). All the other keywords are associated with exchange steps and identify a request from the back end when acquired, and a response from the desktop when sent.

The following sections discuss how to send and acquire keywords.

### 8.3.3.1 CALLTASK

CALLTASK is passed to the DDEV by the first of a series of prescribed DBSend or DBSendItem calls, which collectively pass all required parameters for task initiation. You do not need to acquire the CALLTASK keyword from the DDEV. If an application program knows that it is dealing with a NO I/O task, you can immediately issue DBGetItems to get workspace data. However, you can acquire the CALLTASK keyword from the DDEV, if necessary. See Section 8.3.3.3 for the method to acquire the CALLTASK keyword.

### 8.3.3.2 Keywords that Identify Messages Sent from the Back End

All keywords other than CALLTASK identify request messages from the back end. When a desktop application program does not know what kind of message it may be receiving from the back end, it needs to acquire the message's keyword from the DDEV. See Section 8.3.3.3 for the method to acquire a message's keyword.

### 8.3.3.3 Keyword Acquisition Using DBGetItem

After sending a message to the back end with DBExec, the application program issues a series of DBState calls until a status code other than rcDBExec is returned. The status code rcDBExec indicates that the transaction is executing on the back end. The two successful return statuses from DBState are:

- rcDBNull
  The task step completed successfully but returned no data.
- rcDBValue
  The task step completed successfully and data was returned.

In this context, data means workspaces with data.

When the application receives an rcDBNull or rcDBValue status, it knows it has received an error-free message from the back end. For NO I/O tasks (no exchange steps), the only message type it can receive is CallTask Response. However, with exchange steps, the application might not know what type of message has arrived.

To determine the type of message, the application issues a DBGetItem call to the DDEV to acquire the keyword. The DBGetItem has a special data type associated with it to identify the fact that it is meant to acquire a nonworkspace data item; that is, a data item that is not part of a workspace, such as the keyword. Nonworkspace data items are sometimes referred to as the message's header data.

Example 8-16 (written in C) shows how to issue a DBGetItem to acquire the message's keyword.

Example 8-16 Acquiring a Keyword with DBGetItem

    /*
    ** ELEMENTS DEFINED IN acmsdi_mac.h
    */
    #define maxKWsize 10            /* maximum keyword size */
    #define typeHdrItem 'hdit'      /* message header item data type */

    /*
    ** PROGRAM CODE FOLLOWS
    */
    unsigned short keyword_len;                /* keyword length */
    DBType dataType;                           /* data type for DBGetItem */
    char keyword[maxKWsize];                   /* keyword */
       .
       .
       .
    dataType = typeHdrItem;           /* data type is message header item */
    keyword_len = maxKWsize;          /* keyword field size */

    status = DBGetItem (sessID,       /* session ID */
              NULL,
              &dataType,              /* -> data type */
              (short *) &keyword_len, /* -> length of longest keyword */
              NULL,
              NULL,
              keyword,                /* -> where keyword to be returned */
              NULL);

In Example 8-16, all arguments except session identifier are passed by reference, because they are potentially modifiable by the DDEV. This DDEV (acmsdi), however, does not modify the data type field.

Nonworkspace data items are discussed in Section 8.3.4. The first nonworkspace data item in every logical message type is its keyword, and Example 8-16 illustrates how to obtain it. However, there is no requirement that the keyword be obtained. If you know what message type has been returned, you can start issuing DBGetItems with no data type specified to obtain workspace data.

## 8.3.4 Nonworkspace Data Items

Nonworkspace data items are data items that are not part of a workspace. For example, for a CallTask Request (Start Task), you must provide the task name and the application name. These parameters are not part of any workspace but are inserted into the header portion of the message. All messages have some kind of nonworkspace data that needs to be sent to the DDEV or, in some cases, acquired from the DDEV.

Figure 8-4 illustrates nonworkspace data.

Figure 8-4 Nonworkspace Data

### 8.3.4.1 Sending Nonworkspace Data

A CallTask Request message has the following nonworkspace data items that must be sent from the application to the DDEV:

- Task name
- Application name
- Selection string
- Number of workspaces

The four nonworkspace data items plus the keyword, to identify the message type, are sent to the DDEV by five prescribed DBSend or DBSendItem calls. This method is not restricted to CallTask Request messages. The nonworkspace data associated with the Enable, Send, Receive, Transceive, and TDMS Response messages must be sent to the DDEV in a series of DBSend or DBSendItem calls. The general rule is that you must send the keyword first, followed by each of the required nonworkspace data items in a prescribed order.

The Table 8-9 shows the items that must be sent with each message type and the prescribed order in which they must be sent.

Table 8-9 Messages Sent to the Back End
Message | Items
--- | ---
CallTask request | Keyword (CALLTASK) Task name Application name Selection string Number of workspaces
Enable response | Keyword (ENABLE) Desktop status Forms session ID
Send response | Keyword (SEND) Desktop status Receive control text Receive control text count
Receive response | Keyword (RECEIVE) Desktop status Receive control text Receive control text count Number of workspaces
Transceive response | Keyword (TRANSCEIVE) Desktop status Receive control text Receive control text count Number of workspaces
TDMS response | Keyword (TDMS) Desktop status Number of workspaces

Previous | Next | Contents | Index