This chapter describes how to implement an exchange library. It covers the following topics:
About Exchange Libraries
Exchange Library Components
Implementing an Exchange Library
Prior to implementing an exchange library, you should have a clear understanding of how the Exchange Manager operates. See Chapter 1, "Object Exchange," for an in-depth discussion on the Exchange Manager. Also see Chapter 59, "Exchange Library," of the Palm OS Programmer's API Reference for a detailed description of the functions that must be implemented in each exchange library.
About Exchange Libraries

Exchange libraries are Palm OS® shared libraries that act as "plug-ins" to the Exchange Manager. They deal with protocols and communication devices and allow Palm OS applications to import and export data objects without regard to the transport mechanism. For example, one exchange library always available to Palm PoweredTM handhelds implements the IrDA protocol, IrOBEX. This allows applications to beam objects by way of infrared from one Palm Powered handheld to another.
The following can take advantage of the Exchange Library API:
Removable storage cards
Notification services
Email attachments
Web (HTTP/FTP/CTP/WAP) exchange
HotSync® simplified import and export
Exchange Libraries, Exchange Manager, and Applications

The Exchange Manager is a high-level tool for applications to use. An exchange library is a set of routines that handle the implementation specifics of a particular transport. Typically, exchange library functions are called from the Exchange Manager and are not directly accessed by applications. Applications wanting to send or receive data call the functions provided by the Exchange Manager API, many of which do little more than invoke the corresponding function in the appropriate exchange library.
Exchange libraries also make calls back into the Exchange Manager. For example, an exchange library would call ExgNotifyReceive to have the Exchange Manager deliver objects received by the exchange library.
No one component involved with data exchange (Exchange Manager, exchange library, or application) is complete in itself. However, applications and exchange libraries should be written so the user experiences all interaction as a single seamless interface, even though what takes place is really a complex interaction between different pieces of code.
Figure 2.1 illustrates the relationship between applications, the Exchange Manager, and the exchange libraries within two devices that are in communication.
Figure 2.1 Object exchange using Exchange Manager
The following table lists the division of responsibilities between Palm OS applications, the Exchange Manager, and the exchange libraries.
Table 2.1 Division of responsibility for data object exchange
Palm OS Application |
Exchange Manager |
Exchange Library |
Creates, edits, and stores data |
Maintains registry of exchange libraries |
Sends data to or receives data from other devices |
Converts data to and from the interchange formats |
Maintains registry of applications that can receive data
|
Displays a dialog to get addressing information from user |
Views or describes data |
Passes send and receive requests to appropriate exchange library |
Displays status and error dialogs, possibly using the Progress Manager |
|
Displays a dialog asking if user wants to receive data |
|
Palm OS Exchange Libraries

The Exchange Manager was introduced in Palm OS 3.0 and was significantly enhanced in Palm OS 4.0. Because of this, the various exchange libraries require different versions of the OS. Table 2.2 lists the minimum OS version required by various exchange libraries.
Table 2.2 Version of Palm OS required by 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 |
|
Palm OS 4.0 |
Included with the Palm OS SDK version 4 is the HostTransfer sample exchange library which can be used as a starting point when creating your own exchange libraries.
Exchange Library Components

This section describes the components that make up an exchange library. The topics covered are:
The Exchange Library API
Dispatch Table
The Exchange Library API

