DIGITAL TP Desktop Connector
for ACMS
Client Application Programming Guide


Previous Contents Index

8.3.4.2 Alternate Method for Sending Nonworkspace Data

The standard method for sending nonworkspace data uses multiple DBSend calls or DBSendItem calls; the alternate method requires two DBSendItems or a DBSend and a DBSendItem. Choose the one most convenient for you.

With the alternate method, the first DBSendItem (with no data type specified) or DBSend sends a keyword to the DDEV. The second DBSendItem sends a special data type, typeHdrRec, indicating that you are sending all the other nonworkspace data items at once.

This method requires that you allocate a header record that becomes the data object of the second DBSendItem. The header record has a prescribed format found in the #include file, acmsdi_mac.h. It contains a field for each of the nonworkspace data items (except the keyword), including those to be acquired from the DDEV as well as those to be sent to the DDEV. You can use the same header record for acquiring nonworkspace data items as well as sending them. This header record has a special data type, typeHdrRec.

The four header record formats are:

Refer to the file acmsdi_mac.h on the kit for the four record layouts.

After first sending the keyword with a standard DBSend or DBSendItem, the application must:

  1. Allocate the appropriate record
  2. Move the appropriate parameters into it
  3. Issue the DBSendItem call with data type, typeHdrRec

The data type (typeHdrRec) tells the DDEV that it is passing nonworkspace data with a header record. Because the keyword is sent immediately preceding the header record, the DDEV knows which type of header record is being sent to it.

Example 8-17 shows how to send the nonworkspace data items for a CALLTASK message using the alternate method.

Example 8-17 Alternate Method for Sending Nonworkspace items

/* 
** ELEMENTS DEFINED IN acmsdi_mac.h 
*/ 
#define CALLTASK   "CALLTASK"   /* CALLTASK Keyword */ 
 
struct callTaskHdr 
  { 
  StringPtr TaskName;      /* ->task name */ 
  StringPtr ApplName;      /* ->application name */ 
  StringPtr SelString;     /* ->selection string */ 
  StringPtr NbrWksp;       /* ->number of workspaces */ 
  StringPtr Message;       /* ->status message with CALLTASK response */ 
  }; 
typedef struct callTaskHdr CallTaskHdr, *CallTaskHdrPtr; 
 
#define CallTaskHdrLen (sizeof (struct callTaskHdr)) 
#define typeHdrRec 'hdrc'  /* data type for nonworkspace header record */ 
   .
   .
   .
/* 
** PROGRAM CODE FOLLOWS 
*/ 
CallTaskHdr hdrRec; 
char *keyword, *taskname, *applname, *selstring, *wksp_count; 
DBType dataType;           /* data type for DBSendItem */ 
strcpy (keyword, CALLTASK); 
/* 
** the following parameters are defined as Pascal strings in 
** accordance with Apple standard calling conventions 
*/ 
strcpy (taskname, "\pMY_TASK"); 
strcpy (applname, "\pMY_APPLICATION"); 
strcpy (selstring, "\p"); 
strcpy (wksp_count, "\p2"); 
   .
   .
   .
/* 
** first send the keyword to the DDEV 
*/ 
status = DBSend (sessID, keyword, strlen(keyword), NULL); 
/* 
** then put parameter pointers into the header record 
*/ 
hdrRec.TaskName  = (StringPtr) taskname; 
hdrRec.ApplName  = (StringPtr) applname; 
hdrRec.SelString = (StringPtr) selstring; 
hdrRec.NbrWksp   = (StringPtr) wksp_count; 
/* 
** then set the data type and send the header record 
*/ 
dataType typeHdrRec; 
status = DBSendItem (sessID,   /* session ID */ 
           dataType,           /* data type = header record */ 
           CallTaskHdrLen,     /* length of header record */ 
           NULL, 
           NULL, 
           (Ptr) &hdrRec,      /* -> header record */ 
           NULL); 

8.3.4.3 Acquiring Nonworkspace Data

