OpenWiki

Palm Program Launch

Edit this page (last edited December 2, 2004)
Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
  • Введение
  • Функции, использующиеся для запуска программ
  • PilotMain
  • Флаги sysAppLaunchFlag
  • SysAppLaunch
  • SysUIAppSwitch
  • Механизм запуска графических приложений
  • Старт графического потока
  • Цикл запуска приложений
  • Частые вопросы
  • Как запускать панели?
  • Что использовать - SysAppLaunch или SysUIAppSwitch?
  • Какие флаги следует анализировать в PilotMain?
  • Какие флаги можно использовать при вызове SysAppLaunch?
  • Почему нельзя запускать программы с кодом sysAppLaunchCmdNormalLaunch через SysAppLaunch?
  • А как все-таки запустить калькулятор и вернуться в свое приложение?
  • Как можно залочить машинку для запуска одной программы?
  • Введение

    Настоящая статья обсуждает аспекты запуска программ в среде Palm OS. Статья обсуждает нюансы использования функций SysAppLaunch, SysUIAppSwitch и некоторые внутренние механизмы Palm OS, исполюзующиеся для запуска.

    Функции, использующиеся для запуска программ

    В этой главе кратко обсуждаются функции Palm OS API, имеющие отношение к запуску программ.

    PilotMain

    Начнем с основы - с формата главной функции любой программы.
    UInt32        PilotMain(UInt16 cmd, void *cmdPBP, UInt16 launchFlags);
    

    Параметры:

    Флаги sysAppLaunchFlag

    #define sysAppLaunchFlagNewThread       0x01        // create a new thread for application sysAppLaunchFlagNewStack
    #define sysAppLaunchFlagNewStack        0x02        // create separate stack for application
    #define sysAppLaunchFlagNewGlobals      0x04        // create new globals world for application ID for Memory chunks
    #define sysAppLaunchFlagUIApp           0x08        // notifies launch routine that this is a UI app being
    #define sysAppLaunchFlagSubCall         0x10        // notifies launch routine that the app is calling it's
                                                    //  entry point as a subroutine call. This tells the launch
                                                    //  code that it's OK to keep the A5 (globals) pointer valid 
                                                    //  through the call.
                                                    // IMPORTANT: This flag is for internal use by
                                                    //  SysAppLaunch only!!! It should NEVER be set
                                                    //  by the caller. 
    #define sysAppLaunchFlagDataRelocated  0x80     // global data (static ptrs) have been "relocated"
                                                    //  by either SysAppStartup or StartupCode.c
                                                    // IMPORTANT: This flag is for internal use by
                                                    //  SysAppLaunch only!!! It should NEVER be set
                                                    //  by the caller. 
    
    // The set of private, internal flags that should never be set by the caller
    #define sysAppLaunchFlagPrivateSet        (sysAppLaunchFlagSubCall | sysAppLaunchFlagDataRelocated)
    

    Флаги стоит рассматривать в двух контекстах - в контексте вызывающего приложения и в контексте вызываемого приложения. Некоторые флаги нельзя задавать при запуске приложения, другие флаги не рекомендуется задавать при запуске, а третьи флаги пользовательские программы никогда не получат.

    SysAppLaunch

                                                            
    Err SysAppLaunch(
            UInt16 cardNo, LocalID dbID, UInt16 launchFlags,
            UInt16 cmd, MemPtr cmdPBP, UInt32 *resultP);
    

    Эта функция используется для запуска приложений. Palm OS использует ее для запуска программ в новых потоках, для запуска программ с UI. Прикладному программисту стоит использовать ее только для sub-launch, для запуска прочих приложений, выполняющих отдельные задачи, в духе вызова функций.

    Подобно вызову функции, вызов SysAppLaunch запускает программу и по ее окончании продолжает исполнение вызываемой функции. Исключением является запуск в новом потоке, но поскольку он недоступен программисту, то мы его не рассматриваем.

    Параметры у функции очевидные:

    SysUIAppSwitch

    Err SysUIAppSwitch(UInt16 cardNo, LocalID dbID, UInt16 cmd, MemPtr cmdPBP);
    

    Функция SysUIAppSwitch используется для передачи управления другой программе с интерфейсом. Эта функция традиционно понимается неправильно. Она не запускает приложение немедленно. Вместо этого она сохраняет параметры во внутренних переменных Palm OS и добавляет в очередь сообщений событие sysEventAppStopEvent.

    Что происходит дальше? Дальше функция возвращается в прикладную программу, которая продолжает исполнение. Когда исполнение дойдет до обработки события sysEventAppStopEvent, цикл обработки завершится. Программа вызовет StopApplication и выйдет из PilotMain. Palm OS после выхода из текущей программы считывает сохраненные значения следующей программы и запускает ее.

    Обратите внимание на то, что программа запускается не сразу, только после выхода из текущей программы. Обычно вызов SysUIAppSwitch стоит последним в обработчике события, следующим извлеченным событием будет sysEventAppStopEvent, и выход произойдет автоматом. Но если программа использует нестандартный цикл выборки, то могут возникнуть проблемы.

    Нажатие на кнопки Datebook / Memo / Address / ToDo / Home / Calc генерируют неявный вызов SysUIAppSwitch с программами, заданными своими создателями в свойствах. Так, нажатие на home вызывает запуск программы с кодом создателя из PrefGetPreference(prefLauncherAppCreator).

    Параметры у функции понятны:

    Обратите внимание, что флаги не передаются. Они неявно формируются как sysAppLaunchFlagNewStack | sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp .

    Механизм запуска графических приложений

    В этой главе мы обсудим механизм работы потока, в котором исполняются приложения с UI. Описание базируется на коде Palm OS 4, но вполне применимо к версиям Palm OS 2-5.

    Старт графического потока

    Основой графического потока является приложение UIAppShell.prc. Это приложение запускается из функции SysUILaunch. Запуск происходит с помощью функции SysAppLaunch. Указывается флаг sysAppLaunchFlagNewThread, который указывает на необходимость запуска нового потока. Этот поток становится единственным доступным для прикладных программ.

    Инициализация графического потока состоит из следующих этапов:
    1. Загрузка системных расширений с типом exte.
    2. Если при сбросе не была указана safe загрузка (нажатая стрелка вверх при сбросе), то выполняется загрузка системных расширений с типом extn.
    3. Если при сбросе не была указана safe загрузка, то всем программам рассылается код sysAppLaunchCmdSystemReset.
    4. Всем подписанным рассылается нотификация sysNotifyResetFinishedEvent
    5. Если при сбросе была указана safe загрузка, то сбросить приложение, запускаемое по умолчанию (PrefSetPreference(prefDefaultAppCreator, 0)).

    Цикл запуска приложений

    Самой важной функцией UIAppShell является запуск приложений. Именно UIAppShell отвечает за последовательный запуск программ, указанных при вызове SysUIAppSwitch.

    Программа оперирует переменными Palm OS GNextUIAppCardNo, GNextUIAppDBID, GNextUIAppCmd, GNextUIAppCmdPBP. Это именно те самые переменные, в которые SysUIAppSwitch сохраняет переданные параметры.

    Рассмотрим действия, выполняемые в цикле. Первая задача - выбор приложения, которое будет запущено первым.

    1. Если устройство залочено (PrefGetPreference(prefDeviceLocked)), то будет запущено приложение с создателем 'secr'.
    2. Если устройство стартует после hard reset, то запускается приложение с создателем в ресурсе типа 'tint' и номером sysHardResetAppCreatorConstId. Производители устройств записывают в этот ресурс создателя программы Welcome.
    3. Если PrefGetPreference(prefDefaultAppCreator) выдает ненулевого создателя, то будет запущена эта программа
    4. Во всех остальных случаях выбор запускаемой программы осуществляется в цикле
    5. Цикл запуска начинается здесь
      1. Если не указана запускаемая программа, то выбрать программу с создателем 'pref' - Preferences.
      2. Получить параметры текущей запускаемой программы из переменных Palm OS
      3. Запустить ее с флагами sysAppLaunchFlagNewStack | sysAppLaunchFlagNewGlobals | sysAppLaunchFlagUIApp и параметрами из системных переменных.
      4. Обратим внимание, что к моменту выхода из прикладной программы системные переменные могут измениться в результате вызова SysUIAppSwitch?.Теперь мы имеем три набора cardNo/dbID - запомненные с предыдущего запуска, с текущего запуска и следующего запуска.
      5. Освободить текущий cmdPBP
      6. Если запуск вернул ненулевую ошибку (напомню - это не возврат PilotMain, а ошибка SysAppLaunch) и предыдущее приложение существует, то оно запускается с кодом sysAppLaunchCmdFailedAppNotify и по выходу исполнение продолжается.
      7. Если вызванное приложение не вызывало SysUIAppSwitch и системные переменные не изменились, то цикл выбирает следующее приложение самостоятельно
        1. Единственный случай, когда такая следующее приложение не изменилось - это запуск панели из программы. В этом случае возврат из панели осуществляется запуском предыдущего приложения с кодом sysAppLaunchCmdReturnFromPanel.
        2. Проверяется на существование приложения по умолчанию PrefGetPreference(~prefLauncherAppCreator?), которое и станет следующим
        3. Иначе следующим становится приложение с создателем 'lnch' - Launcher.
      8. Если же параметры следующего приложения существуют, то текущие параметры становятся предыдущими.
      9. Если запуск вернул ненулевую ошибку, то выдается сообщение FrmAlert(GenericLaunchErrAlert) и параметры следующего приложения обнуляются
      10. Переход на начало цикла

    Частые вопросы

    Как запускать панели?

    Панели - это редкий случай возможности запуска приложения с интерфейсом и возврата обратно. Вызов панели реализуется следующим способом:

    Что использовать - SysAppLaunch или SysUIAppSwitch?

    SysAppLaunch запускает следующее приложение с возвратом обратно, а SysUIAppSwitch переключается на следующее приложение без возврата (исключение - механизм панелей). Если вам нужно запустить приложение с интерфейсом, то нужно использовать SysUIAppSwitch. Если вам нужно запросить у приложения данные, например запустить Pocket Tunes, то нужно использовать SysAppLaunch. Не пытайтесь поступать наоборот!

    Какие флаги следует анализировать в PilotMain?

    Все зависит от кода команды. В SDK описаны флаги, передаваемые при вызове стандартных кодов. Если же описания флагов нет, то стоит рассчитывать на худший случай.

    Если мы получаем код, которые подразумевает показ UI (sysAppLaunchCmdNormalLaunch, sysAppLaunchCmdGoTo), то такой вызов был сделан с помощью SysUIAppSwitch, так что мы располагаем своим стеком и глобальными данными. Обратите внимание, что в случае с sysAppLaunchCmdGoTo есть одно исключение - подвызов с выставленным sysAppLaunchFlagSubCall. В этом случае переменные уже проинициализированы предыдущей копией программы.

    Если мы получаем код, требующий только действия (например, sysAppLaunchCmdAlarmTriggered), то его нужно обрабатывать при отсутствии глобальным переменных и большого стека.

    Какие флаги можно использовать при вызове SysAppLaunch?

    Лучше всего не использовать никаких. Правильный принцип - посылаемая команда должна всегда передавать одни и те же флаги, не больше и не меньше. То есть для вызова с кодом sysAppLaunchCmdNormalLaunch не стоит использовать flags == 0, а для вызова sysAppLaunchCmdAlarmTriggered попросту излишне указывать flags == sysAppLaunchFlagNewStack | sysAppLaunchFlagNewGlobals, поскольку обработчик должен уметь обходиться и без глобальных переменных.

    Почему нельзя запускать программы с кодом sysAppLaunchCmdNormalLaunch через SysAppLaunch?

    1. Обычный запуск ожидает корректно заданные графическое окружение. Это достигается указанием флага sysAppLaunchFlagUIApp. Но этот флаг сбрасывает настройки интерфейса текущего приложения после возврата в него
    2. Возможно переполнение числа ownerID для программ. Их число ограничено 14 и скрытые запуски программ могут их еще пооткусывать
    3. Palm OS < 3.5 вообще не уменьшает руками ownerID при выходе из вложенной программы
    4. Если вызываемое приложение вызовет FrmCloseAllForms? (а такой вызов обцчно осуществляется в AppStop?), то закроются ВСЕ формы, включая Ваши.
    5. Palm OS 5 использует кэш трансляции ресурсов. При вложенных вызовах приложений, использующих ресурсы могут начаться конфликты между кэшами.
    6. Наконец, PalmSource попросту не рекомендует это делать. Есть подозрение, что могут вылезти разнообразные тонкости и нюансы при таком запуске.
    Если доводы вас не убедили - попробуйте запустить сами. Возможно у Вас такой запуск заработает.

    Кое-какие детали такого запуска описаны здесь: http://forum.sources.ru/index.php?showtopic=47808

    А как все-таки запустить калькулятор и вернуться в свое приложение?

    Предлагается два неопробованных способа. Кто попробует - присылайте результаты.

    Как можно залочить машинку для запуска одной программы?

    Нужно прописать создателя программы в двух местах preferences: PrefSetPreference(prefDefaultAppCreator, 'хххх'); PrefSetPreference(prefLauncherAppCreator, 'хххх');

    Первая строка будет запускать программу после ресета и в сомнительных случаях, а вторая будет запускать программу вместо лончера.

    Также можно блокировать переключение на стандартные приложения по кнопкам: PrefSetPreference(prefHard1CharAppCreator? , 'хххх');


    Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
    Edit this page | View other revisions
    Print this page | View XML
    Find page by browsing, searching or an index
    Edited December 2, 2004 (diff)
    Valid XHTML 1.0!Valid CSS!