Compaq TP Desktop Connector
for ACMS
Client Application Programming Guide


Previous Contents Index

4.5.3 Establishing an Exit Handler

If the desktop client program uses the standard C routines atexit or onexit to establish an exit handler, and the exit handler calls acmsdi_sign_out, make the call to atexit or onexit after the first call to acmsdi_sign_in. If this precaution is not taken, the exit handling built into TP Desktop Connector occurs before the desktop client program exit handler call to acmsdi_sign_out, the submitter or submitters are already signed out, and the desktop client program gets error statuses that can be ignored.

4.5.4 Calling Tasks and Signing Out

For examples that handle menu traversal, task selection, and sign-out, see the MENU.CBL and LOGOFF.CBL programs from the AVERTZ sample desktop client program.

4.5.5 Passing Multiple Workspaces on acmsdi_call_task

Some TP Desktop Connector client applications may need to pass workspaces on the call to the acmsdi_call_task service. Applications that use NO I/O tasks, for example, must pass workspace data as a parameter of the acmsdi_call_task service.

To do this, the application must create an array of workspace descriptors, which is then passed as the workspaces parameter on acmsdi_call_task.

The workspace descriptor type, ACMSDI_WORKSPACE, is used to describe the size and address of the workspace. The client application can use the ACMSDI_INIT_WORKSPACE macro to create each ACMSDI_WORKSPACE descriptor.

The workspace array should contain a workspace descriptor for each workspace that is to be passed on acmsdi_call_task. Example 4-7 illustrates how an application passes three workspaces on the acmsdi_call_task() service.

Example 4-7 Passing Three Workspaces

ACMSDI_WORKSPACE wksp_array[3];   /* Declare array of wksp descriptors */ 
  
struct { 
  char ctrl_key[5]; 
  char message[80]; 
} control_wksp; 
 
struct { 
  int  id_number; 
  char first_name[15]; 
  char last_name[25]; 
} employee_record; 
 
struct { 
  int  dept_id; 
  char dept_name[15]; 
} department_record; 
int status; 
 
/* 
**  Create the workspace descriptors 
*/ 
 
ACMSDI_INIT_WORKSPACE(wksp_array[0], control_wksp); 
ACMSDI_INIT_WORKSPACE(wksp_array[1], employee_record); 
ACMSDI_INIT_WORKSPACE(wksp_array[2], department_record); 
 
/* 
**  Pass the number of workspaces passed (3) along with 
**  the array of workspace descriptors on the call to 
**  acmsdi_call_task() 
*/ 
 
status = acmsdi_call_task(submitter_id, 
                          NULL, 
                          "MY_TASK", 
     "MY_APPL", 
     NULL, 
     call_status, 
     3, 
     wksp_array, 
     NULL, NULL, NULL, NULL); 

4.5.6 Using Unidirectional Workspaces on acmsdi_call_task

When an application passes workspaces on a call to the acmsdi_call_task service, the unidirectional-workspaces option allows the application to specify which of those workspaces are read-only workspaces, which are write-only workspaces, and which are modify workspaces. See Section 2.4.5.1 to determine what is meant by read-only and write-only for the purposes of the unidirectional workspaces feature.

To use the unidirectional-workspaces option:

  1. Enable the OPTIMIZE_WORKSPACES option in the client program's call to acmsdi_call_task.
  2. Create an array of unidirectional-workspace descriptors to be passed on the call to acmsdi_call_task.

For unidirectional workspaces, the application must use the ACMSDI_WORKSPACE_OPT type in order to specify an access type for each workspace. The workspace descriptor type, ACMSDI_WORKSPACE_OPT, is used to describe the size, address, and access type of the workspace. The access type of each workspace must be specified as either ACMSDI_ACCESS_READ, ACMSDI_ACCESS_WRITE, or ACMSDI_ACCESS_MODIFY.

The client application can use the ACMSDI_INIT_WORKSPACE_OPT macro to create each ACMSDI_WORKSPACE_OPT descriptor. The workspace array should contain a workspace descriptor for each workspace that is to be passed on acmsdi_call_task. Example 4-8 illustrates how an application passes three workspaces on the acmsdi_call_task() service.

Example 4-8 Passing Unidirectional Workspaces

ACMSDI_CALL_OPTION   call_options[2]; /* Declare call options array */ 
 
ACMSDI_WORKSPACE_OPT wksp_array[3];   /* Declare unidirectional wksp 
                                      ** descriptors array 
                                      */ 
  