Acquiring nonworkspace data items is the opposite of sending nonworkspace data items discussed in Section 8.3.4.1. There are two methods:

These header records have the exact same format as the ones discussed in Section 8.3.4.1, and therefore, can be used to send nonworkspace data items as well as to acquire them.

Both of the DBGetItem types used to acquire nonworkspace data items must have a special data type specified: one to indicate keyword acquisition and one to indicate nonworkspace data acquisition. A DBGetItem issued to acquire workspace data has no data type specified.

The application program is not required to acquire any workspace data items or nonworkspace data items. In addition, the order of acquisition is not important. You can acquire workspace data first and then acquire the nonworkspace data, or the other way around.

You can skip the acquisition of a nonworkspace data item by issuing a DBGetItem call with a buffer pointer equal to zero. The DDEV advances the current data item pointer to the next nonworkspace data item without returning any data to the program. Skipping nonworkspace data items is possible only when issuing a series of DBGetItems to acquire the data items one at a time. That is, you cannot skip nonworkspace data items when acquiring them with a header record.

The Table 8-10 shows the nonworkspace data items that you can acquire from the DDEV and the order in which they must be acquired if you use the standard method (a series of DBGetItems).

Table 8-10 Messages Received from the Back End
Message Items
CallTask response Keyword (CALLTASK)
Task status message
Number of workspaces
Enable request Keyword (ENABLE)
Form file specification
Form name
Form version
Print file specification
Forms language
Send request Keyword (SEND)
Forms session ID
Send record ID
Send record count
Send control text
Send control text count
Time out interval
Receive request Keyword (RECEIVE)
Forms session ID
Receive record ID
Receive record count
Send control text
Send control text count
Time out interval
Transceive request Keyword (TRANSCEIVE)
Forms session ID
Send record ID
Send record count
Receive record ID
Receive record count
Send control text
Send control text count
Time out interval
TDMS response Keyword (TDMS)
Request name
Number of workspaces

Example 8-18 shows the acquisition of nonworkspace data items using a header record for a transceive request.

For more samples, see the ACMSDI_EXAMPLES file on your kit.

Example 8-18 Acquiring Nonworkspace Data Using a Header Record

/* 
** ELEMENTS DEFINED IN acmsdi_mac.h... 
*/ 
#define TRANSCEIVE   "TRANSCEIVE"   /* TRANSCEIVE Keyword */ 
 
struct fimsHdr 
  { 
  long      DesktopStatus; /* return status for TRANSCEIVE response */ 
  StringPtr NbrWksp;       /* ->number of workspaces */ 
  StringPtr FormSessID;    /* ->forms session ID */ 
  StringPtr SendRecordID;  /* ->send record ID */ 
  StringPtr SendRecCount;  /* ->send record count */ 
  StringPtr RecvRecordID;  /* ->receive record ID */ 
  StringPtr RecvRecCount;  /* ->receive record count */ 
  StringPtr SendCtrlTxt;   /* ->send control text */ 
  StringPtr SendCtrlCount; /* ->send control count */ 
  StringPtr RecvCtrlTxt;   /* ->receive control text */ 
  StringPtr RecvCtrlCount; /* ->receive control count */ 
  short     TimeOut;       /* time out interval (seconds) */ 
  }; 
typedef struct fimsHdr FIMSHdr, *FIMSHdrPtr; 
 
#define FIMSHdrLen (sizeof (struct fimsHdr)) 
#define maxKWsize 10       /* maximum keyword size */ 
  
#define typeHdrItem 'hdit' /* message header item data type */ 
#define typeHdrRec  'hdrc' /* data type for non-workspace header record */ 
   .
   .
   .
/* 
** PROGRAM CODE FOLLOWS... 
*/ 
FIMSHdr fhdrRec; 
char formSessID[17], sendRecCt[4], recvRecCt[4]; 
char sendCtrTxt[26], sendCtrTxtCt[4], keyword[maxKWsize]; 
Str31 sendRecID, recvRecID; 
DBType dataType;             /* data type */ 
unsigned short keyword_len, len; 
   .
   .
   .