The Palm OS Exchange Library API specifies the minimum set of functions that all exchange libraries must implement. These functions can be classified into three major categories: functions that must be included in all shared libraries, functions that establish a connection and send and receive data, and miscellaneous support functions.
Standard Shared Library Functions
Any Palm OS shared library must implement open, close, sleep, and wake functions.
ExgLibOpen
ExgLibClose
ExgLibSleep
ExgLibWake
Functions That Send and Receive Data
These functions do the work of establishing a connection and sending and receiving data.
ExgLibAccept
ExgLibConnect
ExgLibDisconnect
ExgLibGet
ExgLibPut
ExgLibReceive
ExgLibRequest
ExgLibSend
Note that each of these corresponds directly to an Exchange Manager function; in most cases the Exchange Manager simply calls the corresponding exchange library function.
Support Functions
This category consists of functions that provide information about your exchange library and that handle events.
ExgLibControl
ExgLibHandleEvent
Although each of the functions in these three categories must be present in every exchange library, depending on the specific requirements of the exchange library some of them can simply return errNone or exgErrNotSupported.
As with any shared library, the order in which the functions appear in the exchange library's dispatch table identifies the functions in the library. This order is specified in ExgLib.h. Because it's the function's position in the dispatch table and not its name that is important, the actual function names used in a given exchange library may be different from those specified in ExgLib.h. In fact, you'll likely want to use function names that are unique to your shared library, as the Host Transfer library does with such functions as HostTransferLibPut, HostTransferLibSend, and HostTransferLibDisconnect. By using function names specific to your exchange library, you can link your functions into the Mac Simulator and debug with it. If you use the function names defined in ExgLib.h for your functions, you'll get a link error because the Simulator uses those names for stub functions which call your functions.
Beyond the functions listed above, additional library-specific functions must appear in the exchange library's dispatch table after exgLibTrapLast.
Dispatch Table