struct { 
  char ctrl_key[5]; 
  char message[80]; 
} control_wksp; 
 
struct { 
  int  id_number; 
  char first_name[15]; 
  char last_name[25]; 
} employee_record; 
 
struct { 
  int  dept_id; 
  char dept_name[15]; 
} department_record; 
 
int status; 
 
/* 
** Create the unidirectional workspace descriptors 
*/ 
 
ACMSDI_INIT_WORKSPACE_OPT(wksp_array[0], control_wksp, ACMSDI_ACCESS_WRITE); 
ACMSDI_INIT_WORKSPACE_OPT(wksp_array[1], employee_record, ACMSDI_ACCESS_READ); 
ACMSDI_INIT_WORKSPACE_OPT(wksp_array[2], department_record, ACMSDI_ACCESS_MODIFY); 
 
/* 
**  Turn on the unidirectional workspace call option 
*/ 
 
call_options[0].option = ACMSDI_CALL_OPT_OPTIMIZE_WKSPS; 
call_options[1].option = ACMSDI_CALL_OPT_END_LIST: 
 
/* 
** Pass the call options array, along with the number 
** of workspaces passed and the array of unidirectional 
** workspace descriptors, on the call to acmsdi_call_task() 
*/ 
 
status = acmsdi_call_task(submitter_id, 
                          call_options, 
                          "MY_TASK", 
       "MY_APPL", 
     NULL, 
     call_status, 
     3, 
     wksp_array, 
     NULL, NULL, NULL, NULL); 

Note

The ACMSDI_CALL_OPT_OPTIMIZE_WKSPS option tells the TP Desktop Connector client services to interpret the array of workspace descriptors as data type ACMSDI_WORKSPACE_OPT. The workspace optimization option and the ACMSDI_WORKSPACE_OPT must be used together, or not at all. Using one without the other produces unpredictable results.

4.5.7 Providing Stub Routines

ACMS task definitions do not have to include exchange steps, as is the case with tasks that include only processing steps and specify NO TERMINAL USER I/O as the I/O method. For these tasks, you do not write presentation procedures. However, in your desktop client program, you must supply stub routines for all possible entry points, that is, presentation procedures and action routines (for example, acmsdi_check_version).

The TP Desktop Connector client services refer to all the presentation procedures and the acmsdi_check_version routine. If you do not have code for one or more of these routines in your desktop client program, provide a stub for the linker to use to resolve these references.

Stubs for all presentation procedures and the acmsdi_check_version routine are provided in the file PPSTUBS.C. PPSTUBS.C provides stubs for the following routines:

Note

The file PPSTUBS.C is provided in the ACMSDI$COMMON directory on the OpenVMS system. Copy this file to the desktop system when the TP Desktop Connector client services software is installed.

To use this source code, follow these steps:

  1. Edit or comment out any of the presentation procedures that you implement as part of your desktop client program.
  2. Edit or comment out the acmsdi_check_version routine if you provide your own version-checking routine.
  3. Compile the module in the appropriate memory model.

Include the resulting object module in your LINK command or in your application object library (see Example 4-11).

4.6 Writing Presentation Procedures in a Blocking Environment

If your ACMS tasks include exchange steps, write presentation procedures in your desktop client program to handle the interaction with the user required by these exchange steps. TP Desktop Connector software invokes a given presentation procedure when it receives from the desktop gateway an exchange step message corresponding to that procedure.

Your desktop client program must include presentation procedures that correspond to any of the exchange step types actually used in your task definitions:

TP Desktop Connector client services call acmsdi_read_msg when a TDMS Read exchange is received from the TP Desktop Connector Gateway for ACMS on the host OpenVMS system. The acmsdi_read_msg presentation procedure displays the prompt, if any, sent from the ACMS task, then acquires the text from the form's Message Field to be returned to ACMS.

TP Desktop Connector client services call acmsdi_write_msg when a TDMS Write exchange is received from the TP Desktop Connector Gateway for ACMS on the host OpenVMS system. The acmsdi_write_msg presentation procedure displays the message text sent from the ACMS task in the form's Message Field. See Compaq TP Desktop Connector for ACMS Client Services Reference Manual for the syntax of these procedures.

For a FORM I/O task, include the following presentation procedures as well:

See Section 4.6.1 for more information on acmsdi_enable and acmsdi_disable.

In the AVERTZ sample application, these presentation procedures in turn call routines that correspond to the specific exchange step in which the SEND, RECEIVE, TRANSCEIVE, or REQUEST keyword is used.

