< Home < Developers < Development Support < Documentation

## 1 Object Exchange

Table of Contents | < Previous | Next > | Index

| Title - Palm OS® Programmer's Companion vol. II: Communications 1 Object Exchange About the Exchange Manager Exchange Libraries Typed Data Objects Initializing the Exchange Socket Structure Identifying the Exchange Library Identifying the Type of Data Registering for Data General Registration Guidelines Setting the Default Application Registering to Receive Unwrapped Data Sending Data Sending a Single Object Sending Multiple Objects Implementing the Send Command Receiving Data Controlling the Exchange Dialog Displaying a Preview Receiving the Data Sending and Receiving Databases Sending a Database Receiving a Database Requesting Data Sending a Get Request for a Single Object Responding to a Get Request Two-Way Communications Requesting a URL Sending and Receiving Locally Interacting with the Launcher Summary of Exchange Manager |  |  |  | The simplest form of communication for a Palm OS® application to implement is the sending and receiving of typed data objects, such as MIME data, databases, or database records. You use the Exchange Manager to send and receive typed data objects. The Exchange Manager interface is independent of the transport mechanism. You can use IR, SMS, or any other protocol that has an Exchange Manager plug-in called an exchange library. The Exchange Manager is supported in Palm OS 3.0 and higher. In Palm OS 4.0, significant updates were made. This chapter describes how applications use the Exchange Manager to send and receive typed data objects. It covers the following topics: About the Exchange Manager Initializing the Exchange Socket Structure Registering for Data Registering to Receive Unwrapped Data Receiving Data Sending and Receiving Databases Requesting Data Sending and Receiving Locally Interacting with the Launcher This chapter does not describe how to implement an exchange library. ## About the Exchange Manager This section explains concepts you need to know before you can begin using the Exchange Manager. It discusses the following topics: Exchange Libraries Typed Data Objects ## Exchange Libraries The Exchange Manager works in conjunction with an exchange library. Each exchange library is transport-dependent and performs the actual communication with the remote device. When an application makes an Exchange Manager call, the Exchange Manager forwards the request to the appropriate exchange library. The Exchange Manager's main duty is to maintain a registry of which libraries implement each protocol and which applications receive each type of data. See Figure 1.1. Figure 1.1 Object exchange using Exchange Manager The list of supported exchange libraries depends on the version of Palm OS. See Table 1.1. #####
Table 1.1 Supported exchange libraries
Exchange Library | Minimum Palm OS Version
--- | ---
IR Library (IrDA) | Palm OS 3.0
Local Exchange Library | Palm OS 4.0
SMS Library (Short Messaging System) | Palm OS 4.0
Bluetooth Library1 | Palm OS 4.0
1. The Bluetooth Library is not present in Palm OS 4.0, but is planned to be provided shortly after Palm OS 4.0 ships.
As other exchange libraries become available, users can install them on their Palm PoweredTM handhelds and use the communications functionality they provide. Note that on Palm OS 3.X the only exchange library available is the IR Library, and it is not extensible. The IR Library cannot, for example, be replaced with a different exchange library. ## Typed Data Objects The Exchange Manager sends and receives typed data objects. A typed data object (or object) is a stream of bytes plus some information about its contents. The content information includes any of: a creator ID, a MIME data type, or a filename. The object itself can be in any format, but it's best to use a standardized data format rather than a proprietary one if you have a choice. Table 1.2 lists the standardized data formats that the built-in Palm OS applications can receive. #####
Table 1.2 Built-in applications and standard data types
Application | Data Type
--- | ---
Address Book | vCards (vcf file extension, text/x-vCard MIME type)
Datebook | vCalendars (vcs file extension, text/x-vCalendar MIME type)
Launcher | Palm OS databases (prc, pdb, oprc, and pqa file extensions, application/x-pilot and application/vnd.palm MIME types)
Memo | Plain text (txt file extension, text/plain MIME type)
ToDo | Not explicitly registered, but receives vCalendar objects from Datebook as appropriate
NOTE: The MIME type application/vnd.palm has been registered with the IANA and is preferred over the application/x-pilot MIME type. If you want your application to receive objects, you must first register with the Exchange Manager for the type of data you want to receive. See "Registering for Data" for instructions on how to do so. You can override the built-in applications by registering for any data type listed in Table 1.2 and becoming the default application for that type. See "Setting the Default Application" for more information. If you only want to send data, you do not have to register. Your application can send data of the types listed in Table 1.2, and the Exchange Manager ensures that the appropriate application receives it. ## Initializing the Exchange Socket Structure The Exchange Manager, exchange library, and application use an exchange socket structure (ExgSocketType) to communicate with each other. This structure is passed from the application to the Exchange Manager to the exchange library and vice versa. (The use of the term "socket" in the Exchange Manager API is not related to the term "socket" as used in sockets communication programming.) When your application sends data, you must create this structure and initialize it with the appropriate information. When you receive data, this structure provides information about the connection and the incoming data. The ExgSocketType structure you use must identify two important pieces of information: the exchange library that should do the sending (see "Identifying the Exchange Library") the type of data being sent (see "Identifying the Type of Data") The socket structure defines other fields that you may use to provide other information if you want. See the description of the ExgSocketType structure in the Palm OS Programmer's API Reference for complete details. IMPORTANT: When initializing the ExgSocketType structure, set all unused fields to 0. ## Identifying the Exchange Library The ExgSocketType structure identifies the library to be used in one of the following ways: a library reference number in the libraryRef field a Uniform Resource Locator (URL) in the name field The Exchange Manager checks for a library reference number first. If it is 0, it checks for a URL. When your application sends data, it must identify which exchange library to use. You only need to identify the exchange library in Palm OS 4.0 and higher. Earlier releases contain only one exchange library (for IR), so all sending is automatically done by that library. If you do not specify an exchange library on Palm OS 4.0 and higher, the IR Library is used to maintain backward compatibility. It's more common to identify the library using a URL instead of a library reference number. The URL scheme specifies which exchange library to use. The scheme is the part of the URL that appears before the colon (:). For example, the scheme in the following URL is "http"
    http://www.palmos.com
