Previous Page Table of Contents Index Next Page

Palm OS Programmer's Companion


Palm Logo 3 Application Startup and Stop

This chapter describes how an application launches, how an application stops, and the code you must write to perform these tasks properly. It covers:

This chapter does not cover the main application event loop. The event loop is covered in Chapter 4, "Event Loop."

Launch Codes and Launching an Application

An application launches when it receives a launch code. Launch codes are a means of communication between the Palm OS and the application (or between two applications).

For example, an application typically launches when a user presses one of the buttons on the device or selects an application icon from the application launcher screen. When this happens, the system generates the launch code sysAppLaunchCmdNormalLaunch, which tells the application to perform a full launch and display its user interface.

Other launch codes specify that the application should perform some action but not necessarily become the current application (the application the user sees). A good example of this is the launch code used by the global find facility. The global find facility allows users to search all databases for a certain record, such as a name. In this case, it would be very wasteful to do a full launch--including the user interface--of each application only to access the application's databases in search of that item. Using a launch code avoids this overhead.

Each launch code may be accompanied by two types of information:

A complete list of all launch codes is provided at the end of this chapter in the section "Launch Code Summary." That section contains links into where each launch code is described in the Palm OS SDK Reference.

Responding to Launch Codes

Your application should respond to launch codes in a function named PilotMain. PilotMain is the entry point for all applications.

When an application receives a launch code, it must first check whether it can handle this particular code. For example, only applications that have text data should respond to a launch code requesting a string search. If an application can't handle a launch code, it exits without failure. Otherwise, it performs the action immediately and returns.

Listing 3.1 shows parts of PilotMain from the Datebook application as an example. To see the complete example, go to the examples folder in the Palm OS SDK and look at the file Datebook.c.

Listing 3.1 PilotMain in Datebook.c


UInt32 PilotMain (UInt16 cmd, void *cmdPBP, UInt16 launchFlags)
{
    return DBPilotMain(cmd, cmdPBP, launchFlags);
}

static UInt32 DBPilotMain (UInt16 cmd, void *cmdPBP, UInt16 launchFlags)
{
    UInt16 error;
    Boolean launched;

    // This app makes use of PalmOS 2.0 features.It will crash if
    // run on an earlier version of PalmOS. Detect and warn if this
    // happens, then exit.
    error = RomVersionCompatible (version20, launchFlags);
    if (error)
    return error;

    // Launch code sent by the launcher or the datebook button.
    if (cmd == sysAppLaunchCmdNormalLaunch)
    {
    error = StartApplication ();
    if (error) return (error);

    FrmGotoForm (DayView);
    EventLoop ();
    StopApplication ();
    }
   

    // Launch code sent by text search.
    else if (cmd == sysAppLaunchCmdFind)
    {
    Search ((FindParamsPtr)cmdPBP);
    }
   

    // This launch code might be sent to the app when it's already
    // running if the user hits the "Go To" button in the Find
    // Results dialog box.
    else if (cmd == sysAppLaunchCmdGoTo)
    {
    launched = launchFlags & sysAppLaunchFlagNewGlobals;
    if (launched)
    {
    error = StartApplication ();
    if (error) return (error);

    GoToItem ((GoToParamsPtr) cmdPBP, launched);

    EventLoop ();
    StopApplication ();
    }
    else
    GoToItem ((GoToParamsPtr) cmdPBP, launched);
    }

    // Launch code sent by sync application to notify the datebook
    // application that its database was been synced.
    // ...
    // Launch code sent by Alarm Manager to notify the datebook
    // application that an alarm has triggered.
    // ...
    // Launch code sent by Alarm Manager to notify the datebook
    // application that is should display its alarm dialog.
    // ...
    // Launch code sent when the system time is changed.
    // ...
    // Launch code sent after the system is reset. We use this time
    // to create our default database if this is a hard reset
    // ...
    // Launch code sent by the DesktopLink server when it create
    // a new database. We will initialize the new database.
    return (0);
}


Responding to Normal Launch

When an application receives the launch code sysAppLaunchCmdNormalLaunch, it begins with a startup routine, then goes into an event loop, and finally exits with a stop routine. (The event loop is described in Chapter 4, "Event Loop." The stop routine is shown in the section "Stopping an Application" at the end of this chapter.)