Example 4-9 shows the TRANSCEIVE presentation procedure, in file trans.c from the AVERTZ sample application.

Example 4-9 TRANSCEIVE Presentation Procedure

long acmsdi_transceive(ACMSDI_FORMS_SESSION_ID *session_id, 
                       char *send_record_id, 
                       long send_record_count, 
                       char *recv_record_id, 
                       long recv_record_count, 
                       char *recv_ctl_text, 
                       long *recv_ctl_text_count, 
                       char *send_ctl_text, 
                       long send_ctl_text_count, 
                       short timeout, 
                       ACMSDI_CALL_ID *call_id, 
                       void *call_context, 
                       ACMSDI_FORM_RECORD *send_records, 
                       ACMSDI_FORM_RECORD *recv_records )  (1)
 
{ 
long int sts; 
short int i; 
 
    if (send_record_id == NULL) 
        return (FORMS_BADARG); 
 
    if (recv_record_id == NULL) 
        return (FORMS_BADARG); 
 
    for (i = 0; i < send_record_count; i++) 
    { 
        if (recv_records[i].data_record == NULL) 
            return (FORMS_INVRECDES); 
    } 
 
    sts = FORMS_NORECORD; 
 
    if ((0 == strcmp (send_record_id, "LIST_1")) &&   (2)
        (0 == strcmp (recv_record_id, "LIST_2"))) 
    { 
        /* 
        **  Validate arguments 
        */ 
        if ((send_record_count != 2) || 
            (recv_record_count != 4)) 
            return (FORMS_BADRECCNT); 
 
        if (send_records[0].data_length != 123) 
            return (FORMS_BADRECLEN); 
 
        if (send_records[1].data_length != 1730) 
            return (FORMS_BADRECLEN); 
 
        if (recv_records[0].data_length != 138) 
            return (FORMS_BADRECLEN); 
 
        if (recv_records[1].data_length != 144) 
            return (FORMS_BADRECLEN); 
 
        if (recv_records[2].data_length != 255) 
            return (FORMS_BADRECLEN); 
 
        if (recv_records[3].data_length != 123) 
            return (FORMS_BADRECLEN); 
 
   .
   .
   .
        /*     
        **  Call Presentation Procedure 
        */     
 
        GETSITE (                                        (3)
             session_id, 
             form_data, 
             send_ctl_text, /** VR_SENDCTRL_WKSP **/ 
             send_records[0].data_record, /** VR_CONTROL_WKSP **/ 
             send_records[1].data_record, /** VR_SITES_WKSP **/ 
             recv_records[0].data_record, /** VR_SITES_WKSP **/ 
             recv_records[1].data_record, /** VR_RESERVATIONS_WKSP **/ 
             recv_records[2].data_record, /** VR_CUSTOMERS_WKSP **/ 
             recv_records[3].data_record  /** VR_CONTROL_WKSP **/ 
                    ); 
 
        sts = FORMS_NORMAL; 
 
    } /** end if strcmp **/ 
                  . 
                  . 
                  . 
 
    return (sts); 
} 

The following key points are called out in the example:

  1. The acmsdi_transceive presentation procedure is called when a TRANSCEIVE exchange step executes in the ACMS task.
  2. The procedure looks at the contents of the send and receive record identifier fields to determine what second-level, application-specific routine to call. This is termed the application-specific presentation procedure.
  3. The desktop client program runs the presentation procedure.

In Example 4-10, the GETSITE.CBL program receives data from the acmsdi_transceive presentation procedure.

Note

PPGEN.COM is a sample tool that generates these generic presentation procedures based on task definitions in the TDB. PPGEN.COM determines the appropriate record counts, data record lengths, and so on, for each application-specific presentation procedure. PPGEN.COM is located in ACMSDI$EXAMPLES.

