Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume I/2-7
2-7 ヘルパー・ノティフィケーション
4.0 新フィーチャセットがサポートされていれば、ヘルパー・ノティフィケーション sysNotifyHelperEvent が定義されています。このノティフィケーションは、アプリケーションが他のアプリケーションにサービスをリクエストするためのものです。Palm OS 4.0 では、ダイヤルアプリケーションだけが sysNotifyHelperEvent によるサービスを提供するアプリケーションでした。具体的には、ダイヤルアプリケーションはこのノティフィケーションに応答して電話のダイヤルを行ないます。アドレス帳はダイヤルアプリケーションを使用して、ユーザーが選択した電話番号をダイヤルします。アプリケーションから sysNotifyHelperEvent をブロードキャストすることで、同じようにダイヤルアプリケーションを利用することができます。また、サービスを提供する側を作成することもできます。
このセクションでは、sysNotifyHelperEvent ノティフィケーションに応答するアプリケーションをヘルパー、ノティフィケーションをブロードキャストする側をブロードキャスターと呼びます。
ヘルパーは sysNotifyHelperEvent の通知を登録します。このノティフィケーションハンドラでは、ヘルパーは自分が提供するサービスに関係するリクエストに応答して処理を行ないます。
アクションは、サービスの情報を提供するか、あるいはサービスを実行するためにリクエストすることを指します。sysNotifyHelperEvent の詳細情報の構造体(HelperNotifyEventType)は3つのアクションを定義しています。
- kHelperNotifyActionCodeEnumerate は、ヘルパーに対して実行できるサービスを列挙するようリクエストします。
- kHelperNotifyActionCodeValidate は、ヘルパーに対してサービスが実行可能であることを確認するためのリクエストです。
- kHelperNotifyActionCodeExecute は、実際にサービスを実行するためのリクエストです。
可能な サービスは HelperServiceClass.h で定義され、「 Palm OS Programmer's API Reference 」の 809 ページにある“ヘルパーAPI”の章で解説されています。これらのサービスは電話番号をダイヤルしたり、電子メールやSMSメッセージを送信したり、あるいはFAXを送信したりします。独自のサービスを定義したければ、そのサービスのために一意なクリエータIDを登録する必要があります。そのかわりとして、アプリケーションのクリエータIDを使うことができます。
このセクションでは、ヘルパーAPIについて説明します。ヘルパーAPIには、sysNotifyHelperEvent およびその SysNotifyParamType 構造体の notifyDetailsP メンバが指すデータ構造体が含まれています。以下のトピックがあります。
- ヘルパー API を使う場合
- ヘルパーサービスのリクエスト
- ヘルパーの作成
ヘルパー API を使う場合
4.0 新フィーチャセットがサポートされていれば、アプリケーションがハンドヘルド内の他のアプリケーションとコミュニケーションをとる方法がいくつかあります。まず、アプリケーションは他のアプリケーションに起動コードを送信(この章の「2-3 プログラムからのアプリケーション起動」を参照)できますし、エクスチェンジマネージャとローカルエクスチェンジライブラリを使って他のアプリケーションにデータを送信することもできます( Volume II の「1 オブジェクトエクスチェンジ」を参照)。あるいは、ヘルパーAPIを使用してサービスを実行するようリクエストすることもできます。状況によってどの方式を使うのが最適かを判断するのは難しいかもしれません。
ヘルパーAPIは、以下のような状況で使うのがベストです。
- 4.0 新フィーチャセットが存在している
- リクエストを受信するアプリケーションについてなにも知らない場合。ヘルパーAPIは、送信側と受信側が互いについてなにも知らない場合でも通信を行なうことが可能です。これは起動コードのメカニズムとは対照的です。起動コードの送信側は受信側のカード番号とローカルIDがわかっていなければなりません。
- 様々な種類のプログラムと通信を行ないたい場合。ヘルパーAPIはノティフィケーションなので、シェアードライブラリやその他のコードリソースでもヘルパーになることができます。起動コードはアプリケーションしか受信することができません。エクスチェンジマネージャも起動コードを介して機能するため、アプリケーションとしか通信できません。
ヘルパーサービスのリクエスト
リスト 2.8 に、アプリケーションがどのようにダイヤルサービスをリクエストするかを示します。一般的に、サービスをリクエストするには以下のことをする必要があります。
- サービスが利用可能であることを確認するには、毎回 kHelperNotifyActionCodeValidate アクションで sysNotifyHelperEvent をブロードキャストします。例えば、アドレス帳は一覧画面を初期化する際、アクションコード kHelperNotifyActionCodeValidate でノティフィケーションをブロードキャストすることでダイヤルサービスが利用可能かどうかをチェックしています。ダイヤルアプリケーションはテレフォニーライブラリがオープンされていることを確認します。オープンされていれば、SysNotifyParamType 構造体の handled メンバに true をセットし、オープンされていなければ、false をセットします。ノティフィケーションのブロードキャスト後に handled が false だった場合、アドレス帳はダイヤルのメニュー項目を表示しません。
- サービスを実行したい時に kHelperNotifyActionCodeExecute アクションを指定して sysNotifyHelperEvent をブロードキャストします。リスト 2.8 を参照して下さい。
- 全ての実行可能なサービスのリストを取得したければ、kHelperNotifyActionCodeEnumerate アクションを指定して sysNotifyHelperEvent をブロードキャストします。アプリケーションの起動時や、システムのリセット時、あるいはサービスを提供したいタスクをユーザーが実行したときなどに使用することになるかもしれません。
リスト 2.8 ヘルパーサービスのリクエスト
Boolean PrvDialListDialSelected(FormType* frmP) { SysNotifyParamType param; HelperNotifyEventType details; HelperNotifyExecuteType execute; param.notifyType = sysNotifyHelperEvent; param.broadcaster = sysFileCAddress; param.notifyDetailsP = &details; param.handled = false; details.version = kHelperNotifyCurrentVersion; details.actionCode = kHelperNotifyActionCodeExecute; details.data.executeP = &execute; execute.serviceClassID = kHelperServiceClassIDVoiceDial; execute.helperAppID = 0; execute.dataP = FldGetTextPtr(ToolsGetFrmObjectPtr(frmP, DialListNumberField)); execute.displayedName = gDisplayName; execute.detailsP = 0; execute.err = errNone; SysNotifyBroadcast(¶m); // Check error code if (!param.handled) // Not handled so exit the list - Unexpected error return true; else return (execute.err == errNone); }
sysNotifyHelperEvent をブロードキャストする際、以下の点は重要なので注意してください。
- ノティフィケーションを同期的にブロードキャストするために、常に SysNotifyBroadcast を使って下さい。
- ノティフィケーションの notifyDetailsP パラメータは HelperNotifyEventType を指しています。この構造体によって、ブロードキャスターはヘルパーと通信をすることができます。
- ヘルパーはメモリをアロケートして HelperNotifyEventType 構造体に追加するかもしれません。特にアクションコードが kHelperNotifyActionCodeEnumerate の場合、ヘルパーは少なくとも1つの HelperNotifyEnumerateListType 構造体をアロケートして HelperNotifyEventType 構造体の data フィールドに追加します。ヘルパーがアロケートしたメモリでも、開放はブロードキャスターが行なう必要があります。
- ブロードキャスターは helperAppID を指定することで、リクエストされたサービスを提供するヘルパーのうち、特定のものと直接やりとりすることができます。例えば、2つのアプリケーションがダイヤルサービスを提供しているとします。ブロードキャスターはサービス列挙アクションを通して2つのアプリケーションを発見すると、ユーザーにどちらのアプリケーションを使ってダイヤルするかを選択させます。列挙アクションをブロードキャストする際、ヘルパーID は指定されていないので全てのヘルパーが応答します。ユーザーがヘルパーを選択した後は、ブロードキャスターが確認と実行のためにヘルパーのクリエータIDを helperAppID フィールドにセットします。ヘルパーは helperAppID をチェックし、自分のクリエータIDと一致するかゼロの場合だけノティフィケーションに応答しなければなりません。
- dataP フィールドには、サービスの実行に必要なデータが含まれています。ダイヤルサービスでは、dataP はダイヤルする電話番号を格納しています。他に追加の情報が必要または望ましい場合に備えて、detailsP フィールドが用意されています。電子メールやSMS メッセージをリクエストしているのであれば、detailsP フィールドを使用して送信メッセージを渡します。詳細については「 Palm OS Programmer's API Reference 」の 809 ページにある“ヘルパーAPI”の章を参照して下さい。
- SysNotifyParamType の handled フィールドと HelperNotifyEventType の err フィールドは結果を返すために使用されます。ブロードキャストの前には常に、handled は false に、err は errNone にセットされ、ブロードキャストが完了すると値がチェックされます。ヘルパーはサービスを実行したかどうかを示すために handled を使用します。handled が true の場合、サービスの実行に成功したかどうかを示すために err を使用します。
ヘルパーの作成
ヘルパーを作成するには、以下の手順に従います。
- sysNotifyHelperEvent の受信を登録します。このノティフィケーションを登録するのは、起動コード sysAppLaunchCmdSyncNotify と sysAppLaunchCmdSystemReset の応答時が最適です。これによって最初のインストール時に登録され、システムのリセット時に毎回再登録されます。
- ノティフィケーションハンドラでは、3種類のアクション ── 列挙、実行、および 確認 ── を処理します。注意が必要なのは、列挙がオプションでアドレス帳が現在それを使用していないとしても、他のサードパーティ製アプリケーションが列挙アクションを送信してくる場合に備えて応答できるようにしておかなければならないということです。
ダイヤルアプリケーションが列挙と確認のアクションに対してどのように応答しているかをリスト 2.9 とリスト 2.10 に示します。列挙アクションがヘルパーに対し、メモリをアロケートして SysNotifyParamType パラメータブロックの notifyDetailsP が指す HelperNotifyEventType 構造体に追加するよう要求していることに注意してください。
この場合、notifyDetailsP->dataP は HelperNotifyEnumerateListType 構造体のリンクドリストになっています。各ヘルパーはサービス毎にこの構造体をアロケートし、リストの末尾に追加しなければなりません。ブロードキャスターはノティフィケーションのブロードキャストが完了した後でこれらの構造体を全て開放する責任があります。
リスト 2.9 提供されているサービスの列挙
Boolean PrvAppEnumerate(HelperNotifyEventType *helperNotifyEventP) { HelperNotifyEnumerateListType* newNodeP; MemHandle handle; MemPtr stringP; newNodeP = MemPtrNew(sizeof(HelperNotifyEnumerateListType)); // Get name to display in user interface. handle = DmGetResource(strRsc, HelperAppNameString); stringP = MemHandleLock(handle); StrCopy(newNodeP->helperAppName, stringP); MemHandleUnlock(handle); DmReleaseResource(handle); // Get name of service to display in UI. handle = DmGetResource(strRsc, HelperActionNameString); stringP = MemHandleLock(handle); StrCopy(newNodeP->actionName, stringP); MemHandleUnlock(handle); DmReleaseResource(handle); newNodeP->serviceClassID = kHelperServiceClassIDVoiceDial; newNodeP->helperAppID = kDialCreator; newNodeP->nextP = 0; // Add the new node. if (helperNotifyEventP->data.enumerateP == 0) { helperNotifyEventP->data.enumerateP = newNodeP; } else { HelperNotifyEnumerateListType* nodeP; nodeP = helperNotifyEventP->data.enumerateP; //Look for the end of the list. while ( nodeP->nextP != 0 ) nodeP = nodeP->nextP; nodeP->nextP = newNodeP; } return true; }
リスト 2.10 では、ダイヤルアプリケーションがどのようにして確認アクションに応答しているかを示しています。
リスト 2.10 確認アクションの応答
Boolean PrvAppValidate (SysNotifyParamType *sysNotifyParamP) { HelperNotifyEventType* helperNotifyEvent; helperNotifyEvent = sysNotifyParamP->notifyDetailsP; // Check version if (helperNotifyEvent->version < 1) return false; // Check service if (helperNotifyEvent-> data.validateP->serviceClassID != kHelperServiceClassIDVoiceDial) return false; // check appId (either null or me) if ((helperNotifyEvent->data.validateP->helperAppID != 0) && (helperNotifyEvent->data.validateP->helperAppID != kDialCreator)) return false; // Check Telephony library presence if (!PrvAppCheckTelephony()) return false; sysNotifyParamP->handled = true; return true; }
ヘルパーを作成する場合、以下の点にも注意してください。
- helperAppID を常にチェックして、0 か自分のクリエータIDと一致する場合だけ応答するようにします。確認と実行のアクションでは、ブロードキャスターは helperAppID を使用して目当てのヘルパーとだけやりとりをする可能性があります。
- アクションを処理したら handled に true をセットします。サービスの実行に失敗した場合、notifyDetailsP の err フィールドを設定します。
- サービスを実行する前に必ず handled フィールドをチェックします。他のヘルパーがサービスを実行できる場合、サービスを実行する前に他のヘルパーによってサービスが実行されていないかを確認する必要があります。handled が true ならば既にサービスは実行されています。
- 他の全てのノティフィケーション同様、ノティフィケーションハンドラは大域変数にアクセスできないことに注意してください。アクセスしなければならないデータがある場合、SysNotifyRegister の userDataP パラメータを介して渡すようにします。サービスが完全に終了する前にノティフィケーションハンドラの処理を復帰させたい場合、サービスを完了させるのに必要なパラメータブロックのデータをコピーするようにしてください。