During the startup routine, your application should perform these actions:
Get system-wide preferences (for example for numeric or date and time formats) and use them to initialize global variables that will be referenced throughout the application. Find the application database by creator type. If none exists, create it and initialize it. Get application-specific preferences and initialize related global variables. Initialize any other global variables.

As you saw in Listing 3.1, the Datebook application example responds to sysAppLaunchCmdNormalLaunch by calling a function named StartApplication. Listing 3.2 shows the StartApplication function.

Listing 3.2 StartApplication from Datebook.c


static UInt16 StartApplication (void)
{
    UInt16 error = 0;
    Err err = 0;
    UInt16 mode;
    DateTimeType dateTime;
    DatebookPreferenceType prefs;
    SystemPreferencesType sysPrefs;
    UInt16 prefsSize;

    // Step 1: Get system-wide preferences.
    PrefGetPreferences (&sysPrefs);
    // Determime if secret records should be displayed.
    HideSecretRecords = sysPrefs.hideSecretRecords;
   
    if (HideSecretRecords)
    mode = dmModeReadWrite;
    else
    mode = dmModeReadWrite | dmModeShowSecret;

    // Get the time formats from the system preferences.
    TimeFormat = sysPrefs.timeFormat;

    // Get the date formats from the system preferences.
    LongDateFormat = sysPrefs.longDateFormat;
    ShortDateFormat = sysPrefs.dateFormat;

    // Get the starting day of the week from the
    // system preferences.
    StartDayOfWeek = sysPrefs.weekStartDay;
   

    // Get today's date.
    TimSecondsToDateTime (TimGetSeconds (), &dateTime);
    Date.year = dateTime.year - firstYear;
    Date.month = dateTime.month;
    Date.day = dateTime.day;


    // Step 2. Find the application's data file. If it doesn't
// exist, create it.

    ApptDB = DmOpenDatabaseByTypeCreator(datebookDBType,
sysFileCDatebook, mode);

    if (! ApptDB)
    {
    error = DmCreateDatabase (0, datebookDBName, sysFileCDatebook,
    datebookDBType, false);
    if (error) return error;
   
    ApptDB = DmOpenDatabaseByTypeCreator(datebookDBType,
sysFileCDatebook, mode);

    if (! ApptDB) return (1);

    error = ApptAppInfoInit (ApptDB);
    if (error) return error;
    }
   

    // Step 3. Get application-specific preferences.
    // Read the preferences / saved-state information. There is
    // only one version of the DateBook preferences so don't worry
    // about multiple versions.
    prefsSize = sizeof (DatebookPreferenceType);
    if (PrefGetAppPreferences (sysFileCDatebook, datebookPrefID,
&prefs, &prefsSize,

    true) != noPreferenceFound)
    {
    DayStartHour = prefs.dayStartHour;
    DayEndHour = prefs.dayEndHour;
    AlarmPreset = prefs.alarmPreset;
    NoteFont = prefs.noteFont;
    SaveBackup = prefs.saveBackup;
    ShowTimeBars = prefs.showTimeBars;
    CompressDayView = prefs.compressDayView;
    ShowTimedAppts = prefs.showTimedAppts;
    ShowUntimedAppts = prefs.showUntimedAppts;
    ShowDailyRepeatingAppts = prefs.showDailyRepeatingAppts;
    }

    // Step 4. Initialize any other global variables.
    TopVisibleAppt = 0;
    CurrentRecord = noRecordSelected;
   

    // Load the far call jump table.
    FarCalls.apptGetAppointments = ApptGetAppointments;
    FarCalls.apptGetRecord = ApptGetRecord;
    FarCalls.apptFindFirst = ApptFindFirst;
    FarCalls.apptNextRepeat = ApptNextRepeat;
    FarCalls.apptNewRecord = ApptNewRecord;
    FarCalls.moveEvent = MoveEvent;

    return (error);
}


Responding to Other Launch Codes

If an application receives a launch code other than sysAppLaunchCmdNormalLaunch, it decides if it should respond to that launch code. If it responds to the launch code, it does so by implementing a launch code handler, which is invoked from its PilotMain function.

In most cases, when you respond to other launch codes, you are not able to access global variables. Global variables are generally only allocated after an application receives sysAppLaunchCmdNormalLaunch (see Listing 3.2) or sysAppLaunchCmdGoto; so if the application hasn't received either of these launch codes, its global variables are usually not allocated and not accessible. In addition, if the application has multiple code segments, you cannot access code outside of segment 0 (the first segment) if the application has no access to global variables.

