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
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
Bluetooth Library1 |
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 Powered™ 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
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.
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
-
?
- 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
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 supplyMyDB.pdb
as the value of thename
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
orExgRegisterDatatype
in response to thesysAppLaunchCmdSyncNotify
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.
PalmSource, 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);
address
CreatorStr[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);
address
CreatorStr[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
The most common use of the Exchange Manager is to send or receive a single object. To send an object, do the following:
- 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. - Call
ExgPut
to establish the connection with the exchange library. - 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. - 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) { 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:
- 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 thecount
field to specify how many objects are to be sent. - Call
ExgConnect
to establish the connection with the exchange library. - For each object, do the following:
- Call
ExgPut
to signal the start of a new object. - 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.
- Call
- 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:
- Register for the type of data you want to receive. See "Registering for Data" for more information.
- 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. - 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. - Handle the launch code
sysAppLaunchCmdExgReceiveData
to receive the data. See "Receiving the Data" for more information. - 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:
- 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. - Call
ExgAccept
to establish a connection with the exchange library. - 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.
- Place the data in the parameter block's
string
field if theop
field specifies a string preview. If theop
field specifies a graphical preview, draw the data into the rectangle identified by the parameter block'sbounds
field. - 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:
- Call
ExgAccept
to accept the connection.
- 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 thanlength
specifies. - If you want your application launched again with the
sysAppLaunchCmdGoTo
launch code, place your application's creator ID in theExgSocketType
'sgoToCreator
field and supply the information that should be passed to the launch code in thegotoParams
field. (TheExgSocketType
structure is thesysAppLaunchCmdExgReceiveData
's parameter block.) - 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:
- 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. - Call
ExgPut
to establish the connection with the exchange library. - 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 toExgSend
in that function. - 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:
- Call
ExgAccept
to accept the connection. - 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 toExgReceive
in that function. - 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 Palm™ 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:
- 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. - 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.
- Call
ExgReceive
one or more times to receive the data. - 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:
- Call
ExgSend
one or more times. - 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. WithExgRequest
, 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 thesysAppLaunchCmdGoToURL
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 callingExgRequest
and passing an exchange socket with a URL that begins withmailto
. 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:
- Use a URL in the
name
field of theExgSocketType
structure to identify the Local Exchange Library. Begin the URL with the constant stringexgLocalPrefix
.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. - 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'ssocketRef
field.typedef struct { Boolean freeOnDisconnect; Boolean noAsk; ExgPreviewInfoType *previewInfoP; ExgLocalOpType op; FileHand tempFileH; } ExgLocalSocketInfoType;
Whether the structure is freed when the |
|
Set to |
|
A pointer to an |
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.
- You can suppress the display of the progress dialogs that the exchange libraries typically display by setting the
noStatus
field of theExgSocketType
structure totrue
. - 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.