Previous | Contents | Index |
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); |
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:
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); |
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. |
DIGITAL 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:
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:
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 DIGITAL 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 DIGITAL 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:
In Example 4-10, the GETSITE.CBL program receives data from the acmsdi_transceive presentation procedure.
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:
If your tasks use any of the three DECforms exchange step types (SEND, RECEIVE, TRANSCEIVE), supply these presentation procedures:
DIGITAL 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 DIGITAL 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:
By default, all of the TP Desktop Connector client libraries are configured for DECnet. The automated postinstallation procedures (available for DOS and Microsoft Windows) configure these libraries for other transports for you. To use transports other than DECnet on other platforms, you need to configure the TP Desktop Connector library yourself. See DIGITAL TP Desktop Connector for ACMS Gateway Management Guide for more details. |
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 DIGITAL TP Desktop Connector for ACMS Gateway Management Guide for a description of how to manage the application after testing it.
Previous | Next | Contents | Index |