There is one other case where an application may have access to its global variables (and to code segments other than 0). This is when an application is launched with the code sysAppLaunchCmdURLParams. If this launch code results from a palm URL, then globals are available. If the launch code results from a palmcall URL, then globals are not available. The URL is passed to your application in the launch parameter block.

NOTE:  

Static local variables are stored with the global variables on the system's dynamic heap. They are not accessible if global variables are not accessible.

Checking launch codes is generally a good way to determine if your application has access to global variables. However, it actually depends on the setting of the launch flags that are sent with the launch code. In particular, if the sysAppLaunchFlagNewGlobals flag is set, then your application's global variables have been allocated on this launch. This flag is set by the system and isn't (and shouldn't be) set by the sender of a launch code.

Boolean appHasGlobals = launchFlags & sysAppLaunchFlagNewGlobals;


There's one case where this flag won't be set and your application will still have access to global variables. This is when your application is already running as the current application. In this case, its global variables have already been allocated through a previous launch.

If your application receives a launch code other than sysAppLaunchCmdNormalLaunch or sysAppLaunchCmdGoTo, you can find out if it is the current application by checking the launch flags that are sent with the launch code. If the application is the currently running application, the sysAppLaunchFlagSubCall flag is set. This flag is set by the system and isn't (and shouldn't be) set by the sender of a launch code.

Boolean appIsActive = launchFlags & sysAppLaunchFlagSubCall;


Launching Applications Programmatically

Applications can send launch codes to each other, so your application might be launched from another application or it might be launched from the system. An application can use a launch code to request that another application perform an action or modify its data. For example, a data collection application could instruct an email application to queue up a particular message to be sent.

Sending a launch code to another application is like calling a specific subroutine in that application: the application responding to the launch code is responsible for determining what to do given the launch code constant passed on the stack as a parameter.

To send a launch code to another application, use the System Manager function SysAppLaunch. Use this routine when you want to make use of another application's functionality and eventually return control of the system to your application. Usually, applications use it only for sending launch codes to other user-interface applications.

SysAppLaunch has numerous options, including whether to launch the application as a separate task, whether to allocate a globals world, and whether or not to give the called application its own stack. For example, you would use this function to request that the built in Address List application search its databases for a specified phone number and return the results of the search to your application. You could then call SysAppLaunch again to use the modem handle to dial the number. (In fact, this is how the built-in applications perform this task.) When calling SysAppLaunch do not set launch flags yourself--the SysAppLaunch function sets launch flags appropriately for you.

An alternative, simpler method of sending launch codes is the SysBroadcastActionCode call. This routine automatically finds all other user-interface applications and calls SysAppLaunch to send the launch code to each of them.

If your application is called to process a launch code, it is called as a subroutine from the current user-interface application. Use the routine SysCurAppDatabase to get the card number and database ID of your application (not of the user-interface application that launched your application).

If you want to actually close your application and open another application, use SysUIAppSwitch instead of SysAppLaunch. This routine notifies the system which application to launch next and feeds an application-quit event into the event queue. If and when the current application responds to the quit event and returns, the system launches the new application.

When you allocate a parameter block to pass to SysUIAppSwitch or SysAppLaunch, you must call MemPtrSetOwner to grant ownership of the parameter block chunk to the OS (your application is originally set as the owner). If the parameter block structure contains references by pointer or handle to any other chunks, you also must set the owner of those chunks by calling MemPtrSetOwner or MemHandleSetOwner. If you don't change the ownership of the parameter block, it will get freed before the application you're launching has a chance to use it.

In Palm OS 3.0 and higher, you can also use the Application Launcher to launch any application. For more information, see the section "Application Launcher" in the "User Interface" chapter.

WARNING!

Do not use the SysUIAppSwitch or SysAppLaunch functions to open the Application Launcher application.

Creating Your Own Launch Codes

The Palm OS contains predefined launch codes, which are listed in Table 3.1 at the end of this chapter. In addition, developers can create their own launch codes to implement specific functionality. Both the sending and the receiving application must know about and handle any developer-defined launch codes.

The launch code parameter is a 16-bit word value. All launch codes with values 0-32767 are reserved for use by the system and for future enhancements. Launch codes 32768-65535 are available for private use by applications.

