http://www.developer.com/

Back to article

Application Launching


August 21, 2003

Introduction

The goal of this article is to describe what do you need to do to effectively use Palm OS's launching mechanism. Under an operating system such as Windows, an application usually starts when a user requests it. This may be a result of using some kind of input device such as a keyboard, mouse, or stylus. It may also result from another application. This is also true for Palm OS applications. Additionally, a Palm application may also start in response to events like a HotSync action, a global find, a reset and so forth. Some application may even support specific launch codes that allow other programs use them as a subroutine. Let's start with the code for launching an application in the Palm environment.

Launch Codes

Palm OS application begins to work just after they receive launch code from the operating system. The first parameter of PilotMain is used to pass this code through:

UInt32 PilotMain ( UInt16 cmd, 
                   void *cmdPBP, 
                   UInt16 launchFlags)

In many cases an application is launched normally and thus the application responds to cmd = sysAppLaunchCmdNormalLaunch. Each time the user changes the system time, presses the HotSync button, resets the PDA or does any other action that may launch an application, then the Palm OS sends a corresponding launch code to all installed applications. Therefore, launch codes may be used as a means of communicating between the Palm OS and an application. Other applications are able to interact with each other in this same way.

Let's take a look at the Datebook entry point:

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 has 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
   // creates a new database.  We will initialize the new
   // database.
   return (0);
}

As you see, there are lot of codes your application may receive. It's totally your responsibility to decide which of them your application will respond to. Additionally, you may define your own launch codes as. If you create your own, you'll want to see the note in SystemMgr.h:

//------------------------------------------------------------------------
// Custom action code base (custom action codes begin at this value)
//------------------------------------------------------------------------
#define  sysAppLaunchCmdCustomBase  0x8000

// Your custom launch codes can be defined like this:
//
//  typedef enum {
//    myAppCmdDoSomething = sysAppLaunchCmdCustomBase,
//    myAppCmdDoSomethingElse,
//    myAppCmdEtcetera
//
//    } MyAppCustomActionCodes;

You may ask why a custom launch code may be needed. The answer is that such an approach gives you powerfull possibility to use your application from others mdash; it provides a kind of API. There are many software packages mdash; written for printing, sending e-mails and so forth mdash; that can be used from other programs using custom launch codes.

An important thing to know is that you might not have access to global variables when your application receives launch codes with the exceptions of sysAppLaunchCmdNormalLaunch, sysAppLaunchCmdGoto and sysAppLaunchCmdURLParams, because they aren't allocated. A good practice for determining if your application has access to globals is to check the launch flags (the third parameter of PilotMain). If sysAppLaunchFlagNewGlobals flag is set, globals are allocated:

Boolean bGlobalsAreAllocated = 
    ((launchFlags & sysAppLaunchFlagNewGlobals) == 
                            sysAppLaunchFlagNewGlobals);

The only exception to this rule is when your application calls itself (i.e. is running as current application). In this case the sysAppLaunchFlagNewGlobals flag may not be set, but global variables were already allocated through the previous call. You may check it as follows:

Boolean bAppIsRunning = 
    ((launchFlags & sysAppLaunchFlagSubCall) == 
                            sysAppLaunchFlagSubCall);

Additionionally, if the application is multisegment, you cannot access code outside of the first segment if the application doesn't have access to global variables.

Launching Applications From Your Own Programs

The System Manager API has several functions to allow you to programmatically run other applications. These are SysAppLaunch, SysUIAppSwitch and SysBroadcastActionCode.

SysBroadcastActionCode is the simplest. The operating system finds all UI applications and calls SysAppLaunch with the given launch code for each of them.

SysUIAppSwitch actually closes current application and switches to the called one.

SysAppLaunch launches the application with the given launch code and parameters. If you need to pass parameters to the launched application, you should grant ownership of allocated parameter block to the operating system (using MemPtrSetOwner or MemHandleSetOwner respectively for pointers and handles). Otherwise, the parameter block will get deleted before the launched application will be able to access it. A typical example of launching an application may look like the following:

#define cmdPrintChars     0x8000

Boolean PrintReport(const char* szText)
{
  DWord dwRes = 0;
  LocalID dbID = ::DmFindDatabase(0,"PalmPrint");
  
  if ( !dbID )
  {
    FrmAlert(SCSFailureAlert);
    return false;
  }
  // Grant ownership to OS (if needed) here
  // In this sample it's not needed :)
  // MemPtrSetOwner(szText,0);

  Err err = ::SysAppLaunch( 0,
                            dbID, 
                            0,
                            cmdPrintChars,
                            (void*)szText,
                            &dwRes);
  return (err == 0);
}

Implementing A Custom Launch Code Handler

Taking into account all of the stuff we've discussed, an implementation of a custom launch code handler should seem to be a trivial thing! "All" you need to do is to organize one more 'case' in PilotMain and write the corresponding code chunk. Please don't forget that at this point your application has no access to global variables, so be careful!

As a simple example of all of the theory presented in this article, I've developed a test application that calls SysAppLaunch for itself and for a separate 'server' application. For simplicity (and frankly speaking because it really much simpler!) I've used the POL Object library. The CW wizard has created all of the standard files for both 'server' ("launchsrv") and 'client' ("launchapp") applications, The following code sample describes all needed:

Sample Code

Download the sample code from here: sample5.zip - 67 kb

Where to go

Starting with Palm OS 4.0, the Helper API was introduced. This API is another way to obtain inter-application communications. In my next article I'll tell you what this API is as well as show you when and how to use it.

About the Author

Alex Gusev started to play with mainframes in the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.

# # #

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date