When you pass the preceding URL to a web browser, the scheme tells the browser to connect to the server using the HTTP protocol. Similarly, when you pass the Exchange Manager a URL, the scheme tells the Exchange Manager which exchange library to use. For example, the following URL tells the Exchange Manager to connect to a remote Palm Powered handheld using the IR Library:
    _beam:BusinessCard.vcf
On Palm OS, a URL has the following format:
    [?]scheme1[;scheme2]...:filename
where: #####
? | If more than one exchange library is registered for the provided schemes, the Exchange Manager has the user select the exchange library by displaying the Send With dialog.
#####
scheme1[;scheme2]... | The URL schemes that identify which exchange library should be used. If more than one exchange library is registered for the scheme, the default exchange library is selected unless the URL begins with a question mark.
#####
| As shown, multiple schemes may be provided, separated by semicolons. Multiple schemes are only supported in conjunction with the question mark. For example, the string "?_send;_beam" has the Exchange Manager display a Send With dialog that lists all exchange libraries that support either the _send scheme or the _beam scheme.
#####
filename | The name of the file to send. Typically, this file also has an extension that is used, if necessary, to determine which application should receive the data. See "Identifying the Type of Data" for more information about the file extension.
Palm OS defines some URL prefixes that any application can use to connect with the installed exchange libraries. A URL prefix is everything up to and including the colon character. Table 1.3 describes the prefixes. #####
Table 1.3 Exchange Library URL Prefixes
Exchange Library | URL Prefix
--- | ---
IR Library | exgBeamPrefix
Local Exchange Library | exgLocalPrefix
SMS Library | kSmsScheme
Any library that supports the _send scheme (user's choice) | exgSendPrefix
Any library that supports the _send or _beam scheme (user's choice) | exgSendBeamPrefix
The section "Implementing the Send Command" provides more information on using exgSendPrefix or exgSendBeamPrefix. ## Identifying the Type of Data When your application sends data, the exchange socket structure (ExgSocketType) identifies the type of data being sent. It can do so with one of the following values: A MIME type in the type field. This field is only used on Palm OS 4.0 and higher. A file extension for the file in the name field. That is, you might supply MyDB.pdb as the value of the name field. The part after the last period (.) is the extension. In most cases, the data type determines which application receives the data on the remote side. (If the target field is specified, it determines which application receives the data instead of the data type as described below.) The Exchange Manager maintains a registry of applications and the types of data each application can receive. When the Exchange Manager receives an object, it checks the exchange socket for the data type. It checks the type field first, and if it is not defined or if no application is registered to receive that MIME type, it checks the name field for a file extension. This is discussed in more detail in the "Registering for Data" section. Note that you may also directly specify which application should receive the data. To do so, place the creator ID in the target field. You do not have to specify a MIME type or file extension in this instance. When the target field is nonzero, the Exchange Manager checks for the existence of that application on the receiving device. If it exists, that application receives the data regardless of whether it is registered. If the target application does not exist, the Exchange Manager searches the registry as usual. Use the target field only if you know that you are communicating with a Palm Powered handheld and want to explicitly specify which application should receive the data. On Palm OS 4.0 and higher, an application can register for another application's creator ID and receive all objects targeted to that creator ID. See "Setting the Default Application" for more details. ## Registering for Data In most cases, applications that want to receive data from the Exchange Manager must register for the MIME type and/or file extension that they want to receive. The function that you use to do so differs depending on which operating system versions you want to support. On Palm OS 3.X, you call ExgRegisterData and pass it three parameters: your application's creator ID, a constant that identifies the type of data you want to register to receive (exgRegExtensionID for file extensions or exgRegTypeID for MIME types), and a string that lists the MIME types or file extensions. For example, on Palm OS 3.X the Beamer sample application distributed with the Palm OS SDK makes this call:
    ExgRegisterData(beamerCreator,
      exgRegExtensionID, BitmapExt);
On Palm OS 4.0 and higher, ExgRegisterData is deprecated and replaced with ExgRegisterDatatype. ExgRegisterDatatype supports more types of data and takes more parameters. You still pass the creator ID, the type of data you want to register for, and the string that describes the specifics of what you are registering for. Palm OS 4.0 and higher supports registering for creator IDs (exgRegCreatorID) or URL schemes (exgRegSchemeID) in addition to MIME types and file extensions; however, registering for these new data types is not as common. See "Setting the Default Application" for a case where you would register for a creator ID, and see "Requesting a URL" for a case where you would register for a URL. In addition, you must pass two more parameters to ExgRegisterDatatype: a string containing descriptions of the data you are registering to receive and a flag indicating whether you want to receive the data directly if it is sent as part of another object. The descriptions that you pass in are displayed to preview the data in the exchange dialog under certain circumstances. The flag parameter is described in the "Registering to Receive Unwrapped Data" section. For example, on Palm OS 4.0 the Beamer sample application distributed with the Palm OS SDK makes this call:
    ExgRegisterDatatype(beamerCreator,
      exgRegExtensionID, BitmapExt, "bitmap", 0);
## General Registration Guidelines Follow these guidelines when registering for data: Register as early as possible. To ensure that your application can receive data at any time after it is installed, call ExgRegisterData or ExgRegisterDatatype in response to the sysAppLaunchCmdSyncNotify launch code. This launch code is sent to your application upon its first installation and any time the HotSync® operation modifies the application's database. It's best to use a standardized data format rather than a proprietary one if you have a choice. On Palm OS 4.0 and higher, multiple applications can register to receive the same data type. The section "Setting the Default Application" describes this further. When registering for file extensions, do not include the period (.) as part of the extension. Register for "TXT", for example, not ".TXT". Do not make multiple calls if you want to register for more than one MIME type or more than one file extension. Instead, make one call for all file extensions and one call for all MIME types. Pass a single string containing file extensions or MIME types separated by a tab (\t) character. For example, the following call registers the application for two file extensions, TXT and DOC:
    ExgRegisterData(myCreator, exgRegExtensionID,
    "TXT\tDOC", "plain text", 0);
The description parameter is optional. If you implement the preview mode as described in "Displaying a Preview" later in this chapter, you do not need to provide a description. It is, however, strongly recommended that you provide one. ## Setting the Default Application Because multiple applications can register for the same data type on Palm OS 4.0 and higher, the Exchange Manager supports the concept of a default application that receives all objects of a particular data type. To set the default application, call the function ExgSetDefaultApplication. There is one default application per data type in the registry. Palm OS 3.X does not support having multiple applications registered for the same data types. Suppose a device running Palm OS 4.0 receives a vCard object, and it has three applications registered to receive vCards. The Exchange Manager checks the registry to see if any of these applications is assigned as the default. If so, the default application receives all vCards (unless the exchange socket structure's target field is set). If none of the three applications is the default, the Exchange Manager chooses one, and that application receives all vCards. Palm, Inc. strongly recommends that you allow users to choose which application is the default. To do so, you could display a panel that shows users the applications that can receive the same type of data as your application, show them which is the default, and allow them to select a different default. Use ExgGetRegisteredApplications to get a list of all applications registered to receive the same data type as yours, and use ExgGetDefaultApplication to retrieve the current default, if any. See Listing 1.2 to see how the iMessenger example application performs this task for the mailto URL scheme. The full source code is distributed with the SDK. Listing 1.1 Initializing a List of Registered Applications
    void PrvSetMailAppsList(Int32 listSelection)
    {
       ControlPtr ctl;
       ListPtr lst;
       UInt32 defaultID;

       ctl = GetObjectPtr(PrefDefaultMailTrigger);
       lst = GetObjectPtr(PrefDefaultMailList);

       // crIDs, appCnt, appNames are all global variables.
       // Get the list of creator IDs if we don't have it already.
       if(!crIDs) {
          ExgGetRegisteredApplications(&crIDs, &appCnt, &appNames, NULL,
             exgRegSchemeID, "mailto");
          if(appCnt) {
             MemHandle tmpH = SysFormPointerArrayToStrings(appNames, appCnt);
             if(tmpH)
                appNamesArray = MemHandleLock(tmpH);
             else
                return;
          }
          else
             return;
       }

       if(appNamesArray)
          LstSetListChoices(lst, appNamesArray, appCnt);
       LstSetHeight(lst, appCnt < 6 ? appCnt : 6);

       if(listSelection == -1)
       {
          UInt16 i;
          ExgGetDefaultApplication(&defaultID, exgRegSchemeID, "mailto");

          for(i=0;i<appCnt;i++) {
             if(crIDs[i] == defaultID)
                LstSetSelection(lst, i);
          }
       }
       else
          LstSetSelection(lst, listSelection);

       CtlSetLabel(ctl, appNamesArray[LstGetSelection(lst)]);
    }
To become the default application for a data type that a built-in Palm OS application is registered to receive (see Table 1.2), you must perform some extra steps to ensure that you can receive that type of object when it is beamed from a device running Palm OS 3.X. You must register for the built-in application's creator ID and become the default application for that creator ID. On Palm OS 3.X, the built-in applications always set their creator IDs in the target field when sending data, causing the data to always be sent to that application. On Palm OS 4.0 and higher, the built-in applications still register to receive the same type of data, but they do not set the target field when sending. This means that if your application is registered for the same data type and is the default application, it receives the data from Palm OS 4.0 and higher as expected, but if the data is sent from a device running Palm OS 3.X, you still won't receive that data because it is specifically targeted for the built-in application. To solve this problem, the ExgRegisterData function in Palm OS 4.0 and higher supports registering for another application's creator ID. Listing 1.2 shows how an application that receives vCards might set the default application after allowing the user to select the default from a list, assuming the list is initialized with code similar to that in Listing 1.1. Note that, as with all data types, your application won't receive the data targeted for the other application unless yours is the default application for that creator ID. Listing 1.2 Setting the default application for vCards
    UInt32 PilotMain (UInt16 cmd, void *cmdPBP, UInt16 launchFlags)
    {
       ...
       // Register for vCard MIME type, extension, and Address Book's creator ID.
       // At this point, we are not the default application so we do not receive
       // vCards. We still must register upon install so that our application
       // appears in the preferences list when the user chooses the default
       // application for vCards.
       case sysAppLaunchCmdSyncNotify:
          Char addressCreatorStr[5];

          // Create a string from Address Book's creator ID.
          MemMove(addressCreatorStr, sysFileCAddress, 4);
          addressCreatorStr[4] = chrNull;

          ExgRegisterDatatype(crID, exgRegTypeID, "text/x-vCard", "vCard", 0);
          ExgRegisterDatatype(crID, exgRegExtensionID, "vcf", "vCard", 0);
          ExgRegisterDatatype(crID, exgRegCreatorID, addressCreatorStr, NULL, 0);
          ...
    }

    static void PrefApply (void)
    {
       MemHandle h;
       FieldType *fld;
       ControlType *ctl;
       UInt16 listItem;

       // Set the default vCard app
    vif(appCnt && crIDs)
       {
          UInt32 crID;
          Char addressCreatorStr[5];

          // Create a string from Address Book's creator ID.
          MemMove(addressCreatorStr, sysFileCAddress, 4);
          addressCreatorStr[4] = chrNull;

          listItem = LstGetSelection(GetObjectPtr(PrefDefaultAppList));
          crID = crIDs[listItem];
          ExgSetDefaultApplication(crID, exgRegTypeID, "text/x-vCard");
          ExgSetDefaultApplication(crID, exgRegExtensionID, "vcf");
          ExgSetDefaultApplication(crID, exgRegCreatorID, addressCreatorStr);
       }
    }
## Registering to Receive Unwrapped Data On Palm OS 4.0 or higher, in rare circumstances, you can register to receive data that is sent enclosed in another object. For example, suppose you have a stock quote application that wants to receive vStock objects. If the device is sent an e-mail message that has the vStock object attached, your application may want to register to receive the vStock object directly rather than having the e-mail application receive it. To do so, call ExgRegisterDatatype and pass the constant exgUnwrap as the last parameter. The flag is named exgUnwrap because the exchange library unwraps the received object (the e-mail message in this example) so that it can send the contained objects (the vStock object) directly. If you want to register to receive an object when it is sent as part of another object, you probably also want to receive it when it is sent by itself. This requires two calls to ExgRegisterDatatype: one with the exgUnwrap flag set, and one without.
    ExgRegisterDatatype(myCreator,
      exgRegExtensionID, "TXT\tDOC", "plain text",
      0);
    ExgRegisterDatatype(myCreator,
      exgRegExtensionID, "TXT\tDOC", "plain text",
      exgUnwrap);
Thus, you might make four calls to ExgRegisterDatatype: one call to register for the file extensions one call to register for file extensions that are sent as part of another object one call to register for MIME types one call to register for MIME types that are sent as part of another object As mentioned previously, it's rare for an application to register to receive unwrapped data directly. It's more common for one application (such as an e-mail application) to receive the entire compound object and then unwrap and disperse the enclosed objects using the Local Exchange Library. See "Sending and Receiving Locally" for more information. ## Sending Data This section describes how to send data using the Exchange Manager. It discusses the following topics: Sending a Single Object Sending Multiple Objects Implementing the Send Command ## Sending a Single Object The most common use of the Exchange Manager is to send or receive a single object. To send an object, do the following: 1. Create and initialize an ExgSocketType data structure with information about which library to use and the data to be sent. See "Initializing the Exchange Socket Structure" for more information. 2. Call ExgPut to establish the connection with the exchange library. 3. Call ExgSend one or more times to send the data. In this function, you specify the number of bytes to send, and ExgSend returns the number of bytes that were sent. You may need to call it multiple times if data is remaining to be sent after the first and subsequent calls. 4. Call ExgDisconnect to end the connection. A zero (0) return value indicates a successful transmission. However, this doesn't necessarily mean that the receiver kept the data. If the target application for an object doesn't exist on the receiving device, the data is discarded; or the user can decide to discard any received objects. Note that the ExgSend function blocks until it returns. However, most libraries provide a user interface dialog that keeps the user informed of transmission progress and allows them to cancel the operation. The Exchange Manager automatically displays error dialogs as well, if errors occur. You must check for error codes from Exchange Manager routines, but you don't need to display an error dialog if you get one because the Exchange Manager handles this for you. For example, Listing 1.3 shows how to send the current draw window from one Palm Powered handheld to another Palm Powered handheld. It is modified from the Beamer example application that is included in the Palm OS SDK. Listing 1.3 Sending data using Exchange Manager
    Err SendData(void)
    {
       ExgSocketType exgSocket;
       UInt32 size = 0;
       UInt32 sizeSent = 0;
       Err err = 0;
       BitmapType *bmpP;

       // copy draw area into the bitmap
       SaveWindow();
       bmpP = PrvGetBitmap(canvasWinH, &size, &err);
       // Is there data in the field?
       if (!err && size) {
          // important to init structure to zeros...
          MemSet(&exgSocket,sizeof(exgSocket),0);
          exgSocket.description = "Beamer picture";
          exgSocket.name = "Beamer.pbm";
          exgSocket.length = size;
          err = ExgPut(&exgSocket);
          if (!err) {
             while (!err && sizeSent < size) {
                sizeSent += ExgSend(&exgSocket,bmpP,size,&err);
            }
             ExgDisconnect(&exgSocket,err);
          }
       }
       if (bmpP) MemPtrFree(bmpP);
       return err;
    }
## Sending Multiple Objects On Palm OS 4.0 and higher, if the exchange library supports it, you can send multiple objects in a single connection. To send multiple objects, do the following: 1. Create and initialize an ExgSocketType data structure with information about which library to use and the data to be sent. See "Initializing the Exchange Socket Structure" for more information. You might also supply a value for the count field to specify how many objects are to be sent. 2. Call ExgConnect to establish the connection with the exchange library. 3. For each object, do the following: a. Call ExgPut to signal the start of a new object. b. Call ExgSend multiple times to send the data. In this function you specify the number of bytes to send, and ExgSend returns the number of bytes that were sent. You may need to call it multiple times if data is remaining to be sent after the first and subsequent calls. 4. Call ExgDisconnect to end the connection. A zero (0) return value indicates a successful transmission. However, this doesn't necessarily mean that the receiver kept the data. If the target application for an object doesn't exist on the receiving device, the data is discarded; or the user can decide to discard any beamed objects. The ExgConnect call is optional. Some exchange libraries, such as the IR Library, support the sending of multiple objects but do not support ExgConnect. If ExgConnect returns an error, the first call to ExgPut initiates the connection. You should only continue to send objects if the first ExgPut call succeeds. See Listing 1.4. Libraries that support the ExgConnect call also support sending multiple objects without using ExgConnect. Listing 1.4 Sending multiple objects
    Boolean isConnected = false;
    err = ExgConnect(&exgSocket);      //optional
    if (!err)
       isConnected = true;
    if (!err || err == exgErrNotSupported) {
       while (/* we have objects to send */) {
          err = ExgPut(&exgSocket);
          if (!isConnected && !err)
             isConnected = true; //auto-connected on first put.
          while (!err && (sizeSent < size))
             sizeSent += ExgSend(&exgSocket,dataP,size,&err);
          if (err)
             break;
       }
    }
    if (isConnected)
       ExgDisconnect(&exgSocket, err);
## Implementing the Send Command Starting in Palm OS 4.0, the built-in applications support a Send menu command. The purpose of this command is to allow the user to send data using any available transport mechanism. The Exchange Manager defines a _send URL scheme. The intent is that any exchange library that supports sending is registered for the _send scheme. Currently, only the SMS Library is registered for this scheme on release ROMs. When Bluetooth support becomes available, the Bluetooth Library will be registered for this scheme. The IR Library is not registered for the _send scheme. To implement the Send command in your application, construct a URL that has the prefix exgSendPrefix, and send the data in the normal manner. You can also use the exgSendBeamPrefix instead so that the user can select from all exchange libraries registered for either sending or beaming (which includes the IR Library). Both of these prefixes begin with a question mark, causing the Exchange Manager to display a dialog if it finds more than one exchange library registered for the specified schemes. Currently on a Palm OS 4.0 release ROM, only the SMS Exchange Library supports the _send scheme, so using exgSendPrefix would not cause the dialog to be displayed. If the user later adds Bluetooth support, the prefix would cause the dialog to be displayed. NOTE: On debug ROMs, the Local Exchange Library is listed as one of the possible transport mechanisms. This allows you to debug your Send command. The Local Exchange Library is not listed in the Send With dialog on release ROMs. For an example of how to implement the Send command, see the Memo application example code distributed with the Palm OS SDK. ## Receiving Data To have your application receive data from the Exchange Manager, do the following: 1. Register for the type of data you want to receive. See "Registering for Data" for more information. 2. Handle the launch code sysAppLaunchCmdExgAskUser if you want to control the user confirmation dialog that is displayed. See "Controlling the Exchange Dialog" for more information. 3. Handle the launch code sysAppLaunchCmdExgPreview if you want to display a preview of the data to be received. See "Displaying a Preview" for more information. 4. Handle the launch code sysAppLaunchCmdExgReceiveData to receive the data. See "Receiving the Data" for more information. 5. If you want, handle sysAppLaunchCmdGoto to display the record. ## Controlling the Exchange Dialog When the Exchange Manager receives an object and decides that your application is the target for that object, it sends your application a series of launch codes. The first launch code your application receives, in most cases, is sysAppLaunchCmdExgAskUser. NOTE: In Palm OS 4.0 and higher, the Exchange Manager allows the exchange library to turn off the user confirmation dialog. In this case, your application does not receive the sysAppLaunchCmdExgAskUser launch code. The Exchange Manger sends this launch code because it is about to display the exchange dialog, which asks the user to confirm the receipt of data. The launch code is your opportunity to accept the data without confirmation, reject the data without confirmation, or replace the exchange dialog. Responding to this launch code is optional. If you don't respond, the Exchange Manager calls ExgDoDialog to display the exchange dialog. On Palm OS 3.5 and higher, the ExgDoDialog function allows you to specify that the dialog display a category pop-up list. This pop-up list allows the user to receive the data into a certain category in the database, but the pop-up list is not shown by default. If you want the exchange dialog to display the pop-up list, you must respond to sysAppLaunchCmdExgAskUser and call ExgDoDialog yourself. Pass a pointer to an ExgDialogInfoType structure. The ExgDialogInfoType structure is defined as follows:
    typedef struct {
      UInt16     version;
      DmOpenRef  db;
      UInt16     categoryIndex;
    } ExgDialogInfoType;
#####
-> version | Set this field to 0 to specify version 0 of this structure.
#####
-> db | A pointer to an open database that defines the categories the dialog should display.
#####
<- categoryIndex | The index of the category in which the user wants to file the incoming data.
If db is valid, the function extracts the category information from the specified database and displays it in a pop-up list. Upon return, the categoryIndex field contains the index of the category the user selected, or dmUnfiledCategory if the user did not select a category. If the call to ExgDoDialog is successful, your application is responsible for retaining the value returned in categoryIndex and using it to file the incoming data as a record in that category. One way to do this is to store the categoryIndex in the socket's appData field (see ExgSocketType) and then extract it from the socket in your response to the launch code sysAppLaunchCmdExgReceiveData. See Listing 1.5 for an example. Listing 1.5 Extracting the category from the exchange socket
    UInt16 categoryID = (ExgSocketType *)cmdPBP->appData;

    /* Receive the data, and create a new record using the
       received data. indexNew is the index of this record. */
    if (category != dmUnfiledCategory){
       UInt16 attr;
       Err err;
       err = DmRecordInfo(dbP, indexNew, &attr, NULL, NULL);

       // Set the category to the one the user specified, and
       // mark the record dirty.
       if ((attr & dmRecAttrCategoryMask) != category) {
         attr &= ~dmRecAttrCategoryMask;
         attr |= category | dmRecAttrDirty;
         err = DmSetRecordInfo(dbP, indexNew, &attr, NULL);
       }
    }
Some of the Palm OS built-in applications (Address Book, Memo, and ToDo) use this method of setting the category on data received through beaming. Refer to the example code provided in the Palm OS SDK for these applications for a more complete example of how to use ExgDoDialog. When you explicitly call ExgDoDialog, you must set the result field of the sysAppLaunchCmdExgAskUser launch code's parameter block to either exgAskOk (upon success) or exgAskCancel (upon failure) to prevent the system from displaying the dialog a second time. ## Displaying a Preview On Palm OS 4.0 and higher, the exchange dialog contains a preview of the data to be received. The preview allows the user to see what the data is. The reason for the preview is that Palm OS 4.0 and higher supports exchange libraries other than the IR Library. When you use the IR Library to beam data to another Palm Powered handheld, the sender and the receiver must be in close contact with one another. Other transport mechanisms do not require the devices to be within close proximity, so the user might not know that the data is being received or why. In this case, the user might need more information about the object being received, so the Exchange Manager displays information about the object in the exchange dialog. Also, some exchange libraries do not transmit information for the exchange socket's description field, so the Exchange Manager must provide another means of supplying the user with information about the data being received. To display the preview, the Exchange Manager launches the receiving application with the launch code sysAppLaunchCmdExgPreview. Your application does not have to respond to this launch code. If it doesn't, the Exchange Manager displays the first item that it locates in the following list: The data's description from the exchange socket's description field The filename in the socket's name field The receiving application's description as stored in the exchange registry (you pass this description to ExgRegisterDatatype when registering) The MIME type in the socket's type field The file extension in the socket's name field If you want to support a preview that is more elaborate than those in the previous list, handle the sysAppLaunchCmdExgPreview launch code. The launch code's parameter block is an ExgPreviewInfoType structure. This structure contains the ExgSocketType structure, an op field that describes what type of preview data the Exchange Manager expects, and fields in which to return the data. To respond to the launch code, do the following: 1. Check the op field in the parameter block to see what type of preview data is expected. In most cases, the preview data is a string, but a graphical display might also be requested. 2. Call ExgAccept to establish a connection with the exchange library. 3. Call ExgReceive one or more times to receive the data. In this function, you specify the number of bytes to receive and it returns the number of bytes that were received. You may need to call it multiple times if data is remaining to be received after the first and subsequent calls. 4. Place the data in the parameter block's string field if the op field specifies a string preview. If the op field specifies a graphical preview, draw the data into the rectangle identified by the parameter block's bounds field. 5. Call ExgDisconnect to end the connection. A zero (0) return value indicates a successful transmission. Note that you perform essentially the same steps to preview the data as you do to receive it. The only difference is what you do with the data after you receive it. In response to sysAppLaunchCmdExgPreview, you pass the data back to the Exchange Manager and discard it in case the user rejects the data. In response to sysAppLaunchCmdExgReceiveData, you store the data. For an example of handling the sysAppLaunchCmdExgPreview launch code, see the Address Book example application that is distributed with the Palm OS SDK. The TransferPreview function handles the launch code. ## Receiving the Data If the Exchange Manager receives exgAskOk in response to the exchange dialog or the sysAppLaunchCmdExgAskUser launch code, the next step is to launch the application with sysAppLaunchCmdExgReceiveData. This launch code tells the application to actually receive the data. To respond to this launch code, do the following: 1. Call ExgAccept to accept the connection. 2. Call ExgReceive one or more times to receive the data. In this function you specify the number of bytes to receive, and ExgReceive returns the number of bytes that were received. You may need to call it multiple times if data is remaining to be received after the first and subsequent calls. Note that in the socket structure, the length field may not be accurate, so in your receive loop you should be flexible in handling more or less data than length specifies. 3. If you want your application launched again with the sysAppLaunchCmdGoto launch code, place your application's creator ID in the ExgSocketType's goToCreator field and supply the information that should be passed to the launch code in the gotoParams field. (The ExgSocketType structure is the sysAppLaunchCmdExgReceiveData's parameter block.) 4. Call ExgDisconnect to end the connection. A zero (0) return value indicates a successful transmission. After your application returns from sysAppLaunchCmdExgReceiveData, if the goToCreator specifies your application's creator ID and if the exchange library supports it, your application is launched with sysAppLaunchCmdGoto. In response to this launch code, your application should launch, open its database, and display the record identified by the recordNum field (or matchCustom field) in the parameter block. The Exchange Manager always does a full application launch with sysAppLaunchCmdGoto, so your application has access to global variables; however, if you also use this launch code to implement the global find facility, you may not have access to global variables in that instance. The example code in Listing 1.6 checks to see if globals are available, and if so, calls StartApplication to initialize them. Listing 1.6 Responding to sysAppLaunchCmdGoto
    case sysAppLaunchCmdGoto:
      if (launchFlags & sysAppLaunchFlagNewGlobals) {
         err = StartApplication();
         if (err) return err;
         GoTo(cmdPBP, true);
         EventLoop();
         StopApplication();
      } else {
         GoTo(cmdPBP, false);
    }
On Palm OS 4.0 and higher, not all exchange libraries support using the sysAppLaunchCmdGoto launch code after the receipt of data. Also note that because Palm OS 4.0 and higher supports multiple object exchange, there is no guarantee that your application is the one that is launched at the end of a receipt of data. If multiple objects are being received, it is possible for another application to receive data after yours and to set the goToCreator field to its own creator ID. In this case, the last application to set the field is the one that is launched. Listing 1.7 shows a function that receives a data object and sets the goToCreator and goToParams. This code is taken from the Beamer example application that is distributed with the Palm OS SDK. Listing 1.7 Receiving a data object
    static Err ReceiveData(ExgSocketPtr exgSocketP)
    {
       Err err;
       MemHandle dataH;
       UInt16 size;
       UInt8 *dataP;
       Int16 len;
       UInt16 dataLen = 0;

       if (exgSocketP->length)
          size = exgSocketP->length;
       else
          size = ChunkSize;
       dataH = MemHandleNew(size);
       if (!dataH) return -1;  //
       // accept will open a progress dialog and wait for your receive commands
       err = ExgAccept(exgSocketP);
       if (!err){
          dataP = MemHandleLock(dataH);
          do {
             len = ExgReceive(exgSocketP,&dataP[dataLen], size-dataLen,&err);
             if (len && !err) {
                dataLen+=len;
                // resize block when we reach the limit of this one...
                if (dataLen >= size) {
                   MemHandleUnlock(dataH);
                   err = MemHandleResize(dataH,size+ChunkSize);
                   dataP = MemHandleLock(dataH);
                   if (!err) size += ChunkSize;
                }
             }
          }
          while (len && !err);

          MemHandleUnlock(dataH);

          ExgDisconnect(exgSocketP,err); // closes transfer dialog

          if (!err) {
             exgSocketP->goToCreator = beamerCreator;
             exgSocketP->goToParams.matchCustom = (UInt32)dataH;
          }
       }
       // release memory if an error occured
       if (err) MemHandleFree(dataH);
       return err;
    }
## Sending and Receiving Databases It's common to want to send and receive an entire database using the Exchange Manager. For example, you might want to allow your application's users to share their versions of the PDB file associated with your application by beaming that file to each other. Sending and receiving a database involves the extra steps of flattening the database into a byte stream when sending and un-flattening it upon return. ## Sending a Database To send a database, do the following: 1. Create and initialize an ExgSocketType data structure with information about which library to use and the data to be sent. See "Initializing the Exchange Socket Structure" for more information. 2. Call ExgPut to establish the connection with the exchange library. 3. Call ExgDBWrite and pass it a pointer to a callback function in your application that it can use to send the database. You make the call to ExgSend in that function. 4. Call ExgDisconnect to end the connection. The ExgDBWrite function takes as parameters the local ID and card number of the database to be sent and a pointer to a callback function. You may also pass in the name of the database as it should appear in a file list and any application-specific data you want passed to the callback function. In this case, you would pass the pointer to the exchange socket structure as the application-specific data. If you need any other data, create a structure that contains the exchange socket and pass a pointer to that structure instead. The write callback function is called as many times as is necessary to send the data. It takes three arguments: a pointer to the data to be sent, the size of the data, and the application-specific data passed as the second argument to ExgDBWrite. Listing 1.8 shows an example of how to send a database. The SendMe function looks up the database creator ID and card number and passes it to the SendDatabase function. The SendDatabase function creates and initializes the exchange socket structure and then passes all that information along to the ExgDBWrite function. The ExgDBWrite function locates the database in the storage heap, translates it into a stream of bytes and passes that byte stream as the first argument to the write callback function WriteDBData. WriteDBData forwards the exchange socket and the data stream to the ExgSend call, sets its size parameter to the number of bytes sent (the return value of ExgSend), and returns any error returned by ExgSend. Listing 1.8 Sending a database
    // Callback for ExgDBWrite to send data with Exchange Manager
    Err WriteDBData(const void* dataP, ULong* sizeP, void* userDataP)
    {
       Err err;

       *sizeP = ExgSend((ExgSocketPtr)userDataP, (void*)dataP, *sizeP, &err);
       return err;
    }

    Err SendDatabase (Word cardNo, LocalID dbID, CharPtr nameP,
    CharPtr descriptionP)
    {
       ExgSocketType exgSocket;
       Err err;

       // Create exgSocket structure
       MemSet(&exgSocket, sizeof(exgSocket), 0);
       exgSocket.description = descriptionP;
       exgSocket.name = nameP;

       // Start an exchange put operation
       err = ExgPut(&exgSocket);
       if (!err) {
          err = ExgDBWrite(WriteDBData, &exgSocket, NULL, dbID, cardNo);
          err = ExgDisconnect(&exgSocket, err);
       }
       return err;
    }

    // Sends this application
    Err SendMe(void)
    {
       Err err;

       // Find our app using its internal name
       LocalID dbID = DmFindDatabase(0, "Beamer");

       if (dbID)
          err = SendDatabase(0, dbID, "Beamer.prc", "Beamer application");
       else
          err = DmGetLastErr();
       return err;
    }
Note that there is nothing about ExgDBWrite that is tied to the Exchange Manager, so it may be used to send a database using other transport mechanisms as well. For example, if you wanted to transfer a database from your Palm Powered handheld to your desktop PC using the serial port, you could use ExgDBWrite to do so. ## Receiving a Database The Launcher application receives databases with the .prc or .pdb file extension. If you want your application to be launched when the database is received, you can use a different extension and handle receiving the database within your application. For example, a book reader application might want to be launched when the user is beamed a book. In this case, the book reader application might use an extension such as .bk for the book databases. You receive a database by responding to the same launch codes that you do for receiving any other data object (see "Receiving Data"); however, your response to the sysAppLaunchCmdExgReceiveData launch code is a little different: 1. Call ExgAccept to accept the connection. 2. Call ExgDBRead and pass it a pointer to a callback function in your application that it can use to read the database. You make the call to ExgReceive in that function. 3. Call ExgDisconnect to end the connection. The ExgDBRead function takes as parameters two pointers to callback functions. The first callback function is a function that is called multiple times to read the data. The second function is used if the database to be received already exists on the device. ## Requesting Data On Palm OS 4.0 and higher, some exchange libraries allow you to request data from a remote device through a call to ExgGet. You can use ExgGet to implement two-way communications between two PalmTM devices. This section describes how to use the Exchange Manager to request data. It covers: Sending a Get Request for a Single Object Responding to a Get Request Two-Way Communications Requesting a URL ## Sending a Get Request for a Single Object To request data from a remote device, do the following: 1. Create and initialize an exchange socket structure (ExgSocketType) as described in "Initializing the Exchange Socket Structure"section. The data structure should identify the exchange library and the type of data that your application wants to receive. 2. Call ExgGet to establish the connection and request the data. In response, the exchange library establishes a connection with the remote device, and upon return has data that your application should receive. If the remote device is a Palm Powered handheld, the exchange library obtains this data from an application on the remote side using the process described in the "Responding to a Get Request" section. 3. Call ExgReceive one or more times to receive the data. 4. Call ExgDisconnect to end the connection. ## Responding to a Get Request When the Exchange Manager on the remote device receives the get request, it launches the appropriate application with the launch code sysAppLaunchCmdExgGetData. Your response to the sysAppLaunchCmdExgGetData launch code should be to send the requested data: 1. Call ExgSend one or more times. 2. Call ExgDisconnect when finished. See the "Sending a Single Object" section for more information. ## Two-Way Communications You can use ExgGet and ExgPut in combination with the ExgConnect call to have your application perform two-way communication. For example, you may want to implement two-way communication in a multiuser game. In such a situation, one device acts as a client and the other acts as a server. The client calls ExgConnect, which tells the exchange library that a connection is established to perform multiple operations, such as the sending of multiple objects. The client then calls ExgGet or ExgPut repeatedly and calls ExgDisconnect when finished. On the server device, the appropriate application is launched for each of these requests. The server also calls ExgDisconnect when it is done sending or receiving each object. The swapping of client and server roles is not supported. Remember that not all exchange libraries support ExgConnect and ExgGet. If either one of these returns an error, your application should assume that this feature is not available. ## Requesting a URL In addition to requesting data with an ExgGet call, you can request a URL with a ExgRequest call on Palm OS 4.0 and higher. The idea behind the ExgRequest call is to follow the model of pull technology. You could, for example, implement a web browser if you had an exchange library that supported the HTTP protocol. You could then send an ExgRequest call with an exchange socket containing a URL such as http://www.palmos.com and receive the web page in response. The fundamental differences between ExgRequest and ExgGet are: ExgRequest does not automatically send the data back to the application that requested it. With ExgRequest, when the exchange library receives the requested data, it has the Exchange Manager send it to the default application for that data type. Applications can register for URLs sent using ExgRequest. ExgRequest first looks for an exchange library that handles the URL scheme. If it cannot find one, it looks for an application instead. If it finds an application, it launches it with the sysAppLaunchCmdGoToURL launch code. For example, the iMessenger application distributed with the Palm OS SDK registers for the mailto URL scheme. If another application wants to implement an e-mail command, it could do so by calling ExgRequest and passing an exchange socket with a URL that begins with mailto. In response to this command, the Exchange Manager launches the iMessenger application, allowing the user to compose the email. ## Sending and Receiving Locally Most of this chapter has described how to use the Exchange Manager to send data to a remote device and receive data from a remote device. You may also use the Exchange Manager to exchange data with other applications on the local device. To do so, use the Local Exchange Library. You might want to do so in the following circumstances: You might have an application that creates some sort of event in the Datebook application. Your users might have an application that they use in place of the built-in Datebook. To ensure that the appointment is sent to the user's chosen application, you can send that data as a vCalendar object using the Local Exchange Manager. This way, whichever application is the default in the Exchange Manager registry is the one that receives your vCalendar. You could use the preview feature of the Exchange Manager to have another application display data for you. As described in the "Displaying a Preview" section, an application can be launched with the sysAppLaunchCmdExgPreview launch code to display a preview of the data it is registered to receive. You could use this feature in your own application to display data your application does not recognize. Suppose your application has a GIF and wants to display it in a dialog. It could use the Local Exchange Library to send that GIF to a graphics application on the local device, which in response draws the preview into the bounds of a rectangle you provide. Your application receives compound data objects, such as e-mail messages that contain attachments intended for other applications. As described in the "Registering to Receive Unwrapped Data" section, exchange libraries can "unwrap" a compound object and deliver the objects it contains directly; however, doing so is the exception the rule. It's much more common for the e-mail message to be sent to the e-mail application and have the attachments delivered to the appropriate applications only when the user requests it. In response to a user request, the e-mail application extracts the attached object and uses the Local Exchange Library to send it to the application that should receive it. Your application exchanges data with a remote device, and you want to debug the code that interacts with the Exchange Manager. In this case, using the Local Exchange Library causes your application to send data in loopback mode, where it is also the recipient of the data. To use the Local Exchange Library, do the following: 1. Use a URL in the name field of the ExgSocketType structure to identify the Local Exchange Library. Begin the URL with the constant string exgLocalPrefix. The Exchange Manager only supports URLs on Palm OS 4.0 and higher. On Palm OS 3.X devices, set the localMode flag to 1 to interact with the Local Exchange Library instead of the IR Library. 2. If you want to suppress the exchange dialog or if you want to perform a preview operation, create and initialize an ExgLocalSocketInfoType structure and assign it to the socket's socketRef field.
    typedef struct {
      Boolean freeOnDisconnect;
      Boolean noAsk;
      ExgPreviewInfoType *previewInfoP;
      ExgLocalOpType op;
      FileHand tempFileH;
    } ExgLocalSocketInfoType;
where the following are parameters you might want to set: #####
freeOnDisconnect | Whether the structure is freed when the ExgDisconnect call is made. The default is true. In general, code that allocates a structure should be responsible for freeing that structure. Therefore, if you have allocated ExgLocalSocketInfoType, you should set this field to false and explicitly free the structure when you are finished with it.
noAsk | Set to true to disable the display of the exchange dialog. If you want to, for example, create a vCalendar object and send it to the datebook application in response to a user command, you probably want to set noAsk to true so that the user does not have to confirm the receipt of the data they just requested you to send.
previewInfoP | A pointer to an ExgPreviewInfoType structure, used to display a preview of the data. If you wanted to simply use another application to help display data, you would create and initialize this structure.
All other fields are set by the Local Exchange Library. If you don't create this structure, the library does it for you; therefore, you only need to create this structure if you want to supply non-default values for the noAsk or previewInfoP fields. 3. You can suppress the display of the progress dialogs that the exchange libraries typically display by setting the noStatus field of the ExgSocketType structure to true. 4. Send and receive data in the normal manner. See "Sending Data" and "Receiving Data" for details. ## Interacting with the Launcher On Palm OS 4.0 and higher, when you beam an application from the Launcher, other databases can be automatically beamed with it. If the application has an associated overlay database, the overlay is beamed along with the application. You do not have to perform any extra work to allow this to happen. Overlay database support begins in Palm OS 3.5; however, if you beam an application from the Palm OS 3.5 Launcher application, it does not beam the overlay. In addition to beaming overlays, you can set up a record database so that the Launcher beams it along with the application database and the overlay. For example, a dictionary application might have its dictionary data in an associated database. When a user beams the dictionary application to another user, the dictionary data should be beamed along with the application itself. To allow this to happen, you set the bit dmHdrAttrBundle in the database's attributes, as shown here:
    DmDatabaseInfo(cardNo, dbID, NULL, &attributes,
      NULL, NULL, NULL, NULL, NULL, NULL, NULL,
      NULL, NULL);
    attributes |= dmHdrAttrBundle;
    DmSetDatabaseInfo(cardNo, dbID, NULL,
      &attributes, NULL, NULL, NULL, NULL, NULL,
      NULL, NULL, NULL, NULL);
If you beam an application plus databases to a device running Palm OS 4.0 or higher, the user sees a single confirmation message. If you beam the application to a device running Palm OS 3.X, the device receives only the application database and displays an alert saying that it cannot receive the other databases. ## Summary of Exchange Manager #####
Exchange Manager Functions
Sending Data |
ExgSend ExgPut | ExgDBWrite
Receiving Data |
ExgReceive ExgAccept | ExgDBRead
Registering for Data |
ExgRegisterDatatype ExgSetDefaultApplication | ExgRegisterData
Requesting Data |
ExgGet | ExgRequest
Connecting and Disconnecting |
ExgDisconnect | ExgConnect
Displaying the Exchange Dialog |
ExgDoDialog |
Obtaining Registry Information |
ExgGetTargetApplication ExgGetRegisteredApplications | ExgGetRegisteredTypes ExgGetDefaultApplication
Querying the Exchange Library |
ExgControl |
For Exchange Library Use Only |
ExgNotifyReceive ExgNotifyPreview | ExgNotifyGoto