The dispatch table is a map used by the Palm OS to find the functions in the exchange library. At link time, references to the exchange library functions are resolved to a system trap by way of the SYS_TRAP macro. At runtime, when an exchange library function is called, a trap occurs and the trap finds the function in its library dispatch table and computes the function's offset into the code resource of the exchange library. A JMP instruction to the function's address is made, causing the function to be executed.
NOTE: The structure of the dispatch table for exchange libraries is the same as that of shared libraries. Exchange libraries must do everything shared libraries must do, plus they must register with the Exchange Manager. This gives applications access to their services by way of the Exchange Manager APIs such as ExgPut.
A sample dispatch table source file, HostTransferDispatch.c, is provided with the OS SDK. Listing 2.1 provides a sample of the dispatch table contained within this file (some parts are omitted for clarity).
Listing 2.1 HostTransferDispatch.c
...
void *PrvHostTransferDispatchTable(void);
...
extern Err PrvInstallHostTransferDispatcher(UInt16 refNum, SysLibTblEntryType *entryP);
...
Err __Startup__(UInt16 refNum, SysLibTblEntryType *entryP)
{
return PrvInstallHostTransferDispatcher(refNum, entryP);
}
...
asm void *PrvHostTransferDispatchTable(void)
{
LEA @Table, A0 // table ptr
RTS // exit with it
@Table:
DC.W @Name
DC.W (kOffset) // Open
DC.W (kOffset+(1*4)) // Close
DC.W (kOffset+(2*4)) // Sleep
DC.W (kOffset+(3*4)) // Wake
// Start of the exchange libary
DC.W (kOffset+(4*4)) // HostTransferLibHandleEvent
...
DC.W (kOffset+(12*4)) // HostTransferLibControl
DC.W (kOffset+(13*4)) // HostTransferLibRequest
@GotoOpen:
JMP HostTransferLibOpen
@GotoClose:
JMP HostTransferLibClose
@GotoSleep:
JMP HostTransferLibSleep
@GotoWake:
JMP HostTransferLibWake
@GotoHandleEvent:
JMP HostTransferLibHandleEvent
...
@GotoOption:
JMP HostTransferLibControl
@GotoCheck:
JMP HostTransferLibRequest
@Name:
DC.B HostTransferName
}
...
The last entry in the dispatch table is the name of the exchange library. This must match the name of the database containing the exchange library, and on the simulator, it must end with "-crid", where crid is the creator ID. For example, the Host Transfer library uses "HostTransfer Library-HXfr".
The code segment must be locked so that the dispatch table itself, and the routine addresses in it, will remain valid. The library's database is automatically protected so that it cannot be deleted.
NOTE: The system's shared library table has a slot for library globals for each loaded library. The start-up routine should at least zero this field, if not actually allocate the globals. Some libraries allocate a small structure with an openCount and leave the larger allocation for later, when the library is opened by way of the library's Open() entry point. In this case, the small structure has a reference to the larger one.
The code resource of an exchange library must start with a routine that sets up the dispatch table. This routine must be named __Startup__. The prototype for this function is:
Err __Startup__(UInt16 refNum,
SysLibTblEntryType *entryP)
Usually, __Startup__ consists of a one line call in a MyLibDispatch.c file that calls the actual setup routine in a corresponding MyLib.c file. For example, in the HostTransferDispatch.c sample file provided with the OS SDK the following is used to install the HostTransfer dispatch table:
extern Err PrvInstallHostTransferDispatcher(UInt16 refNum,
SysLibTblEntryType *entryP);
...
Err __Startup__(UInt16 refNum, SysLibTblEntryType *entryP)
{
return PrvInstallHostTransferDispatcher(refNum, entryP);
}
...
__Startup__ is called to set up the dispatch table when a call to SysLibInstall or SysLibLoad is made. For example:
SysLibInstall(PrvInstallHostTransferDispatcher, &refNum);
Listing 2.2 shows how the HostTransfer dispatch table installer function is implemented. This function can be found in the OS SDK sample file HostTransferLib.c. The dispatch table installer function is responsible for making the system's library table entry (entryP) point to the dispatch table. For example:
entryP->dispatchTblP =
(MemPtr *)PrvHostTransferDispatchTable();
The dispatch installer routine generally does a bit of initialization as well.
Listing 2.2 Host transfer dispatch table installer function
Err PrvInstallHostTransferDispatcher(UInt16 refNum, SysLibTblEntryType *entryP)
{
Err err;
HostTransferGlobalsType *gP;
UInt32 value;
Char macro[14];
// Must be 4.0 or greator
err = FtrGet(sysFtrCreator, sysFtrNumROMVersion, &value);
if (err || value < kVersion4_0) return -1;
// Allocate library globals and store pointer to them in the system's
// library table
gP = MemPtrNew(sizeof(HostTransferGlobalsType));
ErrFatalDisplayIf(!gP, "No memory for globals");
if (gP)
{
MemPtrSetOwner(gP, 0);
MemSet(gP, sizeof(HostTransferGlobalsType), 0);
gP->refNum = refNum; // make self reference
entryP->globalsP = gP;
}
// Install pointer to our dispatch table in system's library table
entryP->dispatchTblP = (MemPtr *)PrvHostTransferDispatchTable();
// Check if we're running on the simulator or emulator. On a real device,
// there's no host so we don't register this library with the Exchange
// Manager. In this case, we should really abort the library installation
// altogether, but this demonstrates how exchange libs can change their
// registration status.
#if EMULATION_LEVEL == EMULATION_NONE
if (FtrGet('pose', 0, &value) != ftrErrNoSuchFeature)
#endif
{
Char description[exgTitleBufferSize + 1];
UInt16 descriptionSize = sizeof(description);
Err err;
// Get the title of the library
err = HostTransferLibControl(refNum, exgLibCtlGetTitle, &description,
&descriptionSize);
if (! err)
{
// Register this library with the Exchange Manager
err = ExgRegisterDatatype(HostTransferCreator, exgRegSchemeID,
kHostTransferScheme "\t" exgSendScheme, description, 0 /*flags*/);
}
}
// Add a magic macro to initiate ExgRequest
StrCopy(macro, "\x01" "0117" "0000" "0408");
// virtualkeycode,vchrIrReceive,refnum,libEvtHookKeyMask
macro[7] = PrvHexToAscii((refNum>>4) & 0x0f); // put refnum into string as hex
macro[8] = PrvHexToAscii(refNum & 0x0f);
PrvDeleteExistingMacro(".r");
GrfAddMacro(".r", (UInt8 *)macro, 13);
return err;
}
Implementing an Exchange Library

In order to work with the Palm OS Exchange Manager, an exchange library must implement a required set of functions and must register with the Exchange Manager.
Required Functions

