Previous | Contents | Index |
In a nonblocking environment, saving session context globally serves two purposes. First, it saves the local data for reuse. Second, it allows the desktop client program to coordinate with message passing between the desktop system and the ACMS system when there are multiple sign-ins. Also, saving session context globally gives you a convenient place to store session-related user interface data such as form IDs and icon IDs.
In the AVERTZ desktop client program, a user can sign in to a ACMS system in one window and initiate a task from another window. The AVERTZ desktop client program establishes context and maintains the context as session data across service calls and presentation procedures. Example 5-3 shows the definition of data in the session.h file that keeps track of session context.
Example 5-3 AVERTZ Session Context |
---|
extern enum request_type { NO_OUTSTANDING_TASK, TASK_IN_PROGRESS, SEND_CTRL_RESV_LIST, SEND_VR_CONTROL_WKSP, TRANS_LIST_3_LIST_2, TRANS_LIST_5_LIST_6, TRANS_LIST_7_LIST_6, TRANS_LIST_8_LIST_9, TRANS_VRH_RCLIST_VRH_RESV_LIST, TRANS_VR_CTRL_WKSP_LIST_D, TRANS_LIST_E_LIST_F, TRANS_LIST_F_LIST_F, TRANS_LIST_G_LIST_H}; . . . typedef struct { enum request_type request_id; char *receive_control_text; long *receive_control_text_count; ACMSDI_FORM_RECORD *receive_record; } exchange_request_type; typedef struct { ACMSDI_SUBMITTER_ID *submitter_id; (1) int session_id; ACMSDI_CALL_ID *call_id; (2) char node[MAX_NODE_LENGTH]; char username[MAX_USERNAME_LENGTH]; char password[MAX_PASSWORD_LENGTH]; char print_file[20]; HWND session_icon; HWND resv_form; HWND vehicle_form; HWND billing_form; HWND message_window; exchange_request_type *current_exchange_request; (3) int completion_status; (4) char task_status_message[80]; (5) } session_type; extern session_type *init_session_list; |
The following context data is required for a session:
(1) submitter ID | Returned from the ACMS system at sign-in time |
(2) call ID | Returned by the acmsdi_call_task service |
(3) current exchange request | Needed if the program uses the same form for multiple exchange steps |
(4) completion status | Updated by the TP Desktop Connector client service when the task completes |
(5) task status message | Updated by the TP Desktop Connector client service when the task completes |
The session_type structure enables the desktop client program to access data related to a sign-in session when a Windows operation occurs. The variables submitter_id, call_id, completion_status, and task_status_message are allocated by the desktop client program and updated by TP Desktop Connector client services. The value of the completion_status is updated just before the TP Desktop Connector client services call the completion routine.
The session context structure is also a useful place to maintain window handles of user interface objects related to a session. In the sample, the session context includes window handles for the session's icon, the session's menu entry in the select menu, and window handles for all the forms related to that session.
The AVERTZ.EXE program passes the session context to the acmsdi_call_task service as the call_context parameter. Whenever the TP Desktop Connector client services call a task completion routine or a presentation procedure on behalf of an active ACMS task, the session context is passed to the desktop client program. For example, you can use a session context to determine which form in the application to update with data from an incoming presentation procedure. Example 5-4 shows an example in the avertz.c code where the session context is passed.
Example 5-4 Context Passed to Desktop Client Program |
---|
. . . status = acmsdi_call_task( current_session_ptr->submitter_id, NULL, "VR_RESERVE_TASK", AVERTZ_APPLICATION_NAME, NULL, current_session_ptr->task_status_message, 0, NULL, current_session_ptr->call_id, &(current_session_ptr->completion_status), SessionTask_Complete, (void *) current_session_ptr); (1) . . . |
The parameter at (1) specifies a session context to be passed. The desktop client program can use that context to determine which form to deal with. The session context is useful for determining which presentation procedure is ending and which workspaces are affected (see Section 5.5).
When a presentation procedure later starts as a result of the ACMS task executing, the session context is passed back to the desktop client program as shown in the transw.c code in Example 5-5.
Example 5-5 Call Context Returned with Presentation Procedure |
---|
long int acmsdi_transceive(ACMSDI_FORMS_SESSION_ID *session_id, : ACMSDI_CALL_ID *call_id, void *call_context, ACMSDI_FORM_RECORD *send_records, ACMSDI_FORM_RECORD *recv_records ) { session_type *session_ptr = (session_type *) call_context; . . . save_sessions_PP_data_ptrs( session_ptr, recv_ctl_text, recv_ctl_text_count, recv_records); sts = Trans_List3_List2 ( session_ptr, 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 **/ ); . . . |
The code in Example 5-6 shows how session context is used to establish context for the user interface when the user selects a session icon. The session_type structure contains the information about the form to display for that submitter.
Example 5-6 Session Context Handling for the User Interface |
---|
void select_new_session( session_type *new_session) { session_type *former_current_session_ptr = current_session_ptr; current_session_ptr = new_session; /* ** Hide any forms that are displayed for the former current session */ if (former_current_session_ptr != NULL) close_session(former_current_session_ptr); /* ** Redraw the icons of the former and new current session ** (The WM_DRAWITEM case in MainWindowProc will redraw ** the icon buttons when & if their select state changes. ** Therefore, here we turn the select state OFF for the former ** current session, and turn the select state ON for the ** new current session. */ if (former_current_session_ptr != NULL) SendMessage(former_current_session_ptr->session_icon, BM_SETSTATE, FALSE, NULL); SendMessage(current_session_ptr->session_icon, BM_SETSTATE, TRUE, NULL); /* ** Determine which menus, menu items must be enabled and disabled */ if (former_current_session_ptr != NULL) UncheckSessionInSelectMenu(former_current_session_ptr->session_id); CheckSessionInSelectMenu(current_session_ptr->session_id); if ((current_session_ptr-> current_exchange_request)-> request_id == NO_OUTSTANDING_TASK) { EnableSessionExit; EnableRentalMenu; DisableSearchMenu; } else { DisableSessionExit; DisableRentalMenu; if ((current_session_ptr-> current_exchange_request)-> request_id == TRANS_LIST_3_LIST_2) EnableSearchMenu; else DisableSearchMenu; } } |
A call to the nonblocking acmsdi_call_task or acmsdi_sign_out service must follow the rules described for other nonblocking services (see Section 5.4.1). The calling routine specifies the submitter identification returned from the acmsdi_sign_in service.
The acmsdi_call_task service returns a call
identification and call context that are used in any
completion routine (see Compaq TP Desktop Connector for
ACMS Client Services Reference Manual), presentation
procedure, or acmsdi_complete_pp service call.
5.4.5 Canceling Active Tasks
TP Desktop Connector allows client programs, written with nonblocking services, to cancel active tasks running on the gateway node. Being able to cancel active tasks allows you to create applications that provide a CANCEL function for the user. The main advantage of being able to cancel a task is to permit the user to work on other applications, if the response from the gateway is not immediate. For example, if the user starts a transaction on the database, you can display three buttons in the dialog box:
These features are available with both the portable API client services (acmsdi_cancel) and the Macintosh client services (DBBreak). See Compaq TP Desktop Connector for ACMS Client Services Reference Manual for a description of these client services.
Because of the limitations in MacTCP and NetWare, you cannot use the cancel function with these transports. |
You cannot use a cancel service in exchange steps. If you call a cancel
during a presentation procedure, TP Desktop Connector returns
the message "ACMSDI_EXCHACTV". If you issue a cancel while another
cancel is already in progress, TP Desktop Connector returns
the message "ACMSDI_CANCELACTV". The cancel completion routine is
guaranteed to be called before the task completion routine.
5.5 Writing Nonblocking Presentation Procedures
Writing a presentation procedure in a nonblocking environment differs from writing presentation procedures in a blocking environment. A nonblocking presentation procedure does the following:
In a nonblocking environment, presentation procedures are generally divided as follows:
Typically, the initial and completion routines are separate so that data can be obtained from the user. If user action is not required, such as in a stub routine, the initial routine can call the acmsdi_complete_pp service, and the completion routine is not necessary.
Example 5-7 shows pseudocode from several modules in the AVERTZ sample desktop client program to indicate the flow of processing a presentation procedure.
Example 5-7 Nonblocking Presentation Procedure Pseudocode |
---|
long int acmsdi_transceive(ACMSDI_FORMS_SESSION_ID *session_id, (1) 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 ) { session_type *session_ptr = (session_type *) call_context; (2) . . . if ((0 == strcmp (send_record_id, "LIST_3")) && (0 == strcmp (recv_record_id, "LIST_2"))) . . . /* ** Save Pointers To Exchange Step's Receive Data ** And Call Presentation Procedure */ save_sessions_PP_data_ptrs( (3) session_ptr, recv_ctl_text, recv_ctl_text_count, recv_records); sts = Trans_List3_List2 ( (4) session_ptr, 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 **/ ); } int Trans_List3_List2 ( (5) session_type *session_ptr,...) { . . . enable_initial_fields(session_ptr->resv_form); enable_resv_push_buttons(session_ptr->resv_form); return(FORMS_NORMAL); (6) } . . . return (sts); (7) } |
The code shown in Example 5-7 does the following:
At this point, the user can enter data in the dialog box and the desktop client program no longer has control.
To signal that data entry is complete and to pass status back to the TP Desktop Connector gateway, the user clicks on the OK button in the dialog box some time after the desktop client program yields control to Windows. Example 5-8 shows the processing in the resvform.c module when the user either signals completion or cancels the operation.
Example 5-8 Presentation Procedure Completion Pseudocode |
---|
case WM_COMMAND: /* message: received a command */ switch (wParam) { case IDOK : (1) case IDCANCEL : { exchange_request_type *exchange_request = current_session_ptr->current_exchange_request; switch (exchange_request->request_id) { (2) . . . case TRANS_LIST_3_LIST_2 : (3) End_Trans_List3_List2(current_session_ptr, wParam); return(TRUE); . . . void End_Trans_List3_List2( (4) session_type *session_ptr, WORD button_pressed) { receive_record = (session_ptr->current_exchange_request)->receive_record; sites_wksp = (vr_sites_wksp *) (receive_record[0].data_record); reservations_wksp = (vr_reservations_wksp *) (receive_record[1].data_record); customers_wksp = (vr_customers_wksp *) (receive_record[2].data_record); control_wksp = (vr_control_wksp *) (receive_record[3].data_record); . . . acmsdi_complete_pp(session_ptr->call_id, FORMS_NORMAL); (5) MessageBox( session_ptr->resv_form, "Reservation Data Has Been Submitted.\nWait For Return Data ...", " ", MB_OK | MB_ICONINFORMATION); . . . return; (6) } |
The code in Example 5-8 does the following:
The desktop client program allocates and manages memory while coexisting with the TP Desktop Connector client services and other software on the desktop platform.
The TP Desktop Connector client services use the malloc and calloc functions. However, Windows converts these functions to the LocalAlloc function, which is limited to the 64K bytes in the local heap.
Because messages sent to and received from the TP Desktop Connector Gateway for ACMS can be quite large (depending on the size of workspaces), message buffer allocation can fail, if the desktop client program is already using a substantial portion of the local heap. (Remember that the local heap is also used for the stack, static data, and global data items.)
Message buffers associated with presentation procedures persist for the duration of the call, including a period where control returns to Windows while the user enters data. The use of malloc/calloc with large workspaces can severely restrict the amount of memory available to the desktop client program in the local heap.
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 Compaq TP Desktop Connector for ACMS Client Services Reference Manual).
Do not use GlobalAlloc in the TP Desktop Connector client services memory management routines.
Previous | Next | Contents | Index |