Structure of a Palm Application, Part 1
Pages: 1, 2, 3

C Library Conventions

You will not normally use standard C library routines like strlen or memcpy. While these functions are available as libraries, using them in your code bloats the size of your application. Since space is always tight, you have been provided with another way to use such routines; you'll use the ones in ROM that are small and quick. Table 5-2 shows the Palm OS-equivalents for standard C routines.

Table 5-2: Equivalents to standard C routines

Standard C routine

Palm OS routine

Additional information









Doesn't pad with extra null terminators.






Last parameter is the total length of the string (including null terminator) rather than the number of characters to copy. Doesn't append an extra null terminator if source string is empty.


















Limited subset of sprintf, for example, no %f.



Limited subset of svprintf, for example, no %f.



Although you'll probably use handles instead.









Warning: the last two parameters have been reversed!




That sums up the important conventions you need to know about to create a Palm application.

The Palm OS and an Application

When the Palm OS wants to communicate with an application that may not be running, it calls the application's PilotMain routine.

The Main Routine: PilotMain

This is the main entry point into a Palm OS application; it is always a function named PilotMain. Given its responsibilities, it is worth looking at this routine in some detail. First, we'll start with the parameters, and then we'll show you the code. Following the code is a walk-through discussion of what is happening.

A quick look at PilotMain

The first parameter is the launch code, which specifies why the function is being called. Whenever your application is being opened normally, this parameter will be the constant sysAppLaunchCmdNormalLaunch. The second and third parameters are used when the application is opened at other times (see Example 5-1).

Example 5-1: Typical PilotMain (app-specific portions are emphasized)

UInt32 PilotMain(UInt16 launchCode, MemPtr launchParameters, 
  UInt16 launchFlags)
#pragma unused(launchParameters)
  Err error;

  switch (launchCode) {
  case sysAppLaunchCmdNormalLaunch:
    error = RomVersionCompatible(kOurMinVersion, launchFlags);
    if (error != errNone) 
      return error;
    error = AppStart(  );
    if (error != errNone) 
      return error;
    AppEventLoop(  );
    AppStop(  );

  return errNone;

If the launch code is sysAppLaunchCmdNormalLaunch, we first check to make sure that the version of the device we are running on is one that we support (you'll have to define the minimum version appropriate for your application).

TIP:   A pragma is a compiler-specific directive. The #pragma unused(launchParameters) is an indication to CodeWarrior that the parameter launchParameters is not used in the function. With this in place, CodeWarrior won't be constantly warning us of the unused parameter. GCC (as it should) ignores the pragma.

While we will talk about each of the routines called in our PilotMain in greater detail in just a moment, briefly, this is what they do. First, we call our own routine, AppStart, which does application-specific initialization. The call to FrmGotoForm specifies that the MainForm will initially be displayed (if we left that out, the display would be blank since no form was opened). It will queue a frmLoadEvent in the Event Manager's event queue (we'll talk more about form events in Chapter 8).

Now, the application's motor--our event loop, AppEventLoop--runs until the user does something to close the application. At that point, we handle termination in AppStop.

The Startup Routine: AppStart

Here is where we handle all the standard opening and initialization of our application. In a typical application, this would include opening our databases and reading user preference information. In our skeleton application (OReilly Starter), we won't do anything.

Although it's common to name this routine AppStart, it's only a convention, not a requirement like the name of PilotMain.

TIP:   Note that we call FrmGotoForm in our PilotMain rather than here. This is important because an application will eventually need to support Find. In that case, another launch code will require us to initially open a different form. Because of this, we need FrmGotoForm to be in a location that allows us to switch between forms depending on how the application gets opened.

Since we have a very simple application, our AppStart does nothing:

static Err AppStart(void)
   return 0;

Note that we have a static declaration here for the benefit of CodeWarrior. If we leave off the static, then CodeWarrior will warn us that the function doesn't have a prototype.

CodeWarrior complains about this potential error because the function might have been declared in a header file that wasn't included in this file. Furthermore, that declaration might declare the function differently (for example, different numbers or types of parameters). Specifying that the function is static guarantees that the function won't be called from outside this file, thus no separate function declaration is required.

In general, always add a static when defining functions that are only used within a single file. This is the purpose for the keyword after all.

The Closing Routine: AppStop

Normally, in AppStop we handle all the standard closing operations, such as closing our database, saving the current state in preferences, and so on. Because we are creating such a simple application, we don't actually have to do those things. However, like all applications, ours needs to make sure that any open forms are closed. FrmCloseAllForms will do that closing.

static void AppStop(void)
  FrmCloseAllForms(  );

The Main Event Loop

In PilotMain, after the initialization there is a call to the one main event loop, AppEventLoop. In brief, this is what happens in this loop:

  • We continually process events--handing them off wherever possible to the system.
  • We go through the loop, getting an event with EvtGetEvent, and then dispatch that event to one of four event handlers, each of which gets a chance to handle the event.
  • If any of the event handlers returns true, it has handled the event and we don't process it any further.
  • EvtGetEvent then gets the next event in the queue and our loop repeats the process all over again.
  • The loop doggedly continues in this fashion until we get the appStopEvent, at which time we exit the function and clean things up in AppStop.

Pages: 1, 2, 3

Next Pagearrow