Exchange libraries contain functions to handle implementation specifics of a particular transport plus the functions required by the Exchange Library API. Functions required to handle transport-specific tasks or other tasks that aren't specific to the Exchange Library API are outside the scope of this document. In general, however, other functions required by the exchange library could include tasks such as polling devices, handling interrupts, or checking for user input.
Depending on the application, the exchange library's requirements may be send only, receive only, or both. At a minimum, when sending objects, ExgLibPut, ExgLibSend, and ExgLibDisconnect are typically required; for receiving objects, ExgLibAccept, ExgLibReceive, and ExgLibDisconnect are needed. See Chapter 59, "Exchange Library," of the Palm OS Programmer's API Reference for a detailed description of each exchange library function.
Implementing ExgLibAccept
There are two situations in which an application calls the Exchange Manager's ExgAccept function:
The application wants to initiate a connection to receive data, which it does in response to sysAppLaunchCmdExgReceiveData.
The application wants to initiate a connection to receive a preview of the data, which it does in response to sysAppLaunchCmdExgAskUser.
The Exchange Manager in turn calls ExgLibAccept.
When previewing data, you must buffer incoming data. Your ExgLibAccept function should observe the preview flag and rewind the buffer, preparing for non-destructive read. When it is called again without the preview flag, it should rewind again, this time preparing for destructive read.
ExgLibAccept must update any progress dialogs to indicate that data is being accepted, or received, into an application.
Handling Connection Errors
ExgLibConnect can be used by exchange libraries as a convenient place to put code that needs to be executed prior to the first ExgLibPut call. Many exchange libraries don't support ExgLibConnect, however, instead establishing a connection in the initial call to ExgLibPut. If your library doesn't need to support ExgLibConnect, your implementation of this function should simply return errNone.
If your exchange library doesn't support ExgLibConnect and an error occurs during the initial call to ExgLibPut, your implementation of ExgLibPut should clean up after itself; it should not count on ExgLibDisconnect being called. If the initial call to ExgLibPut succeeds, however, cleanup of subsequent errors can be done in ExgLibDisconnect.
If your exchange library does support ExgLibConnect and an error occurs during a call to it, ExgLibConnect should clean up after itself. Cleanup of errors that occur after a successful call to ExgLibConnect, however, can be delegated to ExgLibDisconnect.
Finally, if your exchange library supports ExgLibConnect but the application doesn't call it prior to calling ExgLibPut, the situation is as if your library didn't implement ExgLibConnect: if an error occurs during the initial call to ExgLibPut your implementation of ExgLibPut should clean up after itself, while if the initial call to ExgLibPut succeeds you can clean up after any subsequent errors in ExgLibDisconnect.
Note that you must support ExgLibConnect if your exchange library supports two-way communication as discussed in "Two-Way Communications."
Buffering Data
Data can be sent by the exchange library as it receives it by using ExgLibSend calls or by buffering the data and sending it in response to an ExgLibDisconnect call. Buffering has some advantages. For example, the communication stack does not have to share cycles with the sending or receiving application and the communication hardware is on for the shortest possible time, conserving battery power. One drawback is that buffering requires extra storage that could be problematic if the amount of data exchanged is large.
Registering with the Exchange Manager

Exchange libraries, like applications, must register with the Exchange Manager for the object types they are to receive. Exchange libraries typically register for two URL schemes, one that is used to uniquely identify the exchange library, and one for how it is used.
For example, the IR library registers for "_irobex", which identifies the specific protocol, and for "_beam" which makes it accessible from the Beam command. The Host Transfer sample exchange library registers for "_host" and "_send". The latter registration makes it accessible from the Send command. Most exchange libraries will probably want to register for the "_send" scheme. These URL schemes all start with an underscore to avoid conflicting with standard URL schemes like "http" and "mailto". See Table 1.3 in Chapter 1, "Object Exchange," for the supported URL schemes.
Summary of Exchange Library

Exchange Library Functions |
Handling the Connection |
|
|
|
Requesting Data |
|
|
|
Transferring Data |
|
|
|
Querying the Exchange Library |
|
|
|
Handling Events |
|
|
|
Required Shared Library Functions |
|
|
|
|