Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume I/1-2
1-2 Palm OS プログラミングのコンセプト
Palm OS アプリケーションは通常、単一スレッドのイベント駆動型プログラムであり、同時に実行されるプログラムは1つだけです。Palm OS アプリケーションを作成するためには、システムがどのように組織化され、またアプリケーションがどのように組織化されるのかを理解する必要があります。
- それぞれのアプリケーションは C プログラムの main 関数にあたる PilotMain 関数を持ちます。アプリケーションを起動するために、システムは PilotMain 関数を呼び出して起動コードを渡します。起動コードは、アプリケーションをアクティブにしてそのユーザーインターフェースを表示(これを通常起動といいます)させたり、あるいはアプリケーションに小さな仕事をさせ、ユーザーインターフェースを表示することなく終了させたりします。PilotMain 関数の唯一の目的は、起動コードを受け取ってそれに応答することです。(「 2 アプリケーションの開始と終了 」を参照して下さい )
- Palm OS はイベントベースのオペレーティングシステムです。ですから、Palm OS アプリケーションはイベントループを持つことになります。しかし、このイベントループは通常起動に応答する時だけ動作します。他の起動コードに応答する場合、アプリケーションはイベントループの外側で動作しなければなりません。「 3 イベントループ 」では、イベントループについて説明しています。
- ほとんどの Palm OS アプリケーションはフォームによるユーザインターフェースを持っています。フォームというのは、デスクトップアプリケーションのウィンドウのようなものです。ユーザーインターフェースには、あらかじめ定義された UI 要素( UI オブジェクトとも言われます )と、カスタムユーザーインターフェースがあります。(「 4 ユーザーインターフェース 」を参照して下さい )
- 全てのアプリケーションはシステムによって提供されるメモリやデータの管理機構を使用しなければなりません。(「 5 メモリ 」、および「 6 ファイルとデータベース 」を参照して下さい )
- アプリケーションは、Palm OS API を呼び出すことによってその機能が実装されます。Palm OS は、特定の機能を実現する関数群によってグループ分けされたいくつかのマネージャで構成されています。ルールとして、同じマネージャに属する全ての関数には同じプレフィクスが付与され、特定の機能を共同で実現するために実装されます。マネージャは、例えば音を鳴らしたり、アラームを発生させたり、ネットワーク通信を行なったり、あるいは赤外線ポートを通して情報をビームしたりします。Palm OS の機能性を一覧する良い方法は、本書と「 Palm OS Programmer's Companion Volume II. Communications 」の目次をざっと眺めることです。
- IMPORTANT
- ANSI C ライブラリは Palm 開発プラットフォームの一部に含まれていません。多くの場合、ANSI C の関数と同等の Palm OS API を利用することができます。例えば、Palm OS は ANSI C プログラムで使えるような文字列処理の多くを備えたストリングマネージャを提供しています。C 標準ライブラリの関数を使ってしまうと、その関数のコードがアプリケーションにリンクされ、結果として実行可能ファイルが大きくなってしまいます。
API の命名に関する慣習
Palm OS API には、一貫して以下の慣習が適用されます。
- 関数名は大文字で始まります。
- 全ての関数は特定のマネージャに属し、2文字か3文字で始まる ──“Ctl”ならばコントロール関係の関数、“Ftr”ならばフィーチャマネージャといった ── プレフィクスによって識別されます。
- イベントやその他の定数は小文字で始まります。
- 構造体のメンバは小文字で始まります。
- グローバル変数名は大文字で始まります。
- typedef による別名は小文字で始まり、“Type”で終わります(例:DateTime.h の DateFormatType)。
- Macintosh ResEdit のリソースタイプは、例えば tSTR や tTBL のように通常小文字で始まり大文字3文字が続きます(開発パッケージによって提供されるカスタム Macintosh リソースは MENU などのように全て大文字です。また、Talt など慣習に従わないものもいくつかあります)。
- 列挙型のメンバは以下に示すように小文字のプレフィクスで始まり、大文字の名前が続きます。
enum formObjects { frmFieldObj, frmControlObj, frmListObj, frmTableObj, frmBitmapObj, frmLineObj, frmFrameObj, frmRectangleObj, frmLabelObj, frmTitleObj, frmPopupObj, frmGraffitiStateObj, frmGadgetObj }; typedef enum formObjects FormObjectKind;
プログラムのPalm OS 環境との協調
ユーザーは Palm OS アプリケーションを使用している時、他のアプリケーションに切り替えたり、Graffiti や Graffiti 2 といった強力な入力ソフト、あるいはオンスクリーンキーボードを使ったり、グローバル検索で情報を検索したり、アラームを受けたりできることを期待します。
このセクションのガイドラインに従えば、アプリケーションをうまく他と協調させることができます。以下の要領でシステムソフトウェアと協調させます。
- sysAppLaunchCmdNormalLaunch 起動コードを処理します。
- 必要に応じて他の起動コードを処理するか、あるいは無視します。詳細については「 2 アプリケーションの開始と終了 」を参照してください。
- システムプリファレンスを正しく処理します。システムプリファレンスには以下の表示書式の設定が格納されています。
- 日付の書式
- 時刻の書式
- 数値の書式
- 週の最初の曜日(日曜か月曜)
アプリケーションが数値や日付、時刻、週の開始曜日の表示にシステムプリファレンスを使用していることを確認して下さい。方法については、「 システムプリファレンスへのアクセス 」を参照して下さい。
- システムが以下のメッセージをポストできるようにします。
- アラーム
- バッテリ残量警告
- 同期処理中のシステムメッセージ
事実上全ての Palm OS アプリケーションが使用している通常のイベントループは、システムがメッセージをポストして必要なイベントを処理するのに十分な時間的余裕を持っています。必要なのは、長時間に及ぶ処理に特に注意することだけです。例えば、20,000 レコードを越えるような大きなデータベースを持つアプリケーションがそのレコード全体を対象として検索するような場合、そのループ中でシステムイベントをチェックした方が良いでしょう。
- アプリケーションが入力エリアや入力エリアのボタン、あるいは電源ボタンを無効化しないようにします。
- Graffiti シフトインジケータが常に見えるようにします。
さらに、以下のルールも守りましょう。
- アプリケーションのデータベースにではなく、プリファレンス用のデータベースに設定を保存します。詳細は「アプリケーション設定の保存 」 を参照して下さい。
- アプリケーションがシリアルポートを使用するのであれば、必要がなくなり次第 HotSync アプリケーションが利用できるようにポートを閉じて下さい。
- アプリケーションがグローバル検索を正しく処理していることを確認して下さい。通常、検索とソートは大文字・小文字を区別しません。
- アプリケーションがプライベートレコードをサポートするのであれば、非表示設定の時にはグローバル検索にはかからないようにします。
- ランチャアプリケーションと協調するために、アプリケーション名と2つのアイコン、およびバージョン文字列を用意します。詳細は「 4-17 アプリケーションランチャ 」を参照して下さい。
- 「 Palm OS User Interface Guidelines 」のガイドラインに従います。
- 同期処理の実行中と実行後のシステムメッセージを正しく処理します。
- 削除されたレコードが表示されないようにします。
- アプリケーションがカテゴリ数の最大値を越えないようにします。15カテゴリと、お約束の「未分類」、の合わせて16カテゴリです。
- アプリケーションは、ユーザーが起動した際に一貫性のある初期状態を使用して下さい。
- いくつかのアプリケーションは、起動時の状態が固定になっています。例えば、Date Book は起動すると常にその日の情報を表示します。
- その他のアプリケーションでは、ユーザーが前回終了した時の状態を再現します。この場合、前回終了時の状態が再現できない場合に表示する初期状態が必要なことを忘れないで下さい。なぜなら、HotSync やプリファレンスがあるために、ユーザーが最後に使用した状態からデータがそのままであるという仮定はできないからです。
- アプリケーションがサウンド機能を使用する場合、警告や確認のサウンドを正しく使って下さい。
頑丈なコードを書くこと
プログラムをより頑丈に、そして将来の Palm OS デバイスと互換性を向上させるために、以下のガイドラインと実践に従うことを強く推奨します。
仮定条件のチェック
所々に ErrNonFatalDisplayIf 関数の呼出を追加することで、守りの堅いコードを書くことができます。これによって、デバッグビルドにおいて仮定条件のチェックを行うことができます。多くのバグはこの方法で捕捉でき、しかも出荷するコードには負担をかけません。リリースビルドでも重要なチェックを残したければ、ErrFatalDisplayIf 関数を使うことができます。
継続的なポーリングを避ける
バッテリを節約するため、継続的なポーリングを避ける必要があります。アプリケーションがウェイトループをしているなら、代わりに短いインターバルのポーリング(例えば1秒に10回とか)に切り替えます。Palm OS SDK に付属の Hardball サンプルアプリケーションのイベントループは、これを実現する方法を示しています。
NULL(あるいは low memory )に対する読込み・書込みを避ける
メモリを確保する関数( MemSet, MemMove や同様の関数 )をコールする場合、それらの関数が返したポインタがNULLでないことを確認してください。( もっと厳密な妥当性確認ができるならそれに越したことはありません。)構造体やその他の関数から取得したポインタについても NULL でないことをチェックすべきです。また、デバッグビルドにおいて MemMove( や同様の関数 )を #define で上書きし、渡されたパラメータを検証することを検討して下さい。
※訳注:「メモリを確保する関数」としか冒頭部分は訳しようがないと判断し ましたが、MemSet や MemMove はメモリを確保しません。「メモリを 操作する関数」とすることも考えましたが、そうすると後ろの文章と の関係がおかしくなります。
ダイナミックヒープを節約する
本当にそうする必要性がない限り、Palm OS 2.0 以上で利用できるダイナミックヒープ領域を使わないことは重要です。ヒープの無駄使いは、アプリケーションを最新のハンドヘルドでしか使えないものにしてしまいます。その場合、すでに市場に出回っているたくさんのデバイスで使えないということになってしまうでしょう。
IrDA スタックや検索ウィンドウなど、システムサービスによってはアプリケーションが動作中でもメモリを確保するものがあることに注意してください。例えば、赤外線やその他の外部入力からの受信が始まると、システムは入力されてくるデータのために新たなヒープ領域を必要とします。そこにあるからというだけの理由で全てのダイナミックメモリを使ったりせず、大量の一時データにはストレージヒープを使用することを検討して下さい。
メモリアロケート時には復帰値をチェックする
将来のハンドヘルドのメモリが増えるのか減るのかは分かりませんから、メモリをアロケートした時に注意深く復帰値をチェックするのは良いことです。大きなデータを扱う際にストレージヒープ(と可能ならばファイルストリーム)を使うのも良い習慣です。
ゼロバイト幅のアロケートを避ける
ゼロバイト幅のバッファを確保すること、およびバッファをゼロバイトにリサイズすることはできません。Palm OS 2.0 以前ではこれは問題ありませんでしたが、それ以降のバージョンのOSではゼロバイト幅のオブジェクトは許可されません。
画面に関する仮定を避ける
スクリーンバッファの配置やサイズ、ピクセルあたりのビット数は石碑に刻まれたように固定されているわけではありません。それは変化するものです。ウィンドウや描画に関連したAPIをハックしないで下さい。もしAPIを迂回するためにハードウェアをハックするのであれば、状態を保存しておき、終わった後で元に戻して下さい。
大域やハードウェアに直接アクセスしない
大域のデータやその配置は変わり得るものです。災難を避けるために、ドキュメントされたAPIを使い、テストしたバージョンのOS以外では動作を抑止しましょう。将来のハンドヘルドは、現在のものとは異なるプロセッサ上で動作するかもしれません。
同様の理由で、カードへの参照もハードコードしてはいけません。現在のPalm OS デバイスが1つのカードスロットしか備えていないからといって、それがいつでも正しいとは限りません。ですから、カードを操作するデータマネージャやファイルストリーミングのような関数をコールする時は、ハードコードされたカード番号0を渡すかわりに対象のカードを参照する変数を渡すようにして下さい。
標準アプリケーションは変更されうる
標準アプリケーションのプリファレンス(やデータ)は変更されうるものです。防衛的なコードを書きましょう。そして、テストしていないバージョンのOS上では動作を抑止することを検討して下さい。