Example 4-10 GETSITE Application-Specific Presentation Procedure

       PROCEDURE DIVISION USING 
                          SESSION-ID, 
                          FORM-DATA, 
                          VR-SENDCTRL-WKSP, 
                          CONTROL-IN, 
                          SITES-IN, 
                          VR-SITES-WKSP, 
                          VR-RESERVATIONS-WKSP, 
                          VR-CUSTOMERS-WKSP, 
                          VR-CONTROL-WKSP. 
   .
   .
   .
      * 
      *    Distribute data 
      * 
           PERFORM 010-INITIALIZE-RECS 
               THRU 010-INITIALIZE-RECS-EXIT. 
           MOVE SITES-IN TO VR-SITES-WKSP.  (1)
           MOVE CORRESPONDING VR-SITES-WKSP TO FORM-DATA. 
           MOVE CONTROL-IN TO VR-CONTROL-WKSP. 
           ACCEPT CURRENT-DATE FROM DATE. 
           MOVE CORRESPONDING CURRENT-DATE 
                TO CHECKOUT-DATE-2, RETURN-DATE-2. 
           MOVE THIS-CENTURY 
                TO CC OF CHECKOUT-DATE-2, 
                   CC OF RETURN-DATE-2. 
   .
   .
   .
      * 
      *    Collect data from screen                      (2)
      * 
           MOVE CORRESPONDING FORM-DATA TO VR-SITES-WKSP. 
           MOVE CORRESPONDING FORM-DATA TO VR-CUSTOMERS-WKSP. 
           MOVE CORRESPONDING FORM-DATA TO VR-RESERVATIONS-WKSP. 
           MOVE CORRESPONDING RETURN-DATE 
               TO VEHICLE-EXPECTED-RETURN-DATE. 
           MOVE CORRESPONDING CHECKOUT-DATE 
               TO VEHICLE-CHECKOUT-DATE. 
   .
   .
   .
      * 
      *    Validate site and customer 
      * 
           IF ((CUSTOMER-ID OF FORM-DATA EQUAL ZERO) AND   (3)
               (CU-LAST-NAME OF FORM-DATA = SPACES AND 
                CU-FIRST-NAME  OF FORM-DATA = SPACES)) 
           THEN 
               MOVE 'N' TO VALID-DATA-FLAG 
               MOVE "Either CUSTOMER ID or NAME is required" 
                   TO MESSAGEPANEL OF VR-CONTROL-WKSP 
               MOVE 5 TO CURSOR-LINE 
               MOVE 15 TO CURSOR-COLUMN 
           ELSE 
           IF ((SITE-ID OF FORM-DATA EQUAL ZERO) AND 
               (CITY OF FORM-DATA EQUAL SPACES)) 
           THEN 
               MOVE 'N' TO VALID-DATA-FLAG 
               MOVE "Either SITE ID or CITY is required" 
                   TO MESSAGEPANEL OF VR-CONTROL-WKSP 
               MOVE 11 TO CURSOR-LINE 
               MOVE 11 TO CURSOR-COLUMN 
           END-IF. 
 
           IF (NOT VALID-DATA) THEN GO TO 100-GET-DATA-EXIT. 
      * 
      *    Validate dates and car type 
      * 
   .
   .
   .
       100-GET-DATA-EXIT. 
           EXIT.             (4)
   .
   .
   .
       END PROGRAM "_GETSITE". 

The GETSITE program does the following:

  1. Displays to the user the data received from the generic presentation procedure.
  2. Accepts new data.
  3. Verifies the data.
  4. Returns the new data to the acmsdi_transceive procedure.

4.6.1 Coding for acmsdi_enable and acmsdi_disable

If your tasks use any of the three DECforms exchange step types (SEND, RECEIVE, TRANSCEIVE), supply these presentation procedures:

4.6.2 Coding Return Status Values

ACMS software expects specific return values from the presentation procedures. These values correspond to the DECforms forms or the TDMS request return values that the customer-written procedure server receives as if the exchange is actually handled by these forms products on the OpenVMS system. In writing presentation procedures, ensure that the values the desktop client program returns to the ACMS system are valid OpenVMS status values.

See Appendix B for more information on determining these status values.

4.7 Building and Debugging the Desktop Client Program

Compile and link the desktop client program as you would any program.

4.7.1 Linking the Desktop Client Program

Link the executable desktop client program with the debug qualifier initially to look for these problems:

Link the desktop client program with the following types of libraries:

Example 4-11 shows the desktop client program client.obj being linked with the appropriate libraries on DOS:

Example 4-11 Linking to the DOS TP Desktop Connector Client Services

C:\>  link /STACK=n client,,,client.lib+acmsdil.lib+lnetv4.lib+llibce.lib
C:\> 

If the libraries do not reside in the current directory, set the LIB environment variable to include the directory, for example:


C:\>  set lib=c:\msvc\include;c:\acmsdi

The /STACK qualifier defines the desired stack size (1000 bytes plus whatever is required by your application).

After generating the executable file, run it as you would run any DOS program.

After you test your presentation code, relink it without the debug qualifier. See Compaq TP Desktop Connector for ACMS Gateway Management Guide for a description of how to manage the application after testing it.


Previous Next Contents Index