/* 
** first get the keyword to see what kind of message we have 
*/ 
dataType = typeHdrItem;      /* set data type for header item */ 
/* 
** NOTE: the following keyword length field will be modified 
** when keyword returned to actual length of the returned keyword 
*/ 
keyword_len = maxKWsize;     /* length of longest keyword */ 
 
status = DBGetItem (sessID,       /* session ID */ 
          NULL, 
          &dataType,              /* ->data type */ 
          (short *) &keyword_len, /* ->length of keyword */ 
          NULL, 
          NULL, 
          keyword,                /* -> where keyword to be returned */ 
          NULL); 
/* 
** keyword returned; check for TRANSCEIVE 
*/ 
if (strncmp (keyword, TRANSCEIVE, keyword_len) == 0) /* if yes... */ 
  { 
  /* 
  ** ...get header items via a header record 
  */ 
  dataType = typeHdrRec;      /* set data type for header record */ 
  /* 
  ** set pointers in hdr rec to items to be returned.  
  ** all items except time out interval (which is a 
  ** short integer within the header record itself) 
  ** will be returned as Pascal strings in accordance 
  ** with the Apple standard. 
  */ 
 
  /* first set the Pascal strings' length bytes */ 
 
  formSessID[0] = (sizeof formSessID) - 1; 
  sendRecID[0] = (sizeof sendRecID) - 1; 
  sendRecCt[0] = (sizeof sendRecCt) - 1; 
  recvRecID[0] = (sizeof recvRecID) - 1; 
  recvRecCt[0] = (sizeof recvRecCt) - 1; 
  sendCtrTxt[0] = (sizeof sendCtrTxt) - 1; 
  sendCtrTxtCt[0] = (sizeof sendCtrTxtCt) - 1; 
  /* then set pointers to them in the header record */ 
 
  fhdrRec.FormSessID    = (StringPtr) &formSessID; 
  fhdrRec.SendRecordID  = (StringPtr) &sendRecID; 
  fhdrRec.SendRecCount  = (StringPtr) &sendRecCt; 
  fhdrRec.RecvRecordID  = (StringPtr) &recvRecID; 
  fhdrRec.RecvRecCount  = (StringPtr) &recvRecCt; 
  fhdrRec.SendCtrlTxt   = (StringPtr) &sendCtrTxt; 
  fhdrRec.SendCtrlCount = (StringPtr) &sendCtrTxtCt; 
 
  len = FIMSHdrLen;                 /* set length of header record */ 
  status = DBGetItem (sessID,       /* session ID */ 
            NULL, 
            &dataType,              /* ->data type */ 
            (short *) &len,         /* ->length of header record */ 
            NULL, 
            NULL, 
            (Ptr) &fhdrRec,         /* -> to header record */ 
            NULL); 

8.3.5 Workspace Data

Workspaces are inserted into their buffers in two different formats depending on whether they are part of a client request message or a gateway response message.

Workspaces included as part of a response message are aligned on a 4-byte boundary with no header data. When part of a request message, each workspace is preceded by the workspace length, a short integer, called the workspace preamble.

Access types for workspaces are read-only, write-only, and modify. The names always relate to the gateway's point of view. Thus, from the client's point of view, a read-only workspace is actually only written. And a write-only workspace is actually only read. This can be confusing. Keep in mind what role (client or gateway) your application is currently playing and that sometimes the application is a client and sometimes it is a server.

Note

For the CallTask message types, specify write-only and read-only messages on the DBSentItem service. For Send, Receive, and Transceive message types, specify write-only and read-only messages as send and receive records.

Table 8-11 shows these roles from the point of view of the desktop application.

Table 8-11 Desktop Application Roles
Message Type Desktop Role Write-Only Workspaces Read-Only Workspaces Modify Workspaces
CALLTASK Client Read Written Read and written
ENABLE Server N/A N/A N/A
SEND Server N/A Read N/A
RECEIVE Server Written N/A N/A
TRANSCEIVE Server Written Read N/A
TDMS Server Written Read Read and written

8.3.5.1 Sending Workspace Data

A workspace is always sent to the DDEV with a single DBSendItem or DBSend, one call for each workspace to be sent. For unidirectional workspaces, DBSendItem must be used with the appropriate flag (kDBReadOnly or kDBWriteOnly) set on. Modify workspaces require no flag settings and can be sent with either a DBSendItem or a DBSend.

When in the role of gateway, the desktop application must send only write-only and modify workspaces to the DDEV.

For responding to exchange step messages, note the following:

Note

Because ENABLE messages are never associated with workspace data and because SEND messages include only read-only workspaces, the application must never send workspaces to the DDEV for these two response message types.

When in the role of client (during a CALLTASK request), the desktop application must send all workspaces (read-only, write-only, and modify) to the DDEV. However, the buffer pointer for a write-only workspace can be null, because the actual workspace data is not inserted into the message. Only the workspace length and access type are inserted.

You can send modify workspaces only with CALLTASK request and TDMS response messages.

Because applications play the role of client when processing CALLTASK messages, the associated workspace data in the response message from the back end has no indication of where one workspace ends and the next begins. The application that issues a CALLTASK request must understand which workspaces are being returned, the order in which they are being returned, and their sizes.

Only write-only and modify workspaces can be associated with a CALLTASK response message. Read-only workspaces are simply eliminated from the workspace buffers.

When sending workspaces to the DDEV, all nonworkspace data items must be sent first in the sequence specified in Section 8.3.4.1. The Number of Workspaces data item must be equal to the actual number of workspaces sent to the DDEV with subsequent DBSendItem or DBSend calls.

8.3.5.2 Acquiring Workspace Data

An application acquires workspace data using DBGetItem calls. Applications can acquire as much or as little of the workspace data as desired. It is possible to bypass acquisition of entire workspaces. There is no requirement that any workspace data be acquired.

To bypass acquiring a part of a workspace, issue a DBGetItem call with a null buffer pointer. When the DDEV recognizes a null buffer pointer with a DBGetItem call, it bumps the current pointer by the length specified but makes no attempt to return any data to the application. You can bypass entire workspaces in this manner.

DBGetItem calls issued to acquire workspace data must always have a valid length parameter to indicate how much data is to be acquired or bypassed.

8.3.5.3 Workspaces in Request Messages

When processing a request message from the back end, the desktop application is playing the role of gateway. In this situation, an indication of each workspace existence is contained in the message. Every workspace is represented by its length, a short integer. However, write-only workspaces do not have any actual workspace data in the message buffer.

Before processing any workspace in a request message, the desktop application must set currency on the workspace. Set currency on a workspace by issuing a DBGetItem call with data type, typeWkspPream, to acquire the workspace preamble, its length, and access type. In response to this call, the DDEV sets the current pointer at the first byte in the workspace data. If a nonzero buffer pointer is passed with the call, the DDEV also returns the workspace length and access type into a structure of type WSPreamble as defined in acmsdi_mac.h.

After setting currency, if the workspace is of access type read-only or modify, the actual workspace data can be retrieved using DBGetItem calls with no data type specified. You can acquire as much of the workspace data as you want with a single DBGetItem call. As is the case with CALLTASK response messages, you can bypass part or all of the workspace data by sending a null buffer pointer on the DBGetItem call.

Another way of bypassing acquiring data from a workspace is to not issue any DBGetItem calls for its data. Issuing back-to-back DBGetItem currency calls bypasses all the data associated with the workspace for which the first currency call is issued.

Example 8-19 shows how an application sets currency on a workspace and then acquires its data.

Example 8-19 Setting Currency on a Workspace

/* 
** ELEMENTS DEFINED IN acmsdi_mac.h 
*/ 
#define typeWkspPream 'wspm'  /* workspace preamble */ 
 
typedef char ACMSDI_ACCESS_TYPE; 
 
#define ACMSDI_ACCESS_READ   '1' 
#define ACMSDI_ACCESS_WRITE  '2' 
#define ACMSDI_ACCESS_MODIFY '3' 
/* 
** workspace preamble structure 
*/ 
 
struct wsPreamble 
  { 
  unsigned short        length;    /* workspace length */ 
  ACMSDI_ACCESS_TYPE    access;    /* workspace access type */ 
  }; 
typedef struct wsPreamble WSPreamble, *WSPreamblePtr; 
 
#define WSPreambleLen (sizeof (struct wsPreamble)) 
   .
   .
   .
/* 
** PROGRAM CODE FOLLOWS 
*/ 
WSPreamble wsPre;    /* preamble structure */ 
char wkspce[100];    /* my workspace buffer */ 
unsigned short len; 
DBType dataType; 
/* 
** first get the workspace preamble and 
** set currency on the workspace 
*/ 
len = WSPreambleLen;         /* length of preamble struct */ 
dataType = typeWkspPream;    /* set data type */ 
status = DBGetItem (sessID,  /* session ID */ 
           NULL, 
           &dataType,        /* data type is workspace preamble */ 
           (short *) &len,   /* -> length of preamble struct */ 
           NULL, 
           NULL, 
           (Ptr) &wsPre,     /* -> to preamble struct */ 
           NULL); 
/* 
** if we have a read-only workspace, get workspace data 
*/ 
if (wsPre.access == ACMSDI_ACCESS_READ) /* if read-only... */ 
  { 
  len = wsPre.length;         /* ...set workspace length */ 
  status = DBGetItem (sessID, /* session ID */ 
             NULL, 
             NULL, 
             (short *) &len,  /* length of workspace */ 
             NULL, 
             NULL, 
             wkspce,          /* -> where workspace data goes */ 
             NULL); 

8.4 Building the Presentation Code

After you write and compile the desktop client program, link it with the appropriate Macintosh libraries. Example 8-20 shows the makefile for a desktop client program written with MPW.

Note

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

Example 8-20 Linking the Macintosh Desktop Client Program

OBJECTS = acmsdi_mac_test.c.o acmsdi_mac_test.c.o 
acmsdi_mac_test    acmsdi_mac_test.make {OBJECTS} 
     Link -w -t APPL -c '????' 
             {OBJECTS} 
             "{CLibraries}"CSANELib.o 
             "{CLibraries}"Math.o 
             #"{CLibraries}"Complex.o 
             "{CLibraries}"StdClib.o 
             "{MPW}"Libraries:Libraries:SIOW.o 
             "{CLibraries}"CInterface.o 
             "{CLibraries}"CRuntime.o 
             "{Libraries}"Interface.o 
             -o acmsdi_mac_test 
acmsdi_mac_test.c.o   acmsdi_mac_test.make acmsdi_mac_test.c 
      C  acmsdi_mac_test.c 
acmsdi_mac_test    "{MPW}"Interfaces:Rincludes:SIOW.r 
     Rez -a "{MPW}"Interfaces:Rincludes:SIOW.r -o acmsdi_mac_test 

Compiled versions of the HyperCard XFCNs are included in the XFCN resources program found in the HyperCard External folder in the TP Desktop Connector for ACMS kit. The XFCN sources, written in C, are also found in this folder. If you do not modify the XFCNs provided, you can place them in your stack by one of these methods:

If you do need to modify the XFCNs, compile, link, and place them in your stack.

Note

If you plan to use exchange steps with HyperCard or 4th Dimension, you must create your own externals for this purpose.

8.5 Debugging the Presentation Code

To debug the desktop client program, use the standard Macintosh debugging tools. HyperCard also provides a debugger with which you can examine HyperTalk scripts as the stack is executing. Though more limited than MPW in its capabilities, the HyperCard debugger is essential for building HyperTalk scripts to handle the kinds of complex activities typical of TP Desktop Connector solutions. For information on debugging ACMS tasks, see Section 3.6.3.


Previous Next Contents Index