DIGITAL TP Desktop Connector
for ACMS
Client Application Programming Guide


Previous Contents Index

  1. X Windows passes a message to the desktop client program when the user clicks on the OK button in the dialog box.
    The reserve function in resvform.c parses the Windows command and determines which presentation procedure completion routine to call, based on the current exchange request saved for the current session.
  2. (2) The session context determines which presentation procedure is completing.
  3. (3) The desktop client program calls the second part of the presentation procedure.
    Based on the pending exchange request, the reserve function calls the routine End_Trans_List3_List2 in m_avertzpp.c.
  4. (4) The End_Trans_List3_List2 routine gains control.
    Using the pointers to workspaces saved when the presentation procedure began, the routine collects new data entered from the dialog box. The session context is passed along to the application-specific presentation procedure completion routine. The completion routine can determine which workspaces to update and which call identification to pass to the acmsdi_complete_pp service.
  5. (5) The End_Trans_List3_List2 routine sends the updated arguments to the gateway.
    To send a reply to the gateway, the routine calls the acmsdi_complete_pp service, specifying a VMS completion status and the call identification that the TP Desktop Connector client services passed into the program.
  6. (6) Control returns to X Windows.

6.7 Special Handling of Workspaces for RISC Client Applications

The RISC architecture for Alpha systems requires that data references be naturally aligned. That is, short words (2 bytes) must be on an even byte boundary. Long words (4 bytes) must be accessed on a boundary evenly divisible by 4.

When an Alpha client defines a C structure, it creates padding in the structure, if necessary, to ensure that each field complies with these requirements. (The padding is not visible to you.)

An ACMS task running on either an OpenVMS VAX or an OpenVMS Alpha system, however, does not impose such restrictions on its data objects and does not pad its structures. The problem arises when data, defined on one of these machines, is transmitted across the network to the other machine, and interpreted using the same C structure definitions. In a TP Desktop Connector application, this is a concern only when ACMS workspaces are being sent (in either direction) between the client program on a RISC machine and the ACMS application (OpenVMS).

Example 6-9 shows how a sample application client program deals with incoming workspaces (or send records). Before calling the application-specific presentation procedure (Trans_List3_List2), the generic presentation procedure (acmsdi_transceive) dynamically allocates structures for all the incoming workspaces (the send_records array).

The data in the send_records array is byte copied field by field into the newly allocated workspaces (load_control_wksp()). These workspaces are then passed to Trans_List3_List2, where their contents are used to update the display. Once Trans_List3_List2() returns, acmsdi_transceive() assumes that the workspaces it dynamically allocated are no longer needed and it frees them.

Example 6-9 OpenVMS to RISC Structure Byte Copy

void load_control_wksp( 
        vr_control_wksp *control_wksp, 
            char            *data_ptr) 
{ 
 
  memcpy(&control_wksp->ctrl_key, 
         data_ptr, 
         sizeof(control_wksp->ctrl_key)); 
  data_ptr = data_ptr + sizeof(control_wksp->ctrl_key); 
 
 
  memcpy(&control_wksp->current_entry, 
         data_ptr, 
         sizeof(control_wksp->current_entry)); 
  data_ptr = data_ptr + sizeof(control_wksp->current_entry); 
   .
   .
   .
} 
long int 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 ) 
{ 
   .
   .
   .
    if ((0 == strcmp (send_record_id, "LIST_3")) && 
        (0 == strcmp (recv_record_id, "LIST_2"))) 
    { 
   .
   .
   .
          /* 
          ** Create the send workspace structures and load their 
          ** fields with the data in the send_records array. 
          */ 
 
          vr_control_wksp *send_control_wksp = 
                (vr_control_wksp *) malloc(sizeof(vr_control_wksp)); 
 
          vr_sites_wksp   *send_sites_wksp  = 
                (vr_sites_wksp *) malloc(sizeof(vr_sites_wksp)); 
 
 
          load_control_wksp(send_control_wksp, 
                           (char *) send_records[0].data_record);    
 
          load_sites_wksp(send_sites_wksp,    
                          (char *) send_records[1].data_record);    
 
   sts = Trans_List3_List2 ( 
    session_ptr, 
    send_ctl_text,               /** VR_SENDCTRL_WKSP **/ 
    send_control_wksp,           /** VR_CONTROL_WKSP **/ 
    send_sites_wksp,             /** 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 **/ 
    
          free(send_control_wksp); 
   free(send_sites_wksp); 
        }  
 
   .
   .
   .
} 

Example 6-10 shows how a client deals with outgoing workspaces (or receive records). In the sample application, the workspaces are not allocated until it is time to pull the data off the form. In the presentation procedure's completion routine, End_Trans_List3_List2(), the structures for all the presentation procedure's outgoing workspaces (receive records) are allocated. They are then initialized to guarantee that string fields are padded with blanks.

These structures are then loaded with data retrieved from the form. When the data retrieval is complete, the contents of the structure are byte copied field by field to the receive_records array (unload_control_wksp()). (This receive_records array is the same receive_records array that was originally passed into the acmsdi_transceive() routine.) Finally, the application calls acmsdi_complete_pp to send the contents of the receive_records array back to the ACMS application.

Example 6-10 RISC to OpenVMS Structure Byte Copy

void unload_control_wksp( 
     vr_control_wksp *control_wksp, 
     char            *data_ptr) 
{ 
 
  memcpy(data_ptr, 
         control_wksp->ctrl_key, 
         sizeof(control_wksp->ctrl_key)); 
  data_ptr = data_ptr + sizeof(control_wksp->ctrl_key); 
 
  memcpy(data_ptr, 
         &(control_wksp->current_entry), 
         sizeof(control_wksp->current_entry)); 
  data_ptr = data_ptr + sizeof(control_wksp->current_entry); 
    
   .
   .
   .
} 
 
void End_Trans_List3_List2( 
     session_type *session_ptr, 
     int    button_pressed) 
 
{ 
 
  receive_record    = (session_ptr->current_exchange_request)->receive_record; 
 
  sites_wksp     = (vr_sites_wksp *) malloc(sizeof(vr_sites_wksp)); 
  reservations_wksp = 
      (vr_reservations_wksp *)  malloc(sizeof(vr_reservations_wksp)); 
  customers_wksp    = (vr_customers_wksp *) malloc(sizeof(vr_customers_wksp)); 
  control_wksp     = (vr_control_wksp *) malloc(sizeof(vr_customers_wksp)); 
  if( ((int) sites_wksp == NULL)        || 
      ((int) reservations_wksp == NULL) || 
      ((int) customers_wksp == NULL)    || 
      ((int) control_wksp == NULL)) 
  { 
    DisplayWarningBox( 
         AvertzMainWindow,         
         "Application Has Run Out Of Memory. \n\nUnable To Continue.", 
         "WARNING!!"); 
 
    return; 
  } 
 
  /* 
  ** Initialize all the workspace fields (set all the 
  ** characters in the character arrays to blanks, etc.). 
  */ 
  init_sites_wksp(sites_wksp); 
  init_reservations_wksp(reservations_wksp); 
  init_customers_wksp(customers_wksp); 
  init_control_wksp(control_wksp); 
   .
   .
   .
    data_missing = get_initial_fields(session_ptr->resv_form, 
          sites_wksp, 
          reservations_wksp, 
          customers_wksp); 
  
   .
   .
   .
    if (!data_missing) 
    { 
   .
   .
   .
       /* 
       ** Move the data collected in the workspace structures 
       ** to the location of the original receive records 
       */ 
 
       unload_sites_wksp(sites_wksp, receive_record[0].data_record); 
       unload_reservations_wksp(reservations_wksp, 
                                receive_record[1].data_record); 
       unload_customers_wksp(customers_wksp, receive_record[2].data_record);         
       unload_control_wksp(control_wksp, receive_record[3].data_record); 
 
   .
   .
   .
 
       acmsdi_complete_pp(session_ptr->call_id, FORMS_NORMAL); 
 
  } 
  free(sites_wksp); 
  free(reservations_wksp); 
  free(customers_wksp); 
  free(control_wksp); 
} 

6.8 Writing Memory Allocation Routines

The desktop client program allocates and manages memory while coexisting with the TP Desktop Connector client services and other software on the desktop platform. By default, the TP Desktop Connector client services use malloc() and free(). However, you do not need to use these services for environments other than DOS. The TP Desktop Connector client services permit you to specify your own allocation and free routines for message buffers. These are passed in to TP Desktop Connector client services using the options parameter on the acmsdi_sign_in call by specifying the ACMSDI_OPT_MALLOC_ROUTINE and ACMSDI_OPT_FREE_ROUTINE options (see DIGITAL TP Desktop Connector for ACMS Client Services Reference Manual).

6.9 Building and Debugging Motif Desktop Client Programs

For guidelines for building TP Desktop Connector client programs for OpenVMS and Digital UNIX, see the makefiles in the appropriate directory for your platform.

6.9.1 Debugging the Nonblocking Desktop Client Program with Tasks

Debug the presentation code on the desktop system. When the presentation code runs, debug the desktop client program with the ACMS software. Follow these guidelines:

6.9.2 Using a Debugger to Step Through the Motif Sample Application

To get a better feel for the flow of a nonblocking Desktop application, use a debugger to step through the Motif sample provided on the kit. Set breakpoints in the various files at the following functions:


Chapter 7
Forced Nonblocking Extension to the Portable API

This chapter describes how to use the forced nonblocking feature of TP Desktop Connector client services to create applications using presentation packages like Visual Basic and PowerBuilder.

The topics in this chapter are:

7.1 Benefits of Forced Nonblocking

Certain desktop application development tools, such as Visual Basic and PowerBuilder, cannot handle ACMS exchange steps, because these tools do not support callbacks from environments such as the C language. Because these tools do not support pointer types, they cannot accept arguments that are passed by reference, such as form records. TP Desktop Connector exchange step callbacks expect the called presentation procedures to accept arguments that are passed by reference. The TP Desktop Connector portable API nonblocking execution is activated by passing the address of a completion routine to the acmsdi_call_task service.

The TP Desktop Connector portable API has been extended to support both exchange steps and nonblocking execution of task calls for development tools that do not support pointer data types, or whose memory management routines relocate data. In addition, the extension to the portable API allows support of acmsdi_cancel service, which must be issued in a nonblocking environment. The extension to the portable API provides a way for these tools to obtain a pointer (a 32-bit integer) to their workspace buffers using the acmsdi_return_pointer service.

7.2 Portable API Extensions for Forced Nonblocking

The extensions to the portable API are:

In a forced nonblocking session, the acmsdi_disable callback to the client application does not occur as part of the acmsdi_sign_out processing. Instead, the client application must clear the structures used by presentation procedures without being prompted by the acmsdi_disable callback. In addition, in a forced nonblocking session, the acmsdi_check_version callback to the client does not occur. Instead, TP Desktop Connector adds the form version to the argument list acquired by the application using the acmsdi_bind_enable_args service. The client application can do the version checking during enable exchange step processing.

See DIGITAL TP Desktop Connector for ACMS Client Services Reference Manual for the syntax and description of these client services for the forced nonblocking environment.

7.3 Forced Nonblocking Programming Considerations

The following sections discuss programming considerations when using forced nonblocking mode.

7.3.1 Establishing a Forced Nonblocking Session

To establish a forced nonblocking session, you request nonblocking calls without specifying a completion address with the acmsdi_sign_in service call. Instead, you specify the ACMSDI_OPT_NONBLK option. If the sign-in succeeds, all calls for the session are nonblocking. Follow these steps to initialize call options to request forced nonblocking calls. (Note the example code, written in Visual Basic syntax, has been altered to make it more readable.)

  1. Declare the options array:


    Static options(2) As ACMSDI_OPTION 
    

  2. Specify forced nonblocking calls in the options array:


    options(0).option = ACMSDI_OPT_NONBLK 
    options(1).option = ACMSDI_OPT_END_LIST 
    

  3. Pass the options array as the options parameter on acmsdi_sign_in:


    status = acmsdi_sign_in(submitter_node$,     ' node to sign-in to 
                           username_str$,        ' user signing in 
                           password_str$,        ' user's password 
                           options(0),           ' options array 
                           submitter_id,         ' submitter identifier 
                           ByVal 0%,             ' final completion status 
                           0&,                   ' completion routine 
                           ByVal 0&)             ' call context 
    

The session is a nonblocking call even though the completion routine address is 0, because the options argument is set to ACMSDI_OPT_NONBLK. Also, all subsequent calls for the session are nonblocking. A successful return status is ACMSDI_PENDING, indicating that the sign-in call has been sent to the back end.

The final completion status is passed as a long integer with a value of 0, which TP Desktop Connector interprets as a null pointer. This is done because its memory location can change before the task completes. When the task completes, you acquire the final completion status with the acmsdi_complete_call service.


Previous Next Contents Index