Stopping an Application

An application shuts itself down when it receives the event appStopEvent. Note that this is an event, not a launch code. The application must detect this event and terminate. (You'll learn more about events in the next chapter.)

When an application stops, it is given an opportunity to perform cleanup activities including closing databases and saving state information.

In the stop routine, an application should first flush all active records, then close the application's database, and finally save those aspects of the current state needed for startup. Listing 3.3 is an example of a StopApplication routine from Datebook.c.

Listing 3.3 StopApplication from Datebook.c


static void StopApplication (void)
{
    DatebookPreferenceType prefs;
   
    // Write the preferences / saved-state information.
    prefs.noteFont = NoteFont;
    prefs.dayStartHour = DayStartHour;
    prefs.dayEndHour = DayEndHour;
    prefs.alarmPreset = AlarmPreset;
    prefs.saveBackup = SaveBackup;
    prefs.showTimeBars = ShowTimeBars;
    prefs.compressDayView = CompressDayView;
    prefs.showTimedAppts = ShowTimedAppts;
    prefs.showUntimedAppts = ShowUntimedAppts;
    prefs.showDailyRepeatingAppts = ShowDailyRepeatingAppts;

    // Write the state information.
    PrefSetAppPreferences (sysFileCDatebook, datebookPrefID,
datebookVersionNum, &prefs, sizeof (DatebookPreferenceType),
true);


    // Send a frmSave event to all the open forms.
    FrmSaveAllForms ();
   
    // Close all the open forms.
    FrmCloseAllForms ();

    // Close the application's data file.
    DmCloseDatabase (ApptDB);
}


Launch Code Summary

Table 3.1 lists all Palm OS standard launch codes. These launch codes are declared in the header SystemMgr.h. All the parameters for a launch code are passed in a single parameter block, and the results are returned in the same parameter block.

Table 3.1 Palm OS Launch Codes 

Code Request
scptLaunchCmdExecuteCmd Execute the specified Network login script plugin command.
scptLaunchCmdListCmds Provide information about the commands that your Network script plugin executes.
sysAppLaunchCmdAddRecord Add a record to a database.
sysAppLaunchCmdAlarmTriggered Schedule next alarm or perform quick actions such as sounding alarm tones.
sysAppLaunchCmdCountryChange Respond to country change.
sysAppLaunchCmdDisplayAlarm Display specified alarm dialog or perform time-consuming alarm-related actions.
sysAppLaunchCmdExgAskUser Let application override display of dialog asking user if they want to receive incoming data via the exchange manager.
sysAppLaunchCmdExgReceiveData Notify application that it should receive incoming data via the exchange manager.
sysAppLaunchCmdFind Find a text string.
sysAppLaunchCmdGoto Go to a particular record, display it, and optionally select the specified text.
sysAppLaunchCmdGoToURL Launch Clipper application and open a URL. (Palm VII system only.)
sysAppLaunchCmdInitDatabase Initialize database.
sysAppLaunchCmdLookup Look up data. In contrast to sysAppLaunchCmdFind, a level of indirection is implied. For example, look up a phone number associated with a name.
sysAppLaunchCmdNormalLaunch Launch normally.
sysAppLaunchCmdNotify Broadcast a notification.
sysAppLaunchCmdOpenDB Launch application and open a database. (Palm VII system only.)
sysAppLaunchCmdPanelCalledFromApp Tell preferences panel that it was invoked from an application, not the Preferences application.
sysAppLaunchCmdReturnFromPanel Tell an application that it's restarting after preferences panel had been called.
sysAppLaunchCmdSaveData Save data. Often sent before find operations.
sysAppLaunchCmdSyncNotify Notify applications that a HotSync has been completed.
sysAppLaunchCmdSystemLock Sent to the Security application to request that the system be locked down.
sysAppLaunchCmdSystemReset Respond to system reset. No UI is allowed during this launch code.
sysAppLaunchCmdTimeChange Respond to system time change.
sysAppLaunchCmdURLParams Launch an application with parameters from Clipper. (Palm VII system only.)



Palm OS Programmer's Companion

  Previous Page Table of Contents Index Next Page  

This is page 72 of 85 in this book

Palm Computing Platform Development Zone
Copyright © 2000, Palm, Inc